Skip to content

Commit 5950288

Browse files
committed
Unify register representation
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent e302469 commit 5950288

File tree

20 files changed

+2120
-1240
lines changed

20 files changed

+2120
-1240
lines changed

src/hyperlight_host/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ cfg_aliases = "0.2.1"
124124
built = { version = "0.8.0", optional = true, features = ["chrono", "git2"] }
125125

126126
[features]
127-
default = ["kvm", "mshv3", "seccomp", "build-metadata", "init-paging"]
127+
default = ["kvm", "mshv3", "seccomp", "build-metadata", "init-paging", "gdb"]
128128
seccomp = ["dep:seccompiler"]
129129
function_call_metrics = []
130130
executable_heap = []

src/hyperlight_host/src/hypervisor/gdb/hyperv_debug.rs

Lines changed: 29 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ use std::collections::HashMap;
1919
use windows::Win32::System::Hypervisor::WHV_VP_EXCEPTION_CONTEXT;
2020

2121
use super::arch::{MAX_NO_OF_HW_BP, vcpu_stop_reason};
22-
use super::{GuestDebug, SW_BP_SIZE, VcpuStopReason, X86_64Regs};
22+
use super::{GuestDebug, SW_BP_SIZE, VcpuStopReason};
23+
use crate::hypervisor::regs::{CommonFpu, CommonRegisters};
2324
use crate::hypervisor::windows_hypervisor_platform::VMProcessor;
24-
use crate::hypervisor::wrappers::{WHvDebugRegisters, WHvGeneralRegisters};
25+
use crate::hypervisor::wrappers::WHvDebugRegisters;
2526
use crate::{HyperlightError, Result, new_error};
2627

2728
/// KVM Debug struct
@@ -54,7 +55,7 @@ impl HypervDebug {
5455
/// Returns the instruction pointer from the stopped vCPU
5556
fn get_instruction_pointer(&self, vcpu_fd: &VMProcessor) -> Result<u64> {
5657
let regs = vcpu_fd
57-
.get_regs()
58+
.regs()
5859
.map_err(|e| new_error!("Could not retrieve registers from vCPU: {:?}", e))?;
5960

6061
Ok(regs.rip)
@@ -103,7 +104,7 @@ impl HypervDebug {
103104
self.single_step = step;
104105

105106
let mut regs = vcpu_fd
106-
.get_regs()
107+
.regs()
107108
.map_err(|e| new_error!("Could not get registers: {:?}", e))?;
108109

109110
// Set TF Flag to enable Traps
@@ -114,7 +115,7 @@ impl HypervDebug {
114115
}
115116

116117
vcpu_fd
117-
.set_general_purpose_registers(&regs)
118+
.set_regs(&regs)
118119
.map_err(|e| new_error!("Could not set guest registers: {:?}", e))?;
119120

120121
Ok(())
@@ -185,45 +186,17 @@ impl GuestDebug for HypervDebug {
185186
self.sw_breakpoints.remove(addr)
186187
}
187188

188-
fn read_regs(&self, vcpu_fd: &Self::Vcpu, regs: &mut X86_64Regs) -> Result<()> {
189+
fn read_regs(&self, vcpu_fd: &Self::Vcpu) -> Result<(CommonRegisters, CommonFpu)> {
189190
log::debug!("Read registers");
190-
let vcpu_regs = vcpu_fd
191-
.get_regs()
191+
let regs = vcpu_fd
192+
.regs()
192193
.map_err(|e| new_error!("Could not read guest registers: {:?}", e))?;
193194

194-
regs.rax = vcpu_regs.rax;
195-
regs.rbx = vcpu_regs.rbx;
196-
regs.rcx = vcpu_regs.rcx;
197-
regs.rdx = vcpu_regs.rdx;
198-
regs.rsi = vcpu_regs.rsi;
199-
regs.rdi = vcpu_regs.rdi;
200-
regs.rbp = vcpu_regs.rbp;
201-
regs.rsp = vcpu_regs.rsp;
202-
regs.r8 = vcpu_regs.r8;
203-
regs.r9 = vcpu_regs.r9;
204-
regs.r10 = vcpu_regs.r10;
205-
regs.r11 = vcpu_regs.r11;
206-
regs.r12 = vcpu_regs.r12;
207-
regs.r13 = vcpu_regs.r13;
208-
regs.r14 = vcpu_regs.r14;
209-
regs.r15 = vcpu_regs.r15;
210-
211-
regs.rip = vcpu_regs.rip;
212-
regs.rflags = vcpu_regs.rflags;
213-
214-
// Fetch XMM from WHVP
215-
if let Ok(fpu) = vcpu_fd.get_fpu() {
216-
regs.xmm = [
217-
fpu.xmm0, fpu.xmm1, fpu.xmm2, fpu.xmm3, fpu.xmm4, fpu.xmm5, fpu.xmm6, fpu.xmm7,
218-
fpu.xmm8, fpu.xmm9, fpu.xmm10, fpu.xmm11, fpu.xmm12, fpu.xmm13, fpu.xmm14,
219-
fpu.xmm15,
220-
];
221-
regs.mxcsr = fpu.mxcsr;
222-
} else {
223-
log::warn!("Failed to read FPU/XMM via WHVP for debug registers");
224-
}
195+
let fpu = vcpu_fd
196+
.fpu()
197+
.map_err(|e| new_error!("Could not read guest FPU registers: {:?}", e))?;
225198

226-
Ok(())
199+
Ok((regs, fpu))
227200
}
228201

229202
fn set_single_step(&mut self, vcpu_fd: &Self::Vcpu, enable: bool) -> Result<()> {
@@ -236,62 +209,28 @@ impl GuestDebug for HypervDebug {
236209
.map_err(|_| HyperlightError::TranslateGuestAddress(gva))
237210
}
238211

239-
fn write_regs(&self, vcpu_fd: &Self::Vcpu, regs: &X86_64Regs) -> Result<()> {
212+
fn write_regs(
213+
&self,
214+
vcpu_fd: &Self::Vcpu,
215+
regs: &CommonRegisters,
216+
fpu: &CommonFpu,
217+
) -> Result<()> {
240218
log::debug!("Write registers");
241-
let gprs = WHvGeneralRegisters {
242-
rax: regs.rax,
243-
rbx: regs.rbx,
244-
rcx: regs.rcx,
245-
rdx: regs.rdx,
246-
rsi: regs.rsi,
247-
rdi: regs.rdi,
248-
rbp: regs.rbp,
249-
rsp: regs.rsp,
250-
r8: regs.r8,
251-
r9: regs.r9,
252-
r10: regs.r10,
253-
r11: regs.r11,
254-
r12: regs.r12,
255-
r13: regs.r13,
256-
r14: regs.r14,
257-
r15: regs.r15,
258-
259-
rip: regs.rip,
260-
rflags: regs.rflags,
261-
};
262219

263220
vcpu_fd
264-
.set_general_purpose_registers(&gprs)
221+
.set_regs(regs)
265222
.map_err(|e| new_error!("Could not write guest registers: {:?}", e))?;
266223

267-
// Load existing FPU state, replace XMM and MXCSR, and write it back.
268-
let mut fpu = match vcpu_fd.get_fpu() {
269-
Ok(f) => f,
270-
Err(e) => {
271-
return Err(new_error!("Could not write guest registers: {:?}", e));
272-
}
273-
};
274-
275-
fpu.xmm0 = regs.xmm[0];
276-
fpu.xmm1 = regs.xmm[1];
277-
fpu.xmm2 = regs.xmm[2];
278-
fpu.xmm3 = regs.xmm[3];
279-
fpu.xmm4 = regs.xmm[4];
280-
fpu.xmm5 = regs.xmm[5];
281-
fpu.xmm6 = regs.xmm[6];
282-
fpu.xmm7 = regs.xmm[7];
283-
fpu.xmm8 = regs.xmm[8];
284-
fpu.xmm9 = regs.xmm[9];
285-
fpu.xmm10 = regs.xmm[10];
286-
fpu.xmm11 = regs.xmm[11];
287-
fpu.xmm12 = regs.xmm[12];
288-
fpu.xmm13 = regs.xmm[13];
289-
fpu.xmm14 = regs.xmm[14];
290-
fpu.xmm15 = regs.xmm[15];
291-
fpu.mxcsr = regs.mxcsr;
224+
// Only xmm and mxcsr is piped though in the given fpu, so only set those
225+
let mut current_fpu: CommonFpu = vcpu_fd
226+
.fpu()
227+
.map_err(|e| new_error!("Could not read guest FPU registers: {:?}", e))?;
228+
current_fpu.mxcsr = fpu.mxcsr;
229+
current_fpu.xmm = fpu.xmm;
292230

293231
vcpu_fd
294-
.set_fpu(&fpu)
295-
.map_err(|e| new_error!("Could not write guest registers: {:?}", e))
232+
.set_fpu(&current_fpu)
233+
.map_err(|e| new_error!("Could not write guest FPU registers: {:?}", e))?;
234+
Ok(())
296235
}
297236
}

src/hyperlight_host/src/hypervisor/gdb/kvm_debug.rs

Lines changed: 24 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ use std::collections::HashMap;
1818

1919
use kvm_bindings::{
2020
KVM_GUESTDBG_ENABLE, KVM_GUESTDBG_SINGLESTEP, KVM_GUESTDBG_USE_HW_BP, KVM_GUESTDBG_USE_SW_BP,
21-
kvm_debug_exit_arch, kvm_guest_debug, kvm_regs,
21+
kvm_debug_exit_arch, kvm_guest_debug,
2222
};
2323
use kvm_ioctls::VcpuFd;
2424

2525
use super::arch::{MAX_NO_OF_HW_BP, SW_BP_SIZE, vcpu_stop_reason};
26-
use super::{GuestDebug, VcpuStopReason, X86_64Regs};
26+
use super::{GuestDebug, VcpuStopReason};
27+
use crate::hypervisor::regs::{CommonFpu, CommonRegisters};
2728
use crate::{HyperlightError, Result, new_error};
2829

2930
/// KVM Debug struct
@@ -167,57 +168,29 @@ impl GuestDebug for KvmDebug {
167168
self.sw_breakpoints.remove(addr)
168169
}
169170

170-
fn read_regs(&self, vcpu_fd: &Self::Vcpu, regs: &mut X86_64Regs) -> Result<()> {
171+
fn read_regs(&self, vcpu_fd: &Self::Vcpu) -> Result<(CommonRegisters, CommonFpu)> {
171172
log::debug!("Read registers");
172-
let vcpu_regs = vcpu_fd
173+
let regs = vcpu_fd
173174
.get_regs()
174175
.map_err(|e| new_error!("Could not read guest registers: {:?}", e))?;
175176

176-
regs.rax = vcpu_regs.rax;
177-
regs.rbx = vcpu_regs.rbx;
178-
regs.rcx = vcpu_regs.rcx;
179-
regs.rdx = vcpu_regs.rdx;
180-
regs.rsi = vcpu_regs.rsi;
181-
regs.rdi = vcpu_regs.rdi;
182-
regs.rbp = vcpu_regs.rbp;
183-
regs.rsp = vcpu_regs.rsp;
184-
regs.r8 = vcpu_regs.r8;
185-
regs.r9 = vcpu_regs.r9;
186-
regs.r10 = vcpu_regs.r10;
187-
regs.r11 = vcpu_regs.r11;
188-
regs.r12 = vcpu_regs.r12;
189-
regs.r13 = vcpu_regs.r13;
190-
regs.r14 = vcpu_regs.r14;
191-
regs.r15 = vcpu_regs.r15;
192-
193-
regs.rip = vcpu_regs.rip;
194-
regs.rflags = vcpu_regs.rflags;
195-
196-
// Read XMM registers from FPU state
197-
// note kvm get_fpu doesn't actually set or read the mxcsr value
198-
// https://elixir.bootlin.com/linux/v6.16/source/arch/x86/kvm/x86.c#L12229
199-
match vcpu_fd.get_fpu() {
200-
Ok(fpu) => {
201-
// Convert KVM XMM registers ([u8; 16] x 16) to [u128; 16]
202-
regs.xmm = fpu.xmm.map(u128::from_le_bytes);
203-
}
204-
Err(e) => {
205-
log::warn!("Failed to read FPU state for XMM registers: {:?}", e);
206-
}
207-
}
177+
let fpu_data = vcpu_fd
178+
.get_fpu()
179+
.map_err(|e| new_error!("Could not read guest FPU registers: {:?}", e))?;
180+
let mut fpu: CommonFpu = CommonFpu::from(&fpu_data);
208181

209182
// Read MXCSR from XSAVE (MXCSR is at byte offset 24 -> u32 index 6)
210183
// 11.5.10 Mode-Specific XSAVE/XRSTOR State Management
211184
match vcpu_fd.get_xsave() {
212185
Ok(xsave) => {
213-
regs.mxcsr = xsave.region[6];
186+
fpu.mxcsr = xsave.region[6];
214187
}
215188
Err(e) => {
216189
log::warn!("Failed to read XSAVE for MXCSR: {:?}", e);
217190
}
218191
}
219192

220-
Ok(())
193+
Ok((CommonRegisters::from(&regs), fpu))
221194
}
222195

223196
fn set_single_step(&mut self, vcpu_fd: &Self::Vcpu, enable: bool) -> Result<()> {
@@ -236,47 +209,25 @@ impl GuestDebug for KvmDebug {
236209
}
237210
}
238211

239-
fn write_regs(&self, vcpu_fd: &Self::Vcpu, regs: &X86_64Regs) -> Result<()> {
212+
fn write_regs(
213+
&self,
214+
vcpu_fd: &Self::Vcpu,
215+
regs: &CommonRegisters,
216+
fpu: &CommonFpu,
217+
) -> Result<()> {
240218
log::debug!("Write registers");
241-
let new_regs = kvm_regs {
242-
rax: regs.rax,
243-
rbx: regs.rbx,
244-
rcx: regs.rcx,
245-
rdx: regs.rdx,
246-
rsi: regs.rsi,
247-
rdi: regs.rdi,
248-
rbp: regs.rbp,
249-
rsp: regs.rsp,
250-
r8: regs.r8,
251-
r9: regs.r9,
252-
r10: regs.r10,
253-
r11: regs.r11,
254-
r12: regs.r12,
255-
r13: regs.r13,
256-
r14: regs.r14,
257-
r15: regs.r15,
258-
259-
rip: regs.rip,
260-
rflags: regs.rflags,
261-
};
219+
let new_regs = regs.into();
262220

263221
vcpu_fd
264222
.set_regs(&new_regs)
265223
.map_err(|e| new_error!("Could not write guest registers: {:?}", e))?;
266224

267-
// load existing values and replace the xmm registers
268-
let mut fpu = match vcpu_fd.get_fpu() {
269-
Ok(fpu) => fpu,
270-
Err(e) => {
271-
return Err(new_error!("Could not write guest registers: {:?}", e));
272-
}
273-
};
274-
275-
// Convert XMM registers from [u128; 16] (our internal representation)
276-
// to [[u8; 16]; 16] (KVM FPU representation) using little-endian byte order.
277-
fpu.xmm = regs.xmm.map(u128::to_le_bytes);
225+
// Only xmm and mxcsr is piped though in the given fpu, so only set those
226+
let mut current_fpu: CommonFpu = (&vcpu_fd.get_fpu()?).into();
227+
current_fpu.mxcsr = fpu.mxcsr;
228+
current_fpu.xmm = fpu.xmm;
278229
vcpu_fd
279-
.set_fpu(&fpu)
230+
.set_fpu(&(&current_fpu).into())
280231
.map_err(|e| new_error!("Could not write guest registers: {:?}", e))?;
281232

282233
// Update MXCSR using XSAVE region entry 6 (MXCSR) if available.
@@ -287,7 +238,7 @@ impl GuestDebug for KvmDebug {
287238
}
288239
};
289240

290-
xsave.region[6] = regs.mxcsr;
241+
xsave.region[6] = fpu.mxcsr;
291242
unsafe {
292243
vcpu_fd
293244
.set_xsave(&xsave)

0 commit comments

Comments
 (0)