Skip to content

Commit 86d8dd5

Browse files
committed
Add Vm trait, implement for kvm, mshv, whp
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Fix interrupt Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Fix gdb bug Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent 0195ff0 commit 86d8dd5

25 files changed

+2504
-4984
lines changed

src/hyperlight_host/src/hypervisor/crashdump.rs

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use elfcore::{
2323
ReadProcessMemory, ThreadView, VaProtection, VaRegion,
2424
};
2525

26-
use super::Hypervisor;
26+
use crate::hypervisor::hyperlight_vm::HyperlightVm;
2727
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags};
2828
use crate::{Result, new_error};
2929

@@ -262,7 +262,7 @@ impl ReadProcessMemory for GuestMemReader {
262262
///
263263
/// # Returns
264264
/// * `Result<()>`: Success or error
265-
pub(crate) fn generate_crashdump(hv: &dyn Hypervisor) -> Result<()> {
265+
pub(crate) fn generate_crashdump(hv: &HyperlightVm) -> Result<()> {
266266
// Get crash context from hypervisor
267267
let ctx = hv
268268
.crashdump_context()
@@ -349,28 +349,23 @@ fn core_dump_file_path(dump_dir: Option<String>) -> String {
349349
/// Returns:
350350
/// * `Result<usize>`: The number of bytes written to the core dump file.
351351
fn checked_core_dump(
352-
ctx: Option<CrashDumpContext>,
352+
ctx: CrashDumpContext,
353353
get_writer: impl FnOnce() -> Result<Box<dyn Write>>,
354354
) -> Result<usize> {
355-
let mut nbytes = 0;
356-
// If the HV returned a context it means we can create a core dump
357-
// This is the case when the sandbox has been configured at runtime to allow core dumps
358-
if let Some(ctx) = ctx {
359-
log::info!("Creating core dump file...");
360-
361-
// Set up data sources for the core dump
362-
let guest_view = GuestView::new(&ctx);
363-
let memory_reader = GuestMemReader::new(&ctx);
364-
365-
// Create and write core dump
366-
let core_builder = CoreDumpBuilder::from_source(guest_view, memory_reader);
367-
368-
let writer = get_writer()?;
369-
// Write the core dump directly to the file
370-
nbytes = core_builder
371-
.write(writer)
372-
.map_err(|e| new_error!("Failed to write core dump: {:?}", e))?;
373-
}
355+
log::info!("Creating core dump file...");
356+
357+
// Set up data sources for the core dump
358+
let guest_view = GuestView::new(&ctx);
359+
let memory_reader = GuestMemReader::new(&ctx);
360+
361+
// Create and write core dump
362+
let core_builder = CoreDumpBuilder::from_source(guest_view, memory_reader);
363+
364+
let writer = get_writer()?;
365+
// Write the core dump directly to the file
366+
let nbytes = core_builder
367+
.write(writer)
368+
.map_err(|e| new_error!("Failed to write core dump: {:?}", e))?;
374369

375370
Ok(nbytes)
376371
}
@@ -424,17 +419,6 @@ mod test {
424419
assert!(path.starts_with(&temp_dir));
425420
}
426421

427-
/// Test core is not created when the context is None
428-
#[test]
429-
fn test_crashdump_not_created_when_context_is_none() {
430-
// Call the function with None context
431-
let result = checked_core_dump(None, || Ok(Box::new(std::io::empty())));
432-
433-
// Check if the result is ok and the number of bytes is 0
434-
assert!(result.is_ok());
435-
assert_eq!(result.unwrap(), 0);
436-
}
437-
438422
/// Test the core dump creation with no regions fails
439423
#[test]
440424
fn test_crashdump_write_fails_when_no_regions() {
@@ -451,7 +435,7 @@ mod test {
451435
let get_writer = || Ok(Box::new(std::io::empty()) as Box<dyn Write>);
452436

453437
// Call the function
454-
let result = checked_core_dump(Some(ctx), get_writer);
438+
let result = checked_core_dump(ctx, get_writer);
455439

456440
// Check if the result is an error
457441
// This should fail because there are no regions
@@ -482,7 +466,7 @@ mod test {
482466
let get_writer = || Ok(Box::new(std::io::empty()) as Box<dyn Write>);
483467

484468
// Call the function
485-
let result = checked_core_dump(Some(ctx), get_writer);
469+
let result = checked_core_dump(ctx, get_writer);
486470

487471
// Check if the result is ok and the number of bytes is 0
488472
assert!(result.is_ok());

src/hyperlight_host/src/hypervisor/gdb/arch.rs

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@ limitations under the License.
1616

1717
//! This file contains architecture specific code for the x86_64
1818
19-
use std::collections::HashMap;
20-
2119
use super::VcpuStopReason;
20+
use crate::Result;
21+
use crate::hypervisor::regs::CommonRegisters;
22+
use crate::hypervisor::vm::Vm;
2223

2324
// Described in Table 6-1. Exceptions and Interrupts at Page 6-13 Vol. 1
2425
// of Intel 64 and IA-32 Architectures Software Developer's Manual
2526
/// Exception id for #DB
26-
const DB_EX_ID: u32 = 1;
27+
pub(crate) const DB_EX_ID: u32 = 1;
2728
/// Exception id for #BP - triggered by the INT3 instruction
28-
const BP_EX_ID: u32 = 3;
29+
pub(crate) const BP_EX_ID: u32 = 3;
2930

3031
/// Software Breakpoint size in memory
3132
pub(crate) const SW_BP_SIZE: usize = 1;
@@ -51,61 +52,52 @@ pub(crate) const DR6_HW_BP_FLAGS_MASK: u64 = 0x0F << DR6_HW_BP_FLAGS_POS;
5152

5253
/// Determine the reason the vCPU stopped
5354
/// This is done by checking the DR6 register and the exception id
54-
/// NOTE: Additional checks are done for the entrypoint, stored hw_breakpoints
55-
/// and sw_breakpoints to ensure the stop reason is valid with internal state
5655
pub(crate) fn vcpu_stop_reason(
57-
single_step: bool,
58-
rip: u64,
59-
dr6: u64,
56+
vm: &mut dyn Vm,
6057
entrypoint: u64,
58+
dr6: u64,
6159
exception: u32,
62-
hw_breakpoints: &[u64],
63-
sw_breakpoints: &HashMap<u64, [u8; SW_BP_SIZE]>,
64-
) -> VcpuStopReason {
60+
) -> Result<VcpuStopReason> {
61+
let CommonRegisters { rip, .. } = vm.regs()?;
6562
if DB_EX_ID == exception {
6663
// If the BS flag in DR6 register is set, it means a single step
6764
// instruction triggered the exit
6865
// Check page 19-4 Vol. 3B of Intel 64 and IA-32
6966
// Architectures Software Developer's Manual
70-
if dr6 & DR6_BS_FLAG_MASK != 0 && single_step {
71-
return VcpuStopReason::DoneStep;
67+
if dr6 & DR6_BS_FLAG_MASK != 0 {
68+
return Ok(VcpuStopReason::DoneStep);
7269
}
7370

7471
// If any of the B0-B3 flags in DR6 register is set, it means a
7572
// hardware breakpoint triggered the exit
7673
// Check page 19-4 Vol. 3B of Intel 64 and IA-32
7774
// Architectures Software Developer's Manual
78-
if DR6_HW_BP_FLAGS_MASK & dr6 != 0 && hw_breakpoints.contains(&rip) {
75+
if DR6_HW_BP_FLAGS_MASK & dr6 != 0 {
7976
if rip == entrypoint {
80-
return VcpuStopReason::EntryPointBp;
77+
vm.remove_hw_breakpoint(entrypoint)?;
78+
return Ok(VcpuStopReason::EntryPointBp);
8179
}
82-
return VcpuStopReason::HwBp;
80+
return Ok(VcpuStopReason::HwBp);
8381
}
8482
}
8583

86-
if BP_EX_ID == exception && sw_breakpoints.contains_key(&rip) {
87-
return VcpuStopReason::SwBp;
84+
if BP_EX_ID == exception {
85+
return Ok(VcpuStopReason::SwBp);
8886
}
8987

9088
// Log an error and provide internal debugging info
9189
log::error!(
9290
r"The vCPU exited because of an unknown reason:
93-
single_step: {:?}
9491
rip: {:?}
9592
dr6: {:?}
9693
entrypoint: {:?}
9794
exception: {:?}
98-
hw_breakpoints: {:?}
99-
sw_breakpoints: {:?}
10095
",
101-
single_step,
10296
rip,
10397
dr6,
10498
entrypoint,
10599
exception,
106-
hw_breakpoints,
107-
sw_breakpoints,
108100
);
109101

110-
VcpuStopReason::Unknown
102+
Ok(VcpuStopReason::Unknown)
111103
}

0 commit comments

Comments
 (0)