# HG changeset patch
# User Steven Hand <steven@xxxxxxxxxxxxx>
# Node ID 3236311a23a5083ec78cac53ccad1e92d619e8a1
# Parent ad22c711ccb7c6734e8579f3d13125d467d25b2c
Fix vmxassist to boot Vista.
Currently, guest_linear_to_real to_real() in vmxassist assumes guest HVM
use 2 level page table when entering protect mode with PG enabled. Vista
uses 3 level (PAE enabled) page table, so memory addressing is wrong.
This patch fixes it, by considering all 4 possible cases.
Signed-off-by: Xiaowei Yang <xiaowei.yang@xxxxxxxxx>
---
tools/firmware/vmxassist/machine.h | 1
tools/firmware/vmxassist/vm86.c | 87 ++++++++++++++++++++++++++++---------
2 files changed, 68 insertions(+), 20 deletions(-)
diff -r ad22c711ccb7 -r 3236311a23a5 tools/firmware/vmxassist/machine.h
--- a/tools/firmware/vmxassist/machine.h Fri Sep 22 11:37:31 2006 +0100
+++ b/tools/firmware/vmxassist/machine.h Fri Sep 22 12:14:22 2006 +0100
@@ -36,6 +36,7 @@
#define CR4_VME (1 << 0)
#define CR4_PVI (1 << 1)
#define CR4_PSE (1 << 4)
+#define CR4_PAE (1 << 5)
#define EFLAGS_ZF (1 << 6)
#define EFLAGS_TF (1 << 8)
diff -r ad22c711ccb7 -r 3236311a23a5 tools/firmware/vmxassist/vm86.c
--- a/tools/firmware/vmxassist/vm86.c Fri Sep 22 11:37:31 2006 +0100
+++ b/tools/firmware/vmxassist/vm86.c Fri Sep 22 12:14:22 2006 +0100
@@ -52,29 +52,74 @@ static char *rnames[] = { "ax", "cx", "d
static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
#endif /* DEBUG */
+#define PDE_PS (1 << 7)
#define PT_ENTRY_PRESENT 0x1
+/* We only support access to <=4G physical memory due to 1:1 mapping */
static unsigned
-guest_linear_to_real(unsigned long base, unsigned off)
-{
- unsigned int gcr3 = oldctx.cr3;
- unsigned int l1_mfn;
- unsigned int l0_mfn;
+guest_linear_to_real(uint32_t base)
+{
+ uint32_t gcr3 = oldctx.cr3;
+ uint64_t l2_mfn;
+ uint64_t l1_mfn;
+ uint64_t l0_mfn;
if (!(oldctx.cr0 & CR0_PG))
- return base + off;
-
- l1_mfn = ((unsigned int *)gcr3)[(base >> 22) & 0x3ff ];
- if (!(l1_mfn & PT_ENTRY_PRESENT))
- panic("l2 entry not present\n");
- l1_mfn = l1_mfn & 0xfffff000 ;
-
- l0_mfn = ((unsigned int *)l1_mfn)[(base >> 12) & 0x3ff];
- if (!(l0_mfn & PT_ENTRY_PRESENT))
- panic("l1 entry not present\n");
- l0_mfn = l0_mfn & 0xfffff000;
-
- return l0_mfn + off + (base & 0xfff);
+ return base;
+
+ if (!(oldctx.cr4 & CR4_PAE)) {
+ l1_mfn = ((uint32_t *)gcr3)[(base >> 22) & 0x3ff];
+
+ if (oldctx.cr4 & CR4_PSE || l1_mfn & PDE_PS) {
+ /* 1 level page table */
+ l0_mfn = l1_mfn;
+ if (!(l0_mfn & PT_ENTRY_PRESENT))
+ panic("l1 entry not present\n");
+
+ l0_mfn &= 0xffc00000;
+ return l0_mfn + (base & 0x3fffff);
+ }
+
+ if (!(l1_mfn & PT_ENTRY_PRESENT))
+ panic("l2 entry not present\n");
+
+ l1_mfn &= 0xfffff000;
+ l0_mfn = ((uint32_t *)l1_mfn)[(base >> 12) & 0x3ff];
+ if (!(l0_mfn & PT_ENTRY_PRESENT))
+ panic("l1 entry not present\n");
+ l0_mfn &= 0xfffff000;
+
+ return l0_mfn + (base & 0xfff);
+ } else if (oldctx.cr4 & CR4_PAE && !(oldctx.cr4 & CR4_PSE)) {
+ l2_mfn = ((uint64_t *)gcr3)[(base >> 30) & 0x3];
+ if (!(l2_mfn & PT_ENTRY_PRESENT))
+ panic("l3 entry not present\n");
+ l2_mfn &= 0x3fffff000ULL;
+
+ l1_mfn = ((uint64_t *)l2_mfn)[(base >> 21) & 0x1ff];
+ if (!(l1_mfn & PT_ENTRY_PRESENT))
+ panic("l2 entry not present\n");
+ l1_mfn &= 0x3fffff000ULL;
+
+ l0_mfn = ((uint64_t *)l1_mfn)[(base >> 12) & 0x1ff];
+ if (!(l0_mfn & PT_ENTRY_PRESENT))
+ panic("l1 entry not present\n");
+ l0_mfn &= 0x3fffff000ULL;
+
+ return l0_mfn + (base & 0xfff);
+ } else { /* oldctx.cr4 & CR4_PAE && oldctx.cr4 & CR4_PSE */
+ l1_mfn = ((uint64_t *)gcr3)[(base >> 30) & 0x3];
+ if (!(l1_mfn & PT_ENTRY_PRESENT))
+ panic("l2 entry not present\n");
+ l1_mfn &= 0x3fffff000ULL;
+
+ l0_mfn = ((uint64_t *)l1_mfn)[(base >> 21) & 0x1ff];
+ if (!(l0_mfn & PT_ENTRY_PRESENT))
+ panic("l1 entry not present\n");
+ l0_mfn &= 0x3ffe00000ULL;
+
+ return l0_mfn + (base & 0x1fffff);
+ }
}
static unsigned
@@ -95,7 +140,8 @@ address(struct regs *regs, unsigned seg,
(mode == VM86_REAL_TO_PROTECTED && regs->cs == seg))
return ((seg & 0xFFFF) << 4) + off;
- entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base,
0))[seg >> 3];
+ entry = ((unsigned long long *)
+ guest_linear_to_real(oldctx.gdtr_base))[seg >> 3];
entry_high = entry >> 32;
entry_low = entry & 0xFFFFFFFF;
@@ -780,7 +826,8 @@ load_seg(unsigned long sel, uint32_t *ba
return 1;
}
- entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base,
0))[sel >> 3];
+ entry = ((unsigned long long *)
+ guest_linear_to_real(oldctx.gdtr_base))[sel >> 3];
/* Check the P bit first */
if (!((entry >> (15+32)) & 0x1) && sel != 0)
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|