hyperlight_guest/exit.rs
1/*
2Copyright 2025 The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17use core::arch::asm;
18use core::ffi::{CStr, c_char};
19
20use hyperlight_common::outb::OutBAction;
21
22/// Halt the execution of the guest and returns control to the host.
23#[inline(never)]
24#[hyperlight_guest_tracing::trace_function]
25pub fn halt() {
26 // Ensure all tracing data is flushed before halting
27 hyperlight_guest_tracing::flush!();
28 unsafe { asm!("hlt", options(nostack)) }
29}
30
31/// Exits the VM with an Abort OUT action and code 0.
32#[unsafe(no_mangle)]
33#[hyperlight_guest_tracing::trace_function]
34pub extern "C" fn abort() -> ! {
35 abort_with_code(&[0, 0xFF])
36}
37
38/// Exits the VM with an Abort OUT action and a specific code.
39#[hyperlight_guest_tracing::trace_function]
40pub fn abort_with_code(code: &[u8]) -> ! {
41 outb(OutBAction::Abort as u16, code);
42 outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code)
43 unreachable!()
44}
45
46/// Aborts the program with a code and a message.
47///
48/// # Safety
49/// This function is unsafe because it dereferences a raw pointer.
50#[hyperlight_guest_tracing::trace_function]
51pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! {
52 unsafe {
53 // Step 1: Send abort code (typically 1 byte, but `code` allows flexibility)
54 outb(OutBAction::Abort as u16, code);
55
56 // Step 2: Convert the C string to bytes
57 let message_bytes = CStr::from_ptr(message_ptr).to_bytes(); // excludes null terminator
58
59 // Step 3: Send the message itself in chunks
60 outb(OutBAction::Abort as u16, message_bytes);
61
62 // Step 4: Send abort terminator to signal completion (e.g., 0xFF)
63 outb(OutBAction::Abort as u16, &[0xFF]);
64
65 // This function never returns
66 unreachable!()
67 }
68}
69
70/// This function exists to give the guest more manual control
71/// over the abort sequence. For example, in `hyperlight_guest_bin`'s panic handler,
72/// we have a message of unknown length that we want to stream
73/// to the host, which requires sending the message in chunks
74pub fn write_abort(code: &[u8]) {
75 outb(OutBAction::Abort as u16, code);
76}
77
78/// OUT bytes to the host through multiple exits.
79#[hyperlight_guest_tracing::trace_function]
80pub(crate) fn outb(port: u16, data: &[u8]) {
81 // Ensure all tracing data is flushed before sending OUT bytes
82 hyperlight_guest_tracing::flush!();
83 unsafe {
84 let mut i = 0;
85 while i < data.len() {
86 let remaining = data.len() - i;
87 let chunk_len = remaining.min(3);
88 let mut chunk = [0u8; 4];
89 chunk[0] = chunk_len as u8;
90 chunk[1..1 + chunk_len].copy_from_slice(&data[i..i + chunk_len]);
91 let val = u32::from_le_bytes(chunk);
92 out32(port, val);
93 i += chunk_len;
94 }
95 }
96}
97
98/// OUT function for sending a 32-bit value to the host.
99#[hyperlight_guest_tracing::trace_function]
100pub(crate) unsafe fn out32(port: u16, val: u32) {
101 unsafe {
102 asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack));
103 }
104}
105
106/// Prints a message using `OutBAction::DebugPrint`. It transmits bytes of a message
107/// through several VMExists and, with such, it is slower than
108/// `print_output_with_host_print`.
109///
110/// This function should be used in debug mode only. This function does not
111/// require memory to be setup to be used.
112pub fn debug_print(msg: &str) {
113 for byte in msg.bytes() {
114 unsafe {
115 out32(OutBAction::DebugPrint as u16, byte as u32);
116 }
117 }
118}