#![no_std]
extern crate alloc;
use core::fmt::Write;
use arch::dispatch::dispatch_function;
use buddy_system_allocator::LockedHeap;
use guest_function::register::GuestFunctionRegister;
use guest_logger::init_logger;
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
use hyperlight_common::log_level::GuestLogFilter;
use hyperlight_common::mem::HyperlightPEB;
#[cfg(feature = "mem_profile")]
use hyperlight_common::outb::OutBAction;
use hyperlight_guest::exit::write_abort;
use hyperlight_guest::guest_handle::handle::GuestHandle;
#[cfg_attr(target_arch = "x86_64", path = "arch/amd64/mod.rs")]
mod arch;
#[cfg(target_arch = "x86_64")]
pub mod exception;
pub mod guest_function {
pub(super) mod call;
pub mod definition;
pub mod register;
}
pub mod guest_logger;
pub mod host_comm;
pub mod memory;
pub mod paging;
#[cfg(feature = "mem_profile")]
struct ProfiledLockedHeap<const ORDER: usize>(LockedHeap<ORDER>);
#[cfg(feature = "mem_profile")]
unsafe impl<const ORDER: usize> alloc::alloc::GlobalAlloc for ProfiledLockedHeap<ORDER> {
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
let addr = unsafe { self.0.alloc(layout) };
unsafe {
core::arch::asm!("out dx, al",
in("dx") OutBAction::TraceMemoryAlloc as u16,
in("rax") layout.size() as u64,
in("rcx") addr as u64);
}
addr
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
unsafe {
core::arch::asm!("out dx, al",
in("dx") OutBAction::TraceMemoryFree as u16,
in("rax") layout.size() as u64,
in("rcx") ptr as u64);
self.0.dealloc(ptr, layout)
}
}
unsafe fn alloc_zeroed(&self, layout: core::alloc::Layout) -> *mut u8 {
let addr = unsafe { self.0.alloc_zeroed(layout) };
unsafe {
core::arch::asm!("out dx, al",
in("dx") OutBAction::TraceMemoryAlloc as u16,
in("rax") layout.size() as u64,
in("rcx") addr as u64);
}
addr
}
unsafe fn realloc(
&self,
ptr: *mut u8,
layout: core::alloc::Layout,
new_size: usize,
) -> *mut u8 {
let new_ptr = unsafe { self.0.realloc(ptr, layout, new_size) };
unsafe {
core::arch::asm!("out dx, al",
in("dx") OutBAction::TraceMemoryFree as u16,
in("rax") layout.size() as u64,
in("rcx") ptr);
core::arch::asm!("out dx, al",
in("dx") OutBAction::TraceMemoryAlloc as u16,
in("rax") new_size as u64,
in("rcx") new_ptr);
}
new_ptr
}
}
#[cfg(not(feature = "mem_profile"))]
#[global_allocator]
pub(crate) static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::empty();
#[cfg(feature = "mem_profile")]
#[global_allocator]
pub(crate) static HEAP_ALLOCATOR: ProfiledLockedHeap<32> =
ProfiledLockedHeap(LockedHeap::<32>::empty());
pub static mut GUEST_HANDLE: GuestHandle = GuestHandle::new();
pub(crate) static mut REGISTERED_GUEST_FUNCTIONS: GuestFunctionRegister<GuestFunc> =
GuestFunctionRegister::new();
pub static mut OS_PAGE_SIZE: u32 = 0;
#[cfg_attr(not(test), panic_handler)]
#[allow(clippy::panic)]
#[allow(dead_code)]
fn panic(info: &core::panic::PanicInfo) -> ! {
_panic_handler(info)
}
struct HyperlightAbortWriter;
impl core::fmt::Write for HyperlightAbortWriter {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
write_abort(s.as_bytes());
Ok(())
}
}
#[inline(always)]
fn _panic_handler(info: &core::panic::PanicInfo) -> ! {
let mut w = HyperlightAbortWriter;
write_abort(&[ErrorCode::UnknownError as u8]);
let write_res = write!(w, "{}", info);
if write_res.is_err() {
write_abort("panic: message format failed".as_bytes());
}
write_abort(&[0xFF]);
unreachable!();
}
unsafe extern "C" {
fn hyperlight_main();
fn srand(seed: u32);
}
pub(crate) extern "C" fn generic_init(
peb_address: u64,
seed: u64,
ops: u64,
max_log_level: u64,
) -> u64 {
unsafe {
GUEST_HANDLE = GuestHandle::init(peb_address as *mut HyperlightPEB);
#[allow(static_mut_refs)]
let peb_ptr = GUEST_HANDLE.peb().unwrap();
let heap_start = (*peb_ptr).guest_heap.ptr as usize;
let heap_size = (*peb_ptr).guest_heap.size as usize;
#[cfg(not(feature = "mem_profile"))]
let heap_allocator = &HEAP_ALLOCATOR;
#[cfg(feature = "mem_profile")]
let heap_allocator = &HEAP_ALLOCATOR.0;
heap_allocator
.try_lock()
.expect("Failed to access HEAP_ALLOCATOR")
.init(heap_start, heap_size);
peb_ptr
};
#[cfg(feature = "trace_guest")]
let guest_start_tsc = hyperlight_guest_tracing::invariant_tsc::read_tsc();
unsafe {
let srand_seed = (((peb_address << 8) ^ (seed >> 4)) >> 32) as u32;
srand(srand_seed);
OS_PAGE_SIZE = ops as u32;
}
let guest_log_level_filter =
GuestLogFilter::try_from(max_log_level).expect("Invalid log level");
init_logger(guest_log_level_filter.into());
#[cfg(feature = "trace_guest")]
if guest_log_level_filter != GuestLogFilter::Off {
hyperlight_guest_tracing::init_guest_tracing(
guest_start_tsc,
guest_log_level_filter.into(),
);
}
#[cfg(all(feature = "trace_guest", target_arch = "x86_64"))]
let _entered = tracing::span!(tracing::Level::INFO, "generic_init").entered();
#[cfg(feature = "macros")]
for registration in __private::GUEST_FUNCTION_INIT {
registration();
}
unsafe {
hyperlight_main();
}
#[cfg(all(feature = "trace_guest", target_arch = "x86_64"))]
{
_entered.exit();
hyperlight_guest_tracing::flush();
}
dispatch_function as usize as u64
}
#[cfg(feature = "macros")]
#[doc(hidden)]
pub mod __private {
pub use hyperlight_common::func::ResultType;
pub use hyperlight_guest::error::HyperlightGuestError;
pub use linkme;
#[linkme::distributed_slice]
pub static GUEST_FUNCTION_INIT: [fn()];
pub trait FromResult {
type Output;
fn from_result(res: Result<Self::Output, HyperlightGuestError>) -> Self;
}
use alloc::string::String;
use alloc::vec::Vec;
use hyperlight_common::for_each_return_type;
macro_rules! impl_maybe_unwrap {
($ty:ty, $enum:ident) => {
impl FromResult for $ty {
type Output = Self;
fn from_result(res: Result<Self::Output, HyperlightGuestError>) -> Self {
res.unwrap()
}
}
impl FromResult for Result<$ty, HyperlightGuestError> {
type Output = $ty;
fn from_result(res: Result<Self::Output, HyperlightGuestError>) -> Self {
res
}
}
};
}
for_each_return_type!(impl_maybe_unwrap);
}
#[cfg(feature = "macros")]
pub use hyperlight_guest_macro::{guest_function, host_function};
pub use crate::guest_function::definition::GuestFunc;