hyperlight_guest_bin/
lib.rs1#![no_std]
17
18extern crate alloc;
20
21use core::fmt::Write;
22
23use buddy_system_allocator::LockedHeap;
24#[cfg(target_arch = "x86_64")]
25use exceptions::{gdt::load_gdt, idtr::load_idt};
26use guest_function::call::dispatch_function;
27use guest_function::register::GuestFunctionRegister;
28use guest_logger::init_logger;
29use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
30use hyperlight_common::mem::HyperlightPEB;
31#[cfg(feature = "mem_profile")]
32use hyperlight_common::outb::OutBAction;
33use hyperlight_guest::exit::{halt, write_abort};
34use hyperlight_guest::guest_handle::handle::GuestHandle;
35use log::LevelFilter;
36use spin::Once;
37
38#[cfg(target_arch = "x86_64")]
40pub mod exceptions {
41 pub(super) mod gdt;
42 pub mod handler;
43 mod idt;
44 pub(super) mod idtr;
45 mod interrupt_entry;
46}
47pub mod guest_function {
48 pub(super) mod call;
49 pub mod definition;
50 pub mod register;
51}
52
53pub mod guest_logger;
54pub mod host_comm;
55pub mod memory;
56pub mod paging;
57
58#[cfg(feature = "mem_profile")]
60struct ProfiledLockedHeap<const ORDER: usize>(LockedHeap<ORDER>);
61#[cfg(feature = "mem_profile")]
62unsafe impl<const ORDER: usize> alloc::alloc::GlobalAlloc for ProfiledLockedHeap<ORDER> {
63 unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
64 let addr = unsafe { self.0.alloc(layout) };
65 unsafe {
66 core::arch::asm!("out dx, al",
67 in("dx") OutBAction::TraceMemoryAlloc as u16,
68 in("rax") layout.size() as u64,
69 in("rcx") addr as u64);
70 }
71 addr
72 }
73 unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
74 unsafe {
75 core::arch::asm!("out dx, al",
76 in("dx") OutBAction::TraceMemoryFree as u16,
77 in("rax") layout.size() as u64,
78 in("rcx") ptr as u64);
79 self.0.dealloc(ptr, layout)
80 }
81 }
82 unsafe fn alloc_zeroed(&self, layout: core::alloc::Layout) -> *mut u8 {
83 let addr = unsafe { self.0.alloc_zeroed(layout) };
84 unsafe {
85 core::arch::asm!("out dx, al",
86 in("dx") OutBAction::TraceMemoryAlloc as u16,
87 in("rax") layout.size() as u64,
88 in("rcx") addr as u64);
89 }
90 addr
91 }
92 unsafe fn realloc(
93 &self,
94 ptr: *mut u8,
95 layout: core::alloc::Layout,
96 new_size: usize,
97 ) -> *mut u8 {
98 let new_ptr = unsafe { self.0.realloc(ptr, layout, new_size) };
99 unsafe {
100 core::arch::asm!("out dx, al",
101 in("dx") OutBAction::TraceMemoryFree as u16,
102 in("rax") layout.size() as u64,
103 in("rcx") ptr);
104 core::arch::asm!("out dx, al",
105 in("dx") OutBAction::TraceMemoryAlloc as u16,
106 in("rax") new_size as u64,
107 in("rcx") new_ptr);
108 }
109 new_ptr
110 }
111}
112
113#[cfg(not(feature = "mem_profile"))]
115#[global_allocator]
116pub(crate) static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::empty();
117#[cfg(feature = "mem_profile")]
118#[global_allocator]
119pub(crate) static HEAP_ALLOCATOR: ProfiledLockedHeap<32> =
120 ProfiledLockedHeap(LockedHeap::<32>::empty());
121
122pub static mut GUEST_HANDLE: GuestHandle = GuestHandle::new();
123pub(crate) static mut REGISTERED_GUEST_FUNCTIONS: GuestFunctionRegister =
124 GuestFunctionRegister::new();
125
126pub static mut MIN_STACK_ADDRESS: u64 = 0;
127
128pub static mut OS_PAGE_SIZE: u32 = 0;
129
130#[cfg_attr(not(test), panic_handler)]
136#[allow(clippy::panic)]
137#[allow(dead_code)]
139fn panic(info: &core::panic::PanicInfo) -> ! {
140 _panic_handler(info)
141}
142
143struct HyperlightAbortWriter;
148impl core::fmt::Write for HyperlightAbortWriter {
149 fn write_str(&mut self, s: &str) -> core::fmt::Result {
150 write_abort(s.as_bytes());
151 Ok(())
152 }
153}
154
155#[inline(always)]
156fn _panic_handler(info: &core::panic::PanicInfo) -> ! {
157 let mut w = HyperlightAbortWriter;
158
159 write_abort(&[ErrorCode::UnknownError as u8]);
161
162 let write_res = write!(w, "{}", info);
163 if write_res.is_err() {
164 write_abort("panic: message format failed".as_bytes());
165 }
166
167 write_abort(&[0xFF]);
170 unreachable!();
171}
172
173unsafe extern "C" {
176 fn hyperlight_main();
177 fn srand(seed: u32);
178}
179
180static INIT: Once = Once::new();
181
182#[unsafe(no_mangle)]
183pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_level: u64) {
184 #[cfg(feature = "trace_guest")]
186 let guest_start_tsc = hyperlight_guest_tracing::invariant_tsc::read_tsc();
187
188 if peb_address == 0 {
189 panic!("PEB address is null");
190 }
191
192 INIT.call_once(|| {
193 unsafe {
194 GUEST_HANDLE = GuestHandle::init(peb_address as *mut HyperlightPEB);
195 #[allow(static_mut_refs)]
196 let peb_ptr = GUEST_HANDLE.peb().unwrap();
197
198 let srand_seed = (((peb_address << 8) ^ (seed >> 4)) >> 32) as u32;
199
200 srand(srand_seed);
202
203 MIN_STACK_ADDRESS = (*peb_ptr).guest_stack.min_user_stack_address;
207
208 #[cfg(target_arch = "x86_64")]
209 {
210 load_gdt();
212 load_idt();
213 }
214
215 let heap_start = (*peb_ptr).guest_heap.ptr as usize;
216 let heap_size = (*peb_ptr).guest_heap.size as usize;
217 #[cfg(not(feature = "mem_profile"))]
218 let heap_allocator = &HEAP_ALLOCATOR;
219 #[cfg(feature = "mem_profile")]
220 let heap_allocator = &HEAP_ALLOCATOR.0;
221 heap_allocator
222 .try_lock()
223 .expect("Failed to access HEAP_ALLOCATOR")
224 .init(heap_start, heap_size);
225
226 OS_PAGE_SIZE = ops as u32;
227
228 (*peb_ptr).guest_function_dispatch_ptr = dispatch_function as usize as u64;
229
230 let max_log_level = LevelFilter::iter()
232 .nth(max_log_level as usize)
233 .expect("Invalid log level");
234 init_logger(max_log_level);
235
236 #[cfg(feature = "trace_guest")]
238 if max_log_level != LevelFilter::Off {
239 hyperlight_guest_tracing::init_guest_tracing(guest_start_tsc);
240 }
241
242 #[cfg(feature = "macros")]
243 for registration in __private::GUEST_FUNCTION_INIT {
244 registration();
245 }
246
247 hyperlight_main();
248 }
249 });
250
251 halt();
252}
253
254#[cfg(feature = "macros")]
255#[doc(hidden)]
256pub mod __private {
257 pub use hyperlight_common::func::ResultType;
258 pub use hyperlight_guest::error::HyperlightGuestError;
259 pub use linkme;
260
261 #[linkme::distributed_slice]
262 pub static GUEST_FUNCTION_INIT: [fn()];
263
264 pub trait FromResult {
265 type Output;
266 fn from_result(res: Result<Self::Output, HyperlightGuestError>) -> Self;
267 }
268
269 use alloc::string::String;
270 use alloc::vec::Vec;
271
272 use hyperlight_common::for_each_return_type;
273
274 macro_rules! impl_maybe_unwrap {
275 ($ty:ty, $enum:ident) => {
276 impl FromResult for $ty {
277 type Output = Self;
278 fn from_result(res: Result<Self::Output, HyperlightGuestError>) -> Self {
279 res.unwrap()
282 }
283 }
284
285 impl FromResult for Result<$ty, HyperlightGuestError> {
286 type Output = $ty;
287 fn from_result(res: Result<Self::Output, HyperlightGuestError>) -> Self {
288 res
289 }
290 }
291 };
292 }
293
294 for_each_return_type!(impl_maybe_unwrap);
295}
296
297#[cfg(feature = "macros")]
298pub use hyperlight_guest_macro::{guest_function, host_function};