Skip to content

Commit 1bb233c

Browse files
committed
Add test set the the registers on kvm
Signed-off-by: James Sturtevant <[email protected]>
1 parent db6bec4 commit 1bb233c

File tree

5 files changed

+197
-37
lines changed

5 files changed

+197
-37
lines changed

Cargo.lock

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hyperlight_host/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ proptest = "1.7.0"
9090
tempfile = "3.22.0"
9191
crossbeam-queue = "0.3.12"
9292
tracing-serde = "0.2.0"
93+
serial_test = "3.1.1"
9394
hyperlight-testing = { workspace = true }
9495
env_logger = "0.11.8"
9596
tracing-forest = { version = "0.2.0", features = ["uuid", "chrono", "smallvec", "serde", "env-filter"] }

src/hyperlight_host/examples/guest-debugging/main.rs

Lines changed: 89 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use hyperlight_host::sandbox::SandboxConfiguration;
2020
#[cfg(gdb)]
2121
use hyperlight_host::sandbox::config::DebugInfo;
2222
use hyperlight_host::{MultiUseSandbox, UninitializedSandbox};
23+
use serial_test::serial;
2324

2425
/// Build a sandbox configuration that enables GDB debugging when the `gdb` feature is enabled.
2526
fn get_sandbox_cfg() -> Option<SandboxConfiguration> {
@@ -72,6 +73,13 @@ fn main() -> hyperlight_host::Result<()> {
7273
let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?;
7374

7475
// Call guest function
76+
multi_use_sandbox_dbg
77+
.call::<()>(
78+
"UseSSE2Registers",
79+
(),
80+
)
81+
.unwrap();
82+
7583
let message =
7684
"Hello, World! I am executing inside of a VM with debugger attached :)\n".to_string();
7785
multi_use_sandbox_dbg
@@ -106,44 +114,23 @@ mod tests {
106114

107115
use super::*;
108116

109-
fn write_cmds_file(cmd_file_path: &str, out_file_path: &str) -> io::Result<()> {
110-
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir");
117+
fn write_cmds_file(cmd_file_path: &str, cmd: &str) -> io::Result<()> {
118+
111119
let file = File::create(cmd_file_path)?;
112120
let mut writer = BufWriter::new(file);
113121

114122
// write from string to file
115123
writer.write_all(
116-
format!(
117-
"file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest
118-
target remote :8080
119-
120-
set pagination off
121-
set logging file {out_file_path}
122-
set logging on
123-
124-
break hyperlight_main
125-
commands
126-
echo \"Stopped at hyperlight_main breakpoint\\n\"
127-
backtrace
128-
continue
129-
end
130-
131-
continue
132-
133-
set logging off
134-
quit
135-
"
136-
)
137-
.as_bytes(),
124+
cmd.as_bytes(),
138125
)?;
139126

140127
writer.flush()
141128
}
142129

143-
fn run_guest_and_gdb(cmd_file_path: &str, out_file_path: &str) -> Result<()> {
130+
fn run_guest_and_gdb(cmd_file_path: &str, out_file_path: &str, cmd: &str, checker: fn(String) -> bool) -> Result<()> {
144131
// write gdb commands to file
145132

146-
write_cmds_file(&cmd_file_path, &out_file_path)
133+
write_cmds_file(&cmd_file_path, cmd)
147134
.expect("Failed to write gdb commands to file");
148135

149136
#[cfg(mshv2)] // mshv3 is a default feature is mutually exclusive with the mshv2 feature
@@ -215,17 +202,17 @@ mod tests {
215202
}
216203
}
217204

218-
check_output(&out_file_path)
205+
check_output(&out_file_path, checker)
219206
}
220207

221-
fn check_output(out_file_path: &str) -> Result<()> {
208+
fn check_output(out_file_path: &str, checker: fn(contents: String) -> bool) -> Result<()> {
222209
let results = File::open(out_file_path)
223210
.map_err(|e| new_error!("Failed to open gdb.output file: {}", e))?;
224211
let mut reader = BufReader::new(results);
225212
let mut contents = String::new();
226213
reader.read_to_string(&mut contents).unwrap();
227214

228-
if contents.contains("Stopped at hyperlight_main breakpoint") {
215+
if checker(contents) {
229216
Ok(())
230217
} else {
231218
Err(new_error!(
@@ -247,12 +234,84 @@ mod tests {
247234
}
248235

249236
#[test]
237+
#[serial]
250238
fn test_gdb_end_to_end() {
251239
let out_dir = std::env::var("OUT_DIR").expect("Failed to get out dir");
240+
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir");
252241
let out_file_path = format!("{out_dir}/gdb.output");
253242
let cmd_file_path = format!("{out_dir}/gdb-commands.txt");
254243

255-
let result = run_guest_and_gdb(&cmd_file_path, &out_file_path);
244+
let cmd = format!(
245+
"file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest
246+
target remote :8080
247+
248+
set pagination off
249+
set logging file {out_file_path}
250+
set logging on
251+
252+
break hyperlight_main
253+
commands
254+
echo \"Stopped at hyperlight_main breakpoint\\n\"
255+
backtrace
256+
257+
continue
258+
end
259+
260+
continue
261+
262+
set logging off
263+
quit
264+
"
265+
);
266+
267+
let checker = |contents: String| {contents.contains("Stopped at hyperlight_main breakpoint")};
268+
269+
let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker);
270+
271+
// cleanup
272+
let cleanup_result = cleanup(&out_file_path, &cmd_file_path);
273+
assert!(cleanup_result.is_ok(), "{}", cleanup_result.unwrap_err());
274+
// check if the test passed - done at the end to ensure cleanup is done
275+
assert!(result.is_ok(), "{}", result.unwrap_err());
276+
}
277+
278+
#[test]
279+
#[serial]
280+
fn test_gdb_sse_check() {
281+
let out_dir = std::env::var("OUT_DIR").expect("Failed to get out dir");
282+
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir");
283+
let out_file_path = format!("{out_dir}/gdb-sse.output");
284+
let cmd_file_path = format!("{out_dir}/gdb-sse--commands.txt");
285+
286+
let cmd = format!(
287+
"file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest
288+
target remote :8080
289+
290+
set pagination off
291+
set logging file {out_file_path}
292+
set logging on
293+
294+
break main.rs:simpleguest::use_sse2_registers
295+
commands 1
296+
print $xmm1.v4_float
297+
break +2
298+
commands 2
299+
print $xmm1.v4_float
300+
continue
301+
end
302+
continue
303+
end
304+
305+
306+
continue
307+
308+
set logging off
309+
quit
310+
"
311+
);
312+
313+
let checker = |contents: String| {contents.contains("$2 = [1.20000005, 0, 0, 0]")};
314+
let result = run_guest_and_gdb(&cmd_file_path, &out_file_path, &cmd, checker);
256315

257316
// cleanup
258317
let cleanup_result = cleanup(&out_file_path, &cmd_file_path);

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,6 @@ impl GuestDebug for KvmDebug {
207207
}
208208

209209
// Read MXCSR from XSAVE (MXCSR is at byte offset 24 -> u32 index 6)
210-
// Todo maybe I could use xsave to read the registers too instead of a separate call to get_fpu
211210
match vcpu_fd.get_xsave() {
212211
Ok(xsave) => {
213212
regs.mxcsr = xsave.region[6];
@@ -262,6 +261,36 @@ impl GuestDebug for KvmDebug {
262261

263262
vcpu_fd
264263
.set_regs(&new_regs)
265-
.map_err(|e| new_error!("Could not write guest registers: {:?}", e))
264+
.map_err(|e| new_error!("Could not write guest registers: {:?}", e))?;
265+
266+
// load existing values and replace the xmm registers
267+
let mut fpu = match vcpu_fd.get_fpu() {
268+
Ok(fpu) => {
269+
fpu
270+
},
271+
Err(e) => {
272+
return Err(new_error!("Could not write guest registers: {:?}", e));
273+
}
274+
};
275+
276+
// Convert XMM registers from [u128; 16] (our internal representation)
277+
// to [[u8; 16]; 16] (KVM FPU representation) using little-endian byte order.
278+
fpu.xmm = regs.xmm.map(u128::to_le_bytes);
279+
vcpu_fd.set_fpu(&fpu).map_err(|e| new_error!("Could not write guest registers: {:?}", e))?;
280+
281+
// Update MXCSR using XSAVE region entry 6 (MXCSR) if available.
282+
let mut xsave = match vcpu_fd.get_xsave() {
283+
Ok(xsave) => {
284+
xsave
285+
}
286+
Err(e) => {
287+
return Err(new_error!("Could not write guest registers: {:?}", e));
288+
}
289+
};
290+
291+
xsave.region[6] = regs.mxcsr;
292+
unsafe { vcpu_fd.set_xsave(&xsave).map_err(|e| new_error!("Could not write guest registers: {:?}", e))? };
293+
294+
Ok(())
266295
}
267296
}

0 commit comments

Comments
 (0)