From e9d504bb8ff0cf6148d5c26eb3a90caee5ebca86 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 16 Jul 2010 15:44:26 +0300 Subject: [PATCH] kvm: Use proper segment + offset in e820 bios This patch fixes E820 BIOS emulation on AMD CPUs that, unlike Intel ones, require proper 16-bit segment/offset addressing in virtualized 16-bit mode. Reported-by: Asias He Tested-by: Asias He Acked-by: Cyrill Gorcunov Signed-off-by: Pekka Enberg --- tools/kvm/bios/bios-rom.S | 3 --- tools/kvm/bios/e820.c | 17 +++++++++++++++-- tools/kvm/include/kvm/segment.h | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 tools/kvm/include/kvm/segment.h diff --git a/tools/kvm/bios/bios-rom.S b/tools/kvm/bios/bios-rom.S index 0a8e69584c0b..0119c11e52e3 100644 --- a/tools/kvm/bios/bios-rom.S +++ b/tools/kvm/bios/bios-rom.S @@ -79,9 +79,6 @@ ENTRY(bios_int15) pushl %ebx pushl %eax - xor %ax, %ax - mov %ax, %fs - movl %esp, %eax call e820_query_map diff --git a/tools/kvm/bios/e820.c b/tools/kvm/bios/e820.c index 8d8b1c7a87b9..7f3f86f213b6 100644 --- a/tools/kvm/bios/e820.c +++ b/tools/kvm/bios/e820.c @@ -1,8 +1,14 @@ #include "kvm/e820.h" +#include "kvm/segment.h" #include "kvm/bios.h" #include "kvm/util.h" +static inline void set_fs(uint16_t seg) +{ + asm volatile("movw %0,%%fs" : : "rm" (seg)); +} + static inline uint8_t rdfs8(unsigned long addr) { uint8_t v; @@ -15,23 +21,30 @@ static inline uint8_t rdfs8(unsigned long addr) void e820_query_map(struct e820_query *query) { uint8_t map_size; + uint16_t fs_seg; uint32_t ndx; + fs_seg = flat_to_seg16(E820_MAP_SIZE); + set_fs(fs_seg); + ndx = query->ebx; - map_size = rdfs8(E820_MAP_SIZE); + map_size = rdfs8(flat_to_off16(E820_MAP_SIZE, fs_seg)); if (ndx < map_size) { unsigned long start; unsigned int i; uint8_t *p; + fs_seg = flat_to_seg16(E820_MAP_START); + set_fs(fs_seg); + 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); + *p++ = rdfs8(flat_to_off16(start + i, fs_seg)); } query->eax = SMAP; diff --git a/tools/kvm/include/kvm/segment.h b/tools/kvm/include/kvm/segment.h new file mode 100644 index 000000000000..0701cd7b4629 --- /dev/null +++ b/tools/kvm/include/kvm/segment.h @@ -0,0 +1,16 @@ +#ifndef KVM_SEGMENT_H +#define KVM_SEGMENT_H + +#include + +static inline uint16_t flat_to_seg16(uint32_t address) +{ + return address >> 4; +} + +static inline uint16_t flat_to_off16(uint32_t address, uint32_t segment) +{ + return address - (segment << 4); +} + +#endif /* KVM_SEGMENT_H */ -- 2.39.5