Skip to content

Commit ad4b41c

Browse files
committed
Merge branch 'main' into vm_trait
2 parents 300d071 + 23dcf47 commit ad4b41c

File tree

17 files changed

+244
-180
lines changed

17 files changed

+244
-180
lines changed

Justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ test-like-ci config=default-target hypervisor="kvm":
6262
just test {{config}} {{ if hypervisor == "mshv3" {"mshv3"} else {""} }}
6363

6464
@# with only one driver enabled + seccomp
65-
just test {{config}} seccomp,{{ if hypervisor == "mshv" {"mshv2"} else if hypervisor == "mshv3" {"mshv3"} else {"kvm"} }}
65+
just test {{config}} seccomp,build-metadata,{{ if hypervisor == "mshv" {"mshv2"} else if hypervisor == "mshv3" {"mshv3"} else {"kvm"} }}
6666

6767
@# make sure certain cargo features compile
6868
cargo check -p hyperlight-host --features crashdump

src/hyperlight_common/src/mem.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,6 @@ pub const PAGE_SIZE_USIZE: usize = 1 << 12;
2222

2323
use core::ffi::{c_char, c_void};
2424

25-
#[repr(C)]
26-
pub struct HostFunctionDefinitions {
27-
pub fbHostFunctionDetailsSize: u64,
28-
pub fbHostFunctionDetails: *mut c_void,
29-
}
30-
31-
#[repr(C)]
32-
pub struct GuestErrorData {
33-
pub guestErrorSize: u64,
34-
pub guestErrorBuffer: *mut c_void,
35-
}
36-
3725
#[repr(u64)]
3826
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3927
pub enum RunMode {

src/hyperlight_guest/src/entrypoint.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use spin::Once;
2525
use crate::gdt::load_gdt;
2626
use crate::guest_function_call::dispatch_function;
2727
use crate::guest_logger::init_logger;
28-
use crate::host_function_call::{debug_print, outb};
28+
use crate::host_function_call::outb;
2929
use crate::idtr::load_idt;
3030
use crate::{
3131
__security_cookie, HEAP_ALLOCATOR, MIN_STACK_ADDRESS, OS_PAGE_SIZE, OUTB_PTR,
@@ -43,11 +43,12 @@ pub fn halt() {
4343

4444
#[no_mangle]
4545
pub extern "C" fn abort() -> ! {
46-
abort_with_code(&[0])
46+
abort_with_code(&[0, 0xFF])
4747
}
4848

4949
pub fn abort_with_code(code: &[u8]) -> ! {
5050
outb(OutBAction::Abort as u16, code);
51+
outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code)
5152
unreachable!()
5253
}
5354

@@ -56,13 +57,19 @@ pub fn abort_with_code(code: &[u8]) -> ! {
5657
/// # Safety
5758
/// This function is unsafe because it dereferences a raw pointer.
5859
pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! {
59-
debug_print(
60-
CStr::from_ptr(message_ptr)
61-
.to_str()
62-
.expect("Invalid UTF-8 string"),
63-
);
64-
60+
// Step 1: Send abort code (typically 1 byte, but `code` allows flexibility)
6561
outb(OutBAction::Abort as u16, code);
62+
63+
// Step 2: Convert the C string to bytes
64+
let message_bytes = CStr::from_ptr(message_ptr).to_bytes(); // excludes null terminator
65+
66+
// Step 3: Send the message itself in chunks
67+
outb(OutBAction::Abort as u16, message_bytes);
68+
69+
// Step 4: Send abort terminator to signal completion (e.g., 0xFF)
70+
outb(OutBAction::Abort as u16, &[0xFF]);
71+
72+
// This function never returns
6673
unreachable!()
6774
}
6875

src/hyperlight_guest/src/host_function_call.rs

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ limitations under the License.
1717
use alloc::format;
1818
use alloc::string::ToString;
1919
use alloc::vec::Vec;
20-
use core::arch::global_asm;
20+
use core::arch;
2121

2222
use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType};
2323
use hyperlight_common::flatbuffer_wrappers::function_types::{
@@ -79,21 +79,16 @@ pub fn outb(port: u16, data: &[u8]) {
7979
unsafe {
8080
match RUNNING_MODE {
8181
RunMode::Hypervisor => {
82-
for chunk in data.chunks(4) {
83-
// Process the data in chunks of 4 bytes. If a chunk has fewer than 4 bytes,
84-
// pad it with 0x7F to ensure it can be converted into a 4-byte array.
85-
// The choice of 0x7F as the padding value is arbitrary and does not carry
86-
// any special meaning; it simply ensures consistent chunk size.
87-
let val = match chunk {
88-
[a, b, c, d] => u32::from_le_bytes([*a, *b, *c, *d]),
89-
[a, b, c] => u32::from_le_bytes([*a, *b, *c, 0x7F]),
90-
[a, b] => u32::from_le_bytes([*a, *b, 0x7F, 0x7F]),
91-
[a] => u32::from_le_bytes([*a, 0x7F, 0x7F, 0x7F]),
92-
[] => break,
93-
_ => unreachable!(),
94-
};
95-
96-
hloutd(val, port);
82+
let mut i = 0;
83+
while i < data.len() {
84+
let remaining = data.len() - i;
85+
let chunk_len = remaining.min(3);
86+
let mut chunk = [0u8; 4];
87+
chunk[0] = chunk_len as u8;
88+
chunk[1..1 + chunk_len].copy_from_slice(&data[i..i + chunk_len]);
89+
let val = u32::from_le_bytes(chunk);
90+
out32(port, val);
91+
i += chunk_len;
9792
}
9893
}
9994
RunMode::InProcessLinux | RunMode::InProcessWindows => {
@@ -119,11 +114,25 @@ pub fn outb(port: u16, data: &[u8]) {
119114
}
120115
}
121116

122-
extern "win64" {
123-
fn hloutd(value: u32, port: u16);
117+
pub(crate) unsafe fn out32(port: u16, val: u32) {
118+
arch::asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack));
124119
}
125120

126-
pub fn print_output_as_guest_function(function_call: &FunctionCall) -> Result<Vec<u8>> {
121+
/// Prints a message using `OutBAction::DebugPrint`. It transmits bytes of a message
122+
/// through several VMExists and, with such, it is slower than
123+
/// `print_output_with_host_print`.
124+
///
125+
/// This function should be used in debug mode only. This function does not
126+
/// require memory to be setup to be used.
127+
pub fn debug_print(msg: &str) {
128+
outb(OutBAction::DebugPrint as u16, msg.as_bytes());
129+
}
130+
131+
/// Print a message using the host's print function.
132+
///
133+
/// This function requires memory to be setup to be used. In particular, the
134+
/// existence of the input and output memory regions.
135+
pub fn print_output_with_host_print(function_call: &FunctionCall) -> Result<Vec<u8>> {
127136
if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() {
128137
call_host_function(
129138
"HostPrint",
@@ -135,20 +144,7 @@ pub fn print_output_as_guest_function(function_call: &FunctionCall) -> Result<Ve
135144
} else {
136145
Err(HyperlightGuestError::new(
137146
ErrorCode::GuestError,
138-
"Wrong Parameters passed to print_output_as_guest_function".to_string(),
147+
"Wrong Parameters passed to print_output_with_host_print".to_string(),
139148
))
140149
}
141150
}
142-
143-
pub fn debug_print(msg: &str) {
144-
outb(OutBAction::DebugPrint as u16, msg.as_bytes());
145-
}
146-
147-
global_asm!(
148-
".global hloutd
149-
hloutd:
150-
mov eax, ecx
151-
mov dx, dx
152-
out dx, eax
153-
ret"
154-
);

src/hyperlight_guest/src/interrupt_handlers.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@ pub extern "sysv64" fn hl_exception_handler(
3131
) {
3232
let exception = Exception::try_from(exception_number as u8).expect("Invalid exception number");
3333
let msg = format!(
34-
"EXCEPTION: {:#?}\n\
35-
Page Fault Address: {:#x}\n\
34+
"Page Fault Address: {:#x}\n\
3635
Stack Pointer: {:#x}",
37-
exception, page_fault_address, stack_pointer
36+
page_fault_address, stack_pointer
3837
);
3938

4039
unsafe {

src/hyperlight_guest/src/lib.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,13 @@ limitations under the License.
1717
#![no_std]
1818
// Deps
1919
use alloc::string::ToString;
20-
use core::hint::unreachable_unchecked;
2120

2221
use buddy_system_allocator::LockedHeap;
2322
use guest_function_register::GuestFunctionRegister;
24-
use host_function_call::debug_print;
2523
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2624
use hyperlight_common::mem::{HyperlightPEB, RunMode};
27-
use hyperlight_common::outb::OutBAction;
2825

29-
use crate::host_function_call::outb;
26+
use crate::entrypoint::abort_with_code_and_message;
3027
extern crate alloc;
3128

3229
// Modules
@@ -73,9 +70,11 @@ pub(crate) static _fltused: i32 = 0;
7370
// to satisfy the clippy when cfg == test
7471
#[allow(dead_code)]
7572
fn panic(info: &core::panic::PanicInfo) -> ! {
76-
debug_print(info.to_string().as_str());
77-
outb(OutBAction::Abort as u16, &[ErrorCode::UnknownError as u8]);
78-
unsafe { unreachable_unchecked() }
73+
let msg = info.to_string();
74+
let c_string = alloc::ffi::CString::new(msg)
75+
.unwrap_or_else(|_| alloc::ffi::CString::new("panic (invalid utf8)").unwrap());
76+
77+
unsafe { abort_with_code_and_message(&[ErrorCode::UnknownError as u8], c_string.as_ptr()) }
7978
}
8079

8180
// Globals

src/hyperlight_host/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ proc-maps = "0.4.0"
113113
[build-dependencies]
114114
anyhow = { version = "1.0.98" }
115115
cfg_aliases = "0.2.1"
116-
built = { version = "0.8.0", features = ["chrono", "git2"] }
116+
built = { version = "0.8.0", optional = true, features = ["chrono", "git2"] }
117117

118118
[features]
119-
default = ["kvm", "mshv2", "seccomp"]
119+
default = ["kvm", "mshv2", "seccomp", "build-metadata"]
120120
seccomp = ["dep:seccompiler"]
121121
function_call_metrics = []
122122
executable_heap = []
@@ -129,6 +129,7 @@ mshv3 = ["dep:mshv-bindings3", "dep:mshv-ioctls3"]
129129
# This enables easy debug in the guest
130130
gdb = ["dep:gdbstub", "dep:gdbstub_arch"]
131131
fuzzing = ["hyperlight-common/fuzzing"]
132+
build-metadata = ["dep:built"]
132133

133134
[[bench]]
134135
name = "benchmarks"

src/hyperlight_host/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ limitations under the License.
1515
*/
1616

1717
use anyhow::Result;
18+
#[cfg(feature = "build-metadata")]
1819
use built::write_built_file;
1920

2021
fn main() -> Result<()> {
@@ -103,6 +104,7 @@ fn main() -> Result<()> {
103104
mshv3: { all(feature = "mshv3", target_os = "linux") },
104105
}
105106

107+
#[cfg(feature = "build-metadata")]
106108
write_built_file()?;
107109

108110
Ok(())

src/hyperlight_host/src/hypervisor/handlers.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{new_error, Result};
2525
/// has initiated an outb operation.
2626
pub trait OutBHandlerCaller: Sync + Send {
2727
/// Function that gets called when an outb operation has occurred.
28-
fn call(&mut self, port: u16, payload: Vec<u8>) -> Result<()>;
28+
fn call(&mut self, port: u16, payload: u32) -> Result<()>;
2929
}
3030

3131
/// A convenient type representing a common way `OutBHandler` implementations
@@ -36,7 +36,7 @@ pub trait OutBHandlerCaller: Sync + Send {
3636
/// a &mut self).
3737
pub type OutBHandlerWrapper = Arc<Mutex<dyn OutBHandlerCaller>>;
3838

39-
pub(crate) type OutBHandlerFunction = Box<dyn FnMut(u16, Vec<u8>) -> Result<()> + Send>;
39+
pub(crate) type OutBHandlerFunction = Box<dyn FnMut(u16, u32) -> Result<()> + Send>;
4040

4141
/// A `OutBHandler` implementation using a `OutBHandlerFunction`
4242
///
@@ -52,7 +52,7 @@ impl From<OutBHandlerFunction> for OutBHandler {
5252

5353
impl OutBHandlerCaller for OutBHandler {
5454
#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
55-
fn call(&mut self, port: u16, payload: Vec<u8>) -> Result<()> {
55+
fn call(&mut self, port: u16, payload: u32) -> Result<()> {
5656
let mut func = self
5757
.0
5858
.try_lock()

src/hyperlight_host/src/hypervisor/hyperlight_vm.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -475,16 +475,18 @@ impl HyperlightVm for HyperlightSandbox {
475475
) -> Result<()> {
476476
// KVM does not need RIP or instruction length, as it automatically sets the RIP
477477

478-
// The payload param for the outb_handle_fn is the first byte
479-
// of the data array cast to an u64. Thus, we need to make sure
480-
// the data array has at least one u8, then convert that to an u64
478+
let mut padded = [0u8; 4];
479+
let copy_len = data.len().min(4);
480+
padded[..copy_len].copy_from_slice(&data[..copy_len]);
481+
let val = u32::from_le_bytes(padded);
482+
481483
if data.is_empty() {
482484
log_then_return!("no data was given in IO interrupt");
483485
} else {
484486
outb_handle_fn
485487
.try_lock()
486488
.map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
487-
.call(port, data)?;
489+
.call(port, val)?;
488490
}
489491

490492
Ok(())
@@ -725,7 +727,7 @@ mod tests {
725727
#[test]
726728
fn test_init() {
727729
let outb_handler: Arc<Mutex<OutBHandler>> = {
728-
let func: Box<dyn FnMut(u16, Vec<u8>) -> Result<()> + Send> =
730+
let func: Box<dyn FnMut(u16, u32) -> Result<()> + Send> =
729731
Box::new(|_, _| -> Result<()> { Ok(()) });
730732
Arc::new(Mutex::new(OutBHandler::from(func)))
731733
};

0 commit comments

Comments
 (0)