Skip to content

Commit e0386c3

Browse files
authored
Merge branch 'main' into bump_0.2.0
2 parents ad30a48 + 8eafa0d commit e0386c3

File tree

10 files changed

+569
-12
lines changed

10 files changed

+569
-12
lines changed

src/hyperlight_guest/src/entrypoint.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ use hyperlight_common::mem::{HyperlightPEB, RunMode};
2222
use log::LevelFilter;
2323
use spin::Once;
2424

25+
use crate::gdt::load_gdt;
2526
use crate::guest_error::reset_error;
2627
use crate::guest_function_call::dispatch_function;
2728
use crate::guest_logger::init_logger;
2829
use crate::host_function_call::{outb, OutBAction};
30+
use crate::idtr::load_idt;
2931
use crate::{
3032
__security_cookie, HEAP_ALLOCATOR, MIN_STACK_ADDRESS, OS_PAGE_SIZE, OUTB_PTR,
3133
OUTB_PTR_WITH_CONTEXT, P_PEB, RUNNING_MODE,
@@ -104,6 +106,10 @@ pub extern "win64" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_
104106
// It also means that should we change the layout of the struct in the future, we
105107
// don't have to change the assembly code.
106108
MIN_STACK_ADDRESS = (*peb_ptr).gueststackData.minUserStackAddress;
109+
110+
// Setup GDT and IDT
111+
load_gdt();
112+
load_idt();
107113
}
108114
RunMode::InProcessLinux | RunMode::InProcessWindows => {
109115
RUNNING_MODE = (*peb_ptr).runMode;

src/hyperlight_guest/src/gdt.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
Copyright 2024 The Hyperlight Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
use core::arch::asm;
18+
use core::ptr::addr_of;
19+
20+
/// Entry in the Global Descriptor Table (GDT)
21+
/// For reference, see page 3-10 Vol. 3A of Intel 64 and IA-32
22+
/// Architectures Software Developer's Manual, figure 3-8
23+
/// (https://i.imgur.com/1i9xUmx.png).
24+
/// From the bottom, we have:
25+
/// - segment limit 15..0 = limit_low
26+
/// - base address 31..16 = base_low
27+
/// - base 23..16 = base_middle
28+
/// - p dpl s type 15..8 = access
29+
/// - p d/b l avl seg. limit 23..16 = flags_limit
30+
/// - base 31..24 = base_high
31+
#[repr(C, align(8))]
32+
pub struct GdtEntry {
33+
limit_low: u16,
34+
base_low: u16,
35+
base_middle: u8,
36+
access: u8,
37+
flags_limit: u8,
38+
base_high: u8,
39+
}
40+
41+
impl GdtEntry {
42+
/// Creates a new GDT entry.
43+
pub const fn new(base: u32, limit: u32, access: u8, flags: u8) -> Self {
44+
Self {
45+
base_low: (base & 0xffff) as u16,
46+
base_middle: ((base >> 16) & 0xff) as u8,
47+
base_high: ((base >> 24) & 0xff) as u8,
48+
limit_low: (limit & 0xffff) as u16,
49+
flags_limit: (((limit >> 16) & 0x0f) as u8) | ((flags & 0x0f) << 4),
50+
access,
51+
}
52+
}
53+
}
54+
55+
// Global Descriptor Table (GDT)
56+
// For reference, see page 2-3 Vol. 3A of Intel 64 and IA-32
57+
// Architectures Software Developer's Manual.
58+
static mut GDT: [GdtEntry; 3] = [
59+
// Null descriptor
60+
GdtEntry::new(0, 0, 0, 0),
61+
// Kernel Code Segment (0x08)
62+
GdtEntry::new(0, 0, 0x9A, 0xA),
63+
// Kernel Data Segment (0x10)
64+
GdtEntry::new(0, 0, 0x92, 0xC),
65+
];
66+
67+
/// GDTR (GDT pointer)
68+
#[repr(C, packed)]
69+
struct GdtPointer {
70+
size: u16,
71+
base: u64,
72+
}
73+
74+
/// Load the GDT
75+
pub unsafe fn load_gdt() {
76+
let gdt_ptr = GdtPointer {
77+
size: (core::mem::size_of::<[GdtEntry; 3]>() - 1) as u16,
78+
base: addr_of!(GDT) as *const _ as u64,
79+
};
80+
81+
asm!(
82+
"lgdt [{0}]",
83+
"mov ax, 0x10", // Load data segment registers
84+
"mov ds, ax",
85+
"mov es, ax",
86+
"mov fs, ax",
87+
"mov gs, ax",
88+
"mov ss, ax",
89+
"push 0x08", // Push CS (kernel code segment)
90+
"lea rax, [2f + rip]", // Load the next instruction's address
91+
"push rax", // Push address onto stack
92+
"retfq", // Far return to update CS
93+
"2:", // Label for continued execution
94+
in(reg) &gdt_ptr,
95+
options(nostack, preserves_flags)
96+
);
97+
}

src/hyperlight_guest/src/idt.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
Copyright 2024 The Hyperlight Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
use crate::interrupt_entry::{
18+
_do_excp0, _do_excp1, _do_excp10, _do_excp11, _do_excp12, _do_excp13, _do_excp14, _do_excp15,
19+
_do_excp16, _do_excp17, _do_excp18, _do_excp19, _do_excp2, _do_excp20, _do_excp3, _do_excp30,
20+
_do_excp4, _do_excp5, _do_excp6, _do_excp7, _do_excp8, _do_excp9,
21+
};
22+
23+
// An entry in the Interrupt Descriptor Table (IDT)
24+
// For reference, see page 7-20 Vol. 3A of Intel 64 and IA-32
25+
// Architectures Software Developer's Manual, figure 7-8
26+
// (i.e., https://i.imgur.com/N4rEjHj.png).
27+
// From the bottom, we have:
28+
// - offset 15..0 = offset_low
29+
// - segment selector 31..16 = selector
30+
// - 000 0 0 Interrupt Stack Table 7..0 = interrupt_stack_table_offset
31+
// - p dpl 0 type 15..8 = type_attr
32+
// - offset 31..16 = offset_mid
33+
// - offset 63..32 = offset_high
34+
// - reserved 31..0 = zero
35+
#[repr(C, align(16))]
36+
pub(crate) struct IdtEntry {
37+
offset_low: u16, // Lower 16 bits of handler address
38+
selector: u16, // code segment selector in GDT
39+
interrupt_stack_table_offset: u8, // Interrupt Stack Table offset
40+
type_attr: u8, // Gate type and flags
41+
offset_mid: u16, // Middle 16 bits of handler address
42+
offset_high: u32, // High 32 bits of handler address
43+
zero: u32, // Reserved (always 0)
44+
}
45+
46+
impl IdtEntry {
47+
fn new(handler: u64) -> Self {
48+
Self {
49+
offset_low: (handler & 0xFFFF) as u16,
50+
selector: 0x08, // Kernel Code Segment
51+
interrupt_stack_table_offset: 0, // No interrupt stack table used
52+
type_attr: 0x8E,
53+
// 0x8E = 10001110b
54+
// 1 00 0 1110
55+
// 1 = Present
56+
// 00 = Descriptor Privilege Level (0)
57+
// 0 = Storage Segment (0)
58+
// 1110 = Gate Type (0b1110 = 14 = 0xE)
59+
// 0xE means it's an interrupt gate
60+
offset_mid: ((handler >> 16) & 0xFFFF) as u16,
61+
offset_high: ((handler >> 32) & 0xFFFFFFFF) as u32,
62+
zero: 0,
63+
}
64+
}
65+
}
66+
67+
// The IDT is an array of 256 IDT entries
68+
// (for reference, see page 7-9 Vol. 3A of Intel 64 and IA-32
69+
// Architectures Software Developer's Manual).
70+
pub(crate) static mut IDT: [IdtEntry; 256] = unsafe { core::mem::zeroed() };
71+
72+
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
95+
}
96+
97+
fn set_idt_entry(index: usize, handler: unsafe extern "sysv64" fn()) {
98+
let handler_addr = handler as *const () as u64;
99+
unsafe {
100+
IDT[index] = IdtEntry::new(handler_addr);
101+
}
102+
}

src/hyperlight_guest/src/idtr.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use core::ptr::addr_of;
2+
3+
use crate::idt::{init_idt, IdtEntry, IDT};
4+
5+
#[repr(C, packed)]
6+
pub struct Idtr {
7+
pub limit: u16,
8+
pub base: u64,
9+
}
10+
11+
static mut IDTR: Idtr = Idtr { limit: 0, base: 0 };
12+
13+
impl Idtr {
14+
pub unsafe fn init(&mut self, base: u64, size: u16) {
15+
self.limit = size - 1;
16+
self.base = base;
17+
}
18+
19+
pub unsafe fn load(&self) {
20+
core::arch::asm!("lidt [{}]", in(reg) self, options(readonly, nostack, preserves_flags));
21+
}
22+
}
23+
24+
pub(crate) unsafe fn load_idt() {
25+
init_idt();
26+
27+
let idt_size = 256 * size_of::<IdtEntry>();
28+
let expected_base = addr_of!(IDT) as *const _ as u64;
29+
30+
IDTR.init(expected_base, idt_size as u16);
31+
IDTR.load();
32+
}

0 commit comments

Comments
 (0)