]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm: BIOS E820 memory map emulation
authorPekka Enberg <penberg@cs.helsinki.fi>
Thu, 8 Jul 2010 18:27:35 +0000 (21:27 +0300)
committerPekka Enberg <penberg@cs.helsinki.fi>
Sat, 10 Jul 2010 21:07:20 +0000 (00:07 +0300)
This patch adds BIOS E820 memory map emulation to KVM.

Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
tools/kvm/Makefile
tools/kvm/bios/e820.c [new file with mode: 0644]
tools/kvm/bios/int15-real.S
tools/kvm/code16gcc.h [new file with mode: 0644]
tools/kvm/include/kvm/bios.h
tools/kvm/include/kvm/e820.h [new file with mode: 0644]
tools/kvm/include/kvm/kvm.h
tools/kvm/kvm.c
tools/kvm/main.c

index a6f73f888bb5c1d3246516dd79dda37745eb6752..eef578d784ccb59a37d05e800ff944f70ebb56f5 100644 (file)
@@ -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 (file)
index 0000000..4032871
--- /dev/null
@@ -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 */
+}
index dc4f73489106e0dde59d87f7c3339d3ea829d707..c30215fd063093d42e085cd4b7dbdfba1aedb198 100644 (file)
 
 #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 (file)
index 0000000..d93e480
--- /dev/null
@@ -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
index 6767bd980f0590d2a3de8ea9079b5042c5b62b2f..e5730841a6a9a84daa058ead3ad520af6789594f 100644 (file)
 #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
 
 #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 (file)
index 0000000..8cde738
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef KVM_E820_H
+#define KVM_E820_H
+
+#include <stdint.h>
+
+#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 */
index d7f4685bf7776a4b670a3fb03d2e823cdc24cb7b..7acca0e1589c6e105273e4d67da5196a60f80d07 100644 (file)
@@ -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);
index a2bedcaf449f3d8590529aa3fe8fe25312304610..045fcd8729b3f2cb865b738d4f6155b7641898ff 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "kvm/interrupt.h"
 #include "kvm/cpufeature.h"
+#include "kvm/e820.h"
 #include "kvm/util.h"
 
 #include <linux/kvm.h>
@@ -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)
index 6711f85d1ef3abefbe72a862e69ac7b4fee5a27f..57ae33babdcfe8e136dc03870cc2fcd289dd7124 100644 (file)
@@ -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);