Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Big refactor #527

Merged
merged 29 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
481914f
Use Guest[Virt|Phys]Addr in uhyve
jounathaen Jun 2, 2023
6c76d43
Renamed UhyveCPU to KvmCpu & XhyveCpu in respective module
jounathaen Jun 5, 2023
bedf10d
Put the virtual CPU trait in a separate module
jounathaen Jun 5, 2023
745cac2
Created Vm_Guest_Memory trait and changed MmapMemory accordingly
jounathaen Jun 7, 2023
c15979e
moved the remaining KVM functionality from linux/uhyve to linux/x86_6…
jounathaen Jun 7, 2023
993126a
Made mmap generic to unix and use it on macos as well
jounathaen Jun 8, 2023
0e7955d
Moved the ioapic for macos to the vcpu section
jounathaen Jun 8, 2023
386339d
Move virtio and virtqueue out of linux, since there seems to be macos…
jounathaen Jun 8, 2023
69c1427
Made the ioapic a static mutex
jounathaen Jun 12, 2023
a1f423c
Merged Linux and Macos Uhyve into UhyveVM struct and removed VM trait
jounathaen Jun 12, 2023
0b2d133
made load_kernel a safe fn and removed the guest_mem() call from it
jounathaen Jun 15, 2023
4d6cdbd
Moved pagetable initialization to arch module and removed obsolete Vm…
jounathaen Jun 15, 2023
682616c
Improved MmapMemory
jounathaen Jun 15, 2023
5475d85
Added virt_to_phys fn to x86
jounathaen Jun 22, 2023
2ab958c
Minor fomatting fixes
jounathaen Jun 22, 2023
fe19fc4
Redesigned VM<->VCpu interaction:
jounathaen Jun 26, 2023
f20f0fe
Moved hypercall related stuff in separate module or the uhyve interfa…
jounathaen Jun 26, 2023
612fdcc
Removed unnecessary setter fn
jounathaen Jun 27, 2023
8026009
Check if GDB memory read is a valid virtual address
jounathaen Jan 29, 2024
06beb56
Fixed Error handling: Panic in hypercall handler caused remaining thr…
jounathaen Jan 30, 2024
1ad977d
Fixed incorrect type of the data buffers in the two file system hyper…
jounathaen Jan 31, 2024
0338c81
Renamed MIN_PAGING_MEM_SIZE to MIN_PHYSMEM_SIZE
jounathaen Mar 12, 2024
dfe54a0
moved generalized init_guest_mem to crate::arch
jounathaen Mar 12, 2024
c2c3e6b
Moved some paging stuff (error) into non-arch module
jounathaen Mar 12, 2024
1d607d8
Use GuestPhysAddr and GuestVirtAddr everywhere, also on aarch64
jounathaen Mar 12, 2024
df5526c
Adapted macos to new UhveVm<VCpuType> architecture
jounathaen Mar 12, 2024
422e16e
Added virt_to_phys fn for aarch64
jounathaen Mar 12, 2024
f4426fd
changed the pagetable location to be a parameter of fn virt_to_phys
jounathaen Mar 12, 2024
3768b34
Untested add of the file hypercall functions
jounathaen Mar 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
jounathaen marked this conversation as resolved.
Show resolved Hide resolved
thiserror = "1.0"
time = "0.3"
uhyve-interface = { version = "0.1", path = "uhyve-interface" }

tun-tap = { version = "0.1.3", default-features = false }
jounathaen marked this conversation as resolved.
Show resolved Hide resolved
uhyve-interface = { version = "0.1", path = "uhyve-interface", features = ["std"] }
virtio-bindings = { version = "0.2", features = ["virtio-v4_14_0"] }
jounathaen marked this conversation as resolved.
Show resolved Hide resolved
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