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
3434 #include <linux/io.h>
3535 #include <linux/ioport.h>
3636 #include <uapi/linux/qemu_fw_cfg.h>
37+#include <linux/delay.h>
38+#include <linux/crash_dump.h>
39+#include <linux/crash_core.h>
3740
3841 MODULE_AUTHOR("Gabriel L. Somlo <somlo@cmu.edu>");
3942 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
4043 MODULE_LICENSE("GPL");
4144
45+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
46+static u32 fw_cfg_rev;
47+
4248 /* fw_cfg device i/o register addresses */
4349 static bool fw_cfg_is_mmio;
4450 static phys_addr_t fw_cfg_p_base;
@@ -60,6 +66,66 @@ static void fw_cfg_sel_endianness(u16 key) · 15 unmodified lines
6066 iowrite16(key, fw_cfg_reg_ctrl);
6167 }
6268
69+#ifdef CONFIG_CRASH_CORE
70+static 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 */
76+static 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+
90+static 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+
122+end:
123+ kfree(d);
124+
125+ return ret;
126+}
127+#endif
128+
63129 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
64130 static ssize_t fw_cfg_read_blob(u16 key,
65131 void *buf, loff_t pos, size_t count)
@@ -89,6 +155,47 @@ static ssize_t fw_cfg_read_blob(u16 key, · 23 unmodified lines
89155 return count;
90156 }
91157
158+#ifdef CONFIG_CRASH_CORE
159+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
160+static 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+
190+end:
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+
92199 /* clean up fw_cfg device i/o */
93200 static void fw_cfg_io_cleanup(void)
94201 {
@@ -188,9 +295,6 @@ static int fw_cfg_do_platform_probe(struct platform_device *pdev) · 93 unmodified lines
188295 return 0;
189296 }
190297
191−/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
192−static u32 fw_cfg_rev;
193−
194298 static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)
195299 {
196300 return sprintf(buf, "%u\n", fw_cfg_rev);
@@ -213,6 +317,32 @@ struct fw_cfg_sysfs_entry { · 16 unmodified lines
213317 struct list_head list;
214318 };
215319
320+#ifdef CONFIG_CRASH_CORE
321+static 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+
216346 /* get fw_cfg_sysfs_entry from kobject member */
217347 static inline struct fw_cfg_sysfs_entry *to_entry(struct kobject *kobj)
218348 {
@@ -452,6 +582,15 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f) · 233 unmodified lines
452582 int err;
453583 struct fw_cfg_sysfs_entry *entry;
454584
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+
455594 /* allocate new entry */
456595 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
457596 if (!entry)
include/uapi/linux/qemu_fw_cfg.h+31−0
@@ -54,6 +54,7 @@ · 53 unmodified lines
5454
5555 /* FW_CFG_ID bits */
5656 #define FW_CFG_VERSION 0x01
57+#define FW_CFG_VERSION_DMA 0x02
5758
5859 /* fw_cfg file directory entry type */
5960 struct fw_cfg_file {
@@ -63,4 +64,34 @@ struct fw_cfg_file { · 3 unmodified lines
6364 char name[FW_CFG_MAX_FILE_PATH];
6465 };
6566
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+ */
79+struct 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+
90+struct fw_cfg_vmcoreinfo {
91+ __le16 host_format;
92+ __le16 guest_format;
93+ __le32 size;
94+ __le64 paddr;
95+};
96+
6697 #endif