Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/firecracker/swagger/firecracker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,11 @@ definitions:
description:
Aarch64 only. If non-zero, causes Firecracker to allocate a specific memory area of this size (in MiB)
which the guest will use as swiotlb region for all I/O.
secret_free:
type: boolean
description:
If enabled, guest memory will be unmapped from the host kernel's address space, providing additional
protection against transitive execution issues. All I/O must then go through a swiotlb region.

MemoryBackend:
type: object
Expand Down
2 changes: 1 addition & 1 deletion src/vmm/benches/memory_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn bench_single_page_fault(c: &mut Criterion, configuration: VmResources) {
c.bench_function("page_fault", |b| {
b.iter_batched(
|| {
let memory = configuration.allocate_guest_memory().unwrap();
let memory = configuration.allocate_guest_memory(None).unwrap();
// Get a pointer to the first memory region (cannot do `.get_slice(GuestAddress(0),
// 1)`, because on ARM64 guest memory does not start at physical
// address 0).
Expand Down
14 changes: 4 additions & 10 deletions src/vmm/src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ pub mod vm;

use std::cmp::min;
use std::fmt::Debug;
use std::fs::File;
use std::io::{Read, Seek};

use linux_loader::loader::pe::PE as Loader;
use linux_loader::loader::{Cmdline, KernelLoader};
use vm_memory::GuestMemoryError;
use vm_memory::{GuestMemoryError, ReadVolatile};

use crate::arch::{BootProtocol, EntryPoint};
use crate::cpu_config::aarch64::{CpuConfiguration, CpuConfigurationError};
Expand Down Expand Up @@ -204,16 +204,10 @@ fn get_fdt_addr(mem: &GuestMemoryMmap) -> u64 {
}

/// Load linux kernel into guest memory.
pub fn load_kernel(
kernel: &File,
pub fn load_kernel<R: ReadVolatile + Read + Seek>(
mut kernel_file: R,
guest_memory: &GuestMemoryMmap,
) -> Result<EntryPoint, ConfigurationError> {
// Need to clone the File because reading from it
// mutates it.
let mut kernel_file = kernel
.try_clone()
.map_err(|_| ConfigurationError::KernelFile)?;

let entry_addr = Loader::load(
guest_memory,
Some(GuestAddress(get_kernel_start())),
Expand Down
12 changes: 10 additions & 2 deletions src/vmm/src/arch/aarch64/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ use crate::arch::aarch64::gic::GicState;
use crate::vstate::memory::{GuestMemoryExtension, GuestMemoryState};
use crate::vstate::vm::{VmCommon, VmError};

/// The VM type for this architecture that allows us to use guest_memfd. On ARM, all VMs
/// support guest_memfd and no special type is needed (in fact, no concept of vm types really
/// exists, and the correspoding field of the CREATE_VM ioctl determines IPA size instead,
/// e.g. the size of the guest physical address space. This value cannot be hardcoded, hence
/// `None` to let the `Vm` constructor now that just normal [`Kvm::create_vm`] should be called,
/// which internally determines the preferred IPA size.
pub const VM_TYPE_FOR_SECRET_FREEDOM: Option<u64> = None;

/// Structure representing the current architecture's understand of what a "virtual machine" is.
#[derive(Debug)]
pub struct ArchVm {
Expand All @@ -30,8 +38,8 @@ pub enum ArchVmError {

impl ArchVm {
/// Create a new `Vm` struct.
pub fn new(kvm: &Kvm) -> Result<ArchVm, VmError> {
let common = Self::create_common(kvm)?;
pub fn new(kvm: &Kvm, vm_type: Option<u64>) -> Result<ArchVm, VmError> {
let common = Self::create_common(kvm, vm_type)?;
Ok(ArchVm {
common,
irqchip_handle: None,
Expand Down
4 changes: 2 additions & 2 deletions src/vmm/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub use aarch64::kvm::{Kvm, KvmArchError, OptionalCapabilities};
#[cfg(target_arch = "aarch64")]
pub use aarch64::vcpu::*;
#[cfg(target_arch = "aarch64")]
pub use aarch64::vm::{ArchVm, ArchVmError, VmState};
pub use aarch64::vm::{ArchVm, ArchVmError, VM_TYPE_FOR_SECRET_FREEDOM, VmState};
#[cfg(target_arch = "aarch64")]
pub use aarch64::{
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions,
Expand All @@ -35,7 +35,7 @@ pub use x86_64::kvm::{Kvm, KvmArchError};
#[cfg(target_arch = "x86_64")]
pub use x86_64::vcpu::*;
#[cfg(target_arch = "x86_64")]
pub use x86_64::vm::{ArchVm, ArchVmError, VmState};
pub use x86_64::vm::{ArchVm, ArchVmError, VM_TYPE_FOR_SECRET_FREEDOM, VmState};

#[cfg(target_arch = "x86_64")]
pub use crate::arch::x86_64::{
Expand Down
15 changes: 5 additions & 10 deletions src/vmm/src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub mod xstate;
#[allow(missing_docs)]
pub mod generated;

use std::fs::File;
use std::io::{Read, Seek};

use layout::CMDLINE_START;
use linux_loader::configurator::linux::LinuxBootConfigurator;
Expand All @@ -44,6 +44,7 @@ use linux_loader::loader::elf::start_info::{
};
use linux_loader::loader::{Cmdline, KernelLoader, PvhBootCapability, load_cmdline};
use log::debug;
use vm_memory::ReadVolatile;

use super::EntryPoint;
use crate::acpi::create_acpi_tables;
Expand Down Expand Up @@ -447,20 +448,14 @@ fn add_e820_entry(
}

/// Load linux kernel into guest memory.
pub fn load_kernel(
kernel: &File,
pub fn load_kernel<R: Read + ReadVolatile + Seek>(
mut kernel: R,
guest_memory: &GuestMemoryMmap,
) -> Result<EntryPoint, ConfigurationError> {
// Need to clone the File because reading from it
// mutates it.
let mut kernel_file = kernel
.try_clone()
.map_err(|_| ConfigurationError::KernelFile)?;

let entry_addr = Loader::load(
guest_memory,
None,
&mut kernel_file,
&mut kernel,
Some(GuestAddress(get_kernel_start())),
)
.map_err(ConfigurationError::KernelLoader)?;
Expand Down
11 changes: 8 additions & 3 deletions src/vmm/src/arch/x86_64/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@ use std::fmt;

use kvm_bindings::{
KVM_CLOCK_TSC_STABLE, KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE,
KVM_PIT_SPEAKER_DUMMY, MsrList, kvm_clock_data, kvm_irqchip, kvm_pit_config, kvm_pit_state2,
KVM_PIT_SPEAKER_DUMMY, KVM_X86_SW_PROTECTED_VM, MsrList, kvm_clock_data, kvm_irqchip,
kvm_pit_config, kvm_pit_state2,
};
use kvm_ioctls::Cap;
use serde::{Deserialize, Serialize};

use crate::arch::Kvm;
use crate::arch::x86_64::msr::MsrError;
use crate::utils::u64_to_usize;
use crate::vstate::memory::{GuestMemoryExtension, GuestMemoryState};
use crate::vstate::vm::{VmCommon, VmError};

/// The VM type for this architecture that allows us to use guest_memfd.
pub const VM_TYPE_FOR_SECRET_FREEDOM: Option<u64> = Some(KVM_X86_SW_PROTECTED_VM as u64);

/// Error type for [`Vm::restore_state`]
#[allow(missing_docs)]
#[cfg(target_arch = "x86_64")]
Expand Down Expand Up @@ -60,8 +65,8 @@ pub struct ArchVm {

impl ArchVm {
/// Create a new `Vm` struct.
pub fn new(kvm: &crate::vstate::kvm::Kvm) -> Result<ArchVm, VmError> {
let common = Self::create_common(kvm)?;
pub fn new(kvm: &Kvm, vm_type: Option<u64>) -> Result<ArchVm, VmError> {
let common = Self::create_common(kvm, vm_type)?;

let msrs_to_save = kvm.msrs_to_save().map_err(ArchVmError::GetMsrsToSave)?;

Expand Down
78 changes: 63 additions & 15 deletions src/vmm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use std::fmt::Debug;
use std::io::{self};
use std::os::unix::fs::MetadataExt;
#[cfg(feature = "gdb")]
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
Expand All @@ -19,7 +20,9 @@
use vm_superio::Serial;
use vmm_sys_util::eventfd::EventFd;

use crate::arch::{ConfigurationError, configure_system_for_boot, load_kernel};
use crate::arch::{
ConfigurationError, VM_TYPE_FOR_SECRET_FREEDOM, configure_system_for_boot, load_kernel,
};
#[cfg(target_arch = "aarch64")]
use crate::construct_kvm_mpidrs;
use crate::cpu_config::templates::{
Expand Down Expand Up @@ -57,12 +60,14 @@
use crate::resources::VmResources;
use crate::seccomp::BpfThreadMap;
use crate::snapshot::Persist;
use crate::utils::u64_to_usize;
use crate::vmm_config::instance_info::InstanceInfo;
use crate::vmm_config::machine_config::MachineConfigError;
use crate::vmm_config::snapshot::{MemBackendConfig, MemBackendType};
use crate::vstate::kvm::Kvm;
use crate::vstate::memory::Bounce;

Check warning on line 68 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L68

Added line #L68 was not covered by tests
use crate::vstate::vcpu::{Vcpu, VcpuError};
use crate::vstate::vm::Vm;
use crate::vstate::vm::{KVM_GMEM_NO_DIRECT_MAP, Vm};

Check warning on line 70 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L70

Added line #L70 was not covered by tests
use crate::{EventManager, Vmm, VmmError, device_manager};

/// Errors associated with starting the instance.
Expand Down Expand Up @@ -139,11 +144,12 @@
event_manager: &mut EventManager,
vcpu_count: u8,
kvm_capabilities: Vec<KvmCapability>,
vm_type: Option<u64>,
) -> Result<(Vmm, Vec<Vcpu>), VmmError> {
let kvm = Kvm::new(kvm_capabilities)?;
// Set up Kvm Vm and register memory regions.
// Build custom CPU config if a custom template is provided.
let mut vm = Vm::new(&kvm)?;
let mut vm = Vm::new(&kvm, vm_type)?;

let resource_allocator = ResourceAllocator::new()?;

Expand Down Expand Up @@ -214,14 +220,6 @@
.as_ref()
.ok_or(MissingKernelConfig)?;

let guest_memory = vm_resources
.allocate_guest_memory()
.map_err(StartMicrovmError::GuestMemory)?;

let swiotlb = vm_resources
.allocate_swiotlb_region()
.map_err(StartMicrovmError::GuestMemory)?;

// Clone the command-line so that a failed boot doesn't pollute the original.
#[allow(unused_mut)]
let mut boot_cmdline = boot_config.cmdline.clone();
Expand All @@ -231,25 +229,69 @@
.cpu_template
.get_cpu_template()?;

let secret_free = vm_resources.machine_config.mem_config.secret_free;
let vm_type = match secret_free {
true => VM_TYPE_FOR_SECRET_FREEDOM,

Check warning on line 234 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L234

Added line #L234 was not covered by tests
false => None,
};

let (mut vmm, mut vcpus) = create_vmm_and_vcpus(
instance_info,
event_manager,
vm_resources.machine_config.vcpu_count,
cpu_template.kvm_capabilities.clone(),
vm_type,
)?;

let guest_memfd = match secret_free {
true => Some(
vmm.vm
.create_guest_memfd(vm_resources.memory_size(), KVM_GMEM_NO_DIRECT_MAP)
.map_err(VmmError::Vm)?,

Check warning on line 250 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L248-L250

Added lines #L248 - L250 were not covered by tests
),
false => None,
};

Check warning on line 254 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L254

Added line #L254 was not covered by tests
let guest_memory = vm_resources
.allocate_guest_memory(guest_memfd)
.map_err(StartMicrovmError::GuestMemory)?;

let swiotlb = vm_resources
.allocate_swiotlb_region()
.map_err(StartMicrovmError::GuestMemory)?;

vmm.vm
.register_memory_regions(guest_memory)
.register_memory_regions(guest_memory, secret_free)
.map_err(VmmError::Vm)?;

#[cfg(target_arch = "x86_64")]
vmm.vm.set_memory_private().map_err(VmmError::Vm)?;

if let Some(swiotlb) = swiotlb {
vmm.vm
.register_swiotlb_region(swiotlb)
.map_err(VmmError::Vm)?;
}

let entry_point = load_kernel(&boot_config.kernel_file, vmm.vm.guest_memory())?;
let initrd = InitrdConfig::from_config(boot_config, vmm.vm.guest_memory())?;
let entry_point = load_kernel(
Bounce(&boot_config.kernel_file, secret_free),
vmm.vm.guest_memory(),
)?;
let initrd = match &boot_config.initrd_file {
Some(initrd_file) => {
let size = initrd_file
.metadata()
.map_err(InitrdError::Metadata)?
.size();

Some(InitrdConfig::from_reader(
vmm.vm.guest_memory(),
Bounce(initrd_file, secret_free),
u64_to_usize(size),
)?)
}

Check warning on line 292 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L281-L292

Added lines #L281 - L292 were not covered by tests
None => None,
};

Check warning on line 294 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L294

Added line #L294 was not covered by tests

#[cfg(feature = "gdb")]
let (gdb_tx, gdb_rx) = mpsc::channel();
Expand Down Expand Up @@ -439,6 +481,11 @@
event_manager,
vm_resources.machine_config.vcpu_count,
microvm_state.kvm_state.kvm_cap_modifiers.clone(),
if vm_resources.machine_config.mem_config.secret_free {
VM_TYPE_FOR_SECRET_FREEDOM

Check warning on line 485 in src/vmm/src/builder.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/builder.rs#L485

Added line #L485 was not covered by tests
} else {
None
},
)
.map_err(StartMicrovmError::Internal)?;

Expand Down Expand Up @@ -467,8 +514,9 @@
guest_memory.iter().map(|r| r.len()).sum(),
)?;

// TODO: sort out gmem support for snapshot restore
vmm.vm
.register_memory_regions(guest_memory)
.register_memory_regions(guest_memory, false)
.map_err(VmmError::Vm)
.map_err(StartMicrovmError::Internal)?;

Expand Down
12 changes: 6 additions & 6 deletions src/vmm/src/device_manager/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,8 +655,8 @@ mod tests {
let start_addr2 = GuestAddress(0x1000);
let guest_mem = multi_region_mem_raw(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]);
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
let mut vm = Vm::new(&kvm).unwrap();
vm.register_memory_regions(guest_mem).unwrap();
let mut vm = Vm::new(&kvm, None).unwrap();
vm.register_memory_regions(guest_mem, false).unwrap();
let mut device_manager = MMIODeviceManager::new();
let mut resource_allocator = ResourceAllocator::new().unwrap();

Expand Down Expand Up @@ -686,8 +686,8 @@ mod tests {
let start_addr2 = GuestAddress(0x1000);
let guest_mem = multi_region_mem_raw(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]);
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
let mut vm = Vm::new(&kvm).unwrap();
vm.register_memory_regions(guest_mem).unwrap();
let mut vm = Vm::new(&kvm, None).unwrap();
vm.register_memory_regions(guest_mem, false).unwrap();
let mut device_manager = MMIODeviceManager::new();
let mut resource_allocator = ResourceAllocator::new().unwrap();

Expand Down Expand Up @@ -742,8 +742,8 @@ mod tests {
let start_addr2 = GuestAddress(0x1000);
let guest_mem = multi_region_mem_raw(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]);
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
let mut vm = Vm::new(&kvm).unwrap();
vm.register_memory_regions(guest_mem).unwrap();
let mut vm = Vm::new(&kvm, None).unwrap();
vm.register_memory_regions(guest_mem, false).unwrap();

#[cfg(target_arch = "x86_64")]
vm.setup_irqchip().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/vmm/src/devices/virtio/block/virtio/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ pub mod tests {
)
.unwrap()
.into_iter()
.map(|region| KvmRegion::from_mmap_region(region, 0))
.map(|region| KvmRegion::from_mmap_region(region, 0, None))
.collect(),
)
.unwrap()
Expand Down
2 changes: 1 addition & 1 deletion src/vmm/src/devices/virtio/vhost_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ pub(crate) mod tests {
)
.unwrap()
.into_iter()
.map(|region| KvmRegion::from_mmap_region(region, 0))
.map(|region| KvmRegion::from_mmap_region(region, 0, None))
.collect(),
)
.unwrap()
Expand Down
Loading