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