]> xenbits.xensource.com Git - qemu-xen.git/commitdiff
optionrom: add a DMA-enabled multiboot ROM
authorMarcus Hähnel <marcus.haehnel@kernkonzept.com>
Wed, 20 Oct 2021 12:55:04 +0000 (14:55 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 2 Nov 2021 14:57:27 +0000 (15:57 +0100)
Add a new option rom for the multiboot loader, using DMA transfers to copy
data instead of "rep insb".

This significantly lowers QEMU's startup latency by a factor of about 40,
for example, going from 30sec to 0.8sec when loading modules of 120MB
in size.

Signed-off-by: Marcus Hähnel <marcus.haehnel@kernkonzept.com>
Signed-off-by: Adam Lackorzynski <adam@l4re.org>
[Modified to keep the non-DMA code depending on #ifdef USE_FW_CFG_DMA;
 do not write below stack. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
pc-bios/meson.build
pc-bios/multiboot_dma.bin [new file with mode: 0644]
pc-bios/optionrom/Makefile
pc-bios/optionrom/multiboot.S
pc-bios/optionrom/multiboot_dma.S [new file with mode: 0644]
pc-bios/optionrom/optionrom.h

index a44c9bc12753a8edc7dde78fe120a4f60b58c24f..b40ff3f2bd395f6ef79f49ba4ac85a566ac7307d 100644 (file)
@@ -63,6 +63,7 @@ blobs = files(
   'petalogix-s3adsp1800.dtb',
   'petalogix-ml605.dtb',
   'multiboot.bin',
+  'multiboot_dma.bin',
   'linuxboot.bin',
   'linuxboot_dma.bin',
   'kvmvapic.bin',
diff --git a/pc-bios/multiboot_dma.bin b/pc-bios/multiboot_dma.bin
new file mode 100644 (file)
index 0000000..c0e2c31
Binary files /dev/null and b/pc-bios/multiboot_dma.bin differ
index 3482508a86347dd7e2fad10b1631ccf13254af97..5d55d25acca2619766054cd73d1ee5cf1933629d 100644 (file)
@@ -2,7 +2,7 @@ include config.mak
 SRC_DIR := $(TOPSRC_DIR)/pc-bios/optionrom
 VPATH = $(SRC_DIR)
 
-all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin
+all: multiboot.bin multiboot_dma.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin
 # Dummy command so that make thinks it has done something
        @true
 
@@ -41,8 +41,6 @@ override CFLAGS += $(call cc-option, $(Wa)-32)
 LD_I386_EMULATION ?= elf_i386
 override LDFLAGS = -m $(LD_I386_EMULATION) -T $(SRC_DIR)/flat.lds
 
-all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin
-
 pvh.img: pvh.o pvh_main.o
 
 %.o: %.S
index b7efe4de343138c767d9e7a43d5f13d788f1048a..181a4b03a3f26e85e8cdc815e5e92d64694445f6 100644 (file)
@@ -68,7 +68,7 @@ run_multiboot:
        mov             %eax, %es
 
        /* Read the bootinfo struct into RAM */
-       read_fw_blob(FW_CFG_INITRD)
+       read_fw_blob_dma(FW_CFG_INITRD)
 
        /* FS = bootinfo_struct */
        read_fw         FW_CFG_INITRD_ADDR
@@ -188,7 +188,7 @@ prot_mode:
        movl            %eax, %gs
 
        /* Read the kernel and modules into RAM */
-       read_fw_blob(FW_CFG_KERNEL)
+       read_fw_blob_dma(FW_CFG_KERNEL)
 
        /* Jump off to the kernel */
        read_fw         FW_CFG_KERNEL_ENTRY
diff --git a/pc-bios/optionrom/multiboot_dma.S b/pc-bios/optionrom/multiboot_dma.S
new file mode 100644 (file)
index 0000000..d809af3
--- /dev/null
@@ -0,0 +1,2 @@
+#define USE_FW_CFG_DMA 1
+#include "multiboot.S"
index a2b612f1a7e3b0dc557146e83e6c7d66b09f9624..8d74c0ddf35bfa68aade4ba91025af9e05981701 100644 (file)
 #define BIOS_CFG_IOPORT_CFG    0x510
 #define BIOS_CFG_IOPORT_DATA   0x511
 
+#define FW_CFG_DMA_CTL_ERROR   0x01
+#define FW_CFG_DMA_CTL_READ    0x02
+#define FW_CFG_DMA_CTL_SKIP    0x04
+#define FW_CFG_DMA_CTL_SELECT  0x08
+#define FW_CFG_DMA_CTL_WRITE   0x10
+
+#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
+
+#define BIOS_CFG_DMA_ADDR_HIGH  0x514
+#define BIOS_CFG_DMA_ADDR_LOW   0x518
+
 /* Break the translation block flow so -d cpu shows us values */
 #define DEBUG_HERE \
        jmp             1f;                             \
        bswap           %eax
 .endm
 
+
+/*
+ * Read data from the fw_cfg device using DMA.
+ * Clobbers:   %edx, %eax, ADDR, SIZE, memory[%esp-16] to memory[%esp]
+ */
+.macro read_fw_dma VAR, SIZE, ADDR
+        /* Address */
+       bswapl          \ADDR
+       pushl           \ADDR
+
+       /* We only support 32 bit target addresses */
+       xorl            %eax, %eax
+       pushl           %eax
+       mov             $BIOS_CFG_DMA_ADDR_HIGH, %dx
+       outl            %eax, (%dx)
+
+       /* Size */
+       bswapl          \SIZE
+       pushl           \SIZE
+
+        /* Control */
+       movl            $(\VAR << 16) | (FW_CFG_DMA_CTL_READ | FW_CFG_DMA_CTL_SELECT), %eax
+       bswapl          %eax
+       pushl           %eax
+
+       movl            %esp, %eax /* Address of the struct we generated */
+       bswapl          %eax
+       mov             $BIOS_CFG_DMA_ADDR_LOW, %dx
+       outl            %eax, (%dx) /* Initiate DMA */
+
+1:  mov                (%esp), %eax /* Wait for completion */
+       bswapl          %eax
+       testl           $~FW_CFG_DMA_CTL_ERROR, %eax
+       jnz             1b
+       addl            $16, %esp
+.endm
+
+
+/*
+ * Read a blob from the fw_cfg device using DMA
+ * Requires _ADDR, _SIZE and _DATA values for the parameter.
+ *
+ * Clobbers:   %eax, %edx, %es, %ecx, %edi and adresses %esp-20 to %esp
+ */
+#ifdef USE_FW_CFG_DMA
+#define read_fw_blob_dma(var) \
+       read_fw         var ## _SIZE; \
+       mov             %eax, %ecx; \
+       read_fw         var ## _ADDR; \
+       mov             %eax, %edi ;\
+       read_fw_dma     var ## _DATA, %ecx, %edi
+#else
+#define read_fw_blob_dma(var) read_fw_blob(var)
+#endif
+
 #define read_fw_blob_pre(var)                          \
        read_fw         var ## _SIZE;                   \
        mov             %eax, %ecx;                     \