1 // Copyright © 2024 Institute of Software, CAS. All rights reserved. 2 // Copyright 2020 Arm Limited (or its affiliates). All rights reserved. 3 // Copyright © 2020, Oracle and/or its affiliates. 4 // 5 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 // SPDX-License-Identifier: Apache-2.0 7 8 //! Implements platform specific functionality. 9 //! Supported platforms: x86_64, aarch64, riscv64. 10 11 #[macro_use] 12 extern crate log; 13 14 use std::collections::BTreeMap; 15 use std::sync::Arc; 16 use std::{fmt, result}; 17 18 use serde::{Deserialize, Serialize}; 19 use thiserror::Error; 20 21 #[cfg(target_arch = "x86_64")] 22 use crate::x86_64::SgxEpcSection; 23 24 type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>; 25 type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>; 26 27 /// Type for returning error code. 28 #[derive(Debug, Error)] 29 pub enum Error { 30 #[cfg(target_arch = "x86_64")] 31 #[error("Platform specific error (x86_64): {0}")] 32 PlatformSpecific(#[from] x86_64::Error), 33 #[cfg(target_arch = "aarch64")] 34 #[error("Platform specific error (aarch64): {0:?}")] 35 PlatformSpecific(#[from] aarch64::Error), 36 #[cfg(target_arch = "riscv64")] 37 #[error("Platform specific error (riscv64): {0:?}")] 38 PlatformSpecific(#[from] riscv64::Error), 39 #[error("The memory map table extends past the end of guest memory")] 40 MemmapTablePastRamEnd, 41 #[error("Error writing memory map table to guest memory")] 42 MemmapTableSetup, 43 #[error("The hvm_start_info structure extends past the end of guest memory")] 44 StartInfoPastRamEnd, 45 #[error("Error writing hvm_start_info to guest memory")] 46 StartInfoSetup, 47 #[error("Failed to compute initramfs address")] 48 InitramfsAddress, 49 #[error("Error writing module entry to guest memory: {0}")] 50 ModlistSetup(#[source] vm_memory::GuestMemoryError), 51 #[error("RSDP extends past the end of guest memory")] 52 RsdpPastRamEnd, 53 #[error("Failed to setup Zero Page for bzImage")] 54 ZeroPageSetup(#[source] vm_memory::GuestMemoryError), 55 #[error("Zero Page for bzImage past RAM end")] 56 ZeroPagePastRamEnd, 57 } 58 59 /// Type for returning public functions outcome. 60 pub type Result<T> = result::Result<T, Error>; 61 62 /// Type for memory region types. 63 #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)] 64 pub enum RegionType { 65 /// RAM type 66 Ram, 67 68 /// SubRegion memory region. 69 /// A SubRegion is a memory region sub-region, allowing for a region 70 /// to be split into sub regions managed separately. 71 /// For example, the x86 32-bit memory hole is a SubRegion. 72 SubRegion, 73 74 /// Reserved type. 75 /// A Reserved memory region is one that should not be used for memory 76 /// allocation. This type can be used to prevent the VMM from allocating 77 /// memory ranges in a specific address range. 78 Reserved, 79 } 80 81 /// Module for aarch64 related functionality. 82 #[cfg(target_arch = "aarch64")] 83 pub mod aarch64; 84 85 #[cfg(target_arch = "aarch64")] 86 pub use aarch64::{ 87 arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt, 88 get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, 89 layout::IRQ_BASE, uefi, EntryPoint, _NSIG, 90 }; 91 92 /// Module for riscv64 related functionality. 93 #[cfg(target_arch = "riscv64")] 94 pub mod riscv64; 95 96 #[cfg(target_arch = "riscv64")] 97 pub use riscv64::{ 98 arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt, 99 get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, 100 layout::IRQ_BASE, EntryPoint, _NSIG, 101 }; 102 103 #[cfg(target_arch = "x86_64")] 104 pub mod x86_64; 105 106 #[cfg(target_arch = "x86_64")] 107 pub use x86_64::{ 108 arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid, 109 generate_ram_ranges, get_host_cpu_phys_bits, initramfs_load_addr, layout, 110 layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs, CpuidConfig, CpuidFeatureEntry, 111 EntryPoint, _NSIG, 112 }; 113 114 /// Safe wrapper for `sysconf(_SC_PAGESIZE)`. 115 #[cfg(target_arch = "x86_64")] 116 #[inline(always)] 117 fn pagesize() -> usize { 118 // SAFETY: Trivially safe 119 unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } 120 } 121 122 #[derive(Clone, Default)] 123 pub struct NumaNode { 124 pub memory_regions: Vec<Arc<GuestRegionMmap>>, 125 pub hotplug_regions: Vec<Arc<GuestRegionMmap>>, 126 pub cpus: Vec<u8>, 127 pub pci_segments: Vec<u16>, 128 pub distances: BTreeMap<u32, u8>, 129 pub memory_zones: Vec<String>, 130 #[cfg(target_arch = "x86_64")] 131 pub sgx_epc_sections: Vec<SgxEpcSection>, 132 } 133 134 pub type NumaNodes = BTreeMap<u32, NumaNode>; 135 136 /// Type for passing information about the initramfs in the guest memory. 137 pub struct InitramfsConfig { 138 /// Load address of initramfs in guest memory 139 pub address: vm_memory::GuestAddress, 140 /// Size of initramfs in guest memory 141 pub size: usize, 142 } 143 144 /// Types of devices that can get attached to this platform. 145 #[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] 146 pub enum DeviceType { 147 /// Device Type: Virtio. 148 Virtio(u32), 149 /// Device Type: Serial. 150 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 151 Serial, 152 /// Device Type: RTC. 153 #[cfg(target_arch = "aarch64")] 154 Rtc, 155 /// Device Type: GPIO. 156 #[cfg(target_arch = "aarch64")] 157 Gpio, 158 } 159 160 /// Default (smallest) memory page size for the supported architectures. 161 pub const PAGE_SIZE: usize = 4096; 162 163 impl fmt::Display for DeviceType { 164 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 165 write!(f, "{self:?}") 166 } 167 } 168 169 /// Structure to describe MMIO device information 170 #[derive(Clone, Debug)] 171 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 172 pub struct MmioDeviceInfo { 173 pub addr: u64, 174 pub len: u64, 175 pub irq: u32, 176 } 177 178 /// Structure to describe PCI space information 179 #[derive(Clone, Debug)] 180 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 181 pub struct PciSpaceInfo { 182 pub pci_segment_id: u16, 183 pub mmio_config_address: u64, 184 pub pci_device_space_start: u64, 185 pub pci_device_space_size: u64, 186 } 187 188 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 189 impl DeviceInfoForFdt for MmioDeviceInfo { 190 fn addr(&self) -> u64 { 191 self.addr 192 } 193 fn irq(&self) -> u32 { 194 self.irq 195 } 196 fn length(&self) -> u64 { 197 self.len 198 } 199 } 200