1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::result;
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
10*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Sregs;
11*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::VcpuX86_64;
12*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Vm;
13*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
14*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
15*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
16*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
17*bb4ee6a4SAndroid Build Coastguard Worker
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::gdt;
19*bb4ee6a4SAndroid Build Coastguard Worker
20*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
21*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
22*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
23*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to get sregs for this cpu.
24*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to get sregs for this cpu: {0}")]
25*bb4ee6a4SAndroid Build Coastguard Worker GetSRegsIoctlFailed(base::Error),
26*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to get base registers for this cpu.
27*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to get base registers for this cpu: {0}")]
28*bb4ee6a4SAndroid Build Coastguard Worker GettingRegistersIoctl(base::Error),
29*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to set sregs for this cpu.
30*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to set sregs for this cpu: {0}")]
31*bb4ee6a4SAndroid Build Coastguard Worker SetSRegsIoctlFailed(base::Error),
32*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to set base registers for this cpu.
33*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to set base registers for this cpu: {0}")]
34*bb4ee6a4SAndroid Build Coastguard Worker SettingRegistersIoctl(base::Error),
35*bb4ee6a4SAndroid Build Coastguard Worker /// Writing the GDT to RAM failed.
36*bb4ee6a4SAndroid Build Coastguard Worker #[error("writing the GDT to RAM failed")]
37*bb4ee6a4SAndroid Build Coastguard Worker WriteGDTFailure,
38*bb4ee6a4SAndroid Build Coastguard Worker /// Writing the IDT to RAM failed.
39*bb4ee6a4SAndroid Build Coastguard Worker #[error("writing the IDT to RAM failed")]
40*bb4ee6a4SAndroid Build Coastguard Worker WriteIDTFailure,
41*bb4ee6a4SAndroid Build Coastguard Worker /// Writing PDE to RAM failed.
42*bb4ee6a4SAndroid Build Coastguard Worker #[error("writing PDE to RAM failed")]
43*bb4ee6a4SAndroid Build Coastguard Worker WritePDEAddress,
44*bb4ee6a4SAndroid Build Coastguard Worker /// Writing PDPTE to RAM failed.
45*bb4ee6a4SAndroid Build Coastguard Worker #[error("writing PDPTE to RAM failed")]
46*bb4ee6a4SAndroid Build Coastguard Worker WritePDPTEAddress,
47*bb4ee6a4SAndroid Build Coastguard Worker /// Writing PML4 to RAM failed.
48*bb4ee6a4SAndroid Build Coastguard Worker #[error("writing PML4 to RAM failed")]
49*bb4ee6a4SAndroid Build Coastguard Worker WritePML4Address,
50*bb4ee6a4SAndroid Build Coastguard Worker }
51*bb4ee6a4SAndroid Build Coastguard Worker
52*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = result::Result<T, Error>;
53*bb4ee6a4SAndroid Build Coastguard Worker
54*bb4ee6a4SAndroid Build Coastguard Worker const MTRR_MEMTYPE_UC: u8 = 0x0;
55*bb4ee6a4SAndroid Build Coastguard Worker const MTRR_MEMTYPE_WB: u8 = 0x6;
56*bb4ee6a4SAndroid Build Coastguard Worker const MTRR_VAR_VALID: u64 = 0x800;
57*bb4ee6a4SAndroid Build Coastguard Worker const MTRR_ENABLE: u64 = 0x800;
58*bb4ee6a4SAndroid Build Coastguard Worker const MTRR_PHYS_BASE_MSR: u32 = 0x200;
59*bb4ee6a4SAndroid Build Coastguard Worker const MTRR_PHYS_MASK_MSR: u32 = 0x201;
60*bb4ee6a4SAndroid Build Coastguard Worker const VAR_MTRR_NUM_MASK: u64 = 0xFF;
61*bb4ee6a4SAndroid Build Coastguard Worker
62*bb4ee6a4SAndroid Build Coastguard Worker // Returns the value of the highest bit in a 64-bit value. Equivalent to
63*bb4ee6a4SAndroid Build Coastguard Worker // 1 << HighBitSet(x)
get_power_of_two(data: u64) -> u6464*bb4ee6a4SAndroid Build Coastguard Worker fn get_power_of_two(data: u64) -> u64 {
65*bb4ee6a4SAndroid Build Coastguard Worker 1 << (64 - data.leading_zeros() - 1)
66*bb4ee6a4SAndroid Build Coastguard Worker }
67*bb4ee6a4SAndroid Build Coastguard Worker
68*bb4ee6a4SAndroid Build Coastguard Worker // Returns the max length which suitable for mtrr setting based on the
69*bb4ee6a4SAndroid Build Coastguard Worker // specified (base, len)
get_max_len(base: u64, len: u64) -> u6470*bb4ee6a4SAndroid Build Coastguard Worker fn get_max_len(base: u64, len: u64) -> u64 {
71*bb4ee6a4SAndroid Build Coastguard Worker let mut ret = get_power_of_two(len);
72*bb4ee6a4SAndroid Build Coastguard Worker
73*bb4ee6a4SAndroid Build Coastguard Worker while base % ret != 0 {
74*bb4ee6a4SAndroid Build Coastguard Worker ret >>= 1;
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker
77*bb4ee6a4SAndroid Build Coastguard Worker ret
78*bb4ee6a4SAndroid Build Coastguard Worker }
79*bb4ee6a4SAndroid Build Coastguard Worker
80*bb4ee6a4SAndroid Build Coastguard Worker // For the specified (Base, Len), returns (base, len) pair which could be
81*bb4ee6a4SAndroid Build Coastguard Worker // set into mtrr register. mtrr requires: the base-address alignment value can't be
82*bb4ee6a4SAndroid Build Coastguard Worker // less than its length
get_mtrr_pairs(base: u64, len: u64) -> Vec<(u64, u64)>83*bb4ee6a4SAndroid Build Coastguard Worker fn get_mtrr_pairs(base: u64, len: u64) -> Vec<(u64, u64)> {
84*bb4ee6a4SAndroid Build Coastguard Worker let mut vecs = Vec::new();
85*bb4ee6a4SAndroid Build Coastguard Worker
86*bb4ee6a4SAndroid Build Coastguard Worker let mut remains = len;
87*bb4ee6a4SAndroid Build Coastguard Worker let mut new = base;
88*bb4ee6a4SAndroid Build Coastguard Worker while remains != 0 {
89*bb4ee6a4SAndroid Build Coastguard Worker let max = get_max_len(new, remains);
90*bb4ee6a4SAndroid Build Coastguard Worker vecs.push((new, max));
91*bb4ee6a4SAndroid Build Coastguard Worker remains -= max;
92*bb4ee6a4SAndroid Build Coastguard Worker new += max;
93*bb4ee6a4SAndroid Build Coastguard Worker }
94*bb4ee6a4SAndroid Build Coastguard Worker
95*bb4ee6a4SAndroid Build Coastguard Worker vecs
96*bb4ee6a4SAndroid Build Coastguard Worker }
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the number of variable MTRR entries supported by `vcpu`.
vcpu_supported_variable_mtrrs(vcpu: &dyn VcpuX86_64) -> usize99*bb4ee6a4SAndroid Build Coastguard Worker pub fn vcpu_supported_variable_mtrrs(vcpu: &dyn VcpuX86_64) -> usize {
100*bb4ee6a4SAndroid Build Coastguard Worker // Get VAR MTRR num from MSR_MTRRcap
101*bb4ee6a4SAndroid Build Coastguard Worker match vcpu.get_msr(crate::msr_index::MSR_MTRRcap) {
102*bb4ee6a4SAndroid Build Coastguard Worker Ok(value) => (value & VAR_MTRR_NUM_MASK) as usize,
103*bb4ee6a4SAndroid Build Coastguard Worker Err(_e) => {
104*bb4ee6a4SAndroid Build Coastguard Worker warn!("failed to get MSR_MTRRcap, guests with passthrough devices may be very slow");
105*bb4ee6a4SAndroid Build Coastguard Worker 0
106*bb4ee6a4SAndroid Build Coastguard Worker }
107*bb4ee6a4SAndroid Build Coastguard Worker }
108*bb4ee6a4SAndroid Build Coastguard Worker }
109*bb4ee6a4SAndroid Build Coastguard Worker
110*bb4ee6a4SAndroid Build Coastguard Worker /// Returns `true` if the given MSR `id` is a MTRR entry.
is_mtrr_msr(id: u32) -> bool111*bb4ee6a4SAndroid Build Coastguard Worker pub fn is_mtrr_msr(id: u32) -> bool {
112*bb4ee6a4SAndroid Build Coastguard Worker // Variable MTRR MSRs are pairs starting at 0x200 (MTRR_PHYS_BASE_MSR) / 0x201
113*bb4ee6a4SAndroid Build Coastguard Worker // (MTRR_PHYS_MASK_MSR) and extending up to 0xFF pairs at most.
114*bb4ee6a4SAndroid Build Coastguard Worker (id >= MTRR_PHYS_BASE_MSR && id <= MTRR_PHYS_BASE_MSR + 2 * VAR_MTRR_NUM_MASK as u32)
115*bb4ee6a4SAndroid Build Coastguard Worker || id == crate::msr_index::MSR_MTRRdefType
116*bb4ee6a4SAndroid Build Coastguard Worker }
117*bb4ee6a4SAndroid Build Coastguard Worker
118*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the count of variable MTRR entries specified by the list of `msrs`.
count_variable_mtrrs(msrs: &BTreeMap<u32, u64>) -> usize119*bb4ee6a4SAndroid Build Coastguard Worker pub fn count_variable_mtrrs(msrs: &BTreeMap<u32, u64>) -> usize {
120*bb4ee6a4SAndroid Build Coastguard Worker // Each variable MTRR takes up two MSRs (base + mask), so divide by 2. This will also count the
121*bb4ee6a4SAndroid Build Coastguard Worker // MTRRdefType entry, but that is only one extra and the division truncates, so it won't affect
122*bb4ee6a4SAndroid Build Coastguard Worker // the final count.
123*bb4ee6a4SAndroid Build Coastguard Worker msrs.keys().filter(|&msr| is_mtrr_msr(*msr)).count() / 2
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker
126*bb4ee6a4SAndroid Build Coastguard Worker /// Returns a set of MSRs containing the MTRR configuration.
set_mtrr_msrs(msrs: &mut BTreeMap<u32, u64>, vm: &dyn Vm, pci_start: u64)127*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_mtrr_msrs(msrs: &mut BTreeMap<u32, u64>, vm: &dyn Vm, pci_start: u64) {
128*bb4ee6a4SAndroid Build Coastguard Worker // Set pci_start .. 4G as UC
129*bb4ee6a4SAndroid Build Coastguard Worker // all others are set to default WB
130*bb4ee6a4SAndroid Build Coastguard Worker let pci_len = (1 << 32) - pci_start;
131*bb4ee6a4SAndroid Build Coastguard Worker let vecs = get_mtrr_pairs(pci_start, pci_len);
132*bb4ee6a4SAndroid Build Coastguard Worker
133*bb4ee6a4SAndroid Build Coastguard Worker let phys_mask: u64 = (1 << vm.get_guest_phys_addr_bits()) - 1;
134*bb4ee6a4SAndroid Build Coastguard Worker for (idx, (base, len)) in vecs.iter().enumerate() {
135*bb4ee6a4SAndroid Build Coastguard Worker let reg_idx = idx as u32 * 2;
136*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(MTRR_PHYS_BASE_MSR + reg_idx, base | MTRR_MEMTYPE_UC as u64);
137*bb4ee6a4SAndroid Build Coastguard Worker let mask: u64 = len.wrapping_neg() & phys_mask | MTRR_VAR_VALID;
138*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(MTRR_PHYS_MASK_MSR + reg_idx, mask);
139*bb4ee6a4SAndroid Build Coastguard Worker }
140*bb4ee6a4SAndroid Build Coastguard Worker // Disable fixed MTRRs and enable variable MTRRs, set default type as WB
141*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(
142*bb4ee6a4SAndroid Build Coastguard Worker crate::msr_index::MSR_MTRRdefType,
143*bb4ee6a4SAndroid Build Coastguard Worker MTRR_ENABLE | MTRR_MEMTYPE_WB as u64,
144*bb4ee6a4SAndroid Build Coastguard Worker );
145*bb4ee6a4SAndroid Build Coastguard Worker }
146*bb4ee6a4SAndroid Build Coastguard Worker
147*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the default value of MSRs at reset.
148*bb4ee6a4SAndroid Build Coastguard Worker ///
149*bb4ee6a4SAndroid Build Coastguard Worker /// Currently only sets IA32_TSC to 0.
set_default_msrs(msrs: &mut BTreeMap<u32, u64>)150*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_default_msrs(msrs: &mut BTreeMap<u32, u64>) {
151*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_IA32_TSC, 0x0);
152*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(
153*bb4ee6a4SAndroid Build Coastguard Worker crate::msr_index::MSR_IA32_MISC_ENABLE,
154*bb4ee6a4SAndroid Build Coastguard Worker crate::msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64,
155*bb4ee6a4SAndroid Build Coastguard Worker );
156*bb4ee6a4SAndroid Build Coastguard Worker }
157*bb4ee6a4SAndroid Build Coastguard Worker
158*bb4ee6a4SAndroid Build Coastguard Worker /// Configure Model specific registers for long (64-bit) mode.
set_long_mode_msrs(msrs: &mut BTreeMap<u32, u64>)159*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_long_mode_msrs(msrs: &mut BTreeMap<u32, u64>) {
160*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_IA32_SYSENTER_CS, 0x0);
161*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_IA32_SYSENTER_ESP, 0x0);
162*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_IA32_SYSENTER_EIP, 0x0);
163*bb4ee6a4SAndroid Build Coastguard Worker
164*bb4ee6a4SAndroid Build Coastguard Worker // x86_64 specific msrs, we only run on x86_64 not x86
165*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_STAR, 0x0);
166*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_CSTAR, 0x0);
167*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_KERNEL_GS_BASE, 0x0);
168*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_SYSCALL_MASK, 0x0);
169*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_LSTAR, 0x0);
170*bb4ee6a4SAndroid Build Coastguard Worker // end of x86_64 specific code
171*bb4ee6a4SAndroid Build Coastguard Worker
172*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(crate::msr_index::MSR_IA32_TSC, 0x0);
173*bb4ee6a4SAndroid Build Coastguard Worker msrs.insert(
174*bb4ee6a4SAndroid Build Coastguard Worker crate::msr_index::MSR_IA32_MISC_ENABLE,
175*bb4ee6a4SAndroid Build Coastguard Worker crate::msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64,
176*bb4ee6a4SAndroid Build Coastguard Worker );
177*bb4ee6a4SAndroid Build Coastguard Worker }
178*bb4ee6a4SAndroid Build Coastguard Worker
179*bb4ee6a4SAndroid Build Coastguard Worker const X86_CR0_PE: u64 = 0x1;
180*bb4ee6a4SAndroid Build Coastguard Worker const X86_CR0_PG: u64 = 0x80000000;
181*bb4ee6a4SAndroid Build Coastguard Worker const X86_CR4_PAE: u64 = 0x20;
182*bb4ee6a4SAndroid Build Coastguard Worker
183*bb4ee6a4SAndroid Build Coastguard Worker const EFER_LME: u64 = 0x100;
184*bb4ee6a4SAndroid Build Coastguard Worker const EFER_LMA: u64 = 0x400;
185*bb4ee6a4SAndroid Build Coastguard Worker
186*bb4ee6a4SAndroid Build Coastguard Worker const BOOT_GDT_OFFSET: u64 = 0x1500;
187*bb4ee6a4SAndroid Build Coastguard Worker const BOOT_IDT_OFFSET: u64 = 0x1528;
188*bb4ee6a4SAndroid Build Coastguard Worker
189*bb4ee6a4SAndroid Build Coastguard Worker const BOOT_GDT_MAX: usize = 5;
190*bb4ee6a4SAndroid Build Coastguard Worker
write_gdt_table(table: &[u64], guest_mem: &GuestMemory) -> Result<()>191*bb4ee6a4SAndroid Build Coastguard Worker fn write_gdt_table(table: &[u64], guest_mem: &GuestMemory) -> Result<()> {
192*bb4ee6a4SAndroid Build Coastguard Worker let boot_gdt_addr = GuestAddress(BOOT_GDT_OFFSET);
193*bb4ee6a4SAndroid Build Coastguard Worker for (index, entry) in table.iter().enumerate() {
194*bb4ee6a4SAndroid Build Coastguard Worker let addr = boot_gdt_addr
195*bb4ee6a4SAndroid Build Coastguard Worker .checked_add((index * mem::size_of::<u64>()) as u64)
196*bb4ee6a4SAndroid Build Coastguard Worker .ok_or(Error::WriteGDTFailure)?;
197*bb4ee6a4SAndroid Build Coastguard Worker if !guest_mem.is_valid_range(addr, mem::size_of::<u64>() as u64) {
198*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::WriteGDTFailure);
199*bb4ee6a4SAndroid Build Coastguard Worker }
200*bb4ee6a4SAndroid Build Coastguard Worker
201*bb4ee6a4SAndroid Build Coastguard Worker guest_mem
202*bb4ee6a4SAndroid Build Coastguard Worker .write_obj_at_addr(*entry, addr)
203*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteGDTFailure)?;
204*bb4ee6a4SAndroid Build Coastguard Worker }
205*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
206*bb4ee6a4SAndroid Build Coastguard Worker }
207*bb4ee6a4SAndroid Build Coastguard Worker
write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()>208*bb4ee6a4SAndroid Build Coastguard Worker fn write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()> {
209*bb4ee6a4SAndroid Build Coastguard Worker let boot_idt_addr = GuestAddress(BOOT_IDT_OFFSET);
210*bb4ee6a4SAndroid Build Coastguard Worker guest_mem
211*bb4ee6a4SAndroid Build Coastguard Worker .write_obj_at_addr(val, boot_idt_addr)
212*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteIDTFailure)
213*bb4ee6a4SAndroid Build Coastguard Worker }
214*bb4ee6a4SAndroid Build Coastguard Worker
215*bb4ee6a4SAndroid Build Coastguard Worker /// Configures the GDT, IDT, and segment registers for long mode.
configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut Sregs) -> Result<()>216*bb4ee6a4SAndroid Build Coastguard Worker pub fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut Sregs) -> Result<()> {
217*bb4ee6a4SAndroid Build Coastguard Worker // reference: https://docs.kernel.org/arch/x86/boot.html?highlight=__BOOT_CS#id1
218*bb4ee6a4SAndroid Build Coastguard Worker let gdt_table: [u64; BOOT_GDT_MAX] = [
219*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0, 0, 0), // NULL
220*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0, 0, 0), // NULL
221*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0xa09b, 0, 0xfffff), // CODE
222*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA
223*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS
224*bb4ee6a4SAndroid Build Coastguard Worker ];
225*bb4ee6a4SAndroid Build Coastguard Worker
226*bb4ee6a4SAndroid Build Coastguard Worker let code_seg = gdt::segment_from_gdt(gdt_table[2], 2);
227*bb4ee6a4SAndroid Build Coastguard Worker let data_seg = gdt::segment_from_gdt(gdt_table[3], 3);
228*bb4ee6a4SAndroid Build Coastguard Worker let tss_seg = gdt::segment_from_gdt(gdt_table[4], 4);
229*bb4ee6a4SAndroid Build Coastguard Worker
230*bb4ee6a4SAndroid Build Coastguard Worker // Write segments
231*bb4ee6a4SAndroid Build Coastguard Worker write_gdt_table(&gdt_table[..], mem)?;
232*bb4ee6a4SAndroid Build Coastguard Worker sregs.gdt.base = BOOT_GDT_OFFSET;
233*bb4ee6a4SAndroid Build Coastguard Worker sregs.gdt.limit = mem::size_of_val(&gdt_table) as u16 - 1;
234*bb4ee6a4SAndroid Build Coastguard Worker
235*bb4ee6a4SAndroid Build Coastguard Worker write_idt_value(0, mem)?;
236*bb4ee6a4SAndroid Build Coastguard Worker sregs.idt.base = BOOT_IDT_OFFSET;
237*bb4ee6a4SAndroid Build Coastguard Worker sregs.idt.limit = mem::size_of::<u64>() as u16 - 1;
238*bb4ee6a4SAndroid Build Coastguard Worker
239*bb4ee6a4SAndroid Build Coastguard Worker sregs.cs = code_seg;
240*bb4ee6a4SAndroid Build Coastguard Worker sregs.ds = data_seg;
241*bb4ee6a4SAndroid Build Coastguard Worker sregs.es = data_seg;
242*bb4ee6a4SAndroid Build Coastguard Worker sregs.fs = data_seg;
243*bb4ee6a4SAndroid Build Coastguard Worker sregs.gs = data_seg;
244*bb4ee6a4SAndroid Build Coastguard Worker sregs.ss = data_seg;
245*bb4ee6a4SAndroid Build Coastguard Worker sregs.tr = tss_seg;
246*bb4ee6a4SAndroid Build Coastguard Worker
247*bb4ee6a4SAndroid Build Coastguard Worker /* 64-bit protected mode */
248*bb4ee6a4SAndroid Build Coastguard Worker sregs.cr0 |= X86_CR0_PE;
249*bb4ee6a4SAndroid Build Coastguard Worker sregs.efer |= EFER_LME;
250*bb4ee6a4SAndroid Build Coastguard Worker
251*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
252*bb4ee6a4SAndroid Build Coastguard Worker }
253*bb4ee6a4SAndroid Build Coastguard Worker
254*bb4ee6a4SAndroid Build Coastguard Worker /// Configures the GDT, IDT, and segment registers for 32-bit protected mode with paging disabled.
configure_segments_and_sregs_flat32(mem: &GuestMemory, sregs: &mut Sregs) -> Result<()>255*bb4ee6a4SAndroid Build Coastguard Worker pub fn configure_segments_and_sregs_flat32(mem: &GuestMemory, sregs: &mut Sregs) -> Result<()> {
256*bb4ee6a4SAndroid Build Coastguard Worker // reference: https://docs.kernel.org/arch/x86/boot.html?highlight=__BOOT_CS#id1
257*bb4ee6a4SAndroid Build Coastguard Worker let gdt_table: [u64; BOOT_GDT_MAX] = [
258*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0, 0, 0), // NULL
259*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0, 0, 0), // NULL
260*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0xc09b, 0, 0xfffff), // CODE
261*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA
262*bb4ee6a4SAndroid Build Coastguard Worker gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS
263*bb4ee6a4SAndroid Build Coastguard Worker ];
264*bb4ee6a4SAndroid Build Coastguard Worker
265*bb4ee6a4SAndroid Build Coastguard Worker let code_seg = gdt::segment_from_gdt(gdt_table[2], 2);
266*bb4ee6a4SAndroid Build Coastguard Worker let data_seg = gdt::segment_from_gdt(gdt_table[3], 3);
267*bb4ee6a4SAndroid Build Coastguard Worker let tss_seg = gdt::segment_from_gdt(gdt_table[4], 4);
268*bb4ee6a4SAndroid Build Coastguard Worker
269*bb4ee6a4SAndroid Build Coastguard Worker // Write segments
270*bb4ee6a4SAndroid Build Coastguard Worker write_gdt_table(&gdt_table[..], mem)?;
271*bb4ee6a4SAndroid Build Coastguard Worker sregs.gdt.base = BOOT_GDT_OFFSET;
272*bb4ee6a4SAndroid Build Coastguard Worker sregs.gdt.limit = mem::size_of_val(&gdt_table) as u16 - 1;
273*bb4ee6a4SAndroid Build Coastguard Worker
274*bb4ee6a4SAndroid Build Coastguard Worker write_idt_value(0, mem)?;
275*bb4ee6a4SAndroid Build Coastguard Worker sregs.idt.base = BOOT_IDT_OFFSET;
276*bb4ee6a4SAndroid Build Coastguard Worker sregs.idt.limit = mem::size_of::<u64>() as u16 - 1;
277*bb4ee6a4SAndroid Build Coastguard Worker
278*bb4ee6a4SAndroid Build Coastguard Worker sregs.cs = code_seg;
279*bb4ee6a4SAndroid Build Coastguard Worker sregs.ds = data_seg;
280*bb4ee6a4SAndroid Build Coastguard Worker sregs.es = data_seg;
281*bb4ee6a4SAndroid Build Coastguard Worker sregs.fs = data_seg;
282*bb4ee6a4SAndroid Build Coastguard Worker sregs.gs = data_seg;
283*bb4ee6a4SAndroid Build Coastguard Worker sregs.ss = data_seg;
284*bb4ee6a4SAndroid Build Coastguard Worker sregs.tr = tss_seg;
285*bb4ee6a4SAndroid Build Coastguard Worker
286*bb4ee6a4SAndroid Build Coastguard Worker /* 32-bit protected mode with paging disabled */
287*bb4ee6a4SAndroid Build Coastguard Worker sregs.cr0 |= X86_CR0_PE;
288*bb4ee6a4SAndroid Build Coastguard Worker sregs.cr0 &= !X86_CR0_PG;
289*bb4ee6a4SAndroid Build Coastguard Worker
290*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
291*bb4ee6a4SAndroid Build Coastguard Worker }
292*bb4ee6a4SAndroid Build Coastguard Worker
293*bb4ee6a4SAndroid Build Coastguard Worker /// Configures the system page tables and control registers for long mode with paging.
294*bb4ee6a4SAndroid Build Coastguard Worker /// Prepares identity mapping for the low 4GB memory.
setup_page_tables(mem: &GuestMemory, sregs: &mut Sregs) -> Result<()>295*bb4ee6a4SAndroid Build Coastguard Worker pub fn setup_page_tables(mem: &GuestMemory, sregs: &mut Sregs) -> Result<()> {
296*bb4ee6a4SAndroid Build Coastguard Worker // Puts PML4 right after zero page but aligned to 4k.
297*bb4ee6a4SAndroid Build Coastguard Worker let boot_pml4_addr = GuestAddress(0x9000);
298*bb4ee6a4SAndroid Build Coastguard Worker let boot_pdpte_addr = GuestAddress(0xa000);
299*bb4ee6a4SAndroid Build Coastguard Worker let boot_pde_addr = GuestAddress(0xb000);
300*bb4ee6a4SAndroid Build Coastguard Worker
301*bb4ee6a4SAndroid Build Coastguard Worker const PDE_FLAGS_TABLE_REFERENCE: u64 = 0x03; // Present | Read/Write
302*bb4ee6a4SAndroid Build Coastguard Worker const PDE_FLAGS_PAGE_MAPPING: u64 = 0x83; // Present | Read/Write | Page Size
303*bb4ee6a4SAndroid Build Coastguard Worker
304*bb4ee6a4SAndroid Build Coastguard Worker // Entry covering VA [0..512GB)
305*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(
306*bb4ee6a4SAndroid Build Coastguard Worker boot_pdpte_addr.offset() | PDE_FLAGS_TABLE_REFERENCE,
307*bb4ee6a4SAndroid Build Coastguard Worker boot_pml4_addr,
308*bb4ee6a4SAndroid Build Coastguard Worker )
309*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WritePML4Address)?;
310*bb4ee6a4SAndroid Build Coastguard Worker
311*bb4ee6a4SAndroid Build Coastguard Worker // Identity mapping for VA [0..4GB)
312*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..4 {
313*bb4ee6a4SAndroid Build Coastguard Worker let pde_addr = boot_pde_addr.unchecked_add(i * 0x1000);
314*bb4ee6a4SAndroid Build Coastguard Worker
315*bb4ee6a4SAndroid Build Coastguard Worker // Entry covering a single 1GB VA area
316*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(
317*bb4ee6a4SAndroid Build Coastguard Worker pde_addr.offset() | PDE_FLAGS_TABLE_REFERENCE,
318*bb4ee6a4SAndroid Build Coastguard Worker boot_pdpte_addr.unchecked_add(i * 8),
319*bb4ee6a4SAndroid Build Coastguard Worker )
320*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WritePDPTEAddress)?;
321*bb4ee6a4SAndroid Build Coastguard Worker
322*bb4ee6a4SAndroid Build Coastguard Worker // 512 2MB entries together covering a single 1GB VA area. Note we are assuming
323*bb4ee6a4SAndroid Build Coastguard Worker // CPU supports 2MB pages (/proc/cpuinfo has 'pse'). All modern CPUs do.
324*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..512 {
325*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(
326*bb4ee6a4SAndroid Build Coastguard Worker (i << 30) | (j << 21) | PDE_FLAGS_PAGE_MAPPING,
327*bb4ee6a4SAndroid Build Coastguard Worker pde_addr.unchecked_add(j * 8),
328*bb4ee6a4SAndroid Build Coastguard Worker )
329*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WritePDEAddress)?;
330*bb4ee6a4SAndroid Build Coastguard Worker }
331*bb4ee6a4SAndroid Build Coastguard Worker }
332*bb4ee6a4SAndroid Build Coastguard Worker
333*bb4ee6a4SAndroid Build Coastguard Worker sregs.cr3 = boot_pml4_addr.offset();
334*bb4ee6a4SAndroid Build Coastguard Worker sregs.cr4 |= X86_CR4_PAE;
335*bb4ee6a4SAndroid Build Coastguard Worker sregs.cr0 |= X86_CR0_PG;
336*bb4ee6a4SAndroid Build Coastguard Worker sregs.efer |= EFER_LMA; // Long mode is active. Must be auto-enabled with CR0_PG.
337*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
338*bb4ee6a4SAndroid Build Coastguard Worker }
339*bb4ee6a4SAndroid Build Coastguard Worker
340*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
341*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
342*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
343*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
344*bb4ee6a4SAndroid Build Coastguard Worker
345*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
346*bb4ee6a4SAndroid Build Coastguard Worker
create_guest_mem() -> GuestMemory347*bb4ee6a4SAndroid Build Coastguard Worker fn create_guest_mem() -> GuestMemory {
348*bb4ee6a4SAndroid Build Coastguard Worker GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap()
349*bb4ee6a4SAndroid Build Coastguard Worker }
350*bb4ee6a4SAndroid Build Coastguard Worker
read_u64(gm: &GuestMemory, offset: u64) -> u64351*bb4ee6a4SAndroid Build Coastguard Worker fn read_u64(gm: &GuestMemory, offset: u64) -> u64 {
352*bb4ee6a4SAndroid Build Coastguard Worker let read_addr = GuestAddress(offset);
353*bb4ee6a4SAndroid Build Coastguard Worker gm.read_obj_from_addr(read_addr).unwrap()
354*bb4ee6a4SAndroid Build Coastguard Worker }
355*bb4ee6a4SAndroid Build Coastguard Worker
356*bb4ee6a4SAndroid Build Coastguard Worker #[test]
segments_and_sregs()357*bb4ee6a4SAndroid Build Coastguard Worker fn segments_and_sregs() {
358*bb4ee6a4SAndroid Build Coastguard Worker let mut sregs = Default::default();
359*bb4ee6a4SAndroid Build Coastguard Worker let gm = create_guest_mem();
360*bb4ee6a4SAndroid Build Coastguard Worker configure_segments_and_sregs(&gm, &mut sregs).unwrap();
361*bb4ee6a4SAndroid Build Coastguard Worker
362*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x0, read_u64(&gm, BOOT_GDT_OFFSET));
363*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0xaf9b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 0x10));
364*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0xcf93000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 0x18));
365*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x8f8b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 0x20));
366*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x0, read_u64(&gm, BOOT_IDT_OFFSET));
367*bb4ee6a4SAndroid Build Coastguard Worker
368*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0, sregs.cs.base);
369*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0xffffffff, sregs.ds.limit_bytes);
370*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x10, sregs.cs.selector);
371*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x18, sregs.ds.selector);
372*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x18, sregs.es.selector);
373*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x18, sregs.ss.selector);
374*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(1, sregs.fs.present);
375*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(1, sregs.gs.g);
376*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0, sregs.ss.avl);
377*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0, sregs.tr.base);
378*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0xffffffff, sregs.tr.limit_bytes);
379*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0, sregs.tr.avl);
380*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(X86_CR0_PE, sregs.cr0 & X86_CR0_PE);
381*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(EFER_LME, sregs.efer);
382*bb4ee6a4SAndroid Build Coastguard Worker }
383*bb4ee6a4SAndroid Build Coastguard Worker
384*bb4ee6a4SAndroid Build Coastguard Worker #[test]
page_tables()385*bb4ee6a4SAndroid Build Coastguard Worker fn page_tables() {
386*bb4ee6a4SAndroid Build Coastguard Worker let mut sregs = Default::default();
387*bb4ee6a4SAndroid Build Coastguard Worker let gm = create_guest_mem();
388*bb4ee6a4SAndroid Build Coastguard Worker setup_page_tables(&gm, &mut sregs).unwrap();
389*bb4ee6a4SAndroid Build Coastguard Worker
390*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0xa003, read_u64(&gm, 0x9000));
391*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0xb003, read_u64(&gm, 0xa000));
392*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..512 {
393*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!((i << 21) + 0x83u64, read_u64(&gm, 0xb000 + i * 8));
394*bb4ee6a4SAndroid Build Coastguard Worker }
395*bb4ee6a4SAndroid Build Coastguard Worker
396*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(0x9000, sregs.cr3);
397*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(X86_CR4_PAE, sregs.cr4);
398*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(X86_CR0_PG, sregs.cr0 & X86_CR0_PG);
399*bb4ee6a4SAndroid Build Coastguard Worker }
400*bb4ee6a4SAndroid Build Coastguard Worker }
401