[SeaBIOS] [PATCH 1/2] Add QEMU fw_cfg DMA interface
Marc Marí
markmb at redhat.com
Thu Aug 6 11:02:32 CET 2015
Add support for the new fw_cfg DMA interface. The protocol is explained in
QEMU documentation.
Signed-off-by: Marc Marí <markmb at redhat.com>
---
src/fw/paravirt.c | 48 +++++++++++++++++++++++++++++++++++++++++++++---
src/fw/paravirt.h | 17 +++++++++++++++++
2 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c
index db22ae8..287bf23 100644
--- a/src/fw/paravirt.c
+++ b/src/fw/paravirt.c
@@ -30,6 +30,13 @@ u32 RamSize;
u64 RamSizeOver4G;
// Type of emulator platform.
int PlatformRunningOn VARFSEG;
+// cfg_dma enabled
+int cfg_dma_enabled = 0;
+
+inline int qemu_cfg_dma_enabled(void)
+{
+ return cfg_dma_enabled;
+}
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
* should be used to determine that a VM is running under KVM.
@@ -201,14 +208,39 @@ qemu_cfg_select(u16 f)
static void
qemu_cfg_read(void *buf, int len)
{
- insb(PORT_QEMU_CFG_DATA, buf, len);
+ if (qemu_cfg_dma_enabled()) {
+ QemuCfgDmaAccess access;
+
+ access.address = (u64)(u32)buf;
+ access.length = len;
+ access.control = QEMU_CFG_DMA_CTL_READ;
+
+ /*
+ * The out is done before the write of the variables on memory. This
+ * causes misread on the QEMU side.
+ */
+ barrier();
+
+ outl((u32)&access, PORT_QEMU_CFG_DMA_ADDR);
+ while(access.length != 0 && !(access.control & QEMU_CFG_DMA_CTL_ERROR));
+ } else {
+ insb(PORT_QEMU_CFG_DATA, buf, len);
+ }
}
static void
qemu_cfg_skip(int len)
{
- while (len--)
- inb(PORT_QEMU_CFG_DATA);
+ if (len == 0) {
+ return;
+ }
+
+ if (qemu_cfg_dma_enabled()) {
+ qemu_cfg_read(NULL, len);
+ } else {
+ while (len--)
+ inb(PORT_QEMU_CFG_DATA);
+ }
}
static void
@@ -422,8 +454,18 @@ void qemu_cfg_init(void)
for (i = 0; i < 4; i++)
if (inb(PORT_QEMU_CFG_DATA) != sig[i])
return;
+
dprintf(1, "Found QEMU fw_cfg\n");
+ // Detect DMA interface.
+ u32 id;
+ qemu_cfg_read_entry(&id, QEMU_CFG_ID, sizeof(id));
+
+ if (id == QEMU_CFG_DMA_ID) {
+ dprintf(1, "QEMU fw_cfg DMA interface supported\n");
+ cfg_dma_enabled = 1;
+ }
+
// Populate romfiles for legacy fw_cfg entries
qemu_cfg_legacy();
diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h
index 95ffb92..05b4997 100644
--- a/src/fw/paravirt.h
+++ b/src/fw/paravirt.h
@@ -9,6 +9,12 @@
#define PF_XEN (1<<1)
#define PF_KVM (1<<2)
+typedef struct QemuCfgDmaAccess {
+ u64 address;
+ u32 length;
+ u32 control;
+} QemuCfgDmaAccess;
+
extern u32 RamSize;
extern u64 RamSizeOver4G;
extern int PlatformRunningOn;
@@ -29,9 +35,20 @@ static inline int runningOnKVM(void) {
#define PORT_SMI_STATUS 0x00b3
#define PORT_QEMU_CFG_CTL 0x0510
#define PORT_QEMU_CFG_DATA 0x0511
+#define PORT_QEMU_CFG_DMA_ADDR 0x0512
+
+// QEMU_CFG_DMA_CONTROL bits
+#define QEMU_CFG_DMA_CTL_ERROR 0x01
+#define QEMU_CFG_DMA_CTL_READ 0x02
+#define QEMU_CFG_DMA_CTL_MASK 0x03
+
+// QEMU_CFG_DMA ID bit
+#define QEMU_CFG_DMA_ID 2
+int qemu_cfg_dma_enabled(void);
void qemu_preinit(void);
void qemu_platform_setup(void);
void qemu_cfg_init(void);
+void qemu_cfg_dma_boot_linux();
#endif
--
2.4.3
More information about the SeaBIOS
mailing list