optionrom: add a DMA-enabled multiboot ROM

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>
This commit is contained in:
Marcus Hähnel 2021-10-20 14:55:04 +02:00 committed by Paolo Bonzini
parent f014c97459
commit 48972f8cad
6 changed files with 72 additions and 5 deletions

View 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',

BIN
pc-bios/multiboot_dma.bin Normal file

Binary file not shown.

View 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

View 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

View file

@ -0,0 +1,2 @@
#define USE_FW_CFG_DMA 1
#include "multiboot.S"

View file

@ -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; \