From 48972f8cad24eb4462c97ea68003e2dd35be0444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20H=C3=A4hnel?= <marcus.haehnel@kernkonzept.com> Date: Wed, 20 Oct 2021 14:55:04 +0200 Subject: [PATCH] optionrom: add a DMA-enabled multiboot ROM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 | 1 + pc-bios/multiboot_dma.bin | Bin 0 -> 1024 bytes pc-bios/optionrom/Makefile | 4 +- pc-bios/optionrom/multiboot.S | 4 +- pc-bios/optionrom/multiboot_dma.S | 2 + pc-bios/optionrom/optionrom.h | 66 ++++++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 pc-bios/multiboot_dma.bin create mode 100644 pc-bios/optionrom/multiboot_dma.S diff --git a/pc-bios/meson.build b/pc-bios/meson.build index a44c9bc1275..b40ff3f2bd3 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -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 index 0000000000000000000000000000000000000000..c0e2c3102a3358207c61d3ae113524fb6007abc3 GIT binary patch literal 1024 zcmWGt#dMkhE0AGO3CIgzWP(XPVtNi|+kgdoPW0XQ^(U?8MB2dzENML#(+)mlN$Y%^ z#&|QW`K3Zy^BaS-gD+Y7UZ!=+tzk-IJe-==DaXLDn}Z>>Q;vn9TkZ~1YNs3<Lt3}o zJ(x5HLz>}%z5_eB8FmS<zTYLt`X=q*0}f<@|3q5n!5v(9<&UTFpHB-<Gdz$MuuFtB z?R^^m$+W<<9b61T3~Br)(gM;tAEfc0*d@W5_C7tWn?(gAxbols|Nl!rq%|KAz;F7& z7c6}b&I+Z?NJ(4F!jO`-(10NgBz7Rp@OGNv|K{T?X*)$27#PxaD7;``NZS?Q=o@@i zv`APjJ+0IKPa5O-lukPxhP2k(rB@99r|n{35MW5Lw$ouKF>5}~qL$WNE5KN)qL$X} z%97T4pj1jNt(!H?@=%eWS{kz}N1ElKV)nGoLx%rfpHfR>uKn}+a9ZOlkQr$QUvZ_R zb&7E?q^9vRim@@I?O<eJVBl9ekec>ikAY!_00RR<--W&#eFyp;^u0*i!NHKWO8^u& zpil+{G7R&d=scLVgB_3basKn+h6e)Dc8RdQ=RX;^gNs3sf&WB6=L7x|X}cs?-*>a9 z@SlJL=$Gar0%<!0@ECRw6fwA+a(D;RhPB%NA2Kj7ykulx-~gvQ2=V_v0|UdX^9*2m t5|p0D0Od0<s55L~Vqge#^$lgnEzK#(Ov=wMQOL<pOi3+*7%)oa0{}$1FAx9# literal 0 HcmV?d00001 diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index 3482508a863..5d55d25acca 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -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 diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S index b7efe4de343..181a4b03a3f 100644 --- a/pc-bios/optionrom/multiboot.S +++ b/pc-bios/optionrom/multiboot.S @@ -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 index 00000000000..d809af3e23f --- /dev/null +++ b/pc-bios/optionrom/multiboot_dma.S @@ -0,0 +1,2 @@ +#define USE_FW_CFG_DMA 1 +#include "multiboot.S" diff --git a/pc-bios/optionrom/optionrom.h b/pc-bios/optionrom/optionrom.h index a2b612f1a7e..8d74c0ddf35 100644 --- a/pc-bios/optionrom/optionrom.h +++ b/pc-bios/optionrom/optionrom.h @@ -37,6 +37,17 @@ #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; \ @@ -62,6 +73,61 @@ 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; \ -- GitLab