History

fw_cfg: write vmcoreinfo details

If the "etc/vmcoreinfo" fw_cfg file is present and we are not running the kdump kernel, write the addr/size of the vmcoreinfo ELF note. The DMA operation is expected to run synchronously with today qemu, but the specification states that it may become async, so we run "control" field check in a loop for eventual changes.

Marc-André Lureau committed 8 years ago

Commit 2d6d60a1 parent 43d4cb42 files · +173 −3Browse files

Unified · Split

2 files
  1. drivers/firmware/qemu_fw_cfg.c +142 −3
  2. include/uapi/linux/qemu_fw_cfg.h +31 −0
drivers/firmware/qemu_fw_cfg.c+142−3
@@ -34,11 +34,17 @@ · 33 unmodified lines
34#include <linux/io.h>34#include <linux/io.h>
35#include <linux/ioport.h>35#include <linux/ioport.h>
36#include <uapi/linux/qemu_fw_cfg.h>36#include <uapi/linux/qemu_fw_cfg.h>
37#include <linux/delay.h>
38#include <linux/crash_dump.h>
39#include <linux/crash_core.h>
37 40
38MODULE_AUTHOR("Gabriel L. Somlo <somlo@cmu.edu>");41MODULE_AUTHOR("Gabriel L. Somlo <somlo@cmu.edu>");
39MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");42MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
40MODULE_LICENSE("GPL");43MODULE_LICENSE("GPL");
41 44
45/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
46static u32 fw_cfg_rev;
47
42/* fw_cfg device i/o register addresses */48/* fw_cfg device i/o register addresses */
43static bool fw_cfg_is_mmio;49static bool fw_cfg_is_mmio;
44static phys_addr_t fw_cfg_p_base;50static phys_addr_t fw_cfg_p_base;
@@ -60,6 +66,66 @@ static void fw_cfg_sel_endianness(u16 key) · 15 unmodified lines
60 iowrite16(key, fw_cfg_reg_ctrl);66 iowrite16(key, fw_cfg_reg_ctrl);
61}67}
62 68
69#ifdef CONFIG_CRASH_CORE
70static inline bool fw_cfg_dma_enabled(void)
71{
72 return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
73}
74
75/* qemu fw_cfg device is sync today, but spec says it may become async */
76static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
77{
78 for (;;) {
79 u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
80
81 /* do not reorder the read to d->control */
82 rmb();
83 if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
84 return;
85
86 cpu_relax();
87 }
88}
89
90static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
91{
92 phys_addr_t dma;
93 struct fw_cfg_dma_access *d = NULL;
94 ssize_t ret = length;
95
96 d = kmalloc(sizeof(*d), GFP_KERNEL);
97 if (!d) {
98 ret = -ENOMEM;
99 goto end;
100 }
101
102 /* fw_cfg device does not need IOMMU protection, so use physical addresses */
103 *d = (struct fw_cfg_dma_access) {
104 .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
105 .length = cpu_to_be32(length),
106 .control = cpu_to_be32(control)
107 };
108
109 dma = virt_to_phys(d);
110
111 iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
112 /* force memory to sync before notifying device via MMIO */
113 wmb();
114 iowrite32be(dma, fw_cfg_reg_dma + 4);
115
116 fw_cfg_wait_for_control(d);
117
118 if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
119 ret = -EIO;
120 }
121
122end:
123 kfree(d);
124
125 return ret;
126}
127#endif
128
63/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */129/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
64static ssize_t fw_cfg_read_blob(u16 key,130static ssize_t fw_cfg_read_blob(u16 key,
65 void *buf, loff_t pos, size_t count)131 void *buf, loff_t pos, size_t count)
@@ -89,6 +155,47 @@ static ssize_t fw_cfg_read_blob(u16 key, · 23 unmodified lines
89 return count;155 return count;
90}156}
91 157
158#ifdef CONFIG_CRASH_CORE
159/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
160static ssize_t fw_cfg_write_blob(u16 key,
161 void *buf, loff_t pos, size_t count)
162{
163 u32 glk = -1U;
164 acpi_status status;
165 ssize_t ret = count;
166
167 /* If we have ACPI, ensure mutual exclusion against any potential
168 * device access by the firmware, e.g. via AML methods:
169 */
170 status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk);
171 if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
172 /* Should never get here */
173 WARN(1, "%s: Failed to lock ACPI!\n", __func__);
174 return -EINVAL;
175 }
176
177 mutex_lock(&fw_cfg_dev_lock);
178 if (pos == 0) {
179 ret = fw_cfg_dma_transfer(buf, count, key << 16
180 | FW_CFG_DMA_CTL_SELECT
181 | FW_CFG_DMA_CTL_WRITE);
182 } else {
183 fw_cfg_sel_endianness(key);
184 ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
185 if (ret < 0)
186 goto end;
187 ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE);
188 }
189
190end:
191 mutex_unlock(&fw_cfg_dev_lock);
192
193 acpi_release_global_lock(glk);
194
195 return ret;
196}
197#endif /* CONFIG_CRASH_CORE */
198
92/* clean up fw_cfg device i/o */199/* clean up fw_cfg device i/o */
93static void fw_cfg_io_cleanup(void)200static void fw_cfg_io_cleanup(void)
94{201{
@@ -188,9 +295,6 @@ static int fw_cfg_do_platform_probe(struct platform_device *pdev) · 93 unmodified lines
188 return 0;295 return 0;
189}296}
190 297
191/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
192static u32 fw_cfg_rev;
193
194static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)298static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)
195{299{
196 return sprintf(buf, "%u\n", fw_cfg_rev);300 return sprintf(buf, "%u\n", fw_cfg_rev);
@@ -213,6 +317,32 @@ struct fw_cfg_sysfs_entry { · 16 unmodified lines
213 struct list_head list;317 struct list_head list;
214};318};
215 319
320#ifdef CONFIG_CRASH_CORE
321static ssize_t fw_cfg_write_vmcoreinfo(const struct fw_cfg_file *f)
322{
323 static struct fw_cfg_vmcoreinfo *data;
324 ssize_t ret;
325
326 data = kmalloc(sizeof(struct fw_cfg_vmcoreinfo), GFP_KERNEL);
327 if (!data)
328 return -ENOMEM;
329
330 *data = (struct fw_cfg_vmcoreinfo) {
331 .guest_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF),
332 .size = cpu_to_le32(VMCOREINFO_NOTE_SIZE),
333 .paddr = cpu_to_le64(paddr_vmcoreinfo_note())
334 };
335 /* spare ourself reading host format support for now since we
336 * don't know what else to format - host may ignore ours
337 */
338 ret = fw_cfg_write_blob(be16_to_cpu(f->select), data,
339 0, sizeof(struct fw_cfg_vmcoreinfo));
340
341 kfree(data);
342 return ret;
343}
344#endif /* CONFIG_CRASH_CORE */
345
216/* get fw_cfg_sysfs_entry from kobject member */346/* get fw_cfg_sysfs_entry from kobject member */
217static inline struct fw_cfg_sysfs_entry *to_entry(struct kobject *kobj)347static inline struct fw_cfg_sysfs_entry *to_entry(struct kobject *kobj)
218{348{
@@ -452,6 +582,15 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f) · 233 unmodified lines
452 int err;582 int err;
453 struct fw_cfg_sysfs_entry *entry;583 struct fw_cfg_sysfs_entry *entry;
454 584
585#ifdef CONFIG_CRASH_CORE
586 if (fw_cfg_dma_enabled() &&
587 strcmp(f->name, FW_CFG_VMCOREINFO_FILENAME) == 0 &&
588 !is_kdump_kernel()) {
589 if (fw_cfg_write_vmcoreinfo(f) < 0)
590 pr_warn("fw_cfg: failed to write vmcoreinfo");
591 }
592#endif
593
455 /* allocate new entry */594 /* allocate new entry */
456 entry = kzalloc(sizeof(*entry), GFP_KERNEL);595 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
457 if (!entry)596 if (!entry)
include/uapi/linux/qemu_fw_cfg.h+31−0
@@ -54,6 +54,7 @@ · 53 unmodified lines
54 54
55/* FW_CFG_ID bits */55/* FW_CFG_ID bits */
56#define FW_CFG_VERSION 0x0156#define FW_CFG_VERSION 0x01
57#define FW_CFG_VERSION_DMA 0x02
57 58
58/* fw_cfg file directory entry type */59/* fw_cfg file directory entry type */
59struct fw_cfg_file {60struct fw_cfg_file {
@@ -63,4 +64,34 @@ struct fw_cfg_file { · 3 unmodified lines
63 char name[FW_CFG_MAX_FILE_PATH];64 char name[FW_CFG_MAX_FILE_PATH];
64};65};
65 66
67/* FW_CFG_DMA_CONTROL bits */
68#define FW_CFG_DMA_CTL_ERROR 0x01
69#define FW_CFG_DMA_CTL_READ 0x02
70#define FW_CFG_DMA_CTL_SKIP 0x04
71#define FW_CFG_DMA_CTL_SELECT 0x08
72#define FW_CFG_DMA_CTL_WRITE 0x10
73
74#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
75
76/* Control as first field allows for different structures selected by this
77 * field, which might be useful in the future
78 */
79struct fw_cfg_dma_access {
80 __be32 control;
81 __be32 length;
82 __be64 address;
83};
84
85#define FW_CFG_VMCOREINFO_FILENAME "etc/vmcoreinfo"
86
87#define FW_CFG_VMCOREINFO_FORMAT_NONE 0x0
88#define FW_CFG_VMCOREINFO_FORMAT_ELF 0x1
89
90struct fw_cfg_vmcoreinfo {
91 __le16 host_format;
92 __le16 guest_format;
93 __le32 size;
94 __le64 paddr;
95};
96
66#endif97#endif