2017-04-21 00:33:17 +00:00
|
|
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2018-02-22 21:26:49 +00:00
|
|
|
use std::error::{self, Error as RegsError};
|
|
|
|
use std::fmt::{self, Display};
|
2018-10-03 17:22:32 +00:00
|
|
|
use std::{mem, result};
|
2017-04-21 00:33:17 +00:00
|
|
|
|
2018-10-03 17:22:32 +00:00
|
|
|
use gdt;
|
2017-04-21 00:33:17 +00:00
|
|
|
use kvm;
|
|
|
|
use kvm_sys::kvm_fpu;
|
|
|
|
use kvm_sys::kvm_msr_entry;
|
|
|
|
use kvm_sys::kvm_msrs;
|
|
|
|
use kvm_sys::kvm_regs;
|
|
|
|
use kvm_sys::kvm_sregs;
|
|
|
|
use sys_util;
|
2017-05-16 00:37:47 +00:00
|
|
|
use sys_util::{GuestAddress, GuestMemory};
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
2017-05-16 00:37:47 +00:00
|
|
|
/// Setting up msrs failed.
|
2017-04-21 00:33:17 +00:00
|
|
|
MsrIoctlFailed(sys_util::Error),
|
2017-05-16 00:37:47 +00:00
|
|
|
/// Failed to configure the FPU.
|
2017-04-21 00:33:17 +00:00
|
|
|
FpuIoctlFailed(sys_util::Error),
|
2018-03-22 01:26:22 +00:00
|
|
|
/// Failed to get sregs for this cpu.
|
|
|
|
GetSRegsIoctlFailed(sys_util::Error),
|
2017-05-16 00:37:47 +00:00
|
|
|
/// Failed to set base registers for this cpu.
|
2017-04-21 00:33:17 +00:00
|
|
|
SettingRegistersIoctl(sys_util::Error),
|
2017-05-16 00:37:47 +00:00
|
|
|
/// Failed to set sregs for this cpu.
|
2018-03-22 01:26:22 +00:00
|
|
|
SetSRegsIoctlFailed(sys_util::Error),
|
2017-05-16 00:37:47 +00:00
|
|
|
/// Writing the GDT to RAM failed.
|
|
|
|
WriteGDTFailure,
|
|
|
|
/// Writing the IDT to RAM failed.
|
|
|
|
WriteIDTFailure,
|
|
|
|
/// Writing PML4 to RAM failed.
|
|
|
|
WritePML4Address,
|
|
|
|
/// Writing PDPTE to RAM failed.
|
|
|
|
WritePDPTEAddress,
|
2018-02-24 04:49:51 +00:00
|
|
|
/// Writing PDE to RAM failed.
|
|
|
|
WritePDEAddress,
|
2017-04-21 00:33:17 +00:00
|
|
|
}
|
|
|
|
pub type Result<T> = result::Result<T, Error>;
|
|
|
|
|
2018-02-22 21:26:49 +00:00
|
|
|
impl error::Error for Error {
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match self {
|
lint: Resolve the easier clippy lints
Hopefully the changes are self-explanatory and uncontroversial. This
eliminates much of the noise from `cargo clippy` and, for my purposes,
gives me a reasonable way to use it as a tool when writing and reviewing
code.
Here is the Clippy invocation I was using:
cargo +nightly clippy -- -W clippy::correctness -A renamed_and_removed_lints -Aclippy::{blacklisted_name,borrowed_box,cast_lossless,cast_ptr_alignment,enum_variant_names,identity_op,if_same_then_else,mut_from_ref,needless_pass_by_value,new_without_default,new_without_default_derive,or_fun_call,ptr_arg,should_implement_trait,single_match,too_many_arguments,trivially_copy_pass_by_ref,unreadable_literal,unsafe_vector_initialization,useless_transmute}
TEST=cargo check --features wl-dmabuf,gpu,usb-emulation
TEST=boot linux
Change-Id: I55eb1b4a72beb2f762480e3333a921909314a0a2
Reviewed-on: https://chromium-review.googlesource.com/1356911
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-12-02 01:49:30 +00:00
|
|
|
Error::MsrIoctlFailed(_) => "Setting up msrs failed",
|
|
|
|
Error::FpuIoctlFailed(_) => "Failed to configure the FPU",
|
|
|
|
Error::GetSRegsIoctlFailed(_) => "Failed to get sregs for this cpu",
|
|
|
|
Error::SettingRegistersIoctl(_) => "Failed to set base registers for this cpu",
|
|
|
|
Error::SetSRegsIoctlFailed(_) => "Failed to set sregs for this cpu",
|
|
|
|
Error::WriteGDTFailure => "Writing the GDT to RAM failed",
|
|
|
|
Error::WriteIDTFailure => "Writing the IDT to RAM failed",
|
|
|
|
Error::WritePML4Address => "Writing PML4 to RAM failed",
|
|
|
|
Error::WritePDPTEAddress => "Writing PDPTE to RAM failed",
|
|
|
|
Error::WritePDEAddress => "Writing PDE to RAM failed",
|
2018-02-22 21:26:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "Interrupt Error: {}", Error::description(self))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-21 00:33:17 +00:00
|
|
|
fn create_msr_entries() -> Vec<kvm_msr_entry> {
|
|
|
|
let mut entries = Vec::<kvm_msr_entry>::new();
|
|
|
|
|
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_IA32_SYSENTER_CS,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_IA32_SYSENTER_ESP,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_IA32_SYSENTER_EIP,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
// x86_64 specific msrs, we only run on x86_64 not x86
|
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_STAR,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_CSTAR,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_KERNEL_GS_BASE,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_SYSCALL_MASK,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_LSTAR,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
// end of x86_64 specific code
|
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_IA32_TSC,
|
|
|
|
data: 0x0,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
entries.push(kvm_msr_entry {
|
2018-10-03 17:22:32 +00:00
|
|
|
index: ::msr_index::MSR_IA32_MISC_ENABLE,
|
|
|
|
data: ::msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
entries
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Configure Model specific registers for x86
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
|
|
|
/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
|
|
|
|
pub fn setup_msrs(vcpu: &kvm::Vcpu) -> Result<()> {
|
|
|
|
let entry_vec = create_msr_entries();
|
2018-10-03 17:22:32 +00:00
|
|
|
let vec_size_bytes =
|
|
|
|
mem::size_of::<kvm_msrs>() + (entry_vec.len() * mem::size_of::<kvm_msr_entry>());
|
2017-04-21 00:33:17 +00:00
|
|
|
let vec: Vec<u8> = Vec::with_capacity(vec_size_bytes);
|
2017-10-13 01:42:01 +00:00
|
|
|
let msrs: &mut kvm_msrs = unsafe {
|
2017-04-21 00:33:17 +00:00
|
|
|
// Converting the vector's memory to a struct is unsafe. Carefully using the read-only
|
|
|
|
// vector to size and set the members ensures no out-of-bounds erros below.
|
|
|
|
&mut *(vec.as_ptr() as *mut kvm_msrs)
|
|
|
|
};
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
// Mapping the unsized array to a slice is unsafe becase the length isn't known. Providing
|
|
|
|
// the length used to create the struct guarantees the entire slice is valid.
|
|
|
|
let entries: &mut [kvm_msr_entry] = msrs.entries.as_mut_slice(entry_vec.len());
|
|
|
|
entries.copy_from_slice(&entry_vec);
|
|
|
|
}
|
|
|
|
msrs.nmsrs = entry_vec.len() as u32;
|
|
|
|
|
2017-05-21 17:58:08 +00:00
|
|
|
vcpu.set_msrs(msrs).map_err(Error::MsrIoctlFailed)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Configure FPU registers for x86
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
|
|
|
/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
|
|
|
|
pub fn setup_fpu(vcpu: &kvm::Vcpu) -> Result<()> {
|
|
|
|
let fpu: kvm_fpu = kvm_fpu {
|
|
|
|
fcw: 0x37f,
|
|
|
|
mxcsr: 0x1f80,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
2017-05-21 17:58:08 +00:00
|
|
|
vcpu.set_fpu(&fpu).map_err(Error::FpuIoctlFailed)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Configure base registers for x86
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
|
|
|
/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
|
|
|
|
/// * `boot_ip` - Starting instruction pointer.
|
|
|
|
/// * `boot_sp` - Starting stack pointer.
|
|
|
|
/// * `boot_si` - Must point to zero page address per Linux ABI.
|
|
|
|
pub fn setup_regs(vcpu: &kvm::Vcpu, boot_ip: u64, boot_sp: u64, boot_si: u64) -> Result<()> {
|
|
|
|
let regs: kvm_regs = kvm_regs {
|
|
|
|
rflags: 0x0000000000000002u64,
|
|
|
|
rip: boot_ip,
|
|
|
|
rsp: boot_sp,
|
|
|
|
rbp: boot_sp,
|
|
|
|
rsi: boot_si,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
2018-10-03 17:22:32 +00:00
|
|
|
vcpu.set_regs(®s).map_err(Error::SettingRegistersIoctl)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
const X86_CR0_PE: u64 = 0x1;
|
|
|
|
const X86_CR0_PG: u64 = 0x80000000;
|
|
|
|
const X86_CR4_PAE: u64 = 0x20;
|
|
|
|
|
|
|
|
const EFER_LME: u64 = 0x100;
|
2018-03-29 03:20:35 +00:00
|
|
|
const EFER_LMA: u64 = 0x400;
|
2017-04-21 00:33:17 +00:00
|
|
|
|
2018-02-01 01:49:07 +00:00
|
|
|
const BOOT_GDT_OFFSET: u64 = 0x500;
|
|
|
|
const BOOT_IDT_OFFSET: u64 = 0x520;
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
const BOOT_GDT_MAX: usize = 4;
|
|
|
|
|
2017-05-16 00:37:47 +00:00
|
|
|
fn write_gdt_table(table: &[u64], guest_mem: &GuestMemory) -> Result<()> {
|
|
|
|
let boot_gdt_addr = GuestAddress(BOOT_GDT_OFFSET);
|
|
|
|
for (index, entry) in table.iter().enumerate() {
|
2018-10-03 17:22:32 +00:00
|
|
|
let addr = guest_mem
|
|
|
|
.checked_offset(boot_gdt_addr, (index * mem::size_of::<u64>()) as u64)
|
2017-05-16 00:37:47 +00:00
|
|
|
.ok_or(Error::WriteGDTFailure)?;
|
2018-10-03 17:22:32 +00:00
|
|
|
guest_mem
|
|
|
|
.write_obj_at_addr(*entry, addr)
|
2017-05-16 00:37:47 +00:00
|
|
|
.map_err(|_| Error::WriteGDTFailure)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
}
|
2017-05-16 00:37:47 +00:00
|
|
|
Ok(())
|
2017-04-21 00:33:17 +00:00
|
|
|
}
|
|
|
|
|
2017-05-16 00:37:47 +00:00
|
|
|
fn write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()> {
|
|
|
|
let boot_idt_addr = GuestAddress(BOOT_IDT_OFFSET);
|
|
|
|
guest_mem
|
|
|
|
.write_obj_at_addr(val, boot_idt_addr)
|
|
|
|
.map_err(|_| Error::WriteIDTFailure)
|
2017-04-21 00:33:17 +00:00
|
|
|
}
|
|
|
|
|
2017-05-16 00:37:47 +00:00
|
|
|
fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
|
2017-04-21 00:33:17 +00:00
|
|
|
let gdt_table: [u64; BOOT_GDT_MAX as usize] = [
|
2018-10-03 17:22:32 +00:00
|
|
|
gdt::gdt_entry(0, 0, 0), // NULL
|
2017-04-21 00:33:17 +00:00
|
|
|
gdt::gdt_entry(0xa09b, 0, 0xfffff), // CODE
|
|
|
|
gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA
|
|
|
|
gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS
|
|
|
|
];
|
|
|
|
|
|
|
|
let code_seg = gdt::kvm_segment_from_gdt(gdt_table[1], 1);
|
|
|
|
let data_seg = gdt::kvm_segment_from_gdt(gdt_table[2], 2);
|
|
|
|
let tss_seg = gdt::kvm_segment_from_gdt(gdt_table[3], 3);
|
|
|
|
|
|
|
|
// Write segments
|
2017-05-16 00:37:47 +00:00
|
|
|
write_gdt_table(&gdt_table[..], mem)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
sregs.gdt.base = BOOT_GDT_OFFSET as u64;
|
|
|
|
sregs.gdt.limit = mem::size_of_val(&gdt_table) as u16 - 1;
|
|
|
|
|
2017-05-16 00:37:47 +00:00
|
|
|
write_idt_value(0, mem)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
sregs.idt.base = BOOT_IDT_OFFSET as u64;
|
|
|
|
sregs.idt.limit = mem::size_of::<u64>() as u16 - 1;
|
|
|
|
|
|
|
|
sregs.cs = code_seg;
|
|
|
|
sregs.ds = data_seg;
|
|
|
|
sregs.es = data_seg;
|
|
|
|
sregs.fs = data_seg;
|
|
|
|
sregs.gs = data_seg;
|
|
|
|
sregs.ss = data_seg;
|
|
|
|
sregs.tr = tss_seg;
|
|
|
|
|
|
|
|
/* 64-bit protected mode */
|
|
|
|
sregs.cr0 |= X86_CR0_PE;
|
|
|
|
sregs.efer |= EFER_LME;
|
2017-05-16 00:37:47 +00:00
|
|
|
|
|
|
|
Ok(())
|
2017-04-21 00:33:17 +00:00
|
|
|
}
|
|
|
|
|
2017-05-16 00:37:47 +00:00
|
|
|
fn setup_page_tables(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
|
2017-04-21 00:33:17 +00:00
|
|
|
// Puts PML4 right after zero page but aligned to 4k.
|
2017-05-16 00:37:47 +00:00
|
|
|
let boot_pml4_addr = GuestAddress(0x9000);
|
|
|
|
let boot_pdpte_addr = GuestAddress(0xa000);
|
2018-02-24 04:49:51 +00:00
|
|
|
let boot_pde_addr = GuestAddress(0xb000);
|
2017-05-16 00:37:47 +00:00
|
|
|
|
2018-02-24 04:49:51 +00:00
|
|
|
// Entry covering VA [0..512GB)
|
2017-05-16 00:37:47 +00:00
|
|
|
mem.write_obj_at_addr(boot_pdpte_addr.offset() as u64 | 0x03, boot_pml4_addr)
|
|
|
|
.map_err(|_| Error::WritePML4Address)?;
|
2018-02-24 04:49:51 +00:00
|
|
|
|
|
|
|
// Entry covering VA [0..1GB)
|
|
|
|
mem.write_obj_at_addr(boot_pde_addr.offset() as u64 | 0x03, boot_pdpte_addr)
|
2017-05-16 00:37:47 +00:00
|
|
|
.map_err(|_| Error::WritePDPTEAddress)?;
|
2018-02-24 04:49:51 +00:00
|
|
|
|
|
|
|
// 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)?;
|
|
|
|
}
|
2017-05-16 00:37:47 +00:00
|
|
|
sregs.cr3 = boot_pml4_addr.offset() as u64;
|
2017-04-21 00:33:17 +00:00
|
|
|
sregs.cr4 |= X86_CR4_PAE;
|
|
|
|
sregs.cr0 |= X86_CR0_PG;
|
2018-03-29 03:20:35 +00:00
|
|
|
sregs.efer |= EFER_LMA; // Long mode is active. Must be auto-enabled with CR0_PG.
|
2017-05-16 00:37:47 +00:00
|
|
|
Ok(())
|
2017-04-21 00:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Configures the segment registers and system page tables for a given CPU.
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
2017-05-16 00:37:47 +00:00
|
|
|
/// * `mem` - The memory that will be passed to the guest.
|
2017-04-21 00:33:17 +00:00
|
|
|
/// * `vcpu_fd` - The FD returned from the KVM_CREATE_VCPU ioctl.
|
2017-05-16 00:37:47 +00:00
|
|
|
pub fn setup_sregs(mem: &GuestMemory, vcpu: &kvm::Vcpu) -> Result<()> {
|
2018-03-22 01:26:22 +00:00
|
|
|
let mut sregs: kvm_sregs = vcpu.get_sregs().map_err(Error::GetSRegsIoctlFailed)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
|
2017-05-16 00:37:47 +00:00
|
|
|
configure_segments_and_sregs(mem, &mut sregs)?;
|
|
|
|
setup_page_tables(mem, &mut sregs)?; // TODO(dgreid) - Can this be done once per system instead?
|
2017-04-21 00:33:17 +00:00
|
|
|
|
2018-03-22 01:26:22 +00:00
|
|
|
vcpu.set_sregs(&sregs).map_err(Error::SetSRegsIoctlFailed)?;
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2017-05-16 00:37:47 +00:00
|
|
|
use sys_util::{GuestAddress, GuestMemory};
|
|
|
|
|
|
|
|
fn create_guest_mem() -> GuestMemory {
|
|
|
|
GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap()
|
|
|
|
}
|
|
|
|
|
2018-02-01 01:49:07 +00:00
|
|
|
fn read_u64(gm: &GuestMemory, offset: u64) -> u64 {
|
2017-05-16 00:37:47 +00:00
|
|
|
let read_addr = GuestAddress(offset);
|
|
|
|
gm.read_obj_from_addr(read_addr).unwrap()
|
|
|
|
}
|
2017-04-21 00:33:17 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn segments_and_sregs() {
|
|
|
|
let mut sregs: kvm_sregs = Default::default();
|
2017-05-16 00:37:47 +00:00
|
|
|
let gm = create_guest_mem();
|
|
|
|
configure_segments_and_sregs(&gm, &mut sregs).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(0x0, read_u64(&gm, BOOT_GDT_OFFSET));
|
|
|
|
assert_eq!(0xaf9b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 8));
|
|
|
|
assert_eq!(0xcf93000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 16));
|
|
|
|
assert_eq!(0x8f8b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 24));
|
|
|
|
assert_eq!(0x0, read_u64(&gm, BOOT_IDT_OFFSET));
|
|
|
|
|
2017-04-21 00:33:17 +00:00
|
|
|
assert_eq!(0, sregs.cs.base);
|
|
|
|
assert_eq!(0xfffff, sregs.ds.limit);
|
|
|
|
assert_eq!(0x10, sregs.es.selector);
|
|
|
|
assert_eq!(1, sregs.fs.present);
|
|
|
|
assert_eq!(1, sregs.gs.g);
|
|
|
|
assert_eq!(0, sregs.ss.avl);
|
|
|
|
assert_eq!(0, sregs.tr.base);
|
|
|
|
assert_eq!(0xfffff, sregs.tr.limit);
|
|
|
|
assert_eq!(0, sregs.tr.avl);
|
|
|
|
assert_eq!(X86_CR0_PE, sregs.cr0);
|
|
|
|
assert_eq!(EFER_LME, sregs.efer);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn page_tables() {
|
|
|
|
let mut sregs: kvm_sregs = Default::default();
|
2017-05-16 00:37:47 +00:00
|
|
|
let gm = create_guest_mem();
|
|
|
|
setup_page_tables(&gm, &mut sregs).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(0xa003, read_u64(&gm, 0x9000));
|
2018-02-24 04:49:51 +00:00
|
|
|
assert_eq!(0xb003, read_u64(&gm, 0xa000));
|
|
|
|
for i in 0..512 {
|
|
|
|
assert_eq!((i << 21) + 0x83u64, read_u64(&gm, 0xb000 + i * 8));
|
|
|
|
}
|
2017-05-16 00:37:47 +00:00
|
|
|
|
2017-04-21 00:33:17 +00:00
|
|
|
assert_eq!(0x9000, sregs.cr3);
|
|
|
|
assert_eq!(X86_CR4_PAE, sregs.cr4);
|
|
|
|
assert_eq!(X86_CR0_PG, sregs.cr0);
|
|
|
|
}
|
|
|
|
}
|