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:
parent
f014c97459
commit
48972f8cad
@ -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
BIN
pc-bios/multiboot_dma.bin
Normal file
Binary file not shown.
@ -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
|
||||
|
@ -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
|
||||
|
2
pc-bios/optionrom/multiboot_dma.S
Normal file
2
pc-bios/optionrom/multiboot_dma.S
Normal file
@ -0,0 +1,2 @@
|
||||
#define USE_FW_CFG_DMA 1
|
||||
#include "multiboot.S"
|
@ -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; \
|
||||
|
Loading…
Reference in New Issue
Block a user