Skip to content

Commit 5eae452

Browse files
committed
[guest,tests/rust_guests] change guest library to conform to new APIs in common library and use CGM
The host now defines a single undifferentiated memory region—the custom guest memory region (or, CGM)—that the guest can address as it sees fit. This commit changes the guest library to leverage that and perform said address using the APIs defined in the common library. Signed-off-by: danbugs <[email protected]>
1 parent 91fb8f3 commit 5eae452

File tree

10 files changed

+146
-149
lines changed

10 files changed

+146
-149
lines changed

src/hyperlight_guest/src/chkstk.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ limitations under the License.
1717
use core::arch::global_asm;
1818
use core::mem::size_of;
1919

20-
use hyperlight_common::mem::RunMode;
20+
use hyperlight_common::hyperlight_peb::RunMode;
2121

2222
use crate::guest_error::{set_invalid_runmode_error, set_stack_allocate_error};
2323
use crate::{MIN_STACK_ADDRESS, RUNNING_MODE};

src/hyperlight_guest/src/entrypoint.rs

Lines changed: 61 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
16-
1716
use core::arch::asm;
18-
use core::ffi::{c_char, c_void, CStr};
17+
use core::ffi::{c_char, CStr};
1918
use core::ptr::copy_nonoverlapping;
2019

21-
use hyperlight_common::mem::{HyperlightPEB, RunMode};
20+
use hyperlight_common::hyperlight_peb::{HyperlightPEB, RunMode};
2221
use log::LevelFilter;
2322
use spin::Once;
2423

@@ -28,10 +27,7 @@ use crate::guest_function_call::dispatch_function;
2827
use crate::guest_logger::init_logger;
2928
use crate::host_function_call::{outb, OutBAction};
3029
use crate::idtr::load_idt;
31-
use crate::{
32-
__security_cookie, HEAP_ALLOCATOR, MIN_STACK_ADDRESS, OS_PAGE_SIZE, OUTB_PTR,
33-
OUTB_PTR_WITH_CONTEXT, P_PEB, RUNNING_MODE,
34-
};
30+
use crate::{__security_cookie, HEAP_ALLOCATOR, MIN_STACK_ADDRESS, PEB, RUNNING_MODE};
3531

3632
#[inline(never)]
3733
pub fn halt() {
@@ -57,10 +53,9 @@ pub fn abort_with_code(code: i32) -> ! {
5753
/// # Safety
5854
/// This function is unsafe because it dereferences a raw pointer.
5955
pub unsafe fn abort_with_code_and_message(code: i32, message_ptr: *const c_char) -> ! {
60-
let peb_ptr = P_PEB.unwrap();
6156
copy_nonoverlapping(
6257
message_ptr,
63-
(*peb_ptr).guestPanicContextData.guestPanicContextDataBuffer as *mut c_char,
58+
(*PEB).guest_panic_context_ptr as *mut c_char,
6459
CStr::from_ptr(message_ptr).count_bytes() + 1, // +1 for null terminator
6560
);
6661
outb(OutBAction::Abort as u16, code as u8);
@@ -77,79 +72,64 @@ static INIT: Once = Once::new();
7772
// Note: entrypoint cannot currently have a stackframe >4KB, as that will invoke __chkstk on msvc
7873
// target without first having setup global `RUNNING_MODE` variable, which __chkstk relies on.
7974
#[no_mangle]
80-
pub extern "win64" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_level: u64) {
81-
if peb_address == 0 {
82-
panic!("PEB address is null");
83-
}
84-
85-
INIT.call_once(|| {
86-
unsafe {
87-
P_PEB = Some(peb_address as *mut HyperlightPEB);
88-
let peb_ptr = P_PEB.unwrap();
89-
__security_cookie = peb_address ^ seed;
90-
91-
let srand_seed = ((peb_address << 8 ^ seed >> 4) >> 32) as u32;
92-
93-
// Set the seed for the random number generator for C code using rand;
94-
srand(srand_seed);
95-
96-
// set up the logger
97-
let max_log_level = LevelFilter::iter()
98-
.nth(max_log_level as usize)
99-
.expect("Invalid log level");
100-
init_logger(max_log_level);
101-
102-
match (*peb_ptr).runMode {
103-
RunMode::Hypervisor => {
104-
RUNNING_MODE = RunMode::Hypervisor;
105-
// This static is to make it easier to implement the __chkstk function in assembly.
106-
// It also means that should we change the layout of the struct in the future, we
107-
// don't have to change the assembly code.
108-
MIN_STACK_ADDRESS = (*peb_ptr).gueststackData.minUserStackAddress;
109-
110-
// Setup GDT and IDT
111-
load_gdt();
112-
load_idt();
113-
}
114-
RunMode::InProcessLinux | RunMode::InProcessWindows => {
115-
RUNNING_MODE = (*peb_ptr).runMode;
116-
117-
OUTB_PTR = {
118-
let outb_ptr: extern "win64" fn(u16, u8) =
119-
core::mem::transmute((*peb_ptr).pOutb);
120-
Some(outb_ptr)
121-
};
122-
123-
if (*peb_ptr).pOutbContext.is_null() {
124-
panic!("OutbContext is null");
125-
}
126-
127-
OUTB_PTR_WITH_CONTEXT = {
128-
let outb_ptr_with_context: extern "win64" fn(*mut c_void, u16, u8) =
129-
core::mem::transmute((*peb_ptr).pOutb);
130-
Some(outb_ptr_with_context)
131-
};
132-
}
133-
_ => {
134-
panic!("Invalid runmode in PEB");
135-
}
136-
}
137-
138-
let heap_start = (*peb_ptr).guestheapData.guestHeapBuffer as usize;
139-
let heap_size = (*peb_ptr).guestheapData.guestHeapSize as usize;
140-
HEAP_ALLOCATOR
141-
.try_lock()
142-
.expect("Failed to access HEAP_ALLOCATOR")
143-
.init(heap_start, heap_size);
144-
145-
OS_PAGE_SIZE = ops as u32;
146-
147-
(*peb_ptr).guest_function_dispatch_ptr = dispatch_function as usize as u64;
148-
149-
reset_error();
150-
151-
hyperlight_main();
75+
pub extern "win64" fn entrypoint(
76+
peb_address: u64,
77+
// TODO(danbugs:297): remove the extra arg
78+
_: u64,
79+
seed: u64,
80+
max_log_level: u64,
81+
) {
82+
INIT.call_once(|| unsafe {
83+
PEB = peb_address as *mut HyperlightPEB;
84+
RUNNING_MODE = (*PEB).clone().run_mode;
85+
86+
// The guest receives an undifferentiated block of memory that it can address as it sees fit.
87+
// This 'addressing' is done by writing to the PEB the guest's memory layout via this function,
88+
// or by directly altering the PEB. `set_default_memory_layout` will configure the PEB to
89+
// with a memory layout that is compatible with the expectations of guests that use the
90+
// `hyperlight_guest` library (e.g., simpleguest, and callbackguest).
91+
(*PEB).set_default_memory_layout();
92+
93+
// The guest sets the address to a "guest function dispatch" function, which is a function
94+
// that is called by the host to dispatch calls to guest functions.
95+
(*PEB).guest_function_dispatch_ptr = dispatch_function as usize as u64;
96+
97+
// Set up the guest heap
98+
HEAP_ALLOCATOR
99+
.try_lock()
100+
.expect("Failed to access HEAP_ALLOCATOR")
101+
.init(
102+
(*PEB).guest_heap_data_ptr as usize,
103+
(*PEB).guest_heap_data_size as usize,
104+
);
105+
106+
__security_cookie = seed;
107+
108+
// Set the seed for the random number generator for C code using rand;
109+
let srand_seed = ((peb_address << 8 ^ seed >> 4) >> 32) as u32;
110+
srand(srand_seed);
111+
112+
// Set up the logger
113+
let max_log_level = LevelFilter::iter()
114+
.nth(max_log_level as usize)
115+
.expect("Invalid log level");
116+
init_logger(max_log_level);
117+
118+
if (*PEB).run_mode == RunMode::Hypervisor {
119+
// This static is to make it easier to implement the __chkstk function in assembly.
120+
// It also means that, should we change the layout of the struct in the future, we
121+
// don't have to change the assembly code. Plus, while this could be accessible via
122+
// the PEB, we don't want to expose it entirely to user code.
123+
MIN_STACK_ADDRESS = (*PEB).guest_stack_data_ptr;
124+
125+
// Setup GDT and IDT
126+
load_gdt();
127+
load_idt();
152128
}
129+
130+
reset_error();
131+
132+
hyperlight_main();
153133
});
154134

155135
halt();

src/hyperlight_guest/src/guest_error.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ use log::error;
2323

2424
use crate::entrypoint::halt;
2525
use crate::host_function_call::{outb, OutBAction};
26-
use crate::P_PEB;
26+
use crate::PEB;
2727

2828
pub(crate) fn write_error(error_code: ErrorCode, message: Option<&str>) {
29+
let peb = unsafe { (*PEB).clone() };
2930
let guest_error = GuestError::new(
3031
error_code.clone(),
3132
message.map_or("".to_string(), |m| m.to_string()),
@@ -35,20 +36,19 @@ pub(crate) fn write_error(error_code: ErrorCode, message: Option<&str>) {
3536
.expect("Invalid guest_error_buffer, could not be converted to a Vec<u8>");
3637

3738
unsafe {
38-
assert!(!(*P_PEB.unwrap()).guestErrorData.guestErrorBuffer.is_null());
39+
assert_ne!(!peb.guest_error_data_ptr, 0);
3940
let len = guest_error_buffer.len();
40-
if guest_error_buffer.len() > (*P_PEB.unwrap()).guestErrorData.guestErrorSize as usize {
41+
if guest_error_buffer.len() > peb.guest_error_data_size as usize {
4142
error!(
4243
"Guest error buffer is too small to hold the error message: size {} buffer size {} message may be truncated",
4344
guest_error_buffer.len(),
44-
(*P_PEB.unwrap()).guestErrorData.guestErrorSize as usize
45+
peb.guest_error_data_size as usize
4546
);
4647
// get the length of the message
4748
let message_len = message.map_or("".to_string(), |m| m.to_string()).len();
4849
// message is too long, truncate it
49-
let truncate_len = message_len
50-
- (guest_error_buffer.len()
51-
- (*P_PEB.unwrap()).guestErrorData.guestErrorSize as usize);
50+
let truncate_len =
51+
message_len - (guest_error_buffer.len() - peb.guest_error_data_size as usize);
5252
let truncated_message = message
5353
.map_or("".to_string(), |m| m.to_string())
5454
.chars()
@@ -67,18 +67,17 @@ pub(crate) fn write_error(error_code: ErrorCode, message: Option<&str>) {
6767
// but, because copy_nonoverlapping doesn't return anything, we can't do that.
6868
// Instead, we do the prior asserts/checks to check the destination pointer isn't null
6969
// and that there is enough space in the destination buffer for the copy.
70-
let dest_ptr = (*P_PEB.unwrap()).guestErrorData.guestErrorBuffer as *mut u8;
70+
let dest_ptr = peb.guest_error_data_ptr as *mut u8;
7171
core::ptr::copy_nonoverlapping(guest_error_buffer.as_ptr(), dest_ptr, len);
7272
}
7373
}
7474

7575
pub(crate) fn reset_error() {
7676
unsafe {
77-
let peb_ptr = P_PEB.unwrap();
7877
core::ptr::write_bytes(
79-
(*peb_ptr).guestErrorData.guestErrorBuffer,
78+
(*PEB).guest_error_data_ptr as *mut u8,
8079
0,
81-
(*peb_ptr).guestErrorData.guestErrorSize as usize,
80+
(*PEB).guest_error_data_size as usize,
8281
);
8382
}
8483
}

src/hyperlight_guest/src/guest_function_call.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@ use alloc::vec::Vec;
2020
use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType};
2121
use hyperlight_common::flatbuffer_wrappers::function_types::ParameterType;
2222
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
23+
use hyperlight_common::input_output::{InputDataSection, OutputDataSection};
2324

2425
use crate::entrypoint::halt;
2526
use crate::error::{HyperlightGuestError, Result};
2627
use crate::guest_error::{reset_error, set_error};
27-
use crate::shared_input_data::try_pop_shared_input_data_into;
28-
use crate::shared_output_data::push_shared_output_data;
29-
use crate::REGISTERED_GUEST_FUNCTIONS;
28+
use crate::{PEB, REGISTERED_GUEST_FUNCTIONS};
3029

3130
type GuestFunc = fn(&FunctionCall) -> Result<Vec<u8>>;
3231

@@ -86,14 +85,22 @@ fn internal_dispatch_function() -> Result<()> {
8685
#[cfg(debug_assertions)]
8786
log::trace!("internal_dispatch_function");
8887

89-
let function_call = try_pop_shared_input_data_into::<FunctionCall>()
88+
let peb = unsafe { (*PEB).clone() };
89+
90+
let input_data_section: InputDataSection = peb.get_input_data_region().into();
91+
let output_data_section: OutputDataSection = peb.get_output_data_region().into();
92+
93+
let function_call = input_data_section
94+
.try_pop_shared_input_data_into::<FunctionCall>()
9095
.expect("Function call deserialization failed");
9196

9297
let result_vec = call_guest_function(function_call).inspect_err(|e| {
9398
set_error(e.kind.clone(), e.message.as_str());
9499
})?;
95100

96-
push_shared_output_data(result_vec)
101+
Ok(output_data_section
102+
.push_shared_output_data(result_vec)
103+
.unwrap())
97104
}
98105

99106
// This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt()

src/hyperlight_guest/src/host_error.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,24 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
use core::ffi::c_void;
1817
use core::slice::from_raw_parts;
1918

2019
use hyperlight_common::flatbuffer_wrappers::guest_error::{ErrorCode, GuestError};
2120

22-
use crate::P_PEB;
21+
use crate::PEB;
2322

2423
pub(crate) fn check_for_host_error() {
2524
unsafe {
26-
let peb_ptr = P_PEB.unwrap();
27-
let guest_error_buffer_ptr = (*peb_ptr).guestErrorData.guestErrorBuffer as *mut u8;
28-
let guest_error_buffer_size = (*peb_ptr).guestErrorData.guestErrorSize as usize;
25+
// TODO(danbugs:297): shouldn't this be `host_error_data_*`?
26+
let guest_error_buffer_ptr = (*PEB).guest_error_data_ptr as *mut u8;
27+
let guest_error_buffer_size = (*PEB).guest_error_data_size as usize;
2928

3029
let guest_error_buffer = from_raw_parts(guest_error_buffer_ptr, guest_error_buffer_size);
3130

3231
if !guest_error_buffer.is_empty() {
3332
let guest_error = GuestError::try_from(guest_error_buffer).expect("Invalid GuestError");
3433
if guest_error.code != ErrorCode::NoError {
35-
(*peb_ptr).outputdata.outputDataBuffer = usize::MAX as *mut c_void;
34+
(*PEB).output_data_ptr = u64::MAX;
3635
panic!(
3736
"Guest Error: {:?} - {}",
3837
guest_error.code, guest_error.message

0 commit comments

Comments
 (0)