Skip to content

Commit c2a4797

Browse files
committed
WIP: kani proofs
Signed-off-by: Babis Chalios <[email protected]>
1 parent d1fda34 commit c2a4797

File tree

5 files changed

+41
-57
lines changed

5 files changed

+41
-57
lines changed

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

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,26 +53,15 @@ pub enum ConfigurationError {
5353

5454
/// Returns a Vec of the valid memory addresses for aarch64.
5555
/// See [`layout`](layout) module for a drawing of the specific memory model for this platform.
56-
///
57-
/// The `offset` parameter specified the offset from [`layout::DRAM_MEM_START`].
58-
pub fn arch_memory_regions(offset: usize, size: usize) -> Vec<(GuestAddress, usize)> {
56+
pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> {
5957
assert!(size > 0, "Attempt to allocate guest memory of length 0");
60-
assert!(
61-
offset.checked_add(size).is_some(),
62-
"Attempt to allocate guest memory such that the address space would wrap around"
63-
);
64-
assert!(
65-
offset < layout::DRAM_MEM_MAX_SIZE,
66-
"offset outside allowed DRAM range"
67-
);
6858

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

7161
if dram_size != size {
7262
logger::warn!(
73-
"Requested offset/memory size {}/{} exceeds architectural maximum (1022GiB). Size has \
63+
"Requested offset/memory size {} exceeds architectural maximum (1022GiB). Size has \
7464
been truncated to {}",
75-
offset,
7665
size,
7766
dram_size
7867
);
@@ -81,7 +70,7 @@ pub fn arch_memory_regions(offset: usize, size: usize) -> Vec<(GuestAddress, usi
8170
let mut regions = vec![];
8271
if let Some((offset, remaining)) = arch_memory_regions_with_gap(
8372
&mut regions,
84-
u64_to_usize(layout::DRAM_MEM_START) + offset,
73+
u64_to_usize(layout::DRAM_MEM_START),
8574
dram_size,
8675
u64_to_usize(layout::MMIO64_MEM_START),
8776
u64_to_usize(layout::MMIO64_MEM_SIZE),
@@ -293,15 +282,15 @@ mod tests {
293282

294283
#[test]
295284
fn test_regions_lt_1024gb() {
296-
let regions = arch_memory_regions(0, 1usize << 29);
285+
let regions = arch_memory_regions(1usize << 29);
297286
assert_eq!(1, regions.len());
298287
assert_eq!(GuestAddress(DRAM_MEM_START), regions[0].0);
299288
assert_eq!(1usize << 29, regions[0].1);
300289
}
301290

302291
#[test]
303292
fn test_regions_gt_1024gb() {
304-
let regions = arch_memory_regions(0, 1usize << 41);
293+
let regions = arch_memory_regions(1usize << 41);
305294
assert_eq!(2, regions.len());
306295
assert_eq!(GuestAddress(DRAM_MEM_START), regions[0].0);
307296
assert_eq!(MMIO64_MEM_START - DRAM_MEM_START, regions[0].1 as u64);

src/vmm/src/arch/x86_64/layout.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
1010
use crate::utils::mib_to_bytes;
1111

12+
/// Maximum physical memory address space.
13+
///
14+
/// Typically, x86_64 architecture supports up to 48 bits of physical addresses.
15+
/// This space includes the MMIO addresses.
16+
pub const MAX_PHYSICAL_ADDRESS_SPACE: usize = 1usize << 48;
17+
1218
/// Initial stack for the boot CPU.
1319
pub const BOOT_STACK_POINTER: u64 = 0x8ff0;
1420

src/vmm/src/arch/x86_64/mod.rs

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ pub mod generated;
3434
use std::fs::File;
3535

3636
use layout::{
37-
CMDLINE_START, FIRST_ADDR_PAST_32BITS, FIRST_ADDR_PAST_64BITS_MMIO, MMIO32_MEM_SIZE,
38-
MMIO32_MEM_START, MMIO64_MEM_SIZE, MMIO64_MEM_START,
37+
CMDLINE_START, FIRST_ADDR_PAST_32BITS, FIRST_ADDR_PAST_64BITS_MMIO, MAX_PHYSICAL_ADDRESS_SPACE,
38+
MMIO32_MEM_SIZE, MMIO32_MEM_START, MMIO64_MEM_SIZE, MMIO64_MEM_START,
3939
};
4040
use linux_loader::configurator::linux::LinuxBootConfigurator;
4141
use linux_loader::configurator::pvh::PvhBootConfigurator;
@@ -101,22 +101,25 @@ pub enum ConfigurationError {
101101

102102
/// Returns a Vec of the valid memory addresses.
103103
/// These should be used to configure the GuestMemoryMmap structure for the platform.
104-
/// For x86_64 all addresses are valid from the start of the kernel except a
105-
/// carve out at the end of 32bit address space.
106-
pub fn arch_memory_regions(offset: usize, size: usize) -> Vec<(GuestAddress, usize)> {
104+
/// For x86_64 all addresses are valid from the start of the kernel except an 1GB
105+
/// carve out at the end of 32bit address space and a second 256GB one at the 256GB limit.
106+
pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> {
107107
// If we get here with size == 0 something has seriously gone wrong. Firecracker should never
108108
// try to allocate guest memory of size 0
109109
assert!(size > 0, "Attempt to allocate guest memory of length 0");
110+
// The resulting address space must fit in 48 bits.
110111
assert!(
111-
offset.checked_add(size).is_some(),
112-
"Attempt to allocate guest memory such that the address space would wrap around"
112+
size <= MAX_PHYSICAL_ADDRESS_SPACE
113+
- u64_to_usize(MMIO32_MEM_SIZE)
114+
- u64_to_usize(MMIO64_MEM_SIZE),
115+
"Memory size would result in an address space that exceeds 48 bits."
113116
);
114117

115118
let mut regions = vec![];
116119

117120
if let Some((start_past_32bit_gap, remaining_past_32bit_gap)) = arch_memory_regions_with_gap(
118121
&mut regions,
119-
offset,
122+
0,
120123
size,
121124
u64_to_usize(MMIO32_MEM_START),
122125
u64_to_usize(MMIO32_MEM_SIZE),
@@ -471,26 +474,33 @@ pub fn load_kernel(
471474

472475
#[cfg(kani)]
473476
mod verification {
477+
474478
use crate::arch::arch_memory_regions;
475479
use crate::arch::x86_64::layout::{
476-
FIRST_ADDR_PAST_32BITS, FIRST_ADDR_PAST_64BITS_MMIO, MMIO32_MEM_START, MMIO64_MEM_START,
480+
FIRST_ADDR_PAST_32BITS, FIRST_ADDR_PAST_64BITS_MMIO, MAX_PHYSICAL_ADDRESS_SPACE,
481+
MMIO32_MEM_SIZE, MMIO32_MEM_START, MMIO64_MEM_SIZE, MMIO64_MEM_START,
477482
};
483+
use crate::utils::usize_to_u64;
478484

479485
#[kani::proof]
480486
#[kani::unwind(4)]
481487
fn verify_arch_memory_regions() {
482-
let offset: u64 = kani::any::<u64>();
483488
let len: u64 = kani::any::<u64>();
484489

485490
kani::assume(len > 0);
486-
kani::assume(offset.checked_add(len).is_some());
491+
kani::assume(
492+
len <= usize_to_u64(MAX_PHYSICAL_ADDRESS_SPACE) - MMIO32_MEM_SIZE - MMIO64_MEM_SIZE,
493+
);
487494

488-
let regions = arch_memory_regions(offset as usize, len as usize);
495+
let regions = arch_memory_regions(len as usize);
489496

490497
// There are two MMIO gaps, so we can get either 1, 2 or 3 regions
491498
assert!(regions.len() <= 3);
492499
assert!(regions.len() >= 1);
493500

501+
// The first address is always 0
502+
assert_eq!(regions[0].0.0, 0);
503+
494504
// The total length of all regions is what we requested
495505
assert_eq!(
496506
regions.iter().map(|&(_, len)| len).sum::<usize>(),
@@ -507,23 +517,15 @@ mod verification {
507517
|| start.0 + len as u64 <= MMIO64_MEM_START))
508518
);
509519

510-
// All regions start after our specified offset
511-
assert!(regions.iter().all(|&(start, _)| start.0 >= offset as u64));
512-
513520
// All regions have non-zero length
514521
assert!(regions.iter().all(|&(_, len)| len > 0));
515522

516523
// If there's at least two regions, they perfectly snuggle up to one of the two MMIO gaps
517524
if regions.len() >= 2 {
518525
kani::cover!();
519526

520-
if offset < MMIO32_MEM_START {
521-
assert_eq!(regions[0].0.0 + regions[0].1 as u64, MMIO32_MEM_START);
522-
assert_eq!(regions[1].0.0, FIRST_ADDR_PAST_32BITS);
523-
} else {
524-
assert_eq!(regions[0].0.0 + regions[0].1 as u64, MMIO64_MEM_START);
525-
assert_eq!(regions[1].0.0, FIRST_ADDR_PAST_64BITS_MMIO);
526-
}
527+
assert_eq!(regions[0].0.0 + regions[0].1 as u64, MMIO32_MEM_START);
528+
assert_eq!(regions[1].0.0, FIRST_ADDR_PAST_32BITS);
527529
}
528530

529531
// If there are three regions, the last two perfectly snuggle up to the 64bit
@@ -548,34 +550,21 @@ mod tests {
548550

549551
#[test]
550552
fn regions_lt_4gb() {
551-
let regions = arch_memory_regions(0, 1usize << 29);
553+
let regions = arch_memory_regions(1usize << 29);
552554
assert_eq!(1, regions.len());
553555
assert_eq!(GuestAddress(0), regions[0].0);
554556
assert_eq!(1usize << 29, regions[0].1);
555-
556-
let regions = arch_memory_regions(1 << 28, 1 << 29);
557-
assert_eq!(1, regions.len());
558-
assert_eq!(regions[0], (GuestAddress(1 << 28), 1 << 29));
559557
}
560558

561559
#[test]
562560
fn regions_gt_4gb() {
563561
const MEMORY_SIZE: usize = (1 << 32) + 0x8000;
564562

565-
let regions = arch_memory_regions(0, MEMORY_SIZE);
563+
let regions = arch_memory_regions(MEMORY_SIZE);
566564
assert_eq!(2, regions.len());
567565
assert_eq!(GuestAddress(0), regions[0].0);
568566
assert_eq!(GuestAddress(1u64 << 32), regions[1].0);
569567

570-
let regions = arch_memory_regions(1 << 31, MEMORY_SIZE);
571-
assert_eq!(2, regions.len());
572-
assert_eq!(
573-
regions[0],
574-
(
575-
GuestAddress(1 << 31),
576-
u64_to_usize(MMIO32_MEM_START) - (1 << 31)
577-
)
578-
);
579568
assert_eq!(
580569
regions[1],
581570
(

src/vmm/src/resources.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ impl VmResources {
474474
// a single way of backing guest memory for vhost-user and non-vhost-user cases,
475475
// that would not be worth the effort.
476476
let regions =
477-
crate::arch::arch_memory_regions(0, mib_to_bytes(self.machine_config.mem_size_mib));
477+
crate::arch::arch_memory_regions(mib_to_bytes(self.machine_config.mem_size_mib));
478478
if vhost_user_device_used {
479479
memory::memfd_backed(
480480
regions.as_ref(),

src/vmm/src/test_utils/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ pub fn multi_region_mem_raw(regions: &[(GuestAddress, usize)]) -> Vec<GuestRegio
5858
/// Creates a [`GuestMemoryMmap`] of the given size with the contained regions laid out in
5959
/// accordance with the requirements of the architecture on which the tests are being run.
6060
pub fn arch_mem(mem_size_bytes: usize) -> GuestMemoryMmap {
61-
multi_region_mem(&crate::arch::arch_memory_regions(0, mem_size_bytes))
61+
multi_region_mem(&crate::arch::arch_memory_regions(mem_size_bytes))
6262
}
6363

6464
pub fn arch_mem_raw(mem_size_bytes: usize) -> Vec<GuestRegionMmap> {
65-
multi_region_mem_raw(&crate::arch::arch_memory_regions(0, mem_size_bytes))
65+
multi_region_mem_raw(&crate::arch::arch_memory_regions(mem_size_bytes))
6666
}
6767

6868
pub fn create_vmm(

0 commit comments

Comments
 (0)