vmm/arch/
mod.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::fmt;
5use std::sync::LazyLock;
6
7use log::warn;
8use serde::{Deserialize, Serialize};
9use vm_memory::GuestAddress;
10
11/// Module for aarch64 related functionality.
12#[cfg(target_arch = "aarch64")]
13pub mod aarch64;
14
15#[cfg(target_arch = "aarch64")]
16pub use aarch64::kvm::{Kvm, KvmArchError, OptionalCapabilities};
17#[cfg(target_arch = "aarch64")]
18pub use aarch64::vcpu::*;
19#[cfg(target_arch = "aarch64")]
20pub use aarch64::vm::{ArchVm, ArchVmError, VmState};
21#[cfg(target_arch = "aarch64")]
22pub use aarch64::{
23    ConfigurationError, arch_memory_regions, configure_system_for_boot, get_kernel_start,
24    initrd_load_addr, layout::*, load_kernel,
25};
26
27/// Module for x86_64 related functionality.
28#[cfg(target_arch = "x86_64")]
29pub mod x86_64;
30
31#[cfg(target_arch = "x86_64")]
32pub use x86_64::kvm::{Kvm, KvmArchError};
33#[cfg(target_arch = "x86_64")]
34pub use x86_64::vcpu::*;
35#[cfg(target_arch = "x86_64")]
36pub use x86_64::vm::{ArchVm, ArchVmError, VmState};
37
38#[cfg(target_arch = "x86_64")]
39pub use crate::arch::x86_64::{
40    ConfigurationError, arch_memory_regions, configure_system_for_boot, get_kernel_start,
41    initrd_load_addr, layout::*, load_kernel,
42};
43
44/// Types of devices that can get attached to this platform.
45#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy, Serialize, Deserialize)]
46pub enum DeviceType {
47    /// Device Type: Virtio.
48    Virtio(u32),
49    /// Device Type: Serial.
50    #[cfg(target_arch = "aarch64")]
51    Serial,
52    /// Device Type: RTC.
53    #[cfg(target_arch = "aarch64")]
54    Rtc,
55    /// Device Type: BootTimer.
56    BootTimer,
57}
58
59/// Default page size for the guest OS.
60pub const GUEST_PAGE_SIZE: usize = 4096;
61
62/// Get the size of the host page size.
63pub fn host_page_size() -> usize {
64    /// Default page size for the host OS.
65    static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| {
66        // # Safety: Value always valid
67        let r = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
68        usize::try_from(r).unwrap_or_else(|_| {
69            warn!("Could not get host page size with sysconf, assuming default 4K host pages");
70            4096
71        })
72    });
73
74    *PAGE_SIZE
75}
76
77impl fmt::Display for DeviceType {
78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        write!(f, "{:?}", self)
80    }
81}
82
83/// Supported boot protocols for
84#[derive(Debug, Copy, Clone, PartialEq)]
85pub enum BootProtocol {
86    /// Linux 64-bit boot protocol
87    LinuxBoot,
88    #[cfg(target_arch = "x86_64")]
89    /// PVH boot protocol (x86/HVM direct boot ABI)
90    PvhBoot,
91}
92
93impl fmt::Display for BootProtocol {
94    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
95        match self {
96            BootProtocol::LinuxBoot => write!(f, "Linux 64-bit boot protocol"),
97            #[cfg(target_arch = "x86_64")]
98            BootProtocol::PvhBoot => write!(f, "PVH boot protocol"),
99        }
100    }
101}
102
103#[derive(Debug, Copy, Clone)]
104/// Specifies the entry point address where the guest must start
105/// executing code, as well as which boot protocol is to be used
106/// to configure the guest initial state.
107pub struct EntryPoint {
108    /// Address in guest memory where the guest must start execution
109    pub entry_addr: GuestAddress,
110    /// Specifies which boot protocol to use
111    pub protocol: BootProtocol,
112}
113
114/// Adds in [`regions`] the valid memory regions suitable for RAM taking into account a gap in the
115/// available address space and returns the remaining region (if any) past this gap
116fn arch_memory_regions_with_gap(
117    regions: &mut Vec<(GuestAddress, usize)>,
118    region_start: usize,
119    region_size: usize,
120    gap_start: usize,
121    gap_size: usize,
122) -> Option<(usize, usize)> {
123    // 0-sized gaps don't really make sense. We should never receive such a gap.
124    assert!(gap_size > 0);
125
126    let first_addr_past_gap = gap_start + gap_size;
127    match (region_start + region_size).checked_sub(gap_start) {
128        // case0: region fits all before gap
129        None | Some(0) => {
130            regions.push((GuestAddress(region_start as u64), region_size));
131            None
132        }
133        // case1: region starts before the gap and goes past it
134        Some(remaining) if region_start < gap_start => {
135            regions.push((GuestAddress(region_start as u64), gap_start - region_start));
136            Some((first_addr_past_gap, remaining))
137        }
138        // case2: region starts past the gap
139        Some(_) => Some((first_addr_past_gap.max(region_start), region_size)),
140    }
141}