Skip to content

Commit 6a56cd6

Browse files
committed
arch: define 64-bit capable MMIO memory regions
PCIe distinguishes MMIO regions between 32bit and 64bit, caring for devices that can't deal with 64-bit addresses. This commit defines the appropriate regions for both x86 and aarch64 architectures, extends the resource allocator to handle allocations for both of these regions and adjusts the logic that calculates the memory regions for the architecture. Also, un-do the change that added an `offset` argument `arch_memory_regions` function. We won't be using this for "secret hiding" so it just made the logic (especially for kani proofs) too convoluted. Signed-off-by: Babis Chalios <[email protected]>
1 parent 29761fc commit 6a56cd6

File tree

15 files changed

+453
-246
lines changed

15 files changed

+453
-246
lines changed

src/vmm/src/arch/aarch64/gic/gicv2/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl GICv2 {
3030

3131
/// Get the address of the GICv2 distributor.
3232
const fn get_dist_addr() -> u64 {
33-
super::layout::MAPPED_IO_START - GICv2::KVM_VGIC_V2_DIST_SIZE
33+
super::layout::MMIO32_MEM_START - GICv2::KVM_VGIC_V2_DIST_SIZE
3434
}
3535

3636
/// Get the size of the GIC_v2 distributor.

src/vmm/src/arch/aarch64/gic/gicv3/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl GICv3 {
3030

3131
/// Get the address of the GIC distributor.
3232
fn get_dist_addr() -> u64 {
33-
super::layout::MAPPED_IO_START - GICv3::KVM_VGIC_V3_DIST_SIZE
33+
super::layout::MMIO32_MEM_START - GICv3::KVM_VGIC_V3_DIST_SIZE
3434
}
3535

3636
/// Get the size of the GIC distributor.

src/vmm/src/arch/aarch64/layout.rs

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,53 @@
44
// ==== Address map in use in ARM development systems today ====
55
//
66
// - 32-bit - - 36-bit - - 40-bit -
7-
// 1024GB + + +-------------------+ <- 40-bit
7+
// 1024GB + + +-------------------+ <- 40-bit
88
// | | DRAM |
99
// ~ ~ ~ ~
1010
// | | |
1111
// | | |
1212
// | | |
1313
// | | |
14-
// 544GB + + +-------------------+
14+
// 544GB + + +-------------------+
1515
// | | Hole or DRAM |
1616
// | | |
17-
// 512GB + + +-------------------+
17+
// 512GB + + +-------------------+
1818
// | | Mapped |
1919
// | | I/O |
2020
// ~ ~ ~ ~
2121
// | | |
22-
// 256GB + + +-------------------+
22+
// 256GB + + +-------------------+
2323
// | | Reserved |
2424
// ~ ~ ~ ~
2525
// | | |
26-
// 64GB + +-----------------------+-------------------+ <- 36-bit
26+
// 64GB + +-----------------------+-------------------+ <- 36-bit
2727
// | | DRAM |
2828
// ~ ~ ~ ~
2929
// | | |
3030
// | | |
31-
// 34GB + +-----------------------+-------------------+
31+
// 34GB + +-----------------------+-------------------+
3232
// | | Hole or DRAM |
33-
// 32GB + +-----------------------+-------------------+
33+
// 32GB + +-----------------------+-------------------+
3434
// | | Mapped I/O |
3535
// ~ ~ ~ ~
3636
// | | |
37-
// 16GB + +-----------------------+-------------------+
37+
// 16GB + +-----------------------+-------------------+
3838
// | | Reserved |
3939
// ~ ~ ~ ~
40-
// 4GB +-------------------+-----------------------+-------------------+ <- 32-bit
40+
// 4GB +-------------------+-----------------------+-------------------+ <- 32-bit
4141
// | 2GB of DRAM |
4242
// | |
43-
// 2GB +-------------------+-----------------------+-------------------+
43+
// 2GB +-------------------+-----------------------+-------------------+
4444
// | Mapped I/O |
45-
// 1GB +-------------------+-----------------------+-------------------+
45+
// 1GB +-------------------+-----------------------+-------------------+
4646
// | ROM & RAM & I/O |
47-
// 0GB +-------------------+-----------------------+-------------------+ 0
47+
// 0GB +-------------------+-----------------------+-------------------+ 0
4848
// - 32-bit - - 36-bit - - 40-bit -
4949
//
5050
// Taken from (http://infocenter.arm.com/help/topic/com.arm.doc.den0001c/DEN0001C_principles_of_arm_memory_maps.pdf).
5151

52+
use crate::device_manager::mmio::MMIO_LEN;
53+
5254
/// Start of RAM on 64 bit ARM.
5355
pub const DRAM_MEM_START: u64 = 0x8000_0000; // 2 GB.
5456
/// The maximum RAM size.
@@ -80,5 +82,46 @@ pub const IRQ_MAX: u32 = 128;
8082
/// First usable interrupt on aarch64.
8183
pub const IRQ_BASE: u32 = 32;
8284

85+
/// The start of the memory area reserved for MMIO 32-bit accesses.
8386
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
84-
pub const MAPPED_IO_START: u64 = 1 << 30; // 1 GB
87+
pub const MMIO32_MEM_START: u64 = 1 << 30; // 1GiB
88+
/// The size of the memory area reserved for MMIO 32-bit accesses (1GiB).
89+
pub const MMIO32_MEM_SIZE: u64 = DRAM_MEM_START - MMIO32_MEM_START;
90+
91+
// The rest of the MMIO address space (256 MiB) we dedicate to PCIe for memory-mapped access to
92+
// configuration.
93+
/// Size of MMIO region for PCIe configuration accesses.
94+
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
95+
/// Start of MMIO region for PCIe configuration accesses.
96+
pub const PCI_MMCONFIG_START: u64 = DRAM_MEM_START - PCI_MMCONFIG_SIZE;
97+
/// MMIO space per PCIe segment
98+
pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256;
99+
100+
// We reserve 768 MiB for devices at the beginning of the MMIO region. This includes space both for
101+
// pure MMIO and PCIe devices.
102+
103+
/// Memory region start for boot device.
104+
pub const BOOT_DEVICE_MEM_START: u64 = MMIO32_MEM_START;
105+
/// Memory region start for RTC device.
106+
pub const RTC_MEM_START: u64 = BOOT_DEVICE_MEM_START + MMIO_LEN;
107+
/// Memory region start for Serial device.
108+
pub const SERIAL_MEM_START: u64 = RTC_MEM_START + MMIO_LEN;
109+
110+
/// Beginning of memory region for device MMIO 32-bit accesses
111+
pub const MEM_32BIT_DEVICES_START: u64 = SERIAL_MEM_START + MMIO_LEN;
112+
/// Size of memory region for device MMIO 32-bit accesses
113+
pub const MEM_32BIT_DEVICES_SIZE: u64 = PCI_MMCONFIG_START - MEM_32BIT_DEVICES_START;
114+
115+
// 64-bits region for MMIO accesses
116+
/// The start of the memory area reserved for MMIO 64-bit accesses.
117+
pub const MMIO64_MEM_START: u64 = 256 << 30;
118+
/// The size of the memory area reserved for MMIO 64-bit accesses.
119+
pub const MMIO64_MEM_SIZE: u64 = 256 << 30;
120+
121+
// At the moment, all of this region goes to devices
122+
/// Beginning of memory region for device MMIO 64-bit accesses
123+
pub const MEM_64BIT_DEVICES_START: u64 = MMIO64_MEM_START;
124+
/// Size of memory region for device MMIO 32-bit accesses
125+
pub const MEM_64BIT_DEVICES_SIZE: u64 = MMIO64_MEM_SIZE;
126+
/// First address past the 64-bit MMIO gap
127+
pub const FIRST_ADDR_PAST_64BITS_MMIO: u64 = MMIO64_MEM_START + MMIO64_MEM_SIZE;

src/vmm/src/arch/aarch64/mod.rs

Lines changed: 86 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ use linux_loader::loader::pe::PE as Loader;
2424
use linux_loader::loader::{Cmdline, KernelLoader};
2525
use vm_memory::GuestMemoryError;
2626

27-
use crate::arch::{BootProtocol, EntryPoint};
27+
use crate::arch::{BootProtocol, EntryPoint, arch_memory_regions_with_gap};
2828
use crate::cpu_config::aarch64::{CpuConfiguration, CpuConfigurationError};
2929
use crate::cpu_config::templates::CustomCpuTemplate;
3030
use crate::initrd::InitrdConfig;
31-
use crate::utils::{align_up, usize_to_u64};
31+
use crate::utils::{align_up, u64_to_usize, usize_to_u64};
3232
use crate::vmm_config::machine_config::MachineConfig;
3333
use crate::vstate::memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
3434
use crate::vstate::vcpu::KvmVcpuError;
@@ -51,42 +51,34 @@ pub enum ConfigurationError {
5151
VcpuConfigure(#[from] KvmVcpuError),
5252
}
5353

54-
/// The start of the memory area reserved for MMIO devices.
55-
pub const MMIO_MEM_START: u64 = layout::MAPPED_IO_START;
56-
/// The size of the memory area reserved for MMIO devices.
57-
pub const MMIO_MEM_SIZE: u64 = layout::DRAM_MEM_START - layout::MAPPED_IO_START; //>> 1GB
58-
5954
/// Returns a Vec of the valid memory addresses for aarch64.
6055
/// See [`layout`](layout) module for a drawing of the specific memory model for this platform.
61-
///
62-
/// The `offset` parameter specified the offset from [`layout::DRAM_MEM_START`].
63-
pub fn arch_memory_regions(offset: usize, size: usize) -> Vec<(GuestAddress, usize)> {
56+
pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> {
6457
assert!(size > 0, "Attempt to allocate guest memory of length 0");
65-
assert!(
66-
offset.checked_add(size).is_some(),
67-
"Attempt to allocate guest memory such that the address space would wrap around"
68-
);
69-
assert!(
70-
offset < layout::DRAM_MEM_MAX_SIZE,
71-
"offset outside allowed DRAM range"
72-
);
7358

74-
let dram_size = min(size, layout::DRAM_MEM_MAX_SIZE - offset);
59+
let dram_size = min(size, layout::DRAM_MEM_MAX_SIZE);
7560

7661
if dram_size != size {
7762
logger::warn!(
78-
"Requested offset/memory size {}/{} exceeds architectural maximum (1022GiB). Size has \
79-
been truncated to {}",
80-
offset,
63+
"Requested memory size {} exceeds architectural maximum (1022GiB). Size has been \
64+
truncated to {}",
8165
size,
8266
dram_size
8367
);
8468
}
8569

86-
vec![(
87-
GuestAddress(layout::DRAM_MEM_START + offset as u64),
70+
let mut regions = vec![];
71+
if let Some((offset, remaining)) = arch_memory_regions_with_gap(
72+
&mut regions,
73+
u64_to_usize(layout::DRAM_MEM_START),
8874
dram_size,
89-
)]
75+
u64_to_usize(layout::MMIO64_MEM_START),
76+
u64_to_usize(layout::MMIO64_MEM_SIZE),
77+
) {
78+
regions.push((GuestAddress(offset as u64), remaining));
79+
}
80+
81+
regions
9082
}
9183

9284
/// Configures the system for booting Linux.
@@ -211,73 +203,109 @@ pub fn load_kernel(
211203

212204
#[cfg(kani)]
213205
mod verification {
214-
use vm_memory::GuestAddress;
215-
216-
use crate::arch::aarch64::layout;
206+
use crate::arch::aarch64::layout::{
207+
DRAM_MEM_MAX_SIZE, DRAM_MEM_START, FIRST_ADDR_PAST_64BITS_MMIO, MMIO64_MEM_START,
208+
};
217209
use crate::arch::arch_memory_regions;
218210

219211
#[kani::proof]
220212
#[kani::unwind(3)]
221213
fn verify_arch_memory_regions() {
222-
let offset: u64 = kani::any::<u64>();
223-
let len: u64 = kani::any::<u64>();
224-
214+
let len: usize = kani::any::<usize>();
225215
kani::assume(len > 0);
226-
kani::assume(offset.checked_add(len).is_some());
227-
kani::assume(offset < layout::DRAM_MEM_MAX_SIZE as u64);
228216

229-
let regions = arch_memory_regions(offset as usize, len as usize);
217+
let regions = arch_memory_regions(len);
230218

231-
// No MMIO gap on ARM
232-
assert_eq!(regions.len(), 1);
219+
for region in &regions {
220+
println!(
221+
"region: [{:x}:{:x})",
222+
region.0.0,
223+
region.0.0 + region.1 as u64
224+
);
225+
}
233226

234-
let (GuestAddress(start), actual_len) = regions[0];
235-
let actual_len = actual_len as u64;
227+
// On Arm we have one MMIO gap that might fall within addressable ranges,
228+
// so we can get either 1 or 2 regions.
229+
assert!(regions.len() >= 1);
230+
assert!(regions.len() <= 2);
236231

237-
assert_eq!(start, layout::DRAM_MEM_START + offset);
238-
assert!(actual_len <= layout::DRAM_MEM_MAX_SIZE as u64);
232+
// The total length of all regions cannot exceed DRAM_MEM_MAX_SIZE
233+
let actual_len = regions.iter().map(|&(_, len)| len).sum::<usize>();
234+
assert!(actual_len <= DRAM_MEM_MAX_SIZE);
235+
// The total length is smaller or equal to the length we asked
239236
assert!(actual_len <= len);
237+
// If it's smaller, it's because we asked more than the the maximum possible.
238+
if (actual_len) < len {
239+
assert!(len > DRAM_MEM_MAX_SIZE);
240+
}
240241

241-
if actual_len < len {
242-
assert_eq!(
243-
start + actual_len,
244-
layout::DRAM_MEM_START + layout::DRAM_MEM_MAX_SIZE as u64
245-
);
246-
assert!(offset + len >= layout::DRAM_MEM_MAX_SIZE as u64);
242+
// No region overlaps the 64-bit MMIO gap
243+
assert!(
244+
regions
245+
.iter()
246+
.all(|&(start, len)| start.0 >= FIRST_ADDR_PAST_64BITS_MMIO
247+
|| start.0 + len as u64 <= MMIO64_MEM_START)
248+
);
249+
250+
// All regions start after our DRAM_MEM_START
251+
assert!(regions.iter().all(|&(start, _)| start.0 >= DRAM_MEM_START));
252+
253+
// All regions have non-zero length
254+
assert!(regions.iter().all(|&(_, len)| len > 0));
255+
256+
// If there's two regions, they perfectly snuggle up the 64bit MMIO gap
257+
if regions.len() == 2 {
258+
kani::cover!();
259+
260+
// The very first address should be DRAM_MEM_START
261+
assert_eq!(regions[0].0.0, DRAM_MEM_START);
262+
// The first region ends at the beginning of the 64 bits gap.
263+
assert_eq!(regions[0].0.0 + regions[0].1 as u64, MMIO64_MEM_START);
264+
// The second region starts exactly after the 64 bits gap.
265+
assert_eq!(regions[1].0.0, FIRST_ADDR_PAST_64BITS_MMIO);
247266
}
248267
}
249268
}
250269

251270
#[cfg(test)]
252271
mod tests {
253272
use super::*;
273+
use crate::arch::aarch64::layout::{
274+
DRAM_MEM_MAX_SIZE, DRAM_MEM_START, FDT_MAX_SIZE, FIRST_ADDR_PAST_64BITS_MMIO,
275+
MMIO64_MEM_START,
276+
};
254277
use crate::test_utils::arch_mem;
255278

256279
#[test]
257280
fn test_regions_lt_1024gb() {
258-
let regions = arch_memory_regions(0, 1usize << 29);
281+
let regions = arch_memory_regions(1usize << 29);
259282
assert_eq!(1, regions.len());
260-
assert_eq!(GuestAddress(super::layout::DRAM_MEM_START), regions[0].0);
283+
assert_eq!(GuestAddress(DRAM_MEM_START), regions[0].0);
261284
assert_eq!(1usize << 29, regions[0].1);
262285
}
263286

264287
#[test]
265288
fn test_regions_gt_1024gb() {
266-
let regions = arch_memory_regions(0, 1usize << 41);
267-
assert_eq!(1, regions.len());
268-
assert_eq!(GuestAddress(super::layout::DRAM_MEM_START), regions[0].0);
269-
assert_eq!(super::layout::DRAM_MEM_MAX_SIZE, regions[0].1);
289+
let regions = arch_memory_regions(1usize << 41);
290+
assert_eq!(2, regions.len());
291+
assert_eq!(GuestAddress(DRAM_MEM_START), regions[0].0);
292+
assert_eq!(MMIO64_MEM_START - DRAM_MEM_START, regions[0].1 as u64);
293+
assert_eq!(GuestAddress(FIRST_ADDR_PAST_64BITS_MMIO), regions[1].0);
294+
assert_eq!(
295+
DRAM_MEM_MAX_SIZE as u64 - MMIO64_MEM_START + DRAM_MEM_START,
296+
regions[1].1 as u64
297+
);
270298
}
271299

272300
#[test]
273301
fn test_get_fdt_addr() {
274-
let mem = arch_mem(layout::FDT_MAX_SIZE - 0x1000);
275-
assert_eq!(get_fdt_addr(&mem), layout::DRAM_MEM_START);
302+
let mem = arch_mem(FDT_MAX_SIZE - 0x1000);
303+
assert_eq!(get_fdt_addr(&mem), DRAM_MEM_START);
276304

277-
let mem = arch_mem(layout::FDT_MAX_SIZE);
278-
assert_eq!(get_fdt_addr(&mem), layout::DRAM_MEM_START);
305+
let mem = arch_mem(FDT_MAX_SIZE);
306+
assert_eq!(get_fdt_addr(&mem), DRAM_MEM_START);
279307

280-
let mem = arch_mem(layout::FDT_MAX_SIZE + 0x1000);
281-
assert_eq!(get_fdt_addr(&mem), 0x1000 + layout::DRAM_MEM_START);
308+
let mem = arch_mem(FDT_MAX_SIZE + 0x1000);
309+
assert_eq!(get_fdt_addr(&mem), 0x1000 + DRAM_MEM_START);
282310
}
283311
}

0 commit comments

Comments
 (0)