mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-15 18:05:49 +00:00
kvm: BIOS E820 memory map emulation
This patch adds BIOS E820 memory map emulation to KVM. Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
This commit is contained in:
committed by
Will Deacon
parent
9292f77631
commit
2f3976eeee
@@ -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
|
||||
|
||||
+46
@@ -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 */
|
||||
}
|
||||
+27
-16
@@ -10,28 +10,39 @@
|
||||
|
||||
#include "macro.S"
|
||||
|
||||
#define EFLAGS_CF (1 << 0)
|
||||
|
||||
ENTRY(___int15)
|
||||
jmp out
|
||||
cmp $0xE820, %eax
|
||||
jne out
|
||||
|
||||
# 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
|
||||
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:
|
||||
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
|
||||
|
||||
+15
@@ -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
|
||||
+9
-8
@@ -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))
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user