Skip to content

Commit ce8410a

Browse files
committed
[common/{mem,outb},guest/*,host/{mem,func,sandbox,tests}] removed guest panic context mem region
We had a guest panic context region to store the panic msg. Now, instead of storing info in shared mem, we use debug_print. To still have some exception info when using OutBAction::Abort, we pass parse the exception name, which is more readable than before and provides information that is useful as illustrated in some of the integration tests. Signed-off-by: danbugs <[email protected]>
1 parent 52988bf commit ce8410a

File tree

18 files changed

+169
-246
lines changed

18 files changed

+169
-246
lines changed

src/hyperlight_common/src/mem.rs

-7
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,6 @@ pub struct GuestStackData {
7474
pub bootStackAddress: u64,
7575
}
7676

77-
#[repr(C)]
78-
pub struct GuestPanicContextData {
79-
pub guestPanicContextDataSize: u64,
80-
pub guestPanicContextDataBuffer: *mut c_void,
81-
}
82-
8377
#[repr(C)]
8478
pub struct HyperlightPEB {
8579
pub security_cookie_seed: u64,
@@ -90,7 +84,6 @@ pub struct HyperlightPEB {
9084
pub runMode: RunMode,
9185
pub inputdata: InputData,
9286
pub outputdata: OutputData,
93-
pub guestPanicContextData: GuestPanicContextData,
9487
pub guestheapData: GuestHeapData,
9588
pub gueststackData: GuestStackData,
9689
}

src/hyperlight_common/src/outb.rs

+71
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,74 @@
1+
use core::convert::TryFrom;
2+
3+
use anyhow::{anyhow, Error};
4+
5+
/// Exception codes for the x86 architecture.
6+
/// These are helpful to identify the type of exception that occurred
7+
/// together with OutBAction::Abort.
8+
#[repr(u8)]
9+
#[derive(Debug, Clone, Copy)]
10+
pub enum Exception {
11+
DivideByZero = 0,
12+
Debug = 1,
13+
NonMaskableInterrupt = 2,
14+
Breakpoint = 3,
15+
Overflow = 4,
16+
BoundRangeExceeded = 5,
17+
InvalidOpcode = 6,
18+
DeviceNotAvailable = 7,
19+
DoubleFault = 8,
20+
CoprocessorSegmentOverrun = 9,
21+
InvalidTSS = 10,
22+
SegmentNotPresent = 11,
23+
StackSegmentFault = 12,
24+
GeneralProtectionFault = 13,
25+
PageFault = 14,
26+
Reserved = 15,
27+
X87FloatingPointException = 16,
28+
AlignmentCheck = 17,
29+
MachineCheck = 18,
30+
SIMDFloatingPointException = 19,
31+
VirtualizationException = 20,
32+
SecurityException = 30,
33+
NoException = 0xFF,
34+
}
35+
36+
impl TryFrom<u8> for Exception {
37+
type Error = Error;
38+
39+
fn try_from(value: u8) -> Result<Self, Self::Error> {
40+
use Exception::*;
41+
let exception = match value {
42+
0 => DivideByZero,
43+
1 => Debug,
44+
2 => NonMaskableInterrupt,
45+
3 => Breakpoint,
46+
4 => Overflow,
47+
5 => BoundRangeExceeded,
48+
6 => InvalidOpcode,
49+
7 => DeviceNotAvailable,
50+
8 => DoubleFault,
51+
9 => CoprocessorSegmentOverrun,
52+
10 => InvalidTSS,
53+
11 => SegmentNotPresent,
54+
12 => StackSegmentFault,
55+
13 => GeneralProtectionFault,
56+
14 => PageFault,
57+
15 => Reserved,
58+
16 => X87FloatingPointException,
59+
17 => AlignmentCheck,
60+
18 => MachineCheck,
61+
19 => SIMDFloatingPointException,
62+
20 => VirtualizationException,
63+
30 => SecurityException,
64+
0x7F => NoException,
65+
_ => return Err(anyhow!("Unknown exception code: {:#x}", value)),
66+
};
67+
68+
Ok(exception)
69+
}
70+
}
71+
172
/// Supported actions when issuing an OUTB actions by Hyperlight.
273
/// - Log: for logging,
374
/// - CallFunction: makes a call to a host function,

src/hyperlight_guest/src/entrypoint.rs

+11-14
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ limitations under the License.
1616

1717
use core::arch::asm;
1818
use core::ffi::{c_char, c_void, CStr};
19-
use core::ptr::copy_nonoverlapping;
2019

2120
use hyperlight_common::mem::{HyperlightPEB, RunMode};
2221
use hyperlight_common::outb::OutBAction;
@@ -26,7 +25,7 @@ use spin::Once;
2625
use crate::gdt::load_gdt;
2726
use crate::guest_function_call::dispatch_function;
2827
use crate::guest_logger::init_logger;
29-
use crate::host_function_call::outb;
28+
use crate::host_function_call::{debug_print, outb};
3029
use crate::idtr::load_idt;
3130
use crate::{
3231
__security_cookie, HEAP_ALLOCATOR, MIN_STACK_ADDRESS, OS_PAGE_SIZE, OUTB_PTR,
@@ -44,28 +43,26 @@ pub fn halt() {
4443

4544
#[no_mangle]
4645
pub extern "C" fn abort() -> ! {
47-
abort_with_code(0)
46+
abort_with_code(&[0])
4847
}
4948

50-
pub fn abort_with_code(code: i32) -> ! {
51-
let byte = code as u8;
52-
outb(OutBAction::Abort as u16, &[byte]);
49+
pub fn abort_with_code(code: &[u8]) -> ! {
50+
outb(OutBAction::Abort as u16, code);
5351
unreachable!()
5452
}
5553

5654
/// Aborts the program with a code and a message.
5755
///
5856
/// # Safety
5957
/// This function is unsafe because it dereferences a raw pointer.
60-
pub unsafe fn abort_with_code_and_message(code: i32, message_ptr: *const c_char) -> ! {
61-
let peb_ptr = P_PEB.unwrap();
62-
copy_nonoverlapping(
63-
message_ptr,
64-
(*peb_ptr).guestPanicContextData.guestPanicContextDataBuffer as *mut c_char,
65-
CStr::from_ptr(message_ptr).count_bytes() + 1, // +1 for null terminator
58+
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"),
6663
);
67-
let byte = code as u8;
68-
outb(OutBAction::Abort as u16, &[byte]);
64+
65+
outb(OutBAction::Abort as u16, code);
6966
unreachable!()
7067
}
7168

src/hyperlight_guest/src/host_function_call.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,15 @@ pub fn outb(port: u16, data: &[u8]) {
8080
match RUNNING_MODE {
8181
RunMode::Hypervisor => {
8282
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.
8387
let val = match chunk {
8488
[a, b, c, d] => u32::from_le_bytes([*a, *b, *c, *d]),
85-
[a, b, c] => u32::from_le_bytes([*a, *b, *c, 0]),
86-
[a, b] => u32::from_le_bytes([*a, *b, 0, 0]),
87-
[a] => u32::from_le_bytes([*a, 0, 0, 0]),
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]),
8892
[] => break,
8993
_ => unreachable!(),
9094
};

src/hyperlight_guest/src/idt.rs

+24-22
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
use hyperlight_common::outb::Exception;
18+
1719
use crate::interrupt_entry::{
1820
_do_excp0, _do_excp1, _do_excp10, _do_excp11, _do_excp12, _do_excp13, _do_excp14, _do_excp15,
1921
_do_excp16, _do_excp17, _do_excp18, _do_excp19, _do_excp2, _do_excp20, _do_excp3, _do_excp30,
@@ -70,28 +72,28 @@ impl IdtEntry {
7072
pub(crate) static mut IDT: [IdtEntry; 256] = unsafe { core::mem::zeroed() };
7173

7274
pub(crate) fn init_idt() {
73-
set_idt_entry(0, _do_excp0); // Divide by zero
74-
set_idt_entry(1, _do_excp1); // Debug
75-
set_idt_entry(2, _do_excp2); // Non-maskable interrupt
76-
set_idt_entry(3, _do_excp3); // Breakpoint
77-
set_idt_entry(4, _do_excp4); // Overflow
78-
set_idt_entry(5, _do_excp5); // Bound Range Exceeded
79-
set_idt_entry(6, _do_excp6); // Invalid Opcode
80-
set_idt_entry(7, _do_excp7); // Device Not Available
81-
set_idt_entry(8, _do_excp8); // Double Fault
82-
set_idt_entry(9, _do_excp9); // Coprocessor Segment Overrun
83-
set_idt_entry(10, _do_excp10); // Invalid TSS
84-
set_idt_entry(11, _do_excp11); // Segment Not Present
85-
set_idt_entry(12, _do_excp12); // Stack-Segment Fault
86-
set_idt_entry(13, _do_excp13); // General Protection Fault
87-
set_idt_entry(14, _do_excp14); // Page Fault
88-
set_idt_entry(15, _do_excp15); // Reserved
89-
set_idt_entry(16, _do_excp16); // x87 Floating-Point Exception
90-
set_idt_entry(17, _do_excp17); // Alignment Check
91-
set_idt_entry(18, _do_excp18); // Machine Check
92-
set_idt_entry(19, _do_excp19); // SIMD Floating-Point Exception
93-
set_idt_entry(20, _do_excp20); // Virtualization Exception
94-
set_idt_entry(30, _do_excp30); // Security Exception
75+
set_idt_entry(Exception::DivideByZero as usize, _do_excp0); // Divide by zero
76+
set_idt_entry(Exception::Debug as usize, _do_excp1); // Debug
77+
set_idt_entry(Exception::NonMaskableInterrupt as usize, _do_excp2); // Non-maskable interrupt
78+
set_idt_entry(Exception::Breakpoint as usize, _do_excp3); // Breakpoint
79+
set_idt_entry(Exception::Overflow as usize, _do_excp4); // Overflow
80+
set_idt_entry(Exception::BoundRangeExceeded as usize, _do_excp5); // Bound Range Exceeded
81+
set_idt_entry(Exception::InvalidOpcode as usize, _do_excp6); // Invalid Opcode
82+
set_idt_entry(Exception::DeviceNotAvailable as usize, _do_excp7); // Device Not Available
83+
set_idt_entry(Exception::DoubleFault as usize, _do_excp8); // Double Fault
84+
set_idt_entry(Exception::CoprocessorSegmentOverrun as usize, _do_excp9); // Coprocessor Segment Overrun
85+
set_idt_entry(Exception::InvalidTSS as usize, _do_excp10); // Invalid TSS
86+
set_idt_entry(Exception::SegmentNotPresent as usize, _do_excp11); // Segment Not Present
87+
set_idt_entry(Exception::StackSegmentFault as usize, _do_excp12); // Stack-Segment Fault
88+
set_idt_entry(Exception::GeneralProtectionFault as usize, _do_excp13); // General Protection Fault
89+
set_idt_entry(Exception::PageFault as usize, _do_excp14); // Page Fault
90+
set_idt_entry(Exception::Reserved as usize, _do_excp15); // Reserved
91+
set_idt_entry(Exception::X87FloatingPointException as usize, _do_excp16); // x87 Floating-Point Exception
92+
set_idt_entry(Exception::AlignmentCheck as usize, _do_excp17); // Alignment Check
93+
set_idt_entry(Exception::MachineCheck as usize, _do_excp18); // Machine Check
94+
set_idt_entry(Exception::SIMDFloatingPointException as usize, _do_excp19); // SIMD Floating-Point Exception
95+
set_idt_entry(Exception::VirtualizationException as usize, _do_excp20); // Virtualization Exception
96+
set_idt_entry(Exception::SecurityException as usize, _do_excp30); // Security Exception
9597
}
9698

9799
fn set_idt_entry(index: usize, handler: unsafe extern "sysv64" fn()) {

src/hyperlight_guest/src/interrupt_handlers.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,33 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
use alloc::format;
18+
use core::ffi::c_char;
19+
20+
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
21+
use hyperlight_common::outb::Exception;
22+
23+
use crate::entrypoint::abort_with_code_and_message;
24+
1725
/// Exception handler
1826
#[no_mangle]
1927
pub extern "sysv64" fn hl_exception_handler(
2028
stack_pointer: u64,
2129
exception_number: u64,
2230
page_fault_address: u64,
2331
) {
24-
panic!(
25-
"EXCEPTION: {:#x}\n\
32+
let exception = Exception::try_from(exception_number as u8).expect("Invalid exception number");
33+
let msg = format!(
34+
"EXCEPTION: {:#?}\n\
2635
Page Fault Address: {:#x}\n\
2736
Stack Pointer: {:#x}",
28-
exception_number, page_fault_address, stack_pointer
37+
exception, page_fault_address, stack_pointer
2938
);
39+
40+
unsafe {
41+
abort_with_code_and_message(
42+
&[ErrorCode::GuestError as u8, exception as u8],
43+
msg.as_ptr() as *const c_char,
44+
);
45+
}
3046
}

src/hyperlight_guest/src/lib.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ limitations under the License.
1818
// Deps
1919
use alloc::string::ToString;
2020
use core::hint::unreachable_unchecked;
21-
use core::ptr::copy_nonoverlapping;
2221

2322
use buddy_system_allocator::LockedHeap;
2423
use guest_function_register::GuestFunctionRegister;
24+
use host_function_call::debug_print;
2525
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2626
use hyperlight_common::mem::{HyperlightPEB, RunMode};
2727
use hyperlight_common::outb::OutBAction;
@@ -73,14 +73,7 @@ pub(crate) static _fltused: i32 = 0;
7373
// to satisfy the clippy when cfg == test
7474
#[allow(dead_code)]
7575
fn panic(info: &core::panic::PanicInfo) -> ! {
76-
unsafe {
77-
let peb_ptr = P_PEB.unwrap();
78-
copy_nonoverlapping(
79-
info.to_string().as_ptr(),
80-
(*peb_ptr).guestPanicContextData.guestPanicContextDataBuffer as *mut u8,
81-
(*peb_ptr).guestPanicContextData.guestPanicContextDataSize as usize,
82-
);
83-
}
76+
debug_print(info.to_string().as_str());
8477
outb(OutBAction::Abort as u16, &[ErrorCode::UnknownError as u8]);
8578
unsafe { unreachable_unchecked() }
8679
}

src/hyperlight_guest/src/memory.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ unsafe fn alloc_helper(size: usize, zero: bool) -> *mut c_void {
6767
false => alloc::alloc::alloc(layout),
6868
};
6969
if raw_ptr.is_null() {
70-
abort_with_code(ErrorCode::MallocFailed as i32);
70+
abort_with_code(&[ErrorCode::MallocFailed as u8]);
7171
} else {
7272
let layout_ptr = raw_ptr as *mut Layout;
7373
layout_ptr.write(layout);
@@ -148,7 +148,7 @@ pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
148148

149149
if new_block_start.is_null() {
150150
// Realloc failed
151-
abort_with_code(ErrorCode::MallocFailed as i32);
151+
abort_with_code(&[ErrorCode::MallocFailed as u8]);
152152
} else {
153153
// Update the stored Layout, then return ptr to memory right after the Layout.
154154
new_block_start.write(new_layout);

src/hyperlight_guest_capi/src/error.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ pub extern "C" fn hl_set_error(err: ErrorCode, message: *const c_char) {
1212

1313
#[no_mangle]
1414
pub extern "C" fn hl_abort_with_code(err: i32) {
15-
hyperlight_guest::entrypoint::abort_with_code(err);
15+
hyperlight_guest::entrypoint::abort_with_code(&[err as u8]);
1616
}
1717

1818
#[no_mangle]
1919
pub extern "C" fn hl_abort_with_code_and_message(err: i32, message: *const c_char) {
20-
unsafe { hyperlight_guest::entrypoint::abort_with_code_and_message(err, message) };
20+
unsafe { hyperlight_guest::entrypoint::abort_with_code_and_message(&[err as u8], message) };
2121
}

src/hyperlight_host/src/func/guest_dispatch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ mod tests {
494494
match res.unwrap_err() {
495495
HyperlightError::GuestAborted(_, msg) => {
496496
// msg should indicate we got an invalid opcode exception
497-
assert!(msg.contains("EXCEPTION: 0x6"));
497+
assert!(msg.contains("InvalidOpcode"));
498498
}
499499
e => panic!(
500500
"Expected HyperlightError::GuestExecutionError but got {:?}",

src/hyperlight_host/src/hypervisor/hyperv_windows.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ impl Hypervisor for HypervWindowsDriver {
393393
outb_handle_fn
394394
.try_lock()
395395
.map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
396-
.call(port, payload)?;
396+
.call(port, data)?;
397397

398398
let mut regs = self.processor.get_regs()?;
399399
regs.rip = rip + instruction_length;
@@ -505,7 +505,7 @@ pub mod tests {
505505
#[serial]
506506
fn test_init() {
507507
let outb_handler = {
508-
let func: Box<dyn FnMut(u16, u64) -> Result<()> + Send> =
508+
let func: Box<dyn FnMut(u16, Vec<u8>) -> Result<()> + Send> =
509509
Box::new(|_, _| -> Result<()> { Ok(()) });
510510
Arc::new(Mutex::new(OutBHandler::from(func)))
511511
};

0 commit comments

Comments
 (0)