summary refs log tree commit diff
path: root/x86_64
diff options
context:
space:
mode:
authorSlava Malyugin <slavamn@google.com>2018-02-23 20:49:51 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-02-26 22:07:23 -0800
commit4567a281a5c28e49479f916a057ee7b1f221925b (patch)
tree167a5430fbc2c244b3928deeecec588c9777af27 /x86_64
parent8836bb51a23163c8d8fb55fbd271f619010d7f00 (diff)
downloadcrosvm-4567a281a5c28e49479f916a057ee7b1f221925b.tar
crosvm-4567a281a5c28e49479f916a057ee7b1f221925b.tar.gz
crosvm-4567a281a5c28e49479f916a057ee7b1f221925b.tar.bz2
crosvm-4567a281a5c28e49479f916a057ee7b1f221925b.tar.lz
crosvm-4567a281a5c28e49479f916a057ee7b1f221925b.tar.xz
crosvm-4567a281a5c28e49479f916a057ee7b1f221925b.tar.zst
crosvm-4567a281a5c28e49479f916a057ee7b1f221925b.zip
crosvm: disable reliance on support of 1GB pages
    The initalization code in crosvm used two-level page table
    in long mode, with last entry covering 1GB. This assumed
    presence of 1GB pages support ('pdpe1gb' in /proc/cpuinfo).
    Some CPUs don't have it.

    BUG=none
    TEST=reproduced bug on Celeron N3150 (Braswell), verified
         VM boots on it with fix

Change-Id: I6014c7ea236d8daf95e9f09b68beb7935a267aa3
Reviewed-on: https://chromium-review.googlesource.com/936323
Commit-Ready: Slava Malyugin <slavamn@chromium.org>
Tested-by: Slava Malyugin <slavamn@chromium.org>
Reviewed-by: Slava Malyugin <slavamn@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'x86_64')
-rw-r--r--x86_64/src/regs.rs20
1 files changed, 18 insertions, 2 deletions
diff --git a/x86_64/src/regs.rs b/x86_64/src/regs.rs
index e364ce4..d43c899 100644
--- a/x86_64/src/regs.rs
+++ b/x86_64/src/regs.rs
@@ -32,6 +32,8 @@ pub enum Error {
     WritePML4Address,
     /// Writing PDPTE to RAM failed.
     WritePDPTEAddress,
+    /// Writing PDE to RAM failed.
+    WritePDEAddress,
 }
 pub type Result<T> = result::Result<T, Error>;
 
@@ -233,11 +235,22 @@ fn setup_page_tables(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
     // Puts PML4 right after zero page but aligned to 4k.
     let boot_pml4_addr = GuestAddress(0x9000);
     let boot_pdpte_addr = GuestAddress(0xa000);
+    let boot_pde_addr = GuestAddress(0xb000);
 
+    // Entry covering VA [0..512GB)
     mem.write_obj_at_addr(boot_pdpte_addr.offset() as u64 | 0x03, boot_pml4_addr)
         .map_err(|_| Error::WritePML4Address)?;
-    mem.write_obj_at_addr(0x83u64, boot_pdpte_addr)
+
+    // Entry covering VA [0..1GB)
+    mem.write_obj_at_addr(boot_pde_addr.offset() as u64 | 0x03, boot_pdpte_addr)
         .map_err(|_| Error::WritePDPTEAddress)?;
+
+    // 512 2MB entries together covering VA [0..1GB). Note we are assuming
+    // CPU supports 2MB pages (/proc/cpuinfo has 'pse'). All modern CPUs do.
+    for i in 0..512 {
+        mem.write_obj_at_addr((i << 21) + 0x83u64, boot_pde_addr.unchecked_add(i * 8))
+            .map_err(|_| Error::WritePDEAddress)?;
+    }
     sregs.cr3 = boot_pml4_addr.offset() as u64;
     sregs.cr4 |= X86_CR4_PAE;
     sregs.cr0 |= X86_CR0_PG;
@@ -307,7 +320,10 @@ mod tests {
         setup_page_tables(&gm, &mut sregs).unwrap();
 
         assert_eq!(0xa003, read_u64(&gm, 0x9000));
-        assert_eq!(0x83, read_u64(&gm, 0xa000));
+        assert_eq!(0xb003, read_u64(&gm, 0xa000));
+        for i in 0..512 {
+            assert_eq!((i << 21) + 0x83u64, read_u64(&gm, 0xb000 + i * 8));
+        }
 
         assert_eq!(0x9000, sregs.cr3);
         assert_eq!(X86_CR4_PAE, sregs.cr4);