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 <gorcunov@gmail.com>
This commit is contained in:
Cyrill Gorcunov
2015-06-01 16:39:40 +01:00
committed by Will Deacon
parent 307a9af02d
commit 28ce0d664b
13 changed files with 110 additions and 158 deletions
+12 -25
View File
@@ -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
+18 -12
View File
@@ -4,6 +4,8 @@
#include <string.h>
#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);
}
+50 -8
View File
@@ -1,5 +1,5 @@
/*
* IRQ 0x10 handler - output in video memory
* Our pretty trivial BIOS emulation
*/
#include <kvm/bios.h>
@@ -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)
+12
View File
@@ -0,0 +1,12 @@
#include <kvm/assembly.h>
.org 0
#ifdef CONFIG_X86_64
.code64
#else
.code32
#endif
GLOBAL(bios_rom)
.incbin "bios/bios-rom.bin"
END(bios_rom)
+13
View File
@@ -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"
-12
View File
@@ -1,12 +0,0 @@
#include <kvm/bios.h>
#include <kvm/assembly.h>
.org 0
#ifdef CONFIG_X86_64
.code64
#else
.code32
#endif
GLOBAL(bios_int10)
.incbin "bios/int10-real.bin"
GLOBAL(bios_int10_end)
-50
View File
@@ -1,50 +0,0 @@
/*
* IRQ 0x15 handler - e820 memory map
*/
#include <kvm/bios.h>
#include <kvm/assembly.h>
.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)
-12
View File
@@ -1,12 +0,0 @@
#include <kvm/bios.h>
#include <kvm/assembly.h>
.org 0
#ifdef CONFIG_X86_64
.code64
#else
.code32
#endif
GLOBAL(bios_int15)
.incbin "bios/int15-real.bin"
GLOBAL(bios_int15_end)
-15
View File
@@ -1,15 +0,0 @@
/*
* BIOS fake interrupt stub, it does nothing
* and lockless
*/
#include <kvm/bios.h>
#include <kvm/assembly.h>
.org 0
.code16gcc
ENTRY(___intfake)
IRET
GLOBAL(___intfake_end)
-12
View File
@@ -1,12 +0,0 @@
#include <kvm/bios.h>
#include <kvm/assembly.h>
.org 0
#ifdef CONFIG_X86_64
.code64
#else
.code32
#endif
GLOBAL(bios_intfake)
.incbin "bios/intfake-real.bin"
GLOBAL(bios_intfake_end)
+2 -1
View File
@@ -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
+3 -11
View File
@@ -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);