From: Pekka Enberg Date: Thu, 8 Jul 2010 18:27:35 +0000 (+0300) Subject: kvm: BIOS E820 memory map emulation X-Git-Tag: next-20110824~3^2~528^2~102 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=febd1686dfd888dd7e2b69e7eeb1935987d4869b;p=karo-tx-linux.git kvm: BIOS E820 memory map emulation This patch adds BIOS E820 memory map emulation to KVM. Signed-off-by: Pekka Enberg --- diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index a6f73f888bb5..eef578d784cc 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -87,10 +87,12 @@ bios/int10.o: bios/int10.S bios/int10-real.S $(Q) $(CC) $(CFLAGS) -c bios/int10.S -o bios/int10.o bios/int15.o: bios/int10.S bios/int15-real.S + $(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 $(E) " LD " $@ - $(Q) ld -T bios/bios-strip.ld.S -o bios/int15-real.bin.elf bios/int15-real.o + $(Q) ld -T bios/bios-strip.ld.S -o bios/int15-real.bin.elf bios/int15-real.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 diff --git a/tools/kvm/bios/e820.c b/tools/kvm/bios/e820.c new file mode 100644 index 000000000000..4032871849a8 --- /dev/null +++ b/tools/kvm/bios/e820.c @@ -0,0 +1,46 @@ +#include "kvm/e820.h" + +#include "kvm/bios.h" +#include "kvm/util.h" + +static inline void outb(uint8_t v, uint16_t port) +{ + asm volatile("outb %0,%1" : : "a" (v), "dN" (port)); +} + +static inline uint8_t rdfs8(unsigned long addr) +{ + uint8_t v; + asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*(uint8_t *)addr)); + return v; +} + +void e820_query_map(struct e820_query *query) +{ + uint8_t map_size; + uint32_t ndx; + + ndx = query->ebx; + + map_size = rdfs8(E820_MAP_SIZE); + + if (ndx < map_size) { + unsigned long start; + unsigned int i; + uint8_t *p; + + start = E820_MAP_START + sizeof(struct e820_entry) * ndx; + + p = (void *) query->edi; + + for (i = 0; i < sizeof(struct e820_entry); i++) + *p++ = rdfs8(start + i); + } + + query->eax = SMAP; + query->ecx = 20; + query->ebx = ++ndx; + + if (ndx >= map_size) + query->ebx = 0; /* end of map */ +} diff --git a/tools/kvm/bios/int15-real.S b/tools/kvm/bios/int15-real.S index dc4f73489106..c30215fd0630 100644 --- a/tools/kvm/bios/int15-real.S +++ b/tools/kvm/bios/int15-real.S @@ -10,28 +10,39 @@ #include "macro.S" +#define EFLAGS_CF (1 << 0) + ENTRY(___int15) - jmp out + cmp $0xE820, %eax + jne out + + pushw %fs + + pushl %edx + pushl %ecx + pushl %edi + pushl %ebx + pushl %eax + + xor %ax, %ax + mov %ax, %fs -# movl %cs, %eax -# movl %eax, %es -# movl $0x534D4150, %eax # 'SMAP' -# movl $0, %ebx # end of map -# movl $20, %ecx -# mov e820entry_start, %di -# mov $(e820entry_end - e820entry_start), %ecx + 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: sti IRET -/* - * private IRQ data - */ -GLOBAL(e820entry_start) - e820entry_addr: .quad 0 - e820entry_size: .quad 0 - e820entry_type: .long 0 -GLOBAL(e820entry_end) /* * must be last in this file diff --git a/tools/kvm/code16gcc.h b/tools/kvm/code16gcc.h new file mode 100644 index 000000000000..d93e48010b61 --- /dev/null +++ b/tools/kvm/code16gcc.h @@ -0,0 +1,15 @@ +/* + * code16gcc.h + * + * This file is -include'd when compiling 16-bit C code. + * Note: this asm() needs to be emitted before gcc emits any code. + * Depending on gcc version, this requires -fno-unit-at-a-time or + * -fno-toplevel-reorder. + * + * Hopefully gcc will eventually have a real -m16 option so we can + * drop this hack long term. + */ + +#ifndef __ASSEMBLY__ +asm(".code16gcc"); +#endif diff --git a/tools/kvm/include/kvm/bios.h b/tools/kvm/include/kvm/bios.h index 6767bd980f05..e5730841a6a9 100644 --- a/tools/kvm/include/kvm/bios.h +++ b/tools/kvm/include/kvm/bios.h @@ -18,6 +18,15 @@ #define REAL_MODE_IVT_BEGIN 0x00000000 #define REAL_MODE_IVT_END 0x000003ff +#define BDA_START 0x00000400UL +#define BDA_END 0x000004FFUL + +#define EBDA_START 0x0009FC00UL +#define EBDA_END 0x0009FFFFUL + +#define E820_MAP_SIZE EBDA_START +#define E820_MAP_START (EBDA_START + 0x01) + #define MB_BIOS_BEGIN 0x000f0000 #define MB_BIOS_END 0x000fffff @@ -39,14 +48,6 @@ #define MB_BIOS_SS 0xFFF7 #define MB_BIOS_SP 0x40 -#define E820_RAM 1 -#define E820_RESERVED 2 -#define E820_ACPI 3 -#define E820_NVS 4 -#define E820_UNUSABLE 5 - -#define E820_MAP_OFFSET 64 - #define ALIGN(x, a) \ (((x) + ((a) - 1)) & ~((a) - 1)) diff --git a/tools/kvm/include/kvm/e820.h b/tools/kvm/include/kvm/e820.h new file mode 100644 index 000000000000..8cde73835fde --- /dev/null +++ b/tools/kvm/include/kvm/e820.h @@ -0,0 +1,27 @@ +#ifndef KVM_E820_H +#define KVM_E820_H + +#include + +#define SMAP 0x534d4150 /* ASCII "SMAP" */ + +#define E820_MEM_USABLE 1 +#define E820_MEM_RESERVED 2 + +struct e820_entry { + uint64_t addr; /* start of memory segment */ + uint64_t size; /* size of memory segment */ + uint32_t type; /* type of memory segment */ +} __attribute__((packed)); + +struct e820_query { + uint32_t eax; + uint32_t ebx; + uint32_t edi; + uint32_t ecx; + uint32_t edx; +}; + +void e820_query_map(struct e820_query *query); + +#endif /* KVM_E820_H */ diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index d7f4685bf777..7acca0e1589c 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -37,6 +37,7 @@ void kvm__setup_cpuid(struct kvm *self); void kvm__enable_singlestep(struct kvm *self); bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename, const char *kernel_cmdline); void kvm__reset_vcpu(struct kvm *self); +void kvm__setup_mem(struct kvm *self); void kvm__run(struct kvm *self); bool kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count); bool kvm__emulate_mmio(struct kvm *self, uint64_t phys_addr, uint8_t *data, uint32_t len, uint8_t is_write); diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index a2bedcaf449f..045fcd8729b3 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -2,6 +2,7 @@ #include "kvm/interrupt.h" #include "kvm/cpufeature.h" +#include "kvm/e820.h" #include "kvm/util.h" #include @@ -526,6 +527,38 @@ void kvm__reset_vcpu(struct kvm *self) kvm__setup_msrs(self); } +void kvm__setup_mem(struct kvm *self) +{ + struct e820_entry *mem_map; + unsigned char *size; + + size = guest_flat_to_host(self, E820_MAP_SIZE); + mem_map = guest_flat_to_host(self, E820_MAP_START); + + *size = 4; + + mem_map[0] = (struct e820_entry) { + .addr = REAL_MODE_IVT_BEGIN, + .size = BDA_END - REAL_MODE_IVT_BEGIN, + .type = E820_MEM_RESERVED, + }; + mem_map[1] = (struct e820_entry) { + .addr = BDA_END, + .size = EBDA_END - BDA_END, + .type = E820_MEM_USABLE, + }; + mem_map[2] = (struct e820_entry) { + .addr = EBDA_END, + .size = BZ_KERNEL_START - EBDA_END, + .type = E820_MEM_RESERVED, + }; + mem_map[3] = (struct e820_entry) { + .addr = BZ_KERNEL_START, + .size = self->ram_size - BZ_KERNEL_START, + .type = E820_MEM_USABLE, + }; +} + void kvm__run(struct kvm *self) { if (ioctl(self->vcpu_fd, KVM_RUN, 0) < 0) diff --git a/tools/kvm/main.c b/tools/kvm/main.c index 6711f85d1ef3..57ae33babdcf 100644 --- a/tools/kvm/main.c +++ b/tools/kvm/main.c @@ -93,6 +93,8 @@ int main(int argc, char *argv[]) kvm__reset_vcpu(kvm); + kvm__setup_mem(kvm); + if (single_step) kvm__enable_singlestep(kvm);