Skip to content

Change host's memory setup to be minimally configured #297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
09bb04e
[.gitignore] added .gdbinit to .gitignore
danbugs Mar 17, 2025
261a797
[docs] updates paging docs
danbugs Mar 19, 2025
5d75c61
[host/{mem/layout,sandbox/mem_mgr}] removes statically defined mem la…
danbugs Mar 19, 2025
e7183ce
[common,guest] added peb and input/output API to common library
danbugs Mar 19, 2025
c1c5781
[host/{mem/region,sandbox{config,builder,uninit}] introduces SandboxB…
danbugs Mar 19, 2025
45f2628
[guest,tests/rust_guests] change guest library to conform to new APIs…
danbugs Mar 19, 2025
9b80eaf
[host/mem/mgr] changes SandboxMemoryManager API to interact w/ CGM
danbugs Mar 19, 2025
39b4ddf
[host/*] change API usage (MemoryRegions, MemMgrWrapper, etc.) across…
danbugs Mar 19, 2025
d90ea82
[host/hypervisor/[*]] update drivers to use CGM
danbugs Mar 19, 2025
5ece18a
[*] clippy fix and fmt
danbugs Apr 11, 2025
4977791
[common,guest] moved outb functionality to hyperlight_common and adde…
danbugs Apr 14, 2025
cba4609
[common/input_output] making input_output stacks portable
danbugs Apr 14, 2025
0bd58d9
[guest,host,common] removed uneeded entrypoint arg
danbugs Apr 15, 2025
849ff55
[guest,host,common] brought back in-process driver
danbugs Apr 16, 2025
b310ebb
[host/hypervisor/hyperv_linux] brought back mshv driver
danbugs Apr 17, 2025
ea4a71a
[host/hypervisor/hyperv_windows] brought back whp driver
danbugs Apr 17, 2025
922b630
[host/{hypervisor/{*drivers,crashdump},sandbox/builder}] re-added cra…
danbugs Apr 17, 2025
58dd56f
[common,guest,host] modified HyperlightPEB API + added rsp mod in hosts
danbugs Apr 17, 2025
38452e0
[common,guest,host] refactored guest and host error data regions
danbugs Apr 19, 2025
6415498
[host,simpleguest] removed remaining references to HostPrint
danbugs Apr 19, 2025
832240d
[host/sandbox/{mem_access,uninit_evolve}] brought back mem_access_han…
danbugs Apr 20, 2025
3273fb1
[host/mem] removed tests in mem/mgr
danbugs Apr 21, 2025
7bfd798
[guest,host/leaked_outb] Fixed inprocess execution for Windows
danbugs Apr 21, 2025
ca42784
[guest/{chkstk,entrypoint},host/{drivers,sandbox_builder},common/peb,…
danbugs Apr 24, 2025
a80a756
[*] bring back tests + benchmarks + fuzzing + examples
danbugs Apr 24, 2025
c76215f
[*] remove uses of panic/unwrap/expect
danbugs Apr 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 244 additions & 0 deletions src/hyperlight_common/src/hyperlight_peb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
use crate::PAGE_SIZE;

/// Hyperlight supports 2 primary modes:
/// 1. Hypervisor mode
/// 2. In-process mode
///
/// When running in process, there's no hypervisor isolation.
/// In-process mode is primarily used for debugging and testing.
#[repr(u64)]
#[derive(Clone, Debug, PartialEq, Default)]
pub enum RunMode {
None = 0,
#[default]
Hypervisor = 1,
InProcessWindows = 2,
InProcessLinux = 3,
Invalid = 4,
}

#[repr(C)]
#[derive(Clone, Default)]
pub struct HyperlightPEB {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that all of these fields should be updated rarely, what's the benefit of placing this structure in shared memory (where it consumes an entire page & host accesses might race with guest accesses) over just having dedicated exits (outb actions) to set the ones that need to be setable?

// - Host configured fields
/// Hyperlight supports two primary modes:
/// 1. Hypervisor mode
/// 2. In-process mode
///
/// When running in process, there's no hypervisor isolation.
/// It's a mode primarily used for debugging and testing.
pub run_mode: RunMode,

/// On Windows, Hyperlight supports in-process execution.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a preexisting issue, but perhaps take the opportunity to clarify that this isn't windows-only anymore?

/// In-process execution means a guest is running in
/// Hyperlight, but with no hypervisor isolation. When we
/// run in-process, we can't rely on the usual mechanism for
/// host function calls (i.e., `outb`). Instead, we call a
/// function directly, which is represented by this pointer.
pub outb_ptr: u64,

/// The base address for the guest memory region.
pub guest_memory_base_address: u64,

/// The size of the guest memory region.
pub guest_memory_size: u64,

// - Guest configured fields
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we refer to guest configured fields does this mean for hyperlight guests rather than something like Nanvix? If so we should probably make this clear here? Also not clear why this is in hypleright common if this is the case?

/// The guest function dispatch pointer is what allows
/// a host to call "guest functions". The host can
/// directly set the instruction pointer register to this
/// before re-entering the guest.
pub guest_function_dispatch_ptr: u64,

/// Guest error data can be used to pass guest error information
/// between host and the guest.
pub guest_error_data_ptr: u64,
pub guest_error_data_size: u64,

/// Host error data can be used to pass host error information
/// between the host and the guest.
pub host_error_data_ptr: u64,
pub host_error_data_size: u64,

/// The input data pointer is used to pass data from
/// the host to the guest.
pub input_data_ptr: u64,
pub input_data_size: u64,

/// The output data pointer is used to pass data from
/// the guest to the host.
pub output_data_ptr: u64,
pub output_data_size: u64,

/// The guest panic context pointer can be used to pass
/// panic context data from the guest to the host.
pub guest_panic_context_ptr: u64,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This question might be answered later but how would an early panic be handled (i.e. before this memory was located/accessible - maybe this cannot happen) or if the pointer or length is zero, any reason why this is not statically defined?

pub guest_panic_context_size: u64,

/// The guest heap data pointer points to a region of
/// memory in the guest that is used for heap allocations.
pub guest_heap_data_ptr: u64,
pub guest_heap_data_size: u64,

/// The guest stack data pointer points to a region of
/// memory in the guest that is used for stack allocations.
pub guest_stack_data_ptr: u64,
pub guest_stack_data_size: u64,

// Host function details may be used in the guest before
// issuing a host function call to validate it before
// ensuing a `VMEXIT`.
pub host_function_details_ptr: u64,
pub host_function_details_size: u64,
}

impl HyperlightPEB {
pub fn set_default_memory_layout(&mut self) {
// we set the guest stack at the start of the guest memory region to leverage
// the stack guard page before it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't the guest setting up this guard page by itself?

self.set_guest_stack_data_region(
self.guest_memory_base_address, // start at base of custom guest memory region,
None, // don't override the stack size
);

let guest_stack_size = self.get_guest_stack_data_size();

self.set_guest_heap_data_region(
guest_stack_size, // start at the end of the stack
None, // don't override the heap size
);

let guest_heap_size = self.get_guest_heap_data_size();

self.set_guest_error_data_region(
guest_stack_size + guest_heap_size as u64, // start at the end of the host function details
PAGE_SIZE as u64, // 4KB
);

self.set_host_error_data_region(
guest_stack_size + guest_heap_size + PAGE_SIZE as u64, // start at the end of the guest error data
PAGE_SIZE as u64, // 4KB
);

self.set_input_data_region(
guest_stack_size + guest_heap_size + PAGE_SIZE as u64 * 2, // start at the end of the host error data
PAGE_SIZE as u64 * 4, // 16KB
);

self.set_output_data_region(
guest_stack_size + guest_heap_size + PAGE_SIZE as u64 * 6, // start at the end of the input data
PAGE_SIZE as u64 * 4, // 16KB
);

self.set_guest_panic_context_region(
guest_stack_size + guest_heap_size + PAGE_SIZE as u64 * 10, // start at the end of the output data
PAGE_SIZE as u64, // 4KB
);

self.set_host_function_details_region(
guest_stack_size + guest_heap_size + PAGE_SIZE as u64 * 11, // start at the end of the guest panic context
PAGE_SIZE as u64, // 4KB
);
}

// Sets the guest error data region, where the guest can write errors to.
pub fn set_guest_error_data_region(&mut self, ptr: u64, size: u64) {
self.guest_error_data_ptr = self.guest_memory_base_address + ptr;
self.guest_error_data_size = size;
}

// Sets the host error data region, where the host can write errors to.
pub fn set_host_error_data_region(&mut self, ptr: u64, size: u64) {
self.host_error_data_ptr = self.guest_memory_base_address + ptr;
self.host_error_data_size = size;
}

// Sets the input data region, where the host can write things like function calls to.
pub fn set_input_data_region(&mut self, ptr: u64, size: u64) {
self.input_data_ptr = self.guest_memory_base_address + ptr;
self.input_data_size = size;
}

// Sets the output data region, where the guest can write things like function return values to.
pub fn set_output_data_region(&mut self, ptr: u64, size: u64) {
self.output_data_ptr = self.guest_memory_base_address + ptr;
self.output_data_size = size;
}

// Sets the guest panic context region, where the guest can write panic context data to.
pub fn set_guest_panic_context_region(&mut self, ptr: u64, size: u64) {
self.guest_panic_context_ptr = self.guest_memory_base_address + ptr;
self.guest_panic_context_size = size;
}

// Gets the guest heap size. If not set, this function panics—this is because the host is always
// expected to set the size of the heap data region in accordance to info from the guest binary,
// so, if this is not set, we have a critical error.
pub fn get_guest_heap_data_size(&self) -> u64 {
if self.guest_heap_data_size == 0 {
panic!("Heap data size is not set");
}

self.guest_heap_data_size
}

// Sets the guest heap data region.
pub fn set_guest_heap_data_region(&mut self, ptr: u64, size_override: Option<u64>) {
self.guest_heap_data_ptr = self.guest_memory_base_address + ptr;
// the Hyperlight host always sets the heap data size to a default value, the
// guest has the option to override it.
if let Some(size) = size_override {
self.guest_heap_data_size = size;
}

// If by this point the size is still None, we have a critical error
// and we should panic.
if self.guest_heap_data_size == 0 {
panic!("Heap data size is 0 after setting guest heap data region");
}
}

// Gets the guest heap size. If not set, this function panics—this is because the host is always
// expected to set the size of the heap data region in accordance to info from the guest binary,
// so, if this is not set, we have a critical error.
pub fn get_guest_stack_data_size(&self) -> u64 {
if self.guest_stack_data_size == 0 {
panic!("Stack data size is not set");
}

self.guest_stack_data_size
}

// Sets the guest stack data region.
pub fn set_guest_stack_data_region(&mut self, ptr: u64, size_override: Option<u64>) {
self.guest_stack_data_ptr = self.guest_memory_base_address + ptr;

// the Hyperlight host always sets the stack data size to a default value, the
// guest has the option to override it.
if let Some(size) = size_override {
self.guest_stack_data_size = size;
}

// If by this point the size is still None, we have a critical error
// and we should panic.
if self.guest_stack_data_size == 0 {
panic!("Stack data size is 0 after setting guest stack data region");
}
}

// Sets the host function details region, where the guest can write host function details to.
pub fn set_host_function_details_region(&mut self, ptr: u64, size: u64) {
self.host_function_details_ptr = self.guest_memory_base_address + ptr;
self.host_function_details_size = size;
}

// Gets the input data region, where the host can write things like function calls to.
pub fn get_input_data_region(&self) -> (u64, u64) {
(self.input_data_ptr, self.input_data_size)
}

// Gets the output data region, where the guest can write things like function return values to.
pub fn get_output_data_region(&self) -> (u64, u64) {
(self.output_data_ptr, self.output_data_size)
}
}
Loading