Skip to content

Commit

Permalink
Merge pull request #527 from hermit-os/big_refactor
Browse files Browse the repository at this point in the history
Big refactor
  • Loading branch information
mkroening authored Apr 4, 2024
2 parents 63cd2fc + 3768b34 commit 403dcb5
Show file tree
Hide file tree
Showing 36 changed files with 1,590 additions and 1,537 deletions.
27 changes: 27 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 5 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ instrument = ["rftrace", "rftrace-frontend"]
[dependencies]
byte-unit = { version = "5", features = ["byte"] }
clap = { version = "4.5", features = ["derive", "env"] }
nix = { version = "0.28", features = ["mman", "pthread", "signal"] }
core_affinity = "0.8"
either = "1.10"
env_logger = "0.11"
Expand All @@ -51,20 +52,18 @@ hermit-entry = { version = "0.9", features = ["loader"] }
lazy_static = "1.4"
libc = "0.2"
log = "0.4"
mac_address = "1.1"
thiserror = "1.0"
time = "0.3"
uhyve-interface = { version = "0.1", path = "uhyve-interface" }

tun-tap = { version = "0.1.3", default-features = false }
uhyve-interface = { version = "0.1", path = "uhyve-interface", features = ["std"] }
virtio-bindings = { version = "0.2", features = ["virtio-v4_14_0"] }
rftrace = { version = "0.1", optional = true }
rftrace-frontend = { version = "0.1", optional = true }

[target.'cfg(target_os = "linux")'.dependencies]
kvm-bindings = "0.7"
kvm-ioctls = "0.16"
mac_address = "1.1"
nix = { version = "0.28", features = ["mman", "pthread", "signal"] }
tun-tap = { version = "0.1", default-features = false }
virtio-bindings = { version = "0.2", features = ["virtio-v4_14_0"] }
vmm-sys-util = "0.12"

[target.'cfg(target_os = "macos")'.dependencies]
Expand Down
12 changes: 7 additions & 5 deletions benches/vm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use byte_unit::Byte;
use criterion::{criterion_group, Criterion};
use uhyvelib::{params::Params, vm::Vm, Uhyve};
use uhyvelib::{
params::Params,
vm::{UhyveVm, VcpuDefault},
};

pub fn load_vm_hello_world(c: &mut Criterion) {
let path = [env!("CARGO_MANIFEST_DIR"), "benches_data/hello_world"]
Expand All @@ -10,12 +13,11 @@ pub fn load_vm_hello_world(c: &mut Criterion) {
memory_size: Byte::from_u64(1024 * 4096 * 500).try_into().unwrap(),
..Default::default()
};
let mut vm = Uhyve::new(path, params).expect("Unable to create VM");

let mut vm = UhyveVm::<VcpuDefault>::new(path, params).expect("Unable to create VM");

c.bench_function("vm::load_kernel(hello world)", |b| {
b.iter(|| unsafe {
vm.load_kernel().unwrap();
})
b.iter(|| vm.load_kernel().unwrap())
});
}

Expand Down
160 changes: 159 additions & 1 deletion src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use std::mem::size_of;

use bitflags::bitflags;
use uhyve_interface::{GuestPhysAddr, GuestVirtAddr};

use crate::{
consts::{BOOT_INFO_ADDR, BOOT_PGT},
mem::MmapMemory,
paging::PagetableError,
};

pub const RAM_START: u64 = 0x00;
pub const RAM_START: GuestPhysAddr = GuestPhysAddr::new(0x00);

pub const PT_DEVICE: u64 = 0x707;
pub const PT_PT: u64 = 0x713;
Expand All @@ -19,6 +28,16 @@ pub const MT_DEVICE_GRE: u64 = 2;
pub const MT_NORMAL_NC: u64 = 3;
pub const MT_NORMAL: u64 = 4;

/// Number of Offset bits of a virtual address for a 4 KiB page, which are shifted away to get its Page Frame Number (PFN).
const PAGE_BITS: usize = 12;
const PAGE_SIZE: usize = 1 << PAGE_BITS;

/// Number of bits of the index in each table (L0Table, L1Table, L2Table, L3Table).
const PAGE_MAP_BITS: usize = 9;

/// A mask where PAGE_MAP_BITS are set to calculate a table index.
const PAGE_MAP_MASK: u64 = 0x1FF;

#[inline(always)]
pub const fn mair(attr: u64, mt: u64) -> u64 {
attr << (mt * 8)
Expand Down Expand Up @@ -58,3 +77,142 @@ bitflags! {
const D_BIT = 0x00000200;
}
}

/// An entry in a L0 page table (coarses). Adapted from hermit-os/kernel.
#[derive(Clone, Copy, Debug)]
struct PageTableEntry {
/// Physical memory address this entry refers, combined with flags from PageTableEntryFlags.
physical_address_and_flags: GuestPhysAddr,
}

impl PageTableEntry {
/// Return the stored physical address.
pub fn address(&self) -> GuestPhysAddr {
// For other granules than 4KiB or hugepages we should check the DESCRIPTOR_TYPE bit and modify the address translation accordingly.
GuestPhysAddr(
self.physical_address_and_flags.as_u64() & !(PAGE_SIZE as u64 - 1) & !(u64::MAX << 48),
)
}
}
impl From<u64> for PageTableEntry {
fn from(i: u64) -> Self {
Self {
physical_address_and_flags: GuestPhysAddr::new(i),
}
}
}

/// Returns whether the given virtual address is a valid one in the AArch64 memory model.
///
/// Current AArch64 supports only 48-bit for virtual memory addresses.
/// The upper bits must always be 0 or 1 and indicate whether TBBR0 or TBBR1 contains the
/// base address. So always enforce 0 here.
fn is_valid_address(virtual_address: GuestVirtAddr) -> bool {
virtual_address < GuestVirtAddr(0x1_0000_0000_0000)
}

/// Converts a virtual address in the guest to a physical address in the guest
pub fn virt_to_phys(
addr: GuestVirtAddr,
mem: &MmapMemory,
pagetable_l0: GuestPhysAddr,
) -> Result<GuestPhysAddr, PagetableError> {
if !is_valid_address(addr) {
return Err(PagetableError::InvalidAddress);
}

// Assumptions:
// - We use 4KiB granule
// - We use maximum VA length
// => We have 4 level paging

// Safety:
// - We are only working in the vm's memory
// - the memory location of the pagetable is not altered by hermit.
// - Our indices can't be larger than 512, so we stay in the borders of the page.
// - We are page_aligned, and thus also PageTableEntry aligned.
let mut pagetable: &[PageTableEntry] =
unsafe { std::mem::transmute(mem.slice_at(pagetable_l0, PAGE_SIZE).unwrap()) };
// TODO: Depending on the virtual address length and granule (defined in TCR register by TG and TxSZ), we could reduce the number of pagetable walks. Hermit doesn't do this at the moment.
for level in 0..3 {
let table_index =
(addr.as_u64() >> PAGE_BITS >> ((3 - level) * PAGE_MAP_BITS) & PAGE_MAP_MASK) as usize;
let pte = PageTableEntry::from(pagetable[table_index]);
// TODO: We could stop here if we have a "Block Entry" (ARM equivalent to huge page). Currently not supported.

pagetable = unsafe { std::mem::transmute(mem.slice_at(pte.address(), PAGE_SIZE).unwrap()) };
}
let table_index = (addr.as_u64() >> PAGE_BITS & PAGE_MAP_MASK) as usize;
let pte = PageTableEntry::from(pagetable[table_index]);

Ok(pte.address())
}

pub fn init_guest_mem(mem: &mut [u8]) {
let mem_addr = std::ptr::addr_of_mut!(mem[0]);

assert!(mem.len() >= BOOT_PGT.as_u64() as usize + 512 * size_of::<u64>());
let pgt_slice = unsafe {
std::slice::from_raw_parts_mut(mem_addr.offset(BOOT_PGT.as_u64() as isize) as *mut u64, 512)
};
pgt_slice.fill(0);
pgt_slice[0] = BOOT_PGT.as_u64() + 0x1000 + PT_PT;
pgt_slice[511] = BOOT_PGT.as_u64() + PT_PT + PT_SELF;

assert!(mem.len() >= BOOT_PGT.as_u64() as usize + 0x1000 + 512 * size_of::<u64>());
let pgt_slice = unsafe {
std::slice::from_raw_parts_mut(
mem_addr.offset(BOOT_PGT.as_u64() as isize + 0x1000) as *mut u64,
512,
)
};
pgt_slice.fill(0);
pgt_slice[0] = BOOT_PGT.as_u64() + 0x2000 + PT_PT;

assert!(mem.len() >= BOOT_PGT.as_u64() as usize + 0x2000 + 512 * size_of::<u64>());
let pgt_slice = unsafe {
std::slice::from_raw_parts_mut(
mem_addr.offset(BOOT_PGT.as_u64() as isize + 0x2000) as *mut u64,
512,
)
};
pgt_slice.fill(0);
pgt_slice[0] = BOOT_PGT.as_u64() + 0x3000 + PT_PT;
pgt_slice[1] = BOOT_PGT.as_u64() + 0x4000 + PT_PT;
pgt_slice[2] = BOOT_PGT.as_u64() + 0x5000 + PT_PT;

assert!(mem.len() >= BOOT_PGT.as_u64() as usize + 0x3000 + 512 * size_of::<u64>());
let pgt_slice = unsafe {
std::slice::from_raw_parts_mut(
mem_addr.offset(BOOT_PGT.as_u64() as isize + 0x3000) as *mut u64,
512,
)
};
pgt_slice.fill(0);
// map uhyve ports into the virtual address space
pgt_slice[0] = PT_MEM_CD;
// map BootInfo into the virtual address space
pgt_slice[BOOT_INFO_ADDR.as_u64() as usize / PAGE_SIZE] = BOOT_INFO_ADDR.as_u64() + PT_MEM;

assert!(mem.len() >= BOOT_PGT.as_u64() as usize + 0x4000 + 512 * size_of::<u64>());
let pgt_slice = unsafe {
std::slice::from_raw_parts_mut(
mem_addr.offset(BOOT_PGT.as_u64() as isize + 0x4000) as *mut u64,
512,
)
};
for (idx, i) in pgt_slice.iter_mut().enumerate() {
*i = 0x200000u64 + (idx * PAGE_SIZE) as u64 + PT_MEM;
}

assert!(mem.len() >= BOOT_PGT.as_u64() as usize + 0x5000 + 512 * size_of::<u64>());
let pgt_slice = unsafe {
std::slice::from_raw_parts_mut(
mem_addr.offset(BOOT_PGT.as_u64() as isize + 0x5000) as *mut u64,
512,
)
};
for (idx, i) in pgt_slice.iter_mut().enumerate() {
*i = 0x400000u64 + (idx * PAGE_SIZE) as u64 + PT_MEM;
}
}
Loading

0 comments on commit 403dcb5

Please sign in to comment.