hyperlight_guest_bin/arch/amd64/context.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025 The Hyperlight Authors.
3
4use super::machine::ExceptionInfo;
5
6#[repr(C)]
7/// Saved context, pushed onto the stack by exception entry code
8pub struct Context {
9 /// in order: ds, gs, fs, es
10 pub segments: [u64; 4],
11 pub fxsave: [u8; 512],
12 /// no `rsp`, since the processor saved it
13 /// `rax` is at the top, `r15` the bottom
14 pub gprs: [u64; 15],
15 _padding: u64,
16}
17const _: () = assert!(size_of::<Context>() == 32 + 512 + 120 + 8);
18// The combination of the ExceptionInfo (pushed by the CPU) and the
19// register Context that we save to the stack must be 16byte aligned
20// before calling the hl_exception_handler as specified in the x86-64
21// ELF System V psABI specification, Section 3.2.2:
22//
23// https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build
24const _: () = assert!((size_of::<Context>() + size_of::<ExceptionInfo>()).is_multiple_of(16));
25
26// Defines `context_save` and `context_restore`
27macro_rules! save {
28 () => {
29 concat!(
30 // Save general-purpose registers
31 " sub rsp, 8\n",
32 " push rax\n",
33 " push rbx\n",
34 " push rcx\n",
35 " push rdx\n",
36 " push rsi\n",
37 " push rdi\n",
38 " push rbp\n",
39 " push r8\n",
40 " push r9\n",
41 " push r10\n",
42 " push r11\n",
43 " push r12\n",
44 " push r13\n",
45 " push r14\n",
46 " push r15\n",
47 // Save floating-point/SSE registers
48 // TODO: Don't do this unconditionally: get the exn
49 // handlers compiled without sse
50 // TODO: Check if we ever generate code with ymm/zmm in
51 // the handlers and save/restore those as well
52 " sub rsp, 512\n",
53 " mov rax, rsp\n",
54 " fxsave [rax]\n",
55 // Save the rest of the segment registers
56 " mov rax, es\n",
57 " push rax\n",
58 " mov rax, fs\n",
59 " push rax\n",
60 " mov rax, gs\n",
61 " push rax\n",
62 " mov rax, ds\n",
63 " push rax\n",
64 )
65 };
66}
67pub(super) use save;
68
69macro_rules! restore {
70 () => {
71 concat!(
72 // Restore most segment registers
73 " pop rax\n",
74 " mov ds, rax\n",
75 " pop rax\n",
76 " mov gs, rax\n",
77 " pop rax\n",
78 " mov fs, rax\n",
79 " pop rax\n",
80 " mov es, rax\n",
81 // Restore floating-point/SSE registers
82 " mov rax, rsp\n",
83 " fxrstor [rax]\n",
84 " add rsp, 512\n",
85 // Restore general-purpose registers
86 " pop r15\n",
87 " pop r14\n",
88 " pop r13\n",
89 " pop r12\n",
90 " pop r11\n",
91 " pop r10\n",
92 " pop r9\n",
93 " pop r8\n",
94 " pop rbp\n",
95 " pop rdi\n",
96 " pop rsi\n",
97 " pop rdx\n",
98 " pop rcx\n",
99 " pop rbx\n",
100 " pop rax\n",
101 " add rsp, 8\n",
102 )
103 };
104}
105pub(super) use restore;