From bde4de80f1456cf6853f88b4e03263acedc30b69 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Tue, 4 Dec 2018 11:11:23 -0600 Subject: [PATCH 1/9] ARM: rename x86_64 crate to arch Also, * move the autogenerated code in a different crate named `arch_gen` * x86_64 code code inside `arch` and `arch_gen` is labeled as such Signed-off-by: Diana Popa --- Cargo.lock | 38 +++-- api_server/Cargo.toml | 2 +- api_server/src/request/mod.rs | 4 +- {x86_64 => arch}/Cargo.toml | 3 +- arch/src/lib.rs | 36 ++++ {x86_64/src => arch/src/x86_64}/gdt.rs | 0 {x86_64/src => arch/src/x86_64}/interrupts.rs | 0 arch/src/x86_64/layout.rs | 20 +++ x86_64/src/lib.rs => arch/src/x86_64/mod.rs | 86 ++++------ {x86_64/src => arch/src/x86_64}/mptable.rs | 156 ++++++++---------- {x86_64/src => arch/src/x86_64}/regs.rs | 73 ++++---- arch_gen/Cargo.toml | 7 + arch_gen/src/lib.rs | 7 + {x86_64/src => arch_gen/src/x86}/bootparam.rs | 2 +- arch_gen/src/x86/mod.rs | 27 +++ {x86_64/src => arch_gen/src/x86}/mpspec.rs | 0 {x86_64/src => arch_gen/src/x86}/msr_index.rs | 0 kernel/Cargo.toml | 2 +- vmm/Cargo.toml | 2 +- vmm/src/lib.rs | 5 +- vmm/src/vmm_config/instance_info.rs | 3 +- vmm/src/vstate.rs | 13 +- x86_64/src/layout.rs | 27 --- 23 files changed, 276 insertions(+), 237 deletions(-) rename {x86_64 => arch}/Cargo.toml (85%) create mode 100644 arch/src/lib.rs rename {x86_64/src => arch/src/x86_64}/gdt.rs (100%) rename {x86_64/src => arch/src/x86_64}/interrupts.rs (100%) create mode 100644 arch/src/x86_64/layout.rs rename x86_64/src/lib.rs => arch/src/x86_64/mod.rs (79%) rename {x86_64/src => arch/src/x86_64}/mptable.rs (69%) rename {x86_64/src => arch/src/x86_64}/regs.rs (87%) create mode 100644 arch_gen/Cargo.toml create mode 100644 arch_gen/src/lib.rs rename {x86_64/src => arch_gen/src/x86}/bootparam.rs (99%) create mode 100644 arch_gen/src/x86/mod.rs rename {x86_64/src => arch_gen/src/x86}/mpspec.rs (100%) rename {x86_64/src => arch_gen/src/x86}/msr_index.rs (100%) delete mode 100644 x86_64/src/layout.rs diff --git a/Cargo.lock b/Cargo.lock index 99543129e89..eccb5056ff6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "api_server" version = "0.1.0" dependencies = [ + "arch 0.1.0", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "devices 0.1.0", "fc_util 0.1.0", @@ -34,7 +35,27 @@ dependencies = [ "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "vmm 0.1.0", - "x86_64 0.1.0", +] + +[[package]] +name = "arch" +version = "0.1.0" +dependencies = [ + "arch_gen 0.1.0", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kvm 0.1.0", + "kvm_wrapper 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "memory_model 0.1.0", + "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "sys_util 0.1.0", +] + +[[package]] +name = "arch_gen" +version = "0.1.0" +dependencies = [ + "memory_model 0.1.0", ] [[package]] @@ -1213,6 +1234,7 @@ version = "0.1.0" name = "vmm" version = "0.1.0" dependencies = [ + "arch 0.1.0", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "cpuid 0.1.0", "devices 0.1.0", @@ -1235,7 +1257,6 @@ dependencies = [ "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "timerfd 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.1.0", ] [[package]] @@ -1276,19 +1297,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "x86_64" -version = "0.1.0" -dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kvm 0.1.0", - "kvm_wrapper 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "memory_model 0.1.0", - "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "sys_util 0.1.0", -] - [metadata] "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" diff --git a/api_server/Cargo.toml b/api_server/Cargo.toml index a102a2e8413..13848a26380 100644 --- a/api_server/Cargo.toml +++ b/api_server/Cargo.toml @@ -21,12 +21,12 @@ sys_util = { path = "../sys_util" } vmm = { path = "../vmm" } [dev-dependencies] +arch = { path = "../arch" } devices = { path = "../devices" } kernel = { path = "../kernel" } memory_model = { path = "../memory_model" } net_util = { path = "../net_util" } rate_limiter = { path = "../rate_limiter" } -x86_64 = { path = "../x86_64" } [features] vsock = ["vmm/vsock"] diff --git a/api_server/src/request/mod.rs b/api_server/src/request/mod.rs index f353a0ea7b3..8f9156e1b92 100644 --- a/api_server/src/request/mod.rs +++ b/api_server/src/request/mod.rs @@ -97,11 +97,11 @@ impl PartialEq for ParsedRequest { #[cfg(test)] mod tests { + extern crate arch; extern crate devices; extern crate kernel; extern crate memory_model; extern crate net_util; - extern crate x86_64; use self::devices::virtio::net::Error as VirtioNetError; use self::memory_model::GuestMemoryError; @@ -300,7 +300,7 @@ mod tests { check_error_response(vmm_resp, StatusCode::InternalServerError); let vmm_resp = VmmActionError::StartMicrovm( ErrorKind::Internal, - StartMicrovmError::ConfigureSystem(x86_64::Error::E820Configuration), + StartMicrovmError::ConfigureSystem(arch::Error::ZeroPagePastRamEnd), ); check_error_response(vmm_resp, StatusCode::InternalServerError); let vmm_resp = VmmActionError::StartMicrovm( diff --git a/x86_64/Cargo.toml b/arch/Cargo.toml similarity index 85% rename from x86_64/Cargo.toml rename to arch/Cargo.toml index d575260fac0..20868119ef8 100644 --- a/x86_64/Cargo.toml +++ b/arch/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "x86_64" +name = "arch" version = "0.1.0" authors = ["The Chromium OS Authors"] @@ -8,6 +8,7 @@ byteorder = "=1.2.1" kvm_wrapper = ">=0.1.0" libc = ">=0.2.39" +arch_gen = { path = "../arch_gen" } kvm = { path = "../kvm" } memory_model = { path = "../memory_model" } sys_util = { path = "../sys_util" } diff --git a/arch/src/lib.rs b/arch/src/lib.rs new file mode 100644 index 00000000000..8d52a17f690 --- /dev/null +++ b/arch/src/lib.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +extern crate byteorder; +extern crate kvm_wrapper; +extern crate libc; + +extern crate arch_gen; +extern crate kvm; +extern crate memory_model; +extern crate sys_util; + +use std::result; + +#[derive(Debug, PartialEq)] +pub enum Error { + /// The zero page extends past the end of guest_mem. + ZeroPagePastRamEnd, + /// Error writing the zero page of guest memory. + ZeroPageSetup, + #[cfg(target_arch = "x86_64")] + /// X86_64 specific error triggered during system configuration. + X86_64Setup(x86_64::Error), +} +pub type Result = result::Result; + +// 1MB. We don't put anything above here except the kernel itself. +pub const HIMEM_START: usize = 0x100000; + +#[cfg(target_arch = "x86_64")] +pub mod x86_64; +impl From for Error { + fn from(e: x86_64::Error) -> Error { + Error::X86_64Setup(e) + } +} diff --git a/x86_64/src/gdt.rs b/arch/src/x86_64/gdt.rs similarity index 100% rename from x86_64/src/gdt.rs rename to arch/src/x86_64/gdt.rs diff --git a/x86_64/src/interrupts.rs b/arch/src/x86_64/interrupts.rs similarity index 100% rename from x86_64/src/interrupts.rs rename to arch/src/x86_64/interrupts.rs diff --git a/arch/src/x86_64/layout.rs b/arch/src/x86_64/layout.rs new file mode 100644 index 00000000000..39f2fdc5d24 --- /dev/null +++ b/arch/src/x86_64/layout.rs @@ -0,0 +1,20 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// Portions 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 THIRD-PARTY file. + +/// Magic addresses externally used to lay out x86_64 VMs. + +/// Initial stack for the boot CPU. +pub const BOOT_STACK_START: usize = 0x8000; +pub const BOOT_STACK_POINTER: usize = 0x8ff0; + +/// Kernel command line start address. +pub const CMDLINE_START: usize = 0x20000; +/// Kernel command line start address maximum size. +pub const CMDLINE_MAX_SIZE: usize = 0x10000; + +/// The 'zero page', a.k.a linux kernel bootparams. +pub const ZERO_PAGE_START: usize = 0x7000; diff --git a/x86_64/src/lib.rs b/arch/src/x86_64/mod.rs similarity index 79% rename from x86_64/src/lib.rs rename to arch/src/x86_64/mod.rs index a15422e1e75..d4f58dc1502 100644 --- a/x86_64/src/lib.rs +++ b/arch/src/x86_64/mod.rs @@ -5,38 +5,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the THIRD-PARTY file. -extern crate byteorder; -extern crate kvm; -extern crate kvm_wrapper; -extern crate libc; -extern crate memory_model; -extern crate sys_util; - -#[allow(dead_code)] -#[allow(non_upper_case_globals)] -#[allow(non_camel_case_types)] -#[allow(non_snake_case)] -mod bootparam; -// boot_params is just a series of ints, it is safe to initialize it. -unsafe impl memory_model::DataInit for bootparam::boot_params {} - -#[allow(dead_code)] -#[allow(non_upper_case_globals)] -mod msr_index; - -#[allow(dead_code)] -#[allow(non_upper_case_globals)] -#[allow(non_camel_case_types)] -mod mpspec; -// These mpspec types are only data, reading them from data is a safe initialization. -unsafe impl memory_model::DataInit for mpspec::mpc_bus {} -unsafe impl memory_model::DataInit for mpspec::mpc_cpu {} -unsafe impl memory_model::DataInit for mpspec::mpc_intsrc {} -unsafe impl memory_model::DataInit for mpspec::mpc_ioapic {} -unsafe impl memory_model::DataInit for mpspec::mpc_table {} -unsafe impl memory_model::DataInit for mpspec::mpc_lintsrc {} -unsafe impl memory_model::DataInit for mpspec::mpf_intel {} - mod gdt; pub mod interrupts; pub mod layout; @@ -44,31 +12,22 @@ mod mptable; pub mod regs; use std::mem; -use std::result; -use bootparam::boot_params; -use bootparam::E820_RAM; +use arch_gen::x86::bootparam::{boot_params, E820_RAM}; use memory_model::{GuestAddress, GuestMemory}; -pub use interrupts::Error as IntError; -pub use mptable::Error as MpTableError; -pub use regs::Error as RegError; +// Where BIOS/VGA magic would live on a real PC. +const EBDA_START: u64 = 0x9fc00; +const FIRST_ADDR_PAST_32BITS: usize = (1 << 32); +const MEM_32BIT_GAP_SIZE: usize = (768 << 20); -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Error { /// Invalid e820 setup params. E820Configuration, /// Error writing MP table to memory. - MpTableSetup(MpTableError), - /// The zero page extends past the end of guest_mem. - ZeroPagePastRamEnd, - /// Error writing the zero page of guest memory. - ZeroPageSetup, + MpTableSetup(mptable::Error), } -pub type Result = result::Result; - -const FIRST_ADDR_PAST_32BITS: usize = (1 << 32); -const MEM_32BIT_GAP_SIZE: usize = (768 << 20); /// Returns a Vec of the valid memory addresses. /// These should be used to configure the GuestMemory structure for the platform. @@ -96,8 +55,7 @@ pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> { regions } -/// X86 specific memory hole/ memory mapped devices/ reserved area. -/// +/// X86 specific memory hole/memory mapped devices/reserved area. pub fn get_32bit_gap_start() -> usize { FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE } @@ -115,7 +73,7 @@ pub fn configure_system( cmdline_addr: GuestAddress, cmdline_size: usize, num_cpus: u8, -) -> Result<()> { +) -> super::Result<()> { const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; const KERNEL_HDR_MAGIC: u32 = 0x53726448; const KERNEL_LOADER_OTHER: u8 = 0xff; @@ -123,7 +81,7 @@ pub fn configure_system( let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS); let end_32bit_gap_start = GuestAddress(get_32bit_gap_start()); - let himem_start = GuestAddress(layout::HIMEM_START); + let himem_start = GuestAddress(super::HIMEM_START); // Note that this puts the mptable at the last 1k of Linux's 640k base RAM mptable::setup_mptable(guest_mem, num_cpus).map_err(Error::MpTableSetup)?; @@ -137,7 +95,7 @@ pub fn configure_system( params.hdr.cmdline_size = cmdline_size as u32; params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES; - add_e820_entry(&mut params, 0, layout::EBDA_START, E820_RAM)?; + add_e820_entry(&mut params, 0, EBDA_START, E820_RAM)?; let mem_end = guest_mem.end_addr(); if mem_end < end_32bit_gap_start { @@ -167,17 +125,22 @@ pub fn configure_system( let zero_page_addr = GuestAddress(layout::ZERO_PAGE_START); guest_mem .checked_offset(zero_page_addr, mem::size_of::()) - .ok_or(Error::ZeroPagePastRamEnd)?; + .ok_or(super::Error::ZeroPagePastRamEnd)?; guest_mem .write_obj_at_addr(params, zero_page_addr) - .map_err(|_| Error::ZeroPageSetup)?; + .map_err(|_| super::Error::ZeroPageSetup)?; Ok(()) } /// Add an e820 region to the e820 map. /// Returns Ok(()) if successful, or an error if there is no space left in the map. -fn add_e820_entry(params: &mut boot_params, addr: u64, size: u64, mem_type: u32) -> Result<()> { +fn add_e820_entry( + params: &mut boot_params, + addr: u64, + size: u64, + mem_type: u32, +) -> Result<(), Error> { if params.e820_entries >= params.e820_map.len() as u8 { return Err(Error::E820Configuration); } @@ -193,7 +156,7 @@ fn add_e820_entry(params: &mut boot_params, addr: u64, size: u64, mem_type: u32) #[cfg(test)] mod tests { use super::*; - use bootparam::e820entry; + use arch_gen::x86::bootparam::e820entry; #[test] fn regions_lt_4gb() { @@ -223,7 +186,14 @@ mod tests { fn test_system_configuration() { let no_vcpus = 4; let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); - assert!(configure_system(&gm, GuestAddress(0), 0, 1).is_err()); + let config_err = configure_system(&gm, GuestAddress(0), 0, 1); + assert!(config_err.is_err()); + assert_eq!( + config_err.unwrap_err(), + super::super::Error::X86_64Setup(super::Error::MpTableSetup( + mptable::Error::NotEnoughMemory + )) + ); // Now assigning some memory that falls before the 32bit memory hole. let mem_size = 128 << 20; diff --git a/x86_64/src/mptable.rs b/arch/src/x86_64/mptable.rs similarity index 69% rename from x86_64/src/mptable.rs rename to arch/src/x86_64/mptable.rs index f5ee2015106..39390e87a0d 100644 --- a/x86_64/src/mptable.rs +++ b/arch/src/x86_64/mptable.rs @@ -12,12 +12,13 @@ use std::slice; use libc::c_char; +use arch_gen::x86::mpspec; use memory_model::{GuestAddress, GuestMemory}; -use layout; -use mpspec::*; +// MPTABLE, describing VCPUS. +const MPTABLE_START: usize = 0x9fc00; -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Error { /// There was too little guest memory to store the entire MP table. NotEnoughMemory, @@ -72,25 +73,25 @@ fn compute_checksum(v: &T) -> u8 { checksum } -fn mpf_intel_compute_checksum(v: &mpf_intel) -> u8 { +fn mpf_intel_compute_checksum(v: &mpspec::mpf_intel) -> u8 { let checksum = compute_checksum(v).wrapping_sub(v.checksum); (!checksum).wrapping_add(1) } fn compute_mp_size(num_cpus: u8) -> usize { - mem::size_of::() - + mem::size_of::() - + mem::size_of::() * (num_cpus as usize) - + mem::size_of::() - + mem::size_of::() - + mem::size_of::() * 16 - + mem::size_of::() * 2 + mem::size_of::() + + mem::size_of::() + + mem::size_of::() * (num_cpus as usize) + + mem::size_of::() + + mem::size_of::() + + mem::size_of::() * 16 + + mem::size_of::() * 2 } /// Performs setup of the MP table for the given `num_cpus`. pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { // Used to keep track of the next base pointer into the MP table. - let mut base_mp = GuestAddress(layout::MPTABLE_START); + let mut base_mp = GuestAddress(MPTABLE_START); let mp_size = compute_mp_size(num_cpus); @@ -111,8 +112,8 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { .map_err(|_| Error::Clear)?; { - let size = mem::size_of::(); - let mut mpf_intel = mpf_intel::default(); + let size = mem::size_of::(); + let mut mpf_intel = mpspec::mpf_intel::default(); mpf_intel.signature = SMP_MAGIC_IDENT; mpf_intel.length = 1; mpf_intel.specification = 4; @@ -126,18 +127,18 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { // We set the location of the mpc_table here but we can't fill it out until we have the length // of the entire table later. let table_base = base_mp; - base_mp = base_mp.unchecked_add(mem::size_of::()); + base_mp = base_mp.unchecked_add(mem::size_of::()); { - let size = mem::size_of::(); + let size = mem::size_of::(); for cpu_id in 0..num_cpus { - let mut mpc_cpu = mpc_cpu::default(); - mpc_cpu.type_ = MP_PROCESSOR as u8; + let mut mpc_cpu = mpspec::mpc_cpu::default(); + mpc_cpu.type_ = mpspec::MP_PROCESSOR as u8; mpc_cpu.apicid = cpu_id; mpc_cpu.apicver = APIC_VERSION; - mpc_cpu.cpuflag = CPU_ENABLED as u8 + mpc_cpu.cpuflag = mpspec::CPU_ENABLED as u8 | if cpu_id == 0 { - CPU_BOOTPROCESSOR as u8 + mpspec::CPU_BOOTPROCESSOR as u8 } else { 0 }; @@ -150,9 +151,9 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { } } { - let size = mem::size_of::(); - let mut mpc_bus = mpc_bus::default(); - mpc_bus.type_ = MP_BUS as u8; + let size = mem::size_of::(); + let mut mpc_bus = mpspec::mpc_bus::default(); + mpc_bus.type_ = mpspec::MP_BUS as u8; mpc_bus.busid = 0; mpc_bus.bustype = BUS_TYPE_ISA; mem.write_obj_at_addr(mpc_bus, base_mp) @@ -161,12 +162,12 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { checksum = checksum.wrapping_add(compute_checksum(&mpc_bus)); } { - let size = mem::size_of::(); - let mut mpc_ioapic = mpc_ioapic::default(); - mpc_ioapic.type_ = MP_IOAPIC as u8; + let size = mem::size_of::(); + let mut mpc_ioapic = mpspec::mpc_ioapic::default(); + mpc_ioapic.type_ = mpspec::MP_IOAPIC as u8; mpc_ioapic.apicid = ioapicid; mpc_ioapic.apicver = APIC_VERSION; - mpc_ioapic.flags = MPC_APIC_USABLE as u8; + mpc_ioapic.flags = mpspec::MPC_APIC_USABLE as u8; mpc_ioapic.apicaddr = IO_APIC_DEFAULT_PHYS_BASE; mem.write_obj_at_addr(mpc_ioapic, base_mp) .map_err(|_| Error::WriteMpcIoapic)?; @@ -175,11 +176,11 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { } // Per kvm_setup_default_irq_routing() in kernel for i in 0..16 { - let size = mem::size_of::(); - let mut mpc_intsrc = mpc_intsrc::default(); - mpc_intsrc.type_ = MP_INTSRC as u8; - mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8; - mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16; + let size = mem::size_of::(); + let mut mpc_intsrc = mpspec::mpc_intsrc::default(); + mpc_intsrc.type_ = mpspec::MP_INTSRC as u8; + mpc_intsrc.irqtype = mpspec::mp_irq_source_types_mp_INT as u8; + mpc_intsrc.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16; mpc_intsrc.srcbus = 0; mpc_intsrc.srcbusirq = i; mpc_intsrc.dstapic = ioapicid; @@ -190,11 +191,11 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc)); } { - let size = mem::size_of::(); - let mut mpc_lintsrc = mpc_lintsrc::default(); - mpc_lintsrc.type_ = MP_LINTSRC as u8; - mpc_lintsrc.irqtype = mp_irq_source_types_mp_ExtINT as u8; - mpc_lintsrc.irqflag = MP_IRQDIR_DEFAULT as u16; + let size = mem::size_of::(); + let mut mpc_lintsrc = mpspec::mpc_lintsrc::default(); + mpc_lintsrc.type_ = mpspec::MP_LINTSRC as u8; + mpc_lintsrc.irqtype = mpspec::mp_irq_source_types_mp_ExtINT as u8; + mpc_lintsrc.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16; mpc_lintsrc.srcbusid = 0; mpc_lintsrc.srcbusirq = 0; mpc_lintsrc.destapic = 0; @@ -205,11 +206,11 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { checksum = checksum.wrapping_add(compute_checksum(&mpc_lintsrc)); } { - let size = mem::size_of::(); - let mut mpc_lintsrc = mpc_lintsrc::default(); - mpc_lintsrc.type_ = MP_LINTSRC as u8; - mpc_lintsrc.irqtype = mp_irq_source_types_mp_NMI as u8; - mpc_lintsrc.irqflag = MP_IRQDIR_DEFAULT as u16; + let size = mem::size_of::(); + let mut mpc_lintsrc = mpspec::mpc_lintsrc::default(); + mpc_lintsrc.type_ = mpspec::MP_LINTSRC as u8; + mpc_lintsrc.irqtype = mpspec::mp_irq_source_types_mp_NMI as u8; + mpc_lintsrc.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16; mpc_lintsrc.srcbusid = 0; mpc_lintsrc.srcbusirq = 0; mpc_lintsrc.destapic = 0xFF; /* to all local APICs */ @@ -224,7 +225,7 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> { let table_end = base_mp; { - let mut mpc_table = mpc_table::default(); + let mut mpc_table = mpspec::mpc_table::default(); mpc_table.signature = MPC_SIGNATURE; mpc_table.length = table_end.offset_from(table_base) as u16; mpc_table.spec = MPC_SPEC; @@ -246,11 +247,11 @@ mod tests { fn table_entry_size(type_: u8) -> usize { match type_ as u32 { - MP_PROCESSOR => mem::size_of::(), - MP_BUS => mem::size_of::(), - MP_IOAPIC => mem::size_of::(), - MP_INTSRC => mem::size_of::(), - MP_LINTSRC => mem::size_of::(), + mpspec::MP_PROCESSOR => mem::size_of::(), + mpspec::MP_BUS => mem::size_of::(), + mpspec::MP_IOAPIC => mem::size_of::(), + mpspec::MP_INTSRC => mem::size_of::(), + mpspec::MP_LINTSRC => mem::size_of::(), _ => panic!("unrecognized mpc table entry type: {}", type_), } } @@ -258,11 +259,8 @@ mod tests { #[test] fn bounds_check() { let num_cpus = 4; - let mem = GuestMemory::new(&[( - GuestAddress(layout::MPTABLE_START), - compute_mp_size(num_cpus), - )]) - .unwrap(); + let mem = + GuestMemory::new(&[(GuestAddress(MPTABLE_START), compute_mp_size(num_cpus))]).unwrap(); setup_mptable(&mem, num_cpus).unwrap(); } @@ -270,11 +268,8 @@ mod tests { #[test] fn bounds_check_fails() { let num_cpus = 4; - let mem = GuestMemory::new(&[( - GuestAddress(layout::MPTABLE_START), - compute_mp_size(num_cpus) - 1, - )]) - .unwrap(); + let mem = GuestMemory::new(&[(GuestAddress(MPTABLE_START), compute_mp_size(num_cpus) - 1)]) + .unwrap(); assert!(setup_mptable(&mem, num_cpus).is_err()); } @@ -282,17 +277,12 @@ mod tests { #[test] fn mpf_intel_checksum() { let num_cpus = 1; - let mem = GuestMemory::new(&[( - GuestAddress(layout::MPTABLE_START), - compute_mp_size(num_cpus), - )]) - .unwrap(); + let mem = + GuestMemory::new(&[(GuestAddress(MPTABLE_START), compute_mp_size(num_cpus))]).unwrap(); setup_mptable(&mem, num_cpus).unwrap(); - let mpf_intel = mem - .read_obj_from_addr(GuestAddress(layout::MPTABLE_START)) - .unwrap(); + let mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap(); assert_eq!(mpf_intel_compute_checksum(&mpf_intel), mpf_intel.checksum); } @@ -300,19 +290,15 @@ mod tests { #[test] fn mpc_table_checksum() { let num_cpus = 4; - let mem = GuestMemory::new(&[( - GuestAddress(layout::MPTABLE_START), - compute_mp_size(num_cpus), - )]) - .unwrap(); + let mem = + GuestMemory::new(&[(GuestAddress(MPTABLE_START), compute_mp_size(num_cpus))]).unwrap(); setup_mptable(&mem, num_cpus).unwrap(); - let mpf_intel: mpf_intel = mem - .read_obj_from_addr(GuestAddress(layout::MPTABLE_START)) - .unwrap(); + let mpf_intel: mpspec::mpf_intel = + mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap(); let mpc_offset = GuestAddress(mpf_intel.physptr as usize); - let mpc_table: mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap(); + let mpc_table: mpspec::mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap(); struct Sum(u8); impl io::Write for Sum { @@ -336,23 +322,21 @@ mod tests { #[test] fn cpu_entry_count() { const MAX_CPUS: u8 = 0xff; - let mem = GuestMemory::new(&[( - GuestAddress(layout::MPTABLE_START), - compute_mp_size(MAX_CPUS), - )]) - .unwrap(); + let mem = + GuestMemory::new(&[(GuestAddress(MPTABLE_START), compute_mp_size(MAX_CPUS))]).unwrap(); for i in 0..MAX_CPUS { setup_mptable(&mem, i).unwrap(); - let mpf_intel: mpf_intel = mem - .read_obj_from_addr(GuestAddress(layout::MPTABLE_START)) - .unwrap(); + let mpf_intel: mpspec::mpf_intel = + mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap(); let mpc_offset = GuestAddress(mpf_intel.physptr as usize); - let mpc_table: mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap(); + let mpc_table: mpspec::mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap(); let mpc_end = mpc_offset.checked_add(mpc_table.length as usize).unwrap(); - let mut entry_offset = mpc_offset.checked_add(mem::size_of::()).unwrap(); + let mut entry_offset = mpc_offset + .checked_add(mem::size_of::()) + .unwrap(); let mut cpu_count = 0; while entry_offset < mpc_end { let entry_type: u8 = mem.read_obj_from_addr(entry_offset).unwrap(); @@ -360,7 +344,7 @@ mod tests { .checked_add(table_entry_size(entry_type)) .unwrap(); assert!(entry_offset <= mpc_end); - if entry_type as u32 == MP_PROCESSOR { + if entry_type as u32 == mpspec::MP_PROCESSOR { cpu_count += 1; } } diff --git a/x86_64/src/regs.rs b/arch/src/x86_64/regs.rs similarity index 87% rename from x86_64/src/regs.rs rename to arch/src/x86_64/regs.rs index 027726eeeb3..eba975cd4f5 100644 --- a/x86_64/src/regs.rs +++ b/arch/src/x86_64/regs.rs @@ -7,13 +7,18 @@ use std::{mem, result}; -use gdt; -use kvm; +use super::gdt::{gdt_entry, kvm_segment_from_gdt}; +use arch_gen::x86::msr_index; +use kvm::VcpuFd; use kvm_wrapper::{kvm_fpu, kvm_msr_entry, kvm_msrs, kvm_regs, kvm_sregs}; -use layout; use memory_model::{GuestAddress, GuestMemory}; use sys_util; +// Initial pagetables. +const PML4_START: usize = 0x9000; +const PDPTE_START: usize = 0xa000; +const PDE_START: usize = 0xb000; + #[derive(Debug)] pub enum Error { /// Failed to get SREGs for this CPU. @@ -45,7 +50,7 @@ pub type Result = result::Result; /// # Arguments /// /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. -pub fn setup_fpu(vcpu: &kvm::VcpuFd) -> Result<()> { +pub fn setup_fpu(vcpu: &VcpuFd) -> Result<()> { let fpu: kvm_fpu = kvm_fpu { fcw: 0x37f, mxcsr: 0x1f80, @@ -60,7 +65,7 @@ pub fn setup_fpu(vcpu: &kvm::VcpuFd) -> Result<()> { /// # Arguments /// /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. -pub fn setup_msrs(vcpu: &kvm::VcpuFd) -> Result<()> { +pub fn setup_msrs(vcpu: &VcpuFd) -> Result<()> { let entry_vec = create_msr_entries(); let vec_size_bytes = mem::size_of::() + (entry_vec.len() * mem::size_of::()); @@ -91,7 +96,7 @@ pub fn setup_msrs(vcpu: &kvm::VcpuFd) -> Result<()> { /// * `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::VcpuFd, boot_ip: u64, boot_sp: u64, boot_si: u64) -> Result<()> { +pub fn setup_regs(vcpu: &VcpuFd, boot_ip: u64, boot_sp: u64, boot_si: u64) -> Result<()> { let regs: kvm_regs = kvm_regs { rflags: 0x0000000000000002u64, rip: boot_ip, @@ -110,7 +115,7 @@ pub fn setup_regs(vcpu: &kvm::VcpuFd, boot_ip: u64, boot_sp: u64, boot_si: u64) /// /// * `mem` - The memory that will be passed to the guest. /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. -pub fn setup_sregs(mem: &GuestMemory, vcpu: &kvm::VcpuFd) -> Result<()> { +pub fn setup_sregs(mem: &GuestMemory, vcpu: &VcpuFd) -> Result<()> { let mut sregs: kvm_sregs = vcpu.get_sregs().map_err(Error::GetStatusRegisters)?; configure_segments_and_sregs(mem, &mut sregs)?; @@ -153,15 +158,15 @@ fn write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()> { fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> { let gdt_table: [u64; BOOT_GDT_MAX as usize] = [ - gdt::gdt_entry(0, 0, 0), // NULL - gdt::gdt_entry(0xa09b, 0, 0xfffff), // CODE - gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA - gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS + gdt_entry(0, 0, 0), // NULL + gdt_entry(0xa09b, 0, 0xfffff), // CODE + gdt_entry(0xc093, 0, 0xfffff), // DATA + 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); + let code_seg = kvm_segment_from_gdt(gdt_table[1], 1); + let data_seg = kvm_segment_from_gdt(gdt_table[2], 2); + let tss_seg = kvm_segment_from_gdt(gdt_table[3], 3); // Write segments write_gdt_table(&gdt_table[..], mem)?; @@ -189,9 +194,9 @@ fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Res 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(layout::PML4_START); - let boot_pdpte_addr = GuestAddress(layout::PDPTE_START); - let boot_pde_addr = GuestAddress(layout::PDE_START); + let boot_pml4_addr = GuestAddress(PML4_START); + let boot_pdpte_addr = GuestAddress(PDPTE_START); + let boot_pde_addr = GuestAddress(PDE_START); // Entry covering VA [0..512GB) mem.write_obj_at_addr(boot_pdpte_addr.offset() as u64 | 0x03, boot_pml4_addr) @@ -220,55 +225,55 @@ fn create_msr_entries() -> Vec { let mut entries = Vec::::new(); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_IA32_SYSENTER_CS, + index: msr_index::MSR_IA32_SYSENTER_CS, data: 0x0, ..Default::default() }); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_IA32_SYSENTER_ESP, + index: msr_index::MSR_IA32_SYSENTER_ESP, data: 0x0, ..Default::default() }); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_IA32_SYSENTER_EIP, + index: msr_index::MSR_IA32_SYSENTER_EIP, data: 0x0, ..Default::default() }); // x86_64 specific msrs, we only run on x86_64 not x86. entries.push(kvm_msr_entry { - index: ::msr_index::MSR_STAR, + index: msr_index::MSR_STAR, data: 0x0, ..Default::default() }); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_CSTAR, + index: msr_index::MSR_CSTAR, data: 0x0, ..Default::default() }); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_KERNEL_GS_BASE, + index: msr_index::MSR_KERNEL_GS_BASE, data: 0x0, ..Default::default() }); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_SYSCALL_MASK, + index: msr_index::MSR_SYSCALL_MASK, data: 0x0, ..Default::default() }); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_LSTAR, + index: msr_index::MSR_LSTAR, data: 0x0, ..Default::default() }); // end of x86_64 specific code entries.push(kvm_msr_entry { - index: ::msr_index::MSR_IA32_TSC, + index: msr_index::MSR_IA32_TSC, data: 0x0, ..Default::default() }); entries.push(kvm_msr_entry { - index: ::msr_index::MSR_IA32_MISC_ENABLE, - data: ::msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64, + index: msr_index::MSR_IA32_MISC_ENABLE, + data: msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64, ..Default::default() }); @@ -321,16 +326,16 @@ mod tests { let gm = create_guest_mem(); setup_page_tables(&gm, &mut sregs).unwrap(); - assert_eq!(0xa003, read_u64(&gm, layout::PML4_START)); - assert_eq!(0xb003, read_u64(&gm, layout::PDPTE_START)); + assert_eq!(0xa003, read_u64(&gm, PML4_START)); + assert_eq!(0xb003, read_u64(&gm, PDPTE_START)); for i in 0..512 { assert_eq!( (i << 21) + 0x83u64, - read_u64(&gm, layout::PDE_START + (i * 8) as usize) + read_u64(&gm, PDE_START + (i * 8) as usize) ); } - assert_eq!(layout::PML4_START as u64, sregs.cr3); + assert_eq!(PML4_START as u64, sregs.cr3); assert_eq!(X86_CR4_PAE, sregs.cr4); assert_eq!(X86_CR0_PG, sregs.cr0); } @@ -367,7 +372,7 @@ mod tests { // This test will check against the last MSR entry configured (the tenth one). // See create_msr_entries for details. let test_kvm_msrs_entry = [kvm_msr_entry { - index: ::msr_index::MSR_IA32_MISC_ENABLE, + index: msr_index::MSR_IA32_MISC_ENABLE, ..Default::default() }]; let vec_size_bytes = mem::size_of::() + mem::size_of::(); @@ -390,7 +395,7 @@ mod tests { assert_eq!(read_msrs, 1); // Official entries that were setup when we did setup_msrs. We need to assert that the - // tenth one (i.e the one with index ::msr_index::MSR_IA32_MISC_ENABLE has the data we + // tenth one (i.e the one with index msr_index::MSR_IA32_MISC_ENABLE has the data we // expect. let entry_vec = create_msr_entries(); unsafe { diff --git a/arch_gen/Cargo.toml b/arch_gen/Cargo.toml new file mode 100644 index 00000000000..6738db97537 --- /dev/null +++ b/arch_gen/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "arch_gen" +version = "0.1.0" +authors = ["Amazon firecracker team "] + +[dependencies] +memory_model = { path = "../memory_model" } diff --git a/arch_gen/src/lib.rs b/arch_gen/src/lib.rs new file mode 100644 index 00000000000..6aa540fc637 --- /dev/null +++ b/arch_gen/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +extern crate memory_model; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub mod x86; diff --git a/x86_64/src/bootparam.rs b/arch_gen/src/x86/bootparam.rs similarity index 99% rename from x86_64/src/bootparam.rs rename to arch_gen/src/x86/bootparam.rs index 8ee379b6664..62b95c5ee5b 100644 --- a/x86_64/src/bootparam.rs +++ b/arch_gen/src/x86/bootparam.rs @@ -7,7 +7,7 @@ /* * automatically generated by rust-bindgen - * From upstream linux bootparam.h at commit: + * From upstream linux arch/x86/include/uapi/asm/bootparam.h at commit: * 806276b7f07a39a1cc3f38bb1ef5c573d4594a38 */ diff --git a/arch_gen/src/x86/mod.rs b/arch_gen/src/x86/mod.rs new file mode 100644 index 00000000000..465f2024971 --- /dev/null +++ b/arch_gen/src/x86/mod.rs @@ -0,0 +1,27 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// Portions 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 THIRD-PARTY file. + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +pub mod bootparam; +#[allow(non_camel_case_types)] +#[allow(non_upper_case_globals)] +pub mod mpspec; +#[allow(non_upper_case_globals)] +pub mod msr_index; + +// `boot_params` is just a series of ints, it is safe to initialize it. +unsafe impl memory_model::DataInit for bootparam::boot_params {} +// These `mpspec` types are only data, reading them from data is a safe initialization. +unsafe impl memory_model::DataInit for mpspec::mpc_bus {} +unsafe impl memory_model::DataInit for mpspec::mpc_cpu {} +unsafe impl memory_model::DataInit for mpspec::mpc_intsrc {} +unsafe impl memory_model::DataInit for mpspec::mpc_ioapic {} +unsafe impl memory_model::DataInit for mpspec::mpc_table {} +unsafe impl memory_model::DataInit for mpspec::mpc_lintsrc {} +unsafe impl memory_model::DataInit for mpspec::mpf_intel {} diff --git a/x86_64/src/mpspec.rs b/arch_gen/src/x86/mpspec.rs similarity index 100% rename from x86_64/src/mpspec.rs rename to arch_gen/src/x86/mpspec.rs diff --git a/x86_64/src/msr_index.rs b/arch_gen/src/x86/msr_index.rs similarity index 100% rename from x86_64/src/msr_index.rs rename to arch_gen/src/x86/msr_index.rs diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 825a3e5c613..7d3f723a0ed 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -3,5 +3,5 @@ name = "kernel" version = "0.1.0" [dependencies] -sys_util = { path = "../sys_util" } memory_model = { path = "../memory_model" } +sys_util = { path = "../sys_util" } diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 21aaaec6a23..c939155fef5 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -14,6 +14,7 @@ serde_json = ">=1.0.9" time = ">=0.1.39" timerfd = ">=1.0" +arch = { path = "../arch" } cpuid = { path = "../cpuid" } devices = { path = "../devices" } fc_util = { path = "../fc_util" } @@ -26,7 +27,6 @@ net_util = { path = "../net_util"} rate_limiter = { path = "../rate_limiter" } seccomp = { path = "../seccomp" } sys_util = { path = "../sys_util" } -x86_64 = { path = "../x86_64" } [dev-dependencies] tempfile = ">=3.0.2" diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 22b04afff51..5318d31b5ca 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -27,12 +27,12 @@ extern crate kernel; extern crate kvm; #[macro_use] extern crate logger; +extern crate arch; extern crate memory_model; extern crate net_util; extern crate rate_limiter; extern crate seccomp; extern crate sys_util; -extern crate x86_64; /// Syscalls allowed through the seccomp filter. pub mod default_syscalls; @@ -61,6 +61,7 @@ use std::time::Duration; use libc::{c_void, siginfo_t}; use timerfd::{ClockId, SetTimeFlags, TimerFd, TimerState}; +use arch::x86_64; use device_manager::legacy::LegacyDeviceManager; use device_manager::mmio::MMIODeviceManager; use devices::virtio; @@ -1092,7 +1093,7 @@ impl Vmm { let entry_addr = kernel_loader::load_kernel( vm_memory, &mut kernel_config.kernel_file, - x86_64::layout::HIMEM_START, + arch::HIMEM_START, ) .map_err(|e| StartMicrovmError::Loader(e))?; kernel_loader::load_cmdline(vm_memory, kernel_config.cmdline_addr, &cmdline_cstring) diff --git a/vmm/src/vmm_config/instance_info.rs b/vmm/src/vmm_config/instance_info.rs index db308a0b0bb..2c087114f3e 100644 --- a/vmm/src/vmm_config/instance_info.rs +++ b/vmm/src/vmm_config/instance_info.rs @@ -11,7 +11,6 @@ use memory_model::GuestMemoryError; use seccomp; use sys_util; use vstate; -use x86_64; /// The microvm state. When Firecracker starts, the instance state is Uninitialized. /// Once start_microvm method is called, the state goes from Uninitialized to Starting. @@ -46,7 +45,7 @@ pub struct InstanceInfo { pub enum StartMicrovmError { /// This error is thrown by the minimal boot loader implementation. /// It is related to a faulty memory configuration. - ConfigureSystem(x86_64::Error), + ConfigureSystem(arch::Error), /// Cannot configure the VM. ConfigureVm(vstate::Error), /// Unable to seek the block device backing file due to invalid permissions or diff --git a/vmm/src/vstate.rs b/vmm/src/vstate.rs index d04f1d86360..79e90201f4a 100644 --- a/vmm/src/vstate.rs +++ b/vmm/src/vstate.rs @@ -5,14 +5,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the THIRD-PARTY file. +extern crate arch; extern crate devices; extern crate logger; extern crate sys_util; -extern crate x86_64; use std::result; use super::KvmContext; +use arch::x86_64; use cpuid::{c3_template, filter_cpuid, t2_template}; use kvm::*; use logger::{LogOption, LOGGER}; @@ -216,21 +217,21 @@ impl Vcpu { .set_cpuid2(&self.cpuid) .map_err(Error::SetSupportedCpusFailed)?; - regs::setup_msrs(&self.fd).map_err(Error::MSRSConfiguration)?; + x86_64::regs::setup_msrs(&self.fd).map_err(Error::MSRSConfiguration)?; // Safe to unwrap because this method is called after the VM is configured let vm_memory = vm .get_memory() .ok_or(Error::GuestMemory(GuestMemoryError::MemoryNotInitialized))?; - regs::setup_regs( + x86_64::regs::setup_regs( &self.fd, kernel_start_addr.offset() as u64, x86_64::layout::BOOT_STACK_POINTER as u64, x86_64::layout::ZERO_PAGE_START as u64, ) .map_err(Error::REGSConfiguration)?; - regs::setup_fpu(&self.fd).map_err(Error::FPUConfiguration)?; - regs::setup_sregs(vm_memory, &self.fd).map_err(Error::SREGSConfiguration)?; - interrupts::set_lint(&self.fd).map_err(Error::LocalIntConfiguration)?; + x86_64::regs::setup_fpu(&self.fd).map_err(Error::FPUConfiguration)?; + x86_64::regs::setup_sregs(vm_memory, &self.fd).map_err(Error::SREGSConfiguration)?; + x86_64::interrupts::set_lint(&self.fd).map_err(Error::LocalIntConfiguration)?; Ok(()) } diff --git a/x86_64/src/layout.rs b/x86_64/src/layout.rs deleted file mode 100644 index 35be23f2c23..00000000000 --- a/x86_64/src/layout.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// -// Portions 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 THIRD-PARTY file. - -// Magic addresses used to lay out x86_64 VMs. - -// The 'zero page', a.k.a linux kernel bootparams. -pub const ZERO_PAGE_START: usize = 0x7000; -// Initial stack for the boot CPU. -pub const BOOT_STACK_START: usize = 0x8000; -pub const BOOT_STACK_POINTER: usize = 0x8ff0; -// Initial pagetables. -pub const PML4_START: usize = 0x9000; -pub const PDPTE_START: usize = 0xa000; -pub const PDE_START: usize = 0xb000; -// Kernel command line. -pub const CMDLINE_START: usize = 0x20000; -pub const CMDLINE_MAX_SIZE: usize = 0x10000; -// MPTABLE, describing VCPUS. -pub const MPTABLE_START: usize = 0x9fc00; -// Where BIOS/VGA magic would live on a real PC. -pub const EBDA_START: u64 = 0x9fc00; -// 1MB. We don't put anything above here except the kernel itself. -pub const HIMEM_START: usize = 0x100000; From 327de58a963222b4e92807554f7df2fbe6b81ea2 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 09:13:06 -0600 Subject: [PATCH 2/9] kvm: label x86 and x86_64 specific code Signed-off-by: Diana Popa --- kvm/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs index 6ccad5f57f3..f9e55536afe 100644 --- a/kvm/src/lib.rs +++ b/kvm/src/lib.rs @@ -185,9 +185,11 @@ impl Kvm { // Safe because we verify the value of ret and we are the owners of the fd. let vm_file = unsafe { File::from_raw_fd(ret) }; let run_mmap_size = self.get_vcpu_mmap_size()?; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] let kvm_cpuid: CpuId = self.get_supported_cpuid(MAX_KVM_CPUID_ENTRIES)?; Ok(VmFd { vm: vm_file, + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] supported_cpuid: kvm_cpuid, run_size: run_mmap_size, }) @@ -222,11 +224,13 @@ impl Into for NoDatamatch { /// A wrapper around creating and using a VM. pub struct VmFd { vm: File, + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] supported_cpuid: CpuId, run_size: usize, } impl VmFd { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// Returns a clone of the system supported CPUID values associated with this VmFd /// pub fn get_supported_cpuid(&self) -> CpuId { From 536bad1dac25abfa49f02cd12850189328c425b4 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 09:23:36 -0600 Subject: [PATCH 3/9] fc_util: correctly label x86_64 specific func On other architectures different than x86_64, the function will return a dummy value. Signed-off-by: Diana Popa --- fc_util/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fc_util/src/lib.rs b/fc_util/src/lib.rs index 2f6de96b43b..bfbfcf32fe3 100644 --- a/fc_util/src/lib.rs +++ b/fc_util/src/lib.rs @@ -5,10 +5,14 @@ extern crate libc; pub mod validators; -#[cfg(target_arch = "x86_64")] pub fn timestamp_cycles() -> u64 { + #[cfg(target_arch = "x86_64")] // Safe because there's nothing that can go wrong with this call. - unsafe { std::arch::x86_64::_rdtsc() as u64 } + unsafe { + std::arch::x86_64::_rdtsc() as u64 + } + #[cfg(not(target_arch = "x86_64"))] + 0 } fn timespec_to_us(time_struct: &libc::timespec) -> u64 { From a54496b1e21ccb772ff107ae1ee37ba905fa7873 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 09:25:19 -0600 Subject: [PATCH 4/9] dumbo: correctly label x86_64 specific function On other architectures, make this function return a dummy value. Also, added unit test for the x86_64 scenarios. Signed-off-by: Diana Popa --- dumbo/src/tcp/connection.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/dumbo/src/tcp/connection.rs b/dumbo/src/tcp/connection.rs index 98da18b7f9e..081cb5a78bf 100644 --- a/dumbo/src/tcp/connection.rs +++ b/dumbo/src/tcp/connection.rs @@ -113,11 +113,16 @@ pub enum WriteNextError { // This generates pseudo random u32 numbers based on the current timestamp. Only works for x86_64, // but can find something else if we ever need to support different architectures. -#[cfg(target_arch = "x86_64")] fn xor_rng_u32() -> u32 { - // Safe because there's nothing that can go wrong with this call. - let mut t = unsafe { std::arch::x86_64::_rdtsc() } as u32; - + let mut t: u32 = { + #[cfg(target_arch = "x86_64")] + // Safe because there's nothing that can go wrong with this call. + unsafe { + std::arch::x86_64::_rdtsc() as u32 + } + #[cfg(not(target_arch = "x86_64"))] + 0 + }; // Taken from https://en.wikipedia.org/wiki/Xorshift t ^= t << 13; t ^= t >> 17; @@ -1786,4 +1791,11 @@ pub(crate) mod tests { // and we don't wait for our FIN to be ACKed. assert!(c.is_done()); } + + #[test] + fn test_xor_rng_u32() { + for _ in 0..1000 { + assert_ne!(xor_rng_u32(), xor_rng_u32()); + } + } } From 5e6575cdd69a6643a13fd3a04eae5c68edaf5fc8 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 09:27:19 -0600 Subject: [PATCH 5/9] arch: prepare crate for aarch64 code - Refactored crate to support addition of non-x86_64 architectures - Labeled code accordingly - non-x86_64 code was moved outside x86_64 folder - Adjusted vmm related code - Added aarch64 dummy template Signed-off-by: Diana Popa --- arch/src/aarch64/layout.rs | 7 +++++++ arch/src/aarch64/mod.rs | 26 +++++++++++++++++++++++++ arch/src/lib.rs | 26 +++++++++++++++++-------- arch/src/x86_64/layout.rs | 3 +++ arch/src/x86_64/mod.rs | 16 +++++++++++----- vmm/src/lib.rs | 34 ++++++++++++++++----------------- vmm/src/vstate.rs | 39 ++++++++++++++++++++------------------ 7 files changed, 102 insertions(+), 49 deletions(-) create mode 100644 arch/src/aarch64/layout.rs create mode 100644 arch/src/aarch64/mod.rs diff --git a/arch/src/aarch64/layout.rs b/arch/src/aarch64/layout.rs new file mode 100644 index 00000000000..c7c319278e2 --- /dev/null +++ b/arch/src/aarch64/layout.rs @@ -0,0 +1,7 @@ +// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +/// Kernel command line start address. +pub const CMDLINE_START: usize = 0x0; +/// Kernel command line start address maximum size. +pub const CMDLINE_MAX_SIZE: usize = 0x0; diff --git a/arch/src/aarch64/mod.rs b/arch/src/aarch64/mod.rs new file mode 100644 index 00000000000..9f06db75053 --- /dev/null +++ b/arch/src/aarch64/mod.rs @@ -0,0 +1,26 @@ +// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod layout; + +use memory_model::{GuestAddress, GuestMemory}; + +/// Stub function that needs to be implemented when aarch64 functionality is added. +pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> { + vec![(GuestAddress(0), size)] +} + +/// Stub function that needs to be implemented when aarch64 functionality is added. +pub fn configure_system( + _guest_mem: &GuestMemory, + _cmdline_addr: GuestAddress, + _cmdline_size: usize, + _num_cpus: u8, +) -> super::Result<()> { + Ok(()) +} + +/// Stub function that needs to be implemented when aarch64 functionality is added. +pub fn get_reserved_mem_addr() -> usize { + 0 +} diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 8d52a17f690..40971fa4059 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -14,23 +14,33 @@ use std::result; #[derive(Debug, PartialEq)] pub enum Error { + #[cfg(target_arch = "x86_64")] + /// X86_64 specific error triggered during system configuration. + X86_64Setup(x86_64::Error), /// The zero page extends past the end of guest_mem. ZeroPagePastRamEnd, /// Error writing the zero page of guest memory. ZeroPageSetup, - #[cfg(target_arch = "x86_64")] - /// X86_64 specific error triggered during system configuration. - X86_64Setup(x86_64::Error), } pub type Result = result::Result; // 1MB. We don't put anything above here except the kernel itself. pub const HIMEM_START: usize = 0x100000; +#[cfg(target_arch = "aarch64")] +pub mod aarch64; + +#[cfg(target_arch = "aarch64")] +pub use aarch64::{ + arch_memory_regions, configure_system, get_reserved_mem_addr, layout::CMDLINE_MAX_SIZE, + layout::CMDLINE_START, +}; + #[cfg(target_arch = "x86_64")] pub mod x86_64; -impl From for Error { - fn from(e: x86_64::Error) -> Error { - Error::X86_64Setup(e) - } -} + +#[cfg(target_arch = "x86_64")] +pub use x86_64::{ + arch_memory_regions, configure_system, get_32bit_gap_start as get_reserved_mem_addr, + layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, +}; diff --git a/arch/src/x86_64/layout.rs b/arch/src/x86_64/layout.rs index 39f2fdc5d24..289ce6f12c7 100644 --- a/arch/src/x86_64/layout.rs +++ b/arch/src/x86_64/layout.rs @@ -16,5 +16,8 @@ pub const CMDLINE_START: usize = 0x20000; /// Kernel command line start address maximum size. pub const CMDLINE_MAX_SIZE: usize = 0x10000; +/// Address for the TSS setup. +pub const KVM_TSS_ADDRESS: usize = 0xfffbd000; + /// The 'zero page', a.k.a linux kernel bootparams. pub const ZERO_PAGE_START: usize = 0x7000; diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index d4f58dc1502..18d8af4f60d 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -16,11 +16,6 @@ use std::mem; use arch_gen::x86::bootparam::{boot_params, E820_RAM}; use memory_model::{GuestAddress, GuestMemory}; -// Where BIOS/VGA magic would live on a real PC. -const EBDA_START: u64 = 0x9fc00; -const FIRST_ADDR_PAST_32BITS: usize = (1 << 32); -const MEM_32BIT_GAP_SIZE: usize = (768 << 20); - #[derive(Debug, PartialEq)] pub enum Error { /// Invalid e820 setup params. @@ -29,6 +24,17 @@ pub enum Error { MpTableSetup(mptable::Error), } +impl From for super::Error { + fn from(e: Error) -> super::Error { + super::Error::X86_64Setup(e) + } +} + +// Where BIOS/VGA magic would live on a real PC. +const EBDA_START: u64 = 0x9fc00; +const FIRST_ADDR_PAST_32BITS: usize = (1 << 32); +const MEM_32BIT_GAP_SIZE: usize = (768 << 20); + /// Returns a Vec of the valid memory addresses. /// These should be used to configure the GuestMemory structure for the platform. /// For x86_64 all addresses are valid from the start of the kernel except a diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 5318d31b5ca..a759b081134 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -61,7 +61,6 @@ use std::time::Duration; use libc::{c_void, siginfo_t}; use timerfd::{ClockId, SetTimeFlags, TimerFd, TimerState}; -use arch::x86_64; use device_manager::legacy::LegacyDeviceManager; use device_manager::mmio::MMIODeviceManager; use devices::virtio; @@ -822,7 +821,7 @@ impl Vmm { memory_model::GuestMemoryError::MemoryNotInitialized, ))? << 20; - let arch_mem_regions = x86_64::arch_memory_regions(mem_size); + let arch_mem_regions = arch::arch_memory_regions(mem_size); self.guest_memory = Some(GuestMemory::new(&arch_mem_regions).map_err(StartMicrovmError::GuestMemory)?); Ok(()) @@ -842,11 +841,11 @@ impl Vmm { .ok_or(StartMicrovmError::GuestMemory( memory_model::GuestMemoryError::MemoryNotInitialized, ))?; + // Instantiate the MMIO device manager. - // 'mmio_base' address has to be an address which is protected by the kernel, in this case - // the start of the x86 specific gap of memory (currently hardcoded at 768MiB). + // 'mmio_base' address has to be an address which is protected by the kernel. let mut device_manager = - MMIODeviceManager::new(guest_mem.clone(), x86_64::get_32bit_gap_start() as u64); + MMIODeviceManager::new(guest_mem.clone(), arch::get_reserved_mem_addr() as u64); self.attach_block_devices(&mut device_manager)?; self.attach_net_devices(&mut device_manager)?; @@ -1105,7 +1104,7 @@ impl Vmm { .vm_config .vcpu_count .ok_or(StartMicrovmError::VcpusNotConfigured)?; - x86_64::configure_system( + arch::configure_system( vm_memory, kernel_config.cmdline_addr, cmdline_cstring.to_bytes().len() + 1, @@ -1406,7 +1405,7 @@ impl Vmm { let kernel_file = File::open(kernel_image_path).map_err(|_| { VmmActionError::BootSource(ErrorKind::User, BootSourceConfigError::InvalidKernelPath) })?; - let mut cmdline = kernel_cmdline::Cmdline::new(x86_64::layout::CMDLINE_MAX_SIZE); + let mut cmdline = kernel_cmdline::Cmdline::new(arch::CMDLINE_MAX_SIZE); cmdline .insert_str(kernel_cmdline.unwrap_or(String::from(DEFAULT_KERNEL_CMDLINE))) .map_err(|_| { @@ -1419,7 +1418,7 @@ impl Vmm { let kernel_config = KernelConfig { kernel_file, cmdline, - cmdline_addr: GuestAddress(x86_64::layout::CMDLINE_START), + cmdline_addr: GuestAddress(arch::CMDLINE_START), }; self.configure_kernel(kernel_config); @@ -1878,12 +1877,12 @@ mod tests { let kernel_path = String::from(kernel_file_temp.path().to_path_buf().to_str().unwrap()); let kernel_file = File::open(kernel_path).unwrap(); - let mut cmdline = kernel_cmdline::Cmdline::new(x86_64::layout::CMDLINE_MAX_SIZE); + let mut cmdline = kernel_cmdline::Cmdline::new(arch::CMDLINE_MAX_SIZE); assert!(cmdline.insert_str(DEFAULT_KERNEL_CMDLINE).is_ok()); let kernel_cfg = KernelConfig { cmdline, kernel_file, - cmdline_addr: GuestAddress(x86_64::layout::CMDLINE_START), + cmdline_addr: GuestAddress(arch::CMDLINE_START), }; self.configure_kernel(kernel_cfg); } @@ -2446,7 +2445,7 @@ mod tests { let guest_mem = vmm.guest_memory.clone().unwrap(); let mut device_manager = - MMIODeviceManager::new(guest_mem.clone(), x86_64::get_32bit_gap_start() as u64); + MMIODeviceManager::new(guest_mem.clone(), arch::get_reserved_mem_addr() as u64); assert!(vmm.attach_block_devices(&mut device_manager).is_ok()); assert!(vmm.get_kernel_cmdline_str().contains("root=/dev/vda")); @@ -2470,7 +2469,7 @@ mod tests { let guest_mem = vmm.guest_memory.clone().unwrap(); let mut device_manager = - MMIODeviceManager::new(guest_mem.clone(), x86_64::get_32bit_gap_start() as u64); + MMIODeviceManager::new(guest_mem.clone(), arch::get_reserved_mem_addr() as u64); assert!(vmm.attach_block_devices(&mut device_manager).is_ok()); assert!(vmm .get_kernel_cmdline_str() @@ -2498,7 +2497,7 @@ mod tests { let guest_mem = vmm.guest_memory.clone().unwrap(); let mut device_manager = - MMIODeviceManager::new(guest_mem.clone(), x86_64::get_32bit_gap_start() as u64); + MMIODeviceManager::new(guest_mem.clone(), arch::get_reserved_mem_addr() as u64); assert!(vmm.attach_block_devices(&mut device_manager).is_ok()); // Test that kernel commandline does not contain either /dev/vda or PARTUUID. assert!(!vmm.get_kernel_cmdline_str().contains("root=PARTUUID=")); @@ -2532,7 +2531,7 @@ mod tests { let guest_mem = vmm.guest_memory.clone().unwrap(); let mut device_manager = - MMIODeviceManager::new(guest_mem.clone(), x86_64::get_32bit_gap_start() as u64); + MMIODeviceManager::new(guest_mem.clone(), arch::get_reserved_mem_addr() as u64); // test create network interface let network_interface = NetworkInterfaceConfig { @@ -2574,8 +2573,7 @@ mod tests { // Test valid kernel path and invalid cmdline. let kernel_file = NamedTempFile::new().expect("Failed to create temporary kernel file."); let kernel_path = String::from(kernel_file.path().to_path_buf().to_str().unwrap()); - let invalid_cmdline = - String::from_utf8(vec![b'X'; x86_64::layout::CMDLINE_MAX_SIZE + 1]).unwrap(); + let invalid_cmdline = String::from_utf8(vec![b'X'; arch::CMDLINE_MAX_SIZE + 1]).unwrap(); assert!(vmm .configure_boot_source(kernel_path.clone(), Some(invalid_cmdline)) .is_err()); @@ -2629,14 +2627,14 @@ mod tests { let guest_mem = vmm.guest_memory.clone().unwrap(); let mut device_manager = - MMIODeviceManager::new(guest_mem.clone(), x86_64::get_32bit_gap_start() as u64); + MMIODeviceManager::new(guest_mem.clone(), arch::get_reserved_mem_addr() as u64); let dummy_box = Box::new(DummyDevice { dummy: 0 }); // Use a dummy command line as it is not used in this test. let _addr = device_manager .register_device( dummy_box, - &mut kernel_cmdline::Cmdline::new(x86_64::layout::CMDLINE_MAX_SIZE), + &mut kernel_cmdline::Cmdline::new(arch::CMDLINE_MAX_SIZE), Some(scratch_id.clone()), ) .unwrap(); diff --git a/vmm/src/vstate.rs b/vmm/src/vstate.rs index 79e90201f4a..1a30a95223c 100644 --- a/vmm/src/vstate.rs +++ b/vmm/src/vstate.rs @@ -13,7 +13,6 @@ extern crate sys_util; use std::result; use super::KvmContext; -use arch::x86_64; use cpuid::{c3_template, filter_cpuid, t2_template}; use kvm::*; use logger::{LogOption, LOGGER}; @@ -21,9 +20,7 @@ use logger::{Metric, METRICS}; use memory_model::{GuestAddress, GuestMemory, GuestMemoryError}; use sys_util::EventFd; use vmm_config::machine_config::{CpuFeaturesTemplate, VmConfig}; -use x86_64::{interrupts, regs}; -pub const KVM_TSS_ADDRESS: usize = 0xfffbd000; const KVM_MEM_LOG_DIRTY_PAGES: u32 = 0x1; /// Errors associated with the wrappers over KVM ioctls. @@ -47,18 +44,23 @@ pub enum Error { SetSupportedCpusFailed(sys_util::Error), /// The number of configured slots is bigger than the maximum reported by KVM. NotEnoughMemorySlots, + #[cfg(target_arch = "x86_64")] /// Cannot set the local interruption due to bad configuration. - LocalIntConfiguration(interrupts::Error), + LocalIntConfiguration(arch::x86_64::interrupts::Error), /// Cannot set the memory regions. SetUserMemoryRegion(sys_util::Error), + #[cfg(target_arch = "x86_64")] /// Error configuring the MSR registers - MSRSConfiguration(regs::Error), + MSRSConfiguration(arch::x86_64::regs::Error), + #[cfg(target_arch = "x86_64")] /// Error configuring the general purpose registers - REGSConfiguration(regs::Error), + REGSConfiguration(arch::x86_64::regs::Error), + #[cfg(target_arch = "x86_64")] /// Error configuring the special registers - SREGSConfiguration(regs::Error), + SREGSConfiguration(arch::x86_64::regs::Error), + #[cfg(target_arch = "x86_64")] /// Error configuring the floating point related registers - FPUConfiguration(regs::Error), + FPUConfiguration(arch::x86_64::regs::Error), /// Cannot configure the IRQ. Irq(sys_util::Error), } @@ -113,9 +115,9 @@ impl Vm { })?; self.guest_mem = Some(guest_mem); - let tss_addr = GuestAddress(KVM_TSS_ADDRESS); + #[cfg(target_arch = "x86_64")] self.fd - .set_tss_address(tss_addr.offset()) + .set_tss_address(GuestAddress(arch::x86_64::layout::KVM_TSS_ADDRESS).offset()) .map_err(Error::VmSetup)?; Ok(()) @@ -173,7 +175,8 @@ impl Vcpu { }) } - /// /// Configures the vcpu and should be called once per vcpu from the vcpu's thread. + #[cfg(target_arch = "x86_64")] + /// Configures the vcpu and should be called once per vcpu from the vcpu's thread. /// /// # Arguments /// @@ -217,21 +220,21 @@ impl Vcpu { .set_cpuid2(&self.cpuid) .map_err(Error::SetSupportedCpusFailed)?; - x86_64::regs::setup_msrs(&self.fd).map_err(Error::MSRSConfiguration)?; + arch::x86_64::regs::setup_msrs(&self.fd).map_err(Error::MSRSConfiguration)?; // Safe to unwrap because this method is called after the VM is configured let vm_memory = vm .get_memory() .ok_or(Error::GuestMemory(GuestMemoryError::MemoryNotInitialized))?; - x86_64::regs::setup_regs( + arch::x86_64::regs::setup_regs( &self.fd, kernel_start_addr.offset() as u64, - x86_64::layout::BOOT_STACK_POINTER as u64, - x86_64::layout::ZERO_PAGE_START as u64, + arch::x86_64::layout::BOOT_STACK_POINTER as u64, + arch::x86_64::layout::ZERO_PAGE_START as u64, ) .map_err(Error::REGSConfiguration)?; - x86_64::regs::setup_fpu(&self.fd).map_err(Error::FPUConfiguration)?; - x86_64::regs::setup_sregs(vm_memory, &self.fd).map_err(Error::SREGSConfiguration)?; - x86_64::interrupts::set_lint(&self.fd).map_err(Error::LocalIntConfiguration)?; + arch::x86_64::regs::setup_fpu(&self.fd).map_err(Error::FPUConfiguration)?; + arch::x86_64::regs::setup_sregs(vm_memory, &self.fd).map_err(Error::SREGSConfiguration)?; + arch::x86_64::interrupts::set_lint(&self.fd).map_err(Error::LocalIntConfiguration)?; Ok(()) } From 7e94f7fc3c223b20fed234668eb3201d2811cb0f Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 10:01:57 -0600 Subject: [PATCH 6/9] vmm: label allowed syscalls as per architecture libc syscalls are dependent on the architecture. Thus, "default_syscalls" is now a module that conditionally compiles allowed syscalls depending on target architecture. Signed-off-by: Diana Popa --- vmm/src/default_syscalls/aarch64.rs | 18 ++++++++++++++ vmm/src/default_syscalls/mod.rs | 13 ++++++++++ .../x86_64.rs} | 24 +++++++++---------- vmm/src/lib.rs | 4 ++-- 4 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 vmm/src/default_syscalls/aarch64.rs create mode 100644 vmm/src/default_syscalls/mod.rs rename vmm/src/{default_syscalls.rs => default_syscalls/x86_64.rs} (97%) diff --git a/vmm/src/default_syscalls/aarch64.rs b/vmm/src/default_syscalls/aarch64.rs new file mode 100644 index 00000000000..8d17b329437 --- /dev/null +++ b/vmm/src/default_syscalls/aarch64.rs @@ -0,0 +1,18 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use seccomp::{Error, SeccompFilterContext}; + +pub const ALLOWED_SYSCALLS: &[i64] = &[]; + +pub fn default_context() -> Result { + Ok(seccomp::SeccompFilterContext::new( + vec![].into_iter().collect(), + seccomp::SeccompAction::Trap, + ) + .unwrap()) +} + +pub fn set_seccomp_level(seccomp_level: u32) -> Result<(), Error> { + Ok(()) +} diff --git a/vmm/src/default_syscalls/mod.rs b/vmm/src/default_syscalls/mod.rs new file mode 100644 index 00000000000..3bf4b5e3e6e --- /dev/null +++ b/vmm/src/default_syscalls/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(target_arch = "x86_64")] +mod x86_64; + +#[cfg(target_arch = "aarch64")] +mod aarch64; + +#[cfg(target_arch = "aarch64")] +pub use self::aarch64::{default_context, set_seccomp_level, ALLOWED_SYSCALLS}; +#[cfg(target_arch = "x86_64")] +pub use self::x86_64::{default_context, set_seccomp_level, ALLOWED_SYSCALLS}; diff --git a/vmm/src/default_syscalls.rs b/vmm/src/default_syscalls/x86_64.rs similarity index 97% rename from vmm/src/default_syscalls.rs rename to vmm/src/default_syscalls/x86_64.rs index c07f15b06a3..80cc5a8fb95 100644 --- a/vmm/src/default_syscalls.rs +++ b/vmm/src/default_syscalls/x86_64.rs @@ -1,15 +1,13 @@ // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -extern crate libc; -extern crate sys_util; - use seccomp::{ setup_seccomp, Error, SeccompAction, SeccompCmpOp, SeccompCondition, SeccompFilterContext, SeccompLevel, SeccompRule, SECCOMP_LEVEL_ADVANCED, SECCOMP_LEVEL_BASIC, SECCOMP_LEVEL_NONE, }; -/// List of allowed syscalls, necessary for Firecracker to function correctly. +/// List of allowed syscalls necessary for correct functioning on x86_64 architectures. +/// Taken from the musl repo (i.e arch/x86_64/bits/syscall.h). pub const ALLOWED_SYSCALLS: &[i64] = &[ libc::SYS_accept, libc::SYS_clock_gettime, @@ -38,17 +36,17 @@ pub const ALLOWED_SYSCALLS: &[i64] = &[ libc::SYS_writev, ]; -// See /usr/include/x86_64-linux-gnu/sys/epoll.h +// See include/uapi/linux/eventpoll.h in the kernel code. const EPOLL_CTL_ADD: u64 = 1; const EPOLL_CTL_DEL: u64 = 2; -// See /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h +// See include/uapi/asm-generic/fcntl.h in the kernel code. const O_RDONLY: u64 = 0x00000000; const O_RDWR: u64 = 0x00000002; const O_NONBLOCK: u64 = 0x00004000; const O_CLOEXEC: u64 = 0x02000000; -// See /usr/include/linux/futex.h +// See include/uapi/linux/futex.h in the kernel code. const FUTEX_WAIT: u64 = 0; const FUTEX_WAKE: u64 = 1; const FUTEX_REQUEUE: u64 = 3; @@ -57,14 +55,14 @@ const FUTEX_WAIT_PRIVATE: u64 = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; const FUTEX_WAKE_PRIVATE: u64 = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; const FUTEX_REQUEUE_PRIVATE: u64 = FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG; -// See /usr/include/asm-generic/ioctls.h +// See include/uapi/asm-generic/ioctls.h in the kernel code. const TCGETS: u64 = 0x5401; const TCSETS: u64 = 0x5402; const TIOCGWINSZ: u64 = 0x5413; const FIOCLEX: u64 = 0x5451; const FIONBIO: u64 = 0x5421; -// See /usr/include/linux/kvm.h +// See include/uapi/linux/if_tun.h in the kernel code. const KVM_GET_API_VERSION: u64 = 0xae00; const KVM_CREATE_VM: u64 = 0xae01; const KVM_CHECK_EXTENSION: u64 = 0xae03; @@ -88,15 +86,17 @@ const KVM_GET_SREGS: u64 = 0x8138ae83; const KVM_GET_LAPIC: u64 = 0x8400ae8e; const KVM_GET_SUPPORTED_CPUID: u64 = 0xc008ae05; -// See /usr/include/linux/if_tun.h +// See include/uapi/linux/if_tun.h in the kernel code. const TUNSETIFF: u64 = 0x400454ca; const TUNSETOFFLOAD: u64 = 0x400454d0; const TUNSETVNETHDRSZ: u64 = 0x400454d8; -// See /usr/include/asm-generic/mman-common.h and /usr/include/asm-generic/mman.h +// See include/uapi/asm-generic/mman-common.h in the kernel code. const PROT_NONE: u64 = 0x0; const PROT_READ: u64 = 0x1; const PROT_WRITE: u64 = 0x2; + +// See include/uapi/asm-generic/mman.h in the kernel code. const MAP_SHARED: u64 = 0x01; const MAP_PRIVATE: u64 = 0x02; const MAP_ANONYMOUS: u64 = 0x20; @@ -529,7 +529,7 @@ pub fn default_context() -> Result { vec![SeccompCondition::new( 1, SeccompCmpOp::Eq, - sys_util::validate_signal_num(super::VCPU_RTSIG_OFFSET, true) + sys_util::validate_signal_num(super::super::VCPU_RTSIG_OFFSET, true) .map_err(|_| Error::InvalidArgumentNumber)? as u64, )?], diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index a759b081134..1b8b229464a 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -86,12 +86,12 @@ use vmm_config::net::{NetworkInterfaceConfig, NetworkInterfaceConfigs, NetworkIn use vmm_config::vsock::{VsockDeviceConfig, VsockDeviceConfigs, VsockError}; use vstate::{Vcpu, Vm}; +const DEFAULT_KERNEL_CMDLINE: &str = "reboot=k panic=1 pci=off nomodules 8250.nr_uarts=0"; const MAGIC_IOPORT_SIGNAL_GUEST_BOOT_COMPLETE: u16 = 0x03f0; const MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE: u8 = 123; - -const DEFAULT_KERNEL_CMDLINE: &str = "reboot=k panic=1 pci=off nomodules 8250.nr_uarts=0"; const VCPU_RTSIG_OFFSET: i32 = 0; const WRITE_METRICS_PERIOD_SECONDS: u64 = 60; + static START_INSTANCE_REQUEST_TS: AtomicUsize = ATOMIC_USIZE_INIT; static START_INSTANCE_REQUEST_CPU_TS: AtomicUsize = ATOMIC_USIZE_INIT; From 21ce2abfeced8eefcc7624b90a656240a187c863 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 10:09:06 -0600 Subject: [PATCH 7/9] vmm: additional x86_64 necessary labeling * labeled x86_64 specific code * conditonal compilation for cpuid Signed-off-by: Diana Popa --- vmm/Cargo.toml | 4 +++- vmm/src/lib.rs | 2 ++ vmm/src/vstate.rs | 32 ++++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index c939155fef5..96f70dda051 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -15,7 +15,6 @@ time = ">=0.1.39" timerfd = ">=1.0" arch = { path = "../arch" } -cpuid = { path = "../cpuid" } devices = { path = "../devices" } fc_util = { path = "../fc_util" } kernel = { path = "../kernel" } @@ -28,6 +27,9 @@ rate_limiter = { path = "../rate_limiter" } seccomp = { path = "../seccomp" } sys_util = { path = "../sys_util" } +[target.'cfg(target_arch = "x86_64")'.dependencies] +cpuid = { path = "../cpuid" } + [dev-dependencies] tempfile = ">=3.0.2" diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 1b8b229464a..5d32c1e604b 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -20,6 +20,7 @@ extern crate serde_json; extern crate time; extern crate timerfd; +#[cfg(target_arch = "x86_64")] extern crate cpuid; extern crate devices; extern crate fc_util; @@ -873,6 +874,7 @@ impl Vmm { &self.legacy_device_manager.com_evt_2_4, ) .map_err(|e| StartMicrovmError::ConfigureVm(e))?; + #[cfg(target_arch = "x86_64")] self.vm .create_pit() .map_err(|e| StartMicrovmError::ConfigureVm(e))?; diff --git a/vmm/src/vstate.rs b/vmm/src/vstate.rs index 1a30a95223c..9c4bbb14eed 100644 --- a/vmm/src/vstate.rs +++ b/vmm/src/vstate.rs @@ -13,19 +13,25 @@ extern crate sys_util; use std::result; use super::KvmContext; +#[cfg(target_arch = "x86_64")] use cpuid::{c3_template, filter_cpuid, t2_template}; use kvm::*; use logger::{LogOption, LOGGER}; use logger::{Metric, METRICS}; use memory_model::{GuestAddress, GuestMemory, GuestMemoryError}; use sys_util::EventFd; -use vmm_config::machine_config::{CpuFeaturesTemplate, VmConfig}; +#[cfg(target_arch = "x86_64")] +use vmm_config::machine_config::CpuFeaturesTemplate; +use vmm_config::machine_config::VmConfig; const KVM_MEM_LOG_DIRTY_PAGES: u32 = 0x1; /// Errors associated with the wrappers over KVM ioctls. #[derive(Debug)] pub enum Error { + #[cfg(target_arch = "x86_64")] + /// A call to cpuid instruction failed. + CpuId(cpuid::Error), /// Invalid guest memory configuration. GuestMemory(GuestMemoryError), /// Hyperthreading flag is not initialized. @@ -90,8 +96,7 @@ impl Vm { }) } - /// Initializes the guest memory. Currently this is x86 specific - /// because of the TSS address setup. + /// Initializes the guest memory. pub fn memory_init(&mut self, guest_mem: GuestMemory, kvm_context: &KvmContext) -> Result<()> { if guest_mem.num_regions() > kvm_context.max_memslots() { return Err(Error::NotEnoughMemorySlots); @@ -133,6 +138,7 @@ impl Vm { Ok(()) } + #[cfg(target_arch = "x86_64")] /// Creates an in-kernel device model for the PIT. pub fn create_pit(&self) -> Result<()> { self.fd.create_pit2().map_err(Error::VmSetup)?; @@ -156,6 +162,7 @@ impl Vm { /// A wrapper around creating and using a kvm-based VCPU. pub struct Vcpu { + #[cfg(target_arch = "x86_64")] cpuid: CpuId, fd: VcpuFd, id: u8, @@ -164,24 +171,29 @@ pub struct Vcpu { impl Vcpu { /// Constructs a new VCPU for `vm`. /// - /// The `id` argument is the CPU number between [0, max vcpus). + /// # Arguments + /// + /// * `id` - Represents the CPU number between [0, max vcpus). + /// * `vm` - The virtual machine this vcpu will get attached to. pub fn new(id: u8, vm: &Vm) -> Result { let kvm_vcpu = vm.fd.create_vcpu(id).map_err(Error::VcpuFd)?; - // Initially the cpuid per vCPU is the one supported by this VM + // Initially the cpuid per vCPU is the one supported by this VM. Ok(Vcpu { - fd: kvm_vcpu, + #[cfg(target_arch = "x86_64")] cpuid: vm.fd.get_supported_cpuid(), + fd: kvm_vcpu, id, }) } #[cfg(target_arch = "x86_64")] - /// Configures the vcpu and should be called once per vcpu from the vcpu's thread. + /// Configures a x86_64 specific vcpu and should be called once per vcpu from the vcpu's thread. /// /// # Arguments /// - /// * `kernel_load_offset` - Offset from `guest_mem` at which the kernel starts. - /// nr cpus is required for checking populating the kvm_cpuid2 entry for ebx and edx registers + /// * `machine_config` - Specifies necessary info used for the CPUID configuration. + /// * `kernel_start_addr` - Offset from `guest_mem` at which the kernel starts. + /// * `vm` - The virtual machine this vcpu will get attached to. pub fn configure( &mut self, machine_config: &VmConfig, @@ -285,7 +297,7 @@ mod tests { assert_eq!(read_val, 67u8); } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + #[cfg(target_arch = "x86_64")] #[test] fn test_configure_vcpu() { let kvm_fd = Kvm::new().unwrap(); From bd3abb8508b23645db08469e72328c3925ae0d64 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 10:10:10 -0600 Subject: [PATCH 8/9] cargo: workaround for successful compilation... for aarch64 musl target. Signed-off-by: Diana Popa --- .cargo/config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.cargo/config b/.cargo/config index d67b66e2b25..d1b32ba41a9 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,8 @@ [build] target = "x86_64-unknown-linux-musl" + +[target.aarch64-unknown-linux-musl] +# On aarch64 musl depends on some libgcc functions (i.e `__addtf3` and other `*tf3` functions) for logic that uses +# long double. Such functions are not builtin in the rust compiler, so we need to get them from libgcc. +# No need for the `crt_static` flag as rustc appends it by default. +rustflags = [ "-C", "link-arg=-lgcc" ] From 06775db71b674ff1e7a6f3114a7f61163fdb00d9 Mon Sep 17 00:00:00 2001 From: Diana Popa Date: Mon, 10 Dec 2018 11:50:02 -0600 Subject: [PATCH 9/9] vmm: no tss cap check on non x86_64 platforms Signed-off-by: Diana Popa --- vmm/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 5d32c1e604b..8658bb1e7e2 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -298,6 +298,7 @@ impl KvmContext { check_cap(&kvm, Cap::Ioeventfd)?; check_cap(&kvm, Cap::Irqfd)?; // check_cap(&kvm, Cap::ImmediateExit)?; + #[cfg(target_arch = "x86_64")] check_cap(&kvm, Cap::SetTssAddr)?; check_cap(&kvm, Cap::UserMemory)?;