1 // Copyright © 2020, Oracle and/or its affiliates. 2 // 3 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 7 // Use of this source code is governed by a BSD-style license that can be 8 // found in the LICENSE-BSD-3-Clause file. 9 use crate::layout::{ 10 BOOT_GDT_START, BOOT_IDT_START, BOOT_STACK_POINTER, PVH_INFO_START, ZERO_PAGE_START, 11 }; 12 use crate::{EntryPoint, GuestMemoryMmap}; 13 use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt}; 14 use hypervisor::arch::x86::regs::CR0_PE; 15 use hypervisor::arch::x86::{FpuState, SpecialRegisters}; 16 use std::sync::Arc; 17 use std::{mem, result}; 18 use thiserror::Error; 19 use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError}; 20 21 #[derive(Debug, Error)] 22 pub enum Error { 23 /// Failed to get SREGs for this CPU. 24 #[error("Failed to get SREGs for this CPU: {0}")] 25 GetStatusRegisters(hypervisor::HypervisorCpuError), 26 /// Failed to set base registers for this CPU. 27 #[error("Failed to set base registers for this CPU: {0}")] 28 SetBaseRegisters(hypervisor::HypervisorCpuError), 29 /// Failed to configure the FPU. 30 #[error("Failed to configure the FPU: {0}")] 31 SetFpuRegisters(hypervisor::HypervisorCpuError), 32 /// Setting up MSRs failed. 33 #[error("Setting up MSRs failed: {0}")] 34 SetModelSpecificRegisters(hypervisor::HypervisorCpuError), 35 /// Failed to set SREGs for this CPU. 36 #[error("Failed to set SREGs for this CPU: {0}")] 37 SetStatusRegisters(hypervisor::HypervisorCpuError), 38 /// Checking the GDT address failed. 39 #[error("Checking the GDT address failed")] 40 CheckGdtAddr, 41 /// Writing the GDT to RAM failed. 42 #[error("Writing the GDT to RAM failed: {0}")] 43 WriteGdt(GuestMemoryError), 44 /// Writing the IDT to RAM failed. 45 #[error("Writing the IDT to RAM failed: {0}")] 46 WriteIdt(GuestMemoryError), 47 /// Writing PDPTE to RAM failed. 48 #[error("Writing PDPTE to RAM failed: {0}")] 49 WritePdpteAddress(GuestMemoryError), 50 /// Writing PDE to RAM failed. 51 #[error("Writing PDE to RAM failed: {0}")] 52 WritePdeAddress(GuestMemoryError), 53 /// Writing PML4 to RAM failed. 54 #[error("Writing PML4 to RAM failed: {0}")] 55 WritePml4Address(GuestMemoryError), 56 /// Writing PML5 to RAM failed. 57 #[error("Writing PML5 to RAM failed: {0}")] 58 WritePml5Address(GuestMemoryError), 59 } 60 61 pub type Result<T> = result::Result<T, Error>; 62 63 /// Configure Floating-Point Unit (FPU) registers for a given CPU. 64 /// 65 /// # Arguments 66 /// 67 /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. 68 pub fn setup_fpu(vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<()> { 69 let fpu: FpuState = FpuState { 70 fcw: 0x37f, 71 mxcsr: 0x1f80, 72 ..Default::default() 73 }; 74 75 vcpu.set_fpu(&fpu).map_err(Error::SetFpuRegisters) 76 } 77 78 /// Configure Model Specific Registers (MSRs) for a given CPU. 79 /// 80 /// # Arguments 81 /// 82 /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. 83 pub fn setup_msrs(vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<()> { 84 vcpu.set_msrs(&vcpu.boot_msr_entries()) 85 .map_err(Error::SetModelSpecificRegisters)?; 86 87 Ok(()) 88 } 89 90 /// Configure base registers for a given CPU. 91 /// 92 /// # Arguments 93 /// 94 /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. 95 /// * `entry_point` - Description of the boot entry to set up. 96 pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, entry_point: EntryPoint) -> Result<()> { 97 let mut regs = vcpu.create_standard_regs(); 98 match entry_point.setup_header { 99 None => { 100 regs.set_rflags(0x0000000000000002u64); 101 regs.set_rip(entry_point.entry_addr.raw_value()); 102 regs.set_rbx(PVH_INFO_START.raw_value()); 103 } 104 Some(_) => { 105 regs.set_rflags(0x0000000000000002u64); 106 regs.set_rip(entry_point.entry_addr.raw_value()); 107 regs.set_rsp(BOOT_STACK_POINTER.raw_value()); 108 regs.set_rsi(ZERO_PAGE_START.raw_value()); 109 } 110 }; 111 vcpu.set_regs(®s).map_err(Error::SetBaseRegisters) 112 } 113 114 /// Configures the segment registers and system page tables for a given CPU. 115 /// 116 /// # Arguments 117 /// 118 /// * `mem` - The memory that will be passed to the guest. 119 /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. 120 pub fn setup_sregs(mem: &GuestMemoryMmap, vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<()> { 121 let mut sregs: SpecialRegisters = vcpu.get_sregs().map_err(Error::GetStatusRegisters)?; 122 configure_segments_and_sregs(mem, &mut sregs)?; 123 vcpu.set_sregs(&sregs).map_err(Error::SetStatusRegisters) 124 } 125 126 const BOOT_GDT_MAX: usize = 4; 127 128 fn write_gdt_table(table: &[u64], guest_mem: &GuestMemoryMmap) -> Result<()> { 129 let boot_gdt_addr = BOOT_GDT_START; 130 for (index, entry) in table.iter().enumerate() { 131 let addr = guest_mem 132 .checked_offset(boot_gdt_addr, index * mem::size_of::<u64>()) 133 .ok_or(Error::CheckGdtAddr)?; 134 guest_mem.write_obj(*entry, addr).map_err(Error::WriteGdt)?; 135 } 136 Ok(()) 137 } 138 139 fn write_idt_value(val: u64, guest_mem: &GuestMemoryMmap) -> Result<()> { 140 let boot_idt_addr = BOOT_IDT_START; 141 guest_mem 142 .write_obj(val, boot_idt_addr) 143 .map_err(Error::WriteIdt) 144 } 145 146 pub fn configure_segments_and_sregs( 147 mem: &GuestMemoryMmap, 148 sregs: &mut SpecialRegisters, 149 ) -> Result<()> { 150 let gdt_table: [u64; BOOT_GDT_MAX] = { 151 // Configure GDT entries as specified by PVH boot protocol 152 [ 153 gdt_entry(0, 0, 0), // NULL 154 gdt_entry(0xc09b, 0, 0xffffffff), // CODE 155 gdt_entry(0xc093, 0, 0xffffffff), // DATA 156 gdt_entry(0x008b, 0, 0x67), // TSS 157 ] 158 }; 159 160 let code_seg = segment_from_gdt(gdt_table[1], 1); 161 let data_seg = segment_from_gdt(gdt_table[2], 2); 162 let tss_seg = segment_from_gdt(gdt_table[3], 3); 163 164 // Write segments 165 write_gdt_table(&gdt_table[..], mem)?; 166 sregs.gdt.base = BOOT_GDT_START.raw_value(); 167 sregs.gdt.limit = mem::size_of_val(&gdt_table) as u16 - 1; 168 169 write_idt_value(0, mem)?; 170 sregs.idt.base = BOOT_IDT_START.raw_value(); 171 sregs.idt.limit = mem::size_of::<u64>() as u16 - 1; 172 173 sregs.cs = code_seg; 174 sregs.ds = data_seg; 175 sregs.es = data_seg; 176 sregs.fs = data_seg; 177 sregs.gs = data_seg; 178 sregs.ss = data_seg; 179 sregs.tr = tss_seg; 180 181 sregs.cr0 = CR0_PE; 182 sregs.cr4 = 0; 183 184 Ok(()) 185 } 186 187 #[cfg(test)] 188 mod tests { 189 use super::*; 190 use vm_memory::GuestAddress; 191 192 fn create_guest_mem() -> GuestMemoryMmap { 193 GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap() 194 } 195 196 fn read_u64(gm: &GuestMemoryMmap, offset: GuestAddress) -> u64 { 197 gm.read_obj(offset).unwrap() 198 } 199 200 #[test] 201 fn segments_and_sregs() { 202 let mut sregs: SpecialRegisters = Default::default(); 203 let gm = create_guest_mem(); 204 configure_segments_and_sregs(&gm, &mut sregs).unwrap(); 205 assert_eq!(0x0, read_u64(&gm, BOOT_GDT_START)); 206 assert_eq!( 207 0xcf9b000000ffff, 208 read_u64(&gm, BOOT_GDT_START.unchecked_add(8)) 209 ); 210 assert_eq!( 211 0xcf93000000ffff, 212 read_u64(&gm, BOOT_GDT_START.unchecked_add(16)) 213 ); 214 assert_eq!( 215 0x8b0000000067, 216 read_u64(&gm, BOOT_GDT_START.unchecked_add(24)) 217 ); 218 assert_eq!(0x0, read_u64(&gm, BOOT_IDT_START)); 219 220 assert_eq!(0, sregs.cs.base); 221 assert_eq!(0xffffffff, sregs.ds.limit); 222 assert_eq!(0x10, sregs.es.selector); 223 assert_eq!(1, sregs.fs.present); 224 assert_eq!(1, sregs.gs.g); 225 assert_eq!(0, sregs.ss.avl); 226 assert_eq!(0, sregs.tr.base); 227 assert_eq!(0, sregs.tr.g); 228 assert_eq!(0x67, sregs.tr.limit); 229 assert_eq!(0xb, sregs.tr.type_); 230 assert_eq!(0, sregs.tr.avl); 231 assert_eq!(CR0_PE, sregs.cr0); 232 assert_eq!(0, sregs.cr4); 233 } 234 } 235