]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
x86: Add 32-bit guest paging support
authorJan Kiszka <jan.kiszka@siemens.com>
Fri, 7 Feb 2014 09:05:35 +0000 (10:05 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Fri, 7 Feb 2014 10:11:18 +0000 (11:11 +0100)
This adds support for reading 32-bit guest page tables, including 4 MB
hugepages. Creating such tables is neither needed nor supported.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/x86/include/asm/paging_modes.h
hypervisor/arch/x86/include/asm/processor.h
hypervisor/arch/x86/paging.c
hypervisor/arch/x86/vmx.c

index f7268f46405e8090377fc66bc4fb0dcf14807096..e55ec29803cbc18e9711c18f1f64020ba77520db 100644 (file)
@@ -13,5 +13,6 @@
 #include <jailhouse/paging.h>
 
 extern const struct paging x86_64_paging[];
+extern const struct paging i386_paging[];
 
 #define hv_paging      x86_64_paging
index 0752e8dba16abd234a9f4d475cc7b78a0b25f1a8..c752fcb1d095fe451cc864ae9f6a48d063012010 100644 (file)
@@ -25,6 +25,7 @@
 #define X86_CR0_CD                                     0x40000000
 #define X86_CR0_PG                                     0x80000000
 
+#define X86_CR4_PAE                                    0x00000020
 #define X86_CR4_PGE                                    0x00000080
 #define X86_CR4_VMXE                                   0x00002000
 
index 5223e7ca6d31c52c9adab4c0a4afb07c330c1a34..60130d1280952bb657e1cbb5c2e5a0ce4542c36f 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <jailhouse/paging.h>
 
-#define X86_64_FLAG_HUGEPAGE   0x80
+#define X86_FLAG_HUGEPAGE      0x80
 
 static bool x86_64_entry_valid(pt_entry_t pte)
 {
@@ -72,13 +72,13 @@ static pt_entry_t x86_64_get_entry_l1(page_table_t page_table,
 static void x86_64_set_terminal_l3(pt_entry_t pte, unsigned long phys,
                                   unsigned long flags)
 {
-       *pte = (phys & 0x000fffffc0000000UL) | X86_64_FLAG_HUGEPAGE | flags;
+       *pte = (phys & 0x000fffffc0000000UL) | X86_FLAG_HUGEPAGE | flags;
 }
 
 static void x86_64_set_terminal_l2(pt_entry_t pte, unsigned long phys,
                                   unsigned long flags)
 {
-       *pte = (phys & 0x000fffffffe00000UL) | X86_64_FLAG_HUGEPAGE | flags;
+       *pte = (phys & 0x000fffffffe00000UL) | X86_FLAG_HUGEPAGE | flags;
 }
 
 static void x86_64_set_terminal_l1(pt_entry_t pte, unsigned long phys,
@@ -89,7 +89,7 @@ static void x86_64_set_terminal_l1(pt_entry_t pte, unsigned long phys,
 
 static unsigned long x86_64_get_phys_l3(pt_entry_t pte, unsigned long virt)
 {
-       if (!(*pte & X86_64_FLAG_HUGEPAGE))
+       if (!(*pte & X86_FLAG_HUGEPAGE))
                return INVALID_PHYS_ADDR;
        return (*pte & 0x000fffffc0000000UL) |
               (virt & 0x000000003fffffffUL);
@@ -97,7 +97,7 @@ static unsigned long x86_64_get_phys_l3(pt_entry_t pte, unsigned long virt)
 
 static unsigned long x86_64_get_phys_l2(pt_entry_t pte, unsigned long virt)
 {
-       if (!(*pte & X86_64_FLAG_HUGEPAGE))
+       if (!(*pte & X86_FLAG_HUGEPAGE))
                return INVALID_PHYS_ADDR;
        return (*pte & 0x000fffffffe00000UL) |
               (virt & 0x00000000001fffffUL);
@@ -159,3 +159,64 @@ const struct paging x86_64_paging[] = {
                /* get_next_pt not valid */
        },
 };
+
+static bool i386_entry_valid(pt_entry_t pte)
+{
+       return *(u32 *)pte & 1;
+}
+
+static pt_entry_t i386_get_entry_l2(page_table_t page_table,
+                                   unsigned long virt)
+{
+       u32 *page_table32 = (u32 *)page_table;
+
+       return (pt_entry_t)&page_table32[(virt >> 22) & 0x3ff];
+}
+
+static pt_entry_t i386_get_entry_l1(page_table_t page_table,
+                                   unsigned long virt)
+{
+       u32 *page_table32 = (u32 *)page_table;
+
+       return (pt_entry_t)&page_table32[(virt >> 12) & 0x3ff];
+}
+
+static unsigned long i386_get_phys_l2(pt_entry_t pte, unsigned long virt)
+{
+       u32 pte32 = *(u32 *)pte;
+
+       if (!(pte32 & X86_FLAG_HUGEPAGE))
+               return INVALID_PHYS_ADDR;
+       return ((unsigned long)(pte32 & 0x0001e000) << (32 - 13)) |
+               (pte32 & 0xffc00000) |
+                (virt & 0x003fffff);
+}
+
+static unsigned long i386_get_phys_l1(pt_entry_t pte, unsigned long virt)
+{
+       return (*(u32 *)pte & 0xfffff000) |
+                     (virt & 0x00000fff);
+}
+
+static unsigned long i386_get_next_pt_l2(pt_entry_t pte)
+{
+       return *(u32 *)pte & 0xfffff000UL;
+}
+
+/* read-only, no page table construction supported */
+const struct paging i386_paging[] = {
+       {
+               .page_size      = 4 * 1024 * 1024,
+               .entry_valid    = i386_entry_valid,
+               .get_entry      = i386_get_entry_l2,
+               .get_phys       = i386_get_phys_l2,
+               .get_next_pt    = i386_get_next_pt_l2,
+       },
+       {
+               .page_size      = PAGE_SIZE,
+               .entry_valid    = i386_entry_valid,
+               .get_entry      = i386_get_entry_l1,
+               .get_phys       = i386_get_phys_l1,
+               /* get_next_pt not valid */
+       },
+};
index f44fbc35678f6efabd3c93603ab4dfaf29fce542..b87742904b67a508d3cf636296aeb7b63ff0bfe6 100644 (file)
@@ -943,6 +943,11 @@ vmx_get_guest_paging_structs(struct guest_paging_structures *pg_structs)
                pg_structs->root_paging = x86_64_paging;
                pg_structs->root_table_gphys =
                        vmcs_read64(GUEST_CR3) & 0x000ffffffffff000UL;
+       } else if (vmcs_read64(GUEST_CR0) & X86_CR0_PG &&
+                !(vmcs_read64(GUEST_CR4) & X86_CR4_PAE)) {
+               pg_structs->root_paging = i386_paging;
+               pg_structs->root_table_gphys =
+                       vmcs_read64(GUEST_CR3) & 0xfffff000UL;
        } else {
                printk("FATAL: Unsupported paging mode\n");
                return false;