From 28ce0d664b37944adf410efdb999846105b4e29e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 14 Jul 2010 21:28:59 +0400 Subject: [PATCH] kvm, bios: BIOS code redesign Instead of keeping bios code in various bin junks make it to host in one binary blob. This blob gets copied to a predefined place at startup and IVT handlers set as appropriate. Also we need to generate header file which will contain BIOS tourine offsets for symbols being used. Signed-off-by: Cyrill Gorcunov --- Makefile | 37 +++++++------------ bios.c | 30 +++++++++------- bios/{int10-real.S => bios-rom.S} | 58 +++++++++++++++++++++++++----- bios/bios.S | 12 +++++++ bios/gen-offsets.sh | 13 +++++++ bios/int10.S | 12 ------- bios/int15-real.S | 50 -------------------------- bios/int15.S | 12 ------- bios/intfake-real.S | 15 -------- bios/intfake.S | 12 ------- bios/{bios-strip.ld.S => rom.ld.S} | 0 include/kvm/assembly.h | 3 +- include/kvm/bios-export.h | 14 ++------ 13 files changed, 110 insertions(+), 158 deletions(-) rename bios/{int10-real.S => bios-rom.S} (56%) create mode 100644 bios/bios.S create mode 100644 bios/gen-offsets.sh delete mode 100644 bios/int10.S delete mode 100644 bios/int15-real.S delete mode 100644 bios/int15.S delete mode 100644 bios/intfake-real.S delete mode 100644 bios/intfake.S rename bios/{bios-strip.ld.S => rom.ld.S} (100%) diff --git a/Makefile b/Makefile index 953b934..aa26499 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,7 @@ OBJS += main.o OBJS += mmio.o OBJS += util.o OBJS += bios.o -OBJS += bios/intfake.o -OBJS += bios/int10.o -OBJS += bios/int15.o +OBJS += bios/bios.o uname_M := $(shell uname -m | sed -e s/i.86/i386/) ifeq ($(uname_M),i386) @@ -69,34 +67,22 @@ $(OBJS): BIOS_CFLAGS += -m32 BIOS_CFLAGS += -march=i386 BIOS_CFLAGS += -mregparm=3 -bios/intfake.o: bios/intfake.S bios/intfake-real.S - $(E) " CC " $@ - $(Q) $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s bios/intfake-real.S -o bios/intfake-real.o - $(E) " LD " $@ - $(Q) ld -T bios/bios-strip.ld.S -o bios/intfake-real.bin.elf bios/intfake-real.o - $(E) " OBJCOPY " $@ - $(Q) objcopy -O binary -j .text bios/intfake-real.bin.elf bios/intfake-real.bin - $(Q) $(CC) $(CFLAGS) -c bios/intfake.S -o bios/intfake.o -bios/int10.o: bios/int10.S bios/int10-real.S +bios.o: bios/bios-rom.bin +bios/bios.o: bios/bios.S bios/bios-rom.bin $(E) " CC " $@ - $(Q) $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s bios/int10-real.S -o bios/int10-real.o - $(E) " LD " $@ - $(Q) ld -T bios/bios-strip.ld.S -o bios/int10-real.bin.elf bios/int10-real.o - $(E) " OBJCOPY " $@ - $(Q) objcopy -O binary -j .text bios/int10-real.bin.elf bios/int10-real.bin - $(Q) $(CC) $(CFLAGS) -c bios/int10.S -o bios/int10.o - -bios/int15.o: bios/int10.S bios/int15-real.S + $(Q) $(CC) -c $(CFLAGS) bios/bios.S -o bios/bios.o + +bios/bios-rom.bin: bios/bios-rom.S bios/e820.c $(E) " CC " $@ $(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s bios/e820.c -o bios/e820.o - $(E) " CC " $@ - $(Q) $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s bios/int15-real.S -o bios/int15-real.o + $(Q) $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s bios/bios-rom.S -o bios/bios-rom.o $(E) " LD " $@ - $(Q) ld -T bios/bios-strip.ld.S -o bios/int15-real.bin.elf bios/int15-real.o bios/e820.o + $(Q) ld -T bios/rom.ld.S -o bios/bios-rom.bin.elf bios/bios-rom.o bios/e820.o $(E) " OBJCOPY " $@ - $(Q) objcopy -O binary -j .text bios/int15-real.bin.elf bios/int15-real.bin - $(Q) $(CC) $(CFLAGS) -c bios/int15.S -o bios/int15.o + $(Q) objcopy -O binary -j .text bios/bios-rom.bin.elf bios/bios-rom.bin + $(E) " NM " $@ + $(Q) cd bios && sh gen-offsets.sh > bios-rom.h && cd .. check: $(PROGRAM) $(MAKE) -C tests @@ -108,6 +94,7 @@ clean: $(Q) rm -f bios/*.bin $(Q) rm -f bios/*.elf $(Q) rm -f bios/*.o + $(Q) rm -f bios/bios-rom.h $(Q) rm -f $(OBJS) $(PROGRAM) .PHONY: clean diff --git a/bios.c b/bios.c index aef4402..df1d368 100644 --- a/bios.c +++ b/bios.c @@ -4,6 +4,8 @@ #include +#include "bios/bios-rom.h" + static void bios_setup_irq_handler(struct kvm *kvm, unsigned int address, unsigned int irq, void *handler, unsigned int size) { @@ -19,40 +21,44 @@ static void bios_setup_irq_handler(struct kvm *kvm, unsigned int address, interrupt_table__set(&kvm->interrupt_table, &intr_desc, irq); } +#define BIOS_IRQ_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name) +#define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name]) +#define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name)) + void setup_bios(struct kvm *kvm) { unsigned long address = MB_BIOS_BEGIN; struct real_intr_desc intr_desc; void *p; + /* just copy the bios rom into the place */ + p = guest_flat_to_host(kvm, MB_BIOS_BEGIN); + memcpy(p, bios_rom, bios_rom_size); + /* * Setup a *fake* real mode vector table, it has only * one real hadler which does just iret */ - address = BIOS_NEXT_IRQ_ADDR(address, 0); - p = guest_flat_to_host(kvm, address); - memcpy(p, bios_intfake, bios_intfake_size); + address = BIOS_IRQ_ADDR(bios_intfake); intr_desc = (struct real_intr_desc) { .segment = REAL_SEGMENT(address), .offset = REAL_OFFSET(address), }; interrupt_table__setup(&kvm->interrupt_table, &intr_desc); - /* - * int 0x10 - */ - address = BIOS_NEXT_IRQ_ADDR(address, bios_intfake_size); - bios_setup_irq_handler(kvm, address, 0x10, bios_int10, bios_int10_size); + /* int 0x10 */ + address = BIOS_IRQ_ADDR(bios_int10); + bios_setup_irq_handler(kvm, address, 0x10, BIOS_IRQ_FUNC(bios_int10), BIOS_IRQ_SIZE(bios_int10)); /* - * We don't have valid BIOS yet so we put one single memory - * region in e820 memory map + * e820 memory map * * int 0x15 */ - address = BIOS_NEXT_IRQ_ADDR(address, bios_int10_size); - bios_setup_irq_handler(kvm, address, 0x15, bios_int15, bios_int15_size); + address = BIOS_IRQ_ADDR(bios_int15); + bios_setup_irq_handler(kvm, address, 0x15, BIOS_IRQ_FUNC(bios_int15), BIOS_IRQ_SIZE(bios_int15)); + /* we almost done */ p = guest_flat_to_host(kvm, 0); interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE); } diff --git a/bios/int10-real.S b/bios/bios-rom.S similarity index 56% rename from bios/int10-real.S rename to bios/bios-rom.S index 58c3c09..0a8e695 100644 --- a/bios/int10-real.S +++ b/bios/bios-rom.S @@ -1,5 +1,5 @@ /* - * IRQ 0x10 handler - output in video memory + * Our pretty trivial BIOS emulation */ #include @@ -10,6 +10,13 @@ #include "macro.S" +/* + * fake interrupt handler, nothing can be faster ever + */ +ENTRY(bios_intfake) + IRET +ENTRY_END(bios_intfake) + /* * int 10 - video - write character and advance cursor (tty write) * ah = 0eh @@ -19,10 +26,10 @@ * * We ignore bx settings */ -ENTRY(___int10) +ENTRY(bios_int10) cli test $0x0e, %ah - jne out + jne 1f /* * put char in AL at current cursor and @@ -49,16 +56,51 @@ putchar_new: pop %fs stack_restore -out: +1: sti IRET /* * private IRQ data */ cursor: .long 0 +ENTRY_END(bios_int10) + +#define EFLAGS_CF (1 << 0) + +ENTRY(bios_int15) + cmp $0xE820, %eax + jne 1f + + pushw %fs + + pushl %edx + pushl %ecx + pushl %edi + pushl %ebx + pushl %eax + + xor %ax, %ax + mov %ax, %fs + + movl %esp, %eax + call e820_query_map + + popl %eax + popl %ebx + popl %edi + popl %ecx + popl %edx + + popw %fs + + /* Clear CF */ + andl $~EFLAGS_CF, 0x4(%esp) +1: + IRET +ENTRY_END(bios_int15) + +GLOBAL(__locals) -/* - * must be last in this file - */ #include "local.S" -ENTRY_END(___int10_end) + +END(__locals) diff --git a/bios/bios.S b/bios/bios.S new file mode 100644 index 0000000..e840dde --- /dev/null +++ b/bios/bios.S @@ -0,0 +1,12 @@ +#include + + .org 0 +#ifdef CONFIG_X86_64 + .code64 +#else + .code32 +#endif + +GLOBAL(bios_rom) + .incbin "bios/bios-rom.bin" +END(bios_rom) diff --git a/bios/gen-offsets.sh b/bios/gen-offsets.sh new file mode 100644 index 0000000..d954e11 --- /dev/null +++ b/bios/gen-offsets.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +echo "/* Autogenerated file, don't edit */" +echo "#ifndef BIOS_OFFSETS_H" +echo "#define BIOS_OFFSETS_H" + +echo "" +echo "#define BIOS_ENTRY_SIZE(name) (name##_end - name)" +echo "" + +nm bios-rom.bin.elf | grep ' [:Tt:] ' | awk '{ print "#define BIOS_OFFSET__" $3 " 0x" $1; }' + +echo "#endif" diff --git a/bios/int10.S b/bios/int10.S deleted file mode 100644 index 06d5b66..0000000 --- a/bios/int10.S +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - - .org 0 -#ifdef CONFIG_X86_64 - .code64 -#else - .code32 -#endif -GLOBAL(bios_int10) - .incbin "bios/int10-real.bin" -GLOBAL(bios_int10_end) diff --git a/bios/int15-real.S b/bios/int15-real.S deleted file mode 100644 index 4ef95d3..0000000 --- a/bios/int15-real.S +++ /dev/null @@ -1,50 +0,0 @@ -/* - * IRQ 0x15 handler - e820 memory map - */ - -#include -#include - - .org 0 - .code16gcc - -#include "macro.S" - -#define EFLAGS_CF (1 << 0) - -ENTRY(___int15) - cmp $0xE820, %eax - jne out - - pushw %fs - - pushl %edx - pushl %ecx - pushl %edi - pushl %ebx - pushl %eax - - xor %ax, %ax - mov %ax, %fs - - movl %esp, %eax - call e820_query_map - - popl %eax - popl %ebx - popl %edi - popl %ecx - popl %edx - - popw %fs - - /* Clear CF */ - andl $~EFLAGS_CF, 0x4(%esp) -out: - IRET - -/* - * must be last in this file - */ -#include "local.S" -ENTRY_END(___int15_end) diff --git a/bios/int15.S b/bios/int15.S deleted file mode 100644 index c7e17ff..0000000 --- a/bios/int15.S +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - - .org 0 -#ifdef CONFIG_X86_64 - .code64 -#else - .code32 -#endif -GLOBAL(bios_int15) - .incbin "bios/int15-real.bin" -GLOBAL(bios_int15_end) diff --git a/bios/intfake-real.S b/bios/intfake-real.S deleted file mode 100644 index 593ad83..0000000 --- a/bios/intfake-real.S +++ /dev/null @@ -1,15 +0,0 @@ -/* - * BIOS fake interrupt stub, it does nothing - * and lockless - */ - -#include -#include - - .org 0 - .code16gcc - -ENTRY(___intfake) - IRET -GLOBAL(___intfake_end) - diff --git a/bios/intfake.S b/bios/intfake.S deleted file mode 100644 index 8be50b6..0000000 --- a/bios/intfake.S +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - - .org 0 -#ifdef CONFIG_X86_64 - .code64 -#else - .code32 -#endif -GLOBAL(bios_intfake) - .incbin "bios/intfake-real.bin" -GLOBAL(bios_intfake_end) diff --git a/bios/bios-strip.ld.S b/bios/rom.ld.S similarity index 100% rename from bios/bios-strip.ld.S rename to bios/rom.ld.S diff --git a/include/kvm/assembly.h b/include/kvm/assembly.h index 85549aa..e70baab 100644 --- a/include/kvm/assembly.h +++ b/include/kvm/assembly.h @@ -11,7 +11,8 @@ .globl name; \ name: -#define ENTRY_END(name) +#define ENTRY_END(name) GLOBAL(name##_end) +#define END(name) GLOBAL(name##_end) /* * gas produces size override prefix with which diff --git a/include/kvm/bios-export.h b/include/kvm/bios-export.h index c312c5c..23825aa 100644 --- a/include/kvm/bios-export.h +++ b/include/kvm/bios-export.h @@ -3,18 +3,10 @@ struct kvm; -extern char bios_intfake[0]; -extern char bios_intfake_end[0]; +extern char bios_rom[0]; +extern char bios_rom_end[0]; -extern char bios_int10[0]; -extern char bios_int10_end[0]; - -extern char bios_int15[0]; -extern char bios_int15_end[0]; - -#define bios_intfake_size (bios_intfake_end - bios_intfake) -#define bios_int10_size (bios_int10_end - bios_int10) -#define bios_int15_size (bios_int15_end - bios_int15) +#define bios_rom_size (bios_rom_end - bios_rom) extern void setup_bios(struct kvm *kvm);