Skip to main content

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;