xref: /cloud-hypervisor/arch/src/lib.rs (revision 3f3489e38e32a652241e889a9a1f6c67823d584b)
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