Skip to content

Commit 855dcfe

Browse files
authored
Merge branch 'main' into clippy-updates
2 parents fe4fe13 + ea6fa8f commit 855dcfe

File tree

15 files changed

+579
-26
lines changed

15 files changed

+579
-26
lines changed

src/hyperlight_guest_bin/build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ fn cargo_main() {
8888
// targets will eventually show up.
8989
cfg.flag("--target=x86_64-unknown-linux-none");
9090

91+
// We don't use a different stack for all interrupts, so there
92+
// can be no red zone
93+
cfg.flag("-mno-red-zone");
94+
9195
// We don't support stack protectors at the moment, but Arch Linux clang
9296
// auto-enables them for -linux platforms, so explicitly disable them.
9397
cfg.flag("-fno-stack-protector");
@@ -245,6 +249,7 @@ fn main() -> std::process::ExitCode {
245249
"-fno-stack-protector",
246250
"-fstack-clash-protection",
247251
"-mstack-probe-size=4096",
252+
"-mno-red-zone",
248253
])
249254
.arg("-nostdinc")
250255
.arg("-isystem")

src/hyperlight_guest_bin/src/exceptions/handler.rs

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,89 @@ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2121
use hyperlight_common::outb::Exception;
2222
use hyperlight_guest::exit::abort_with_code_and_message;
2323

24+
use crate::paging;
25+
26+
/// See AMD64 Architecture Programmer's Manual, Volume 2
27+
/// §8.9.3 Interrupt Stack Frame, pp. 283--284
28+
/// Figure 8-14: Long-Mode Stack After Interrupt---Same Privilege,
29+
/// Figure 8-15: Long-Mode Stack After Interrupt---Higher Privilege
30+
/// Subject to the proviso that we push a dummy error code of 0 for exceptions
31+
/// for which the processor does not provide one
32+
#[repr(C)]
33+
pub struct ExceptionInfo {
34+
pub error_code: u64,
35+
pub rip: u64,
36+
pub cs: u64,
37+
pub rflags: u64,
38+
pub rsp: u64,
39+
pub ss: u64,
40+
}
41+
const _: () = assert!(core::mem::offset_of!(ExceptionInfo, rip) == 8);
42+
const _: () = assert!(core::mem::offset_of!(ExceptionInfo, rsp) == 32);
43+
44+
#[repr(C)]
45+
/// Saved context, pushed onto the stack by exception entry code
46+
pub struct Context {
47+
/// in order: gs, fs, es
48+
pub segments: [u64; 3],
49+
pub fxsave: [u8; 512],
50+
pub ds: u64,
51+
/// no `rsp`, since the processor saved it
52+
/// `rax` is at the top, `r15` the bottom
53+
pub gprs: [u64; 15],
54+
}
55+
const _: () = assert!(size_of::<Context>() == 152 + 512);
56+
57+
// TODO: This will eventually need to end up in a per-thread context,
58+
// when there are threads.
59+
pub static handlers: [core::sync::atomic::AtomicU64; 31] =
60+
[const { core::sync::atomic::AtomicU64::new(0) }; 31];
61+
type handler_t = fn(n: u64, info: *mut ExceptionInfo, ctx: *mut Context, pf_addr: u64) -> bool;
62+
2463
/// Exception handler
2564
#[unsafe(no_mangle)]
2665
pub extern "C" fn hl_exception_handler(
2766
stack_pointer: u64,
2867
exception_number: u64,
2968
page_fault_address: u64,
3069
) {
70+
let ctx = stack_pointer as *mut Context;
71+
let exn_info = (stack_pointer + size_of::<Context>() as u64) as *mut ExceptionInfo;
72+
3173
let exception = Exception::try_from(exception_number as u8).expect("Invalid exception number");
74+
75+
let saved_rip = unsafe { (&raw const (*exn_info).rip).read_volatile() };
76+
let error_code = unsafe { (&raw const (*exn_info).error_code).read_volatile() };
77+
3278
let msg = format!(
33-
"Page Fault Address: {:#x}\n\
34-
Stack Pointer: {:#x}",
35-
page_fault_address, stack_pointer
79+
"Exception vector: {:#}\n\
80+
Faulting Instruction: {:#x}\n\
81+
Page Fault Address: {:#x}\n\
82+
Error code: {:#x}\n\
83+
Stack Pointer: {:#x}",
84+
exception_number, saved_rip, page_fault_address, error_code, stack_pointer
3685
);
3786

87+
// We don't presently have any need for user-defined interrupts,
88+
// so we only support handlers for the architecture-defined
89+
// vectors (0-31)
90+
if exception_number < 31 {
91+
let handler =
92+
handlers[exception_number as usize].load(core::sync::atomic::Ordering::Acquire);
93+
if handler != 0
94+
&& unsafe {
95+
core::mem::transmute::<_, handler_t>(handler)(
96+
exception_number,
97+
exn_info,
98+
ctx,
99+
page_fault_address,
100+
)
101+
}
102+
{
103+
return;
104+
}
105+
}
106+
38107
unsafe {
39108
abort_with_code_and_message(
40109
&[ErrorCode::GuestError as u8, exception as u8],

src/hyperlight_guest_bin/src/exceptions/interrupt_entry.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,19 @@ macro_rules! context_save {
6767
" push r13\n",
6868
" push r14\n",
6969
" push r15\n",
70-
// Save segment registers
70+
// Save one of the segment registers to get 16-byte alignment for
71+
// FXSAVE. TODO: consider packing the segment registers
7172
" mov rax, ds\n",
7273
" push rax\n",
74+
// Save floating-point/SSE registers
75+
// TODO: Don't do this unconditionally: get the exn
76+
// handlers compiled without sse
77+
// TODO: Check if we ever generate code with ymm/zmm in
78+
// the handlers and save/restore those as well
79+
" sub rsp, 512\n",
80+
" mov rax, rsp\n",
81+
" fxsave [rax]\n",
82+
// Save the rest of the segment registers
7383
" mov rax, es\n",
7484
" push rax\n",
7585
" mov rax, fs\n",
@@ -83,13 +93,18 @@ macro_rules! context_save {
8393
macro_rules! context_restore {
8494
() => {
8595
concat!(
86-
// Restore segment registers
96+
// Restore most segment registers
8797
" pop rax\n",
8898
" mov gs, rax\n",
8999
" pop rax\n",
90100
" mov fs, rax\n",
91101
" pop rax\n",
92102
" mov es, rax\n",
103+
// Restore floating-point/SSE registers
104+
" mov rax, rsp\n",
105+
" fxrstor [rax]\n",
106+
" add rsp, 512\n",
107+
// Restore the last segment register
93108
" pop rax\n",
94109
" mov ds, rax\n",
95110
// Restore general-purpose registers
@@ -123,7 +138,8 @@ macro_rules! generate_exceptions {
123138
" mov rdi, rsp\n",
124139
" call {hl_exception_handler}\n",
125140
context_restore!(),
126-
" iretq\n", // iretq is used to return from exception in x86_64
141+
" add rsp, 8\n", // error code
142+
" iretq\n", // iretq is used to return from exception in x86_64
127143
generate_excp!(0, pusherrcode),
128144
generate_excp!(1, pusherrcode),
129145
generate_excp!(2, pusherrcode),

src/hyperlight_guest_bin/src/guest_function/call.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ fn internal_dispatch_function() -> Result<()> {
101101
// which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return
102102
// when running in the hypervisor.
103103
pub(crate) extern "C" fn dispatch_function() {
104+
// The hyperlight host likes to use one partition and reset it in
105+
// various ways; if that has happened, there might stale TLB
106+
// entries hanging around from the former user of the
107+
// partition. Flushing the TLB here is not quite the right thing
108+
// to do, since incorrectly cached entries could make even this
109+
// code not exist, but regrettably there is not a simple way for
110+
// the host to trigger flushing when it ought to happen, so for
111+
// now this works in practice, since the text segment is always
112+
// part of the big identity-mapped region at the base of the
113+
// guest.
114+
crate::paging::flush_tlb();
104115
let _ = internal_dispatch_function();
105116
halt();
106117
}

src/hyperlight_guest_bin/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ use spin::Once;
3535

3636
// === Modules ===
3737
#[cfg(target_arch = "x86_64")]
38-
mod exceptions {
38+
pub mod exceptions {
3939
pub(super) mod gdt;
40-
mod handler;
40+
pub mod handler;
4141
mod idt;
4242
pub(super) mod idtr;
4343
mod interrupt_entry;
@@ -52,6 +52,7 @@ pub mod guest_function {
5252
pub mod guest_logger;
5353
pub mod host_comm;
5454
pub mod memory;
55+
pub mod paging;
5556

5657
// === Globals ===
5758
#[global_allocator]

0 commit comments

Comments
 (0)