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)")]
32 PlatformSpecific(#[from] x86_64::Error),
33 #[cfg(target_arch = "aarch64")]
34 #[error("Platform specific error (aarch64)")]
35 PlatformSpecific(#[from] aarch64::Error),
36 #[cfg(target_arch = "riscv64")]
37 #[error("Platform specific error (riscv64)")]
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")]
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)]
pagesize() -> usize117 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 {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result164 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 {
addr(&self) -> u64190 fn addr(&self) -> u64 {
191 self.addr
192 }
irq(&self) -> u32193 fn irq(&self) -> u32 {
194 self.irq
195 }
length(&self) -> u64196 fn length(&self) -> u64 {
197 self.len
198 }
199 }
200