]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm: Use proper segment + offset in e820 bios
authorPekka Enberg <penberg@cs.helsinki.fi>
Fri, 16 Jul 2010 12:44:26 +0000 (15:44 +0300)
committerPekka Enberg <penberg@cs.helsinki.fi>
Mon, 19 Jul 2010 05:30:26 +0000 (08:30 +0300)
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 <asias.hejun@gmail.com>
Tested-by: Asias He <asias.hejun@gmail.com>
Acked-by: Cyrill Gorcunov <gorcunov@gmail.com>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
tools/kvm/bios/bios-rom.S
tools/kvm/bios/e820.c
tools/kvm/include/kvm/segment.h [new file with mode: 0644]

index 0a8e69584c0bac37b4fbb53ed5c5cdf183ae15b1..0119c11e52e329ce0d78b320aded2903f7274db4 100644 (file)
@@ -79,9 +79,6 @@ ENTRY(bios_int15)
        pushl   %ebx
        pushl   %eax
 
-       xor     %ax, %ax
-       mov     %ax, %fs
-
        movl    %esp, %eax
        call    e820_query_map
 
index 8d8b1c7a87b93b246a68f2325e22f51d228c1375..7f3f86f213b64ff81f0eaf8d06df84d565ad2040 100644 (file)
@@ -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 (file)
index 0000000..0701cd7
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef KVM_SEGMENT_H
+#define KVM_SEGMENT_H
+
+#include <stdint.h>
+
+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 */