Skip to content

Commit c674c6d

Browse files
committed
MSR
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 350b8e0 commit c674c6d

File tree

8 files changed

+366
-11
lines changed

8 files changed

+366
-11
lines changed

src/hyperlight_host/src/hypervisor/hyperlight_vm.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use crate::hypervisor::hyperv_linux::MshvVm;
4646
use crate::hypervisor::hyperv_windows::WhpVm;
4747
#[cfg(kvm)]
4848
use crate::hypervisor::kvm::KvmVm;
49-
use crate::hypervisor::regs::CommonSpecialRegisters;
49+
use crate::hypervisor::regs::{CommonDebugRegs, CommonSpecialRegisters};
5050
use crate::hypervisor::vm::{Vm, VmExit};
5151
#[cfg(target_os = "windows")]
5252
use crate::hypervisor::wrappers::HandleWrapper;
@@ -592,6 +592,16 @@ impl HyperlightVm {
592592
self.interrupt_handle.clone()
593593
}
594594

595+
pub(crate) fn reset_vcpu(&self) -> Result<()> {
596+
self.vm.set_regs(&CommonRegisters::default())?;
597+
self.vm.set_sregs(&CommonSpecialRegisters::default())?;
598+
self.vm.set_fpu(&CommonFpu::default())?;
599+
self.vm.set_xsave(&[0; 1024])?;
600+
self.vm.set_debug_regs(&CommonDebugRegs::default())?;
601+
// TODO reset MSRs
602+
Ok(())
603+
}
604+
595605
#[cfg(gdb)]
596606
fn handle_debug(
597607
&mut self,

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ use std::sync::LazyLock;
2222
use mshv_bindings::DebugRegisters;
2323
#[cfg(gdb)]
2424
use mshv_bindings::hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT;
25+
use mshv_bindings::hv_message_type_HVMSG_X64_MSR_INTERCEPT;
26+
use mshv_bindings::{XSave, mshv_install_intercept};
2527
use mshv_bindings::{
26-
hv_message_type, hv_message_type_HVMSG_GPA_INTERCEPT, hv_message_type_HVMSG_UNMAPPED_GPA,
28+
hv_intercept_parameters, hv_intercept_type_HV_INTERCEPT_TYPE_X64_MSR_INDEX, hv_message_type,
29+
hv_message_type_HVMSG_GPA_INTERCEPT, hv_message_type_HVMSG_UNMAPPED_GPA,
2730
hv_message_type_HVMSG_X64_HALT, hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT,
2831
hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES,
2932
hv_partition_synthetic_processor_features, hv_register_assoc,
@@ -32,7 +35,9 @@ use mshv_bindings::{
3235
use mshv_ioctls::{Mshv, VcpuFd, VmFd};
3336
use tracing::{Span, instrument};
3437

35-
use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
38+
use crate::hypervisor::regs::{
39+
CommonDebugRegs, CommonFpu, CommonRegisters, CommonSpecialRegisters,
40+
};
3641
use crate::hypervisor::vm::{Vm, VmExit};
3742
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags};
3843
use crate::{Result, new_error};
@@ -83,8 +88,21 @@ impl MshvVm {
8388
vm_fd
8489
};
8590

86-
let vcpu_fd = vm_fd.create_vcpu(0)?;
91+
let intercept = mshv_install_intercept {
92+
access_type_mask: mshv_bindings::HV_INTERCEPT_ACCESS_MASK_WRITE, // | mshv_bindings::HV_INTERCEPT_ACCESS_MASK_READ to work
93+
intercept_type: mshv_bindings::hv_intercept_type_HV_INTERCEPT_TYPE_X64_MSR,
94+
intercept_parameter: Default::default(),
95+
};
96+
vm_fd.install_intercept(intercept)?;
97+
98+
// let intercept = mshv_install_intercept {
99+
// access_type_mask: mshv_bindings::HV_INTERCEPT_ACCESS_MASK_NONE,
100+
// intercept_type: mshv_bindings::hv_intercept_type_HV_INTERCEPT_TYPE_X64_MSR,
101+
// intercept_parameter: Default::default(),
102+
// };
103+
// vm_fd.install_intercept(intercept)?;
87104

105+
let vcpu_fd = vm_fd.create_vcpu(0)?;
88106
Ok(Self { vm_fd, vcpu_fd })
89107
}
90108
}
@@ -116,12 +134,32 @@ impl Vm for MshvVm {
116134
Ok(())
117135
}
118136

119-
#[cfg(crashdump)]
120137
fn xsave(&self) -> Result<Vec<u8>> {
121138
let xsave = self.vcpu_fd.get_xsave()?;
122139
Ok(xsave.buffer.to_vec())
123140
}
124141

142+
fn set_xsave(&self, xsave: &[u32; 1024]) -> Result<()> {
143+
let mut buf = XSave::default();
144+
let (prefix, bytes, suffix) = unsafe { xsave.align_to() };
145+
assert!(prefix.is_empty());
146+
assert!(suffix.is_empty());
147+
buf.buffer.copy_from_slice(bytes);
148+
self.vcpu_fd.set_xsave(&buf)?;
149+
Ok(())
150+
}
151+
152+
fn debug_regs(&self) -> Result<CommonDebugRegs> {
153+
let debug_regs = self.vcpu_fd.get_debug_regs()?;
154+
Ok(debug_regs.into())
155+
}
156+
157+
fn set_debug_regs(&self, drs: &CommonDebugRegs) -> Result<()> {
158+
let mshv_debug_regs = drs.into();
159+
self.vcpu_fd.set_debug_regs(&mshv_debug_regs)?;
160+
Ok(())
161+
}
162+
125163
/// # Safety
126164
/// The caller must ensure that the memory region is valid and points to valid memory,
127165
/// and lives long enough for the VM to use it.
@@ -142,6 +180,7 @@ impl Vm for MshvVm {
142180
const IO_PORT: hv_message_type = hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT;
143181
const UNMAPPED_GPA: hv_message_type = hv_message_type_HVMSG_UNMAPPED_GPA;
144182
const INVALID_GPA: hv_message_type = hv_message_type_HVMSG_GPA_INTERCEPT;
183+
const MSR: hv_message_type = hv_message_type_HVMSG_X64_MSR_INTERCEPT;
145184
#[cfg(gdb)]
146185
const EXCEPTION_INTERCEPT: hv_message_type = hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT;
147186

@@ -183,6 +222,17 @@ impl Vm for MshvVm {
183222
_ => VmExit::Unknown("Unknown MMIO access".to_string()),
184223
}
185224
}
225+
MSR => {
226+
let msr_message = m.to_msr_info().map_err(mshv_ioctls::MshvError::from)?;
227+
let read = msr_message.header.intercept_access_type;
228+
let msr_number = msr_message.msr_number;
229+
let rdx = msr_message.rdx;
230+
let rax = msr_message.rax;
231+
panic!(
232+
"MSR access: msr_number=0x{:X}, read={}, rdx=0x{:X}, rax=0x{:X}",
233+
msr_number, read, rdx, rax
234+
);
235+
}
186236
#[cfg(gdb)]
187237
EXCEPTION_INTERCEPT => {
188238
let exception_message = m

src/hyperlight_host/src/hypervisor/kvm.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ use std::sync::LazyLock;
1818

1919
#[cfg(gdb)]
2020
use kvm_bindings::kvm_guest_debug;
21-
use kvm_bindings::kvm_userspace_memory_region;
22-
use kvm_ioctls::Cap::UserMemory;
21+
use kvm_bindings::{kvm_debugregs, kvm_userspace_memory_region, kvm_xsave};
22+
use kvm_ioctls::Cap::{self, UserMemory};
2323
use kvm_ioctls::{Kvm, VcpuExit, VcpuFd, VmFd};
2424
use tracing::{Span, instrument};
2525

26-
use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
26+
use crate::hypervisor::regs::{
27+
CommonDebugRegs, CommonFpu, CommonRegisters, CommonSpecialRegisters,
28+
};
2729
use crate::hypervisor::vm::{Vm, VmExit};
2830
use crate::mem::memory_region::MemoryRegion;
2931
use crate::{Result, new_error};
@@ -107,7 +109,6 @@ impl Vm for KvmVm {
107109
Ok(self.vcpu_fd.set_fpu(&fpu.into())?)
108110
}
109111

110-
#[cfg(crashdump)]
111112
fn xsave(&self) -> Result<Vec<u8>> {
112113
let xsave = self.vcpu_fd.get_xsave()?;
113114
Ok(xsave
@@ -117,6 +118,34 @@ impl Vm for KvmVm {
117118
.collect())
118119
}
119120

121+
fn set_xsave(&self, xsave: &[u32; 1024]) -> Result<()> {
122+
if self.vm_fd.check_extension_int(Cap::Xsave2) as usize != xsave.len() * size_of::<u32>() {
123+
return Err(new_error!(
124+
"KVM_CAP_XSAVE2 not supported: {}",
125+
self.vm_fd.check_extension_int(Cap::Xsave2)
126+
));
127+
}
128+
let xsave = kvm_xsave {
129+
region: *xsave,
130+
..Default::default()
131+
};
132+
// we made sure above that SET_XSAVE only copies 4096 bytes
133+
unsafe { self.vcpu_fd.set_xsave(&xsave)? };
134+
135+
Ok(())
136+
}
137+
138+
fn debug_regs(&self) -> Result<CommonDebugRegs> {
139+
let kvm_debug_regs = self.vcpu_fd.get_debug_regs()?;
140+
Ok(kvm_debug_regs.into())
141+
}
142+
143+
fn set_debug_regs(&self, drs: &CommonDebugRegs) -> Result<()> {
144+
let kvm_debug_regs: kvm_debugregs = drs.into();
145+
self.vcpu_fd.set_debug_regs(&kvm_debug_regs)?;
146+
Ok(())
147+
}
148+
120149
unsafe fn map_memory(&mut self, (slot, region): (u32, &MemoryRegion)) -> Result<()> {
121150
let mut kvm_region: kvm_userspace_memory_region = region.into();
122151
kvm_region.slot = slot;
@@ -258,3 +287,16 @@ impl Vm for KvmVm {
258287
Ok(())
259288
}
260289
}
290+
291+
#[test]
292+
fn test() {
293+
let msr_feature_index_list = KVM.as_ref().unwrap().get_msr_index_list().unwrap();
294+
msr_feature_index_list.as_slice().iter().for_each(|msr| {
295+
println!("Writable MSR: 0x{:08X}", msr);
296+
});
297+
println!(
298+
"Total Writable MSRs: {}",
299+
msr_feature_index_list.as_slice().len()
300+
);
301+
// println!("msr_feature_index_list: {:?}", msr_feature_index_list);
302+
}

src/hyperlight_host/src/hypervisor/regs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
mod debug_regs;
1718
mod fpu;
1819
mod special_regs;
1920
mod standard_regs;
2021

2122
#[cfg(target_os = "windows")]
2223
use std::collections::HashSet;
2324

25+
pub(crate) use debug_regs::*;
2426
pub(crate) use fpu::*;
2527
pub(crate) use special_regs::*;
2628
pub(crate) use standard_regs::*;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
Copyright 2025 The Hyperlight Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#[cfg(kvm)]
18+
use kvm_bindings::kvm_debugregs;
19+
#[cfg(mshv3)]
20+
use mshv_bindings::DebugRegisters;
21+
22+
#[derive(Debug, Default, Copy, Clone, PartialEq)]
23+
pub(crate) struct CommonDebugRegs {
24+
pub dr0: u64,
25+
pub dr1: u64,
26+
pub dr2: u64,
27+
pub dr3: u64,
28+
pub dr6: u64,
29+
pub dr7: u64,
30+
}
31+
32+
#[cfg(kvm)]
33+
impl From<kvm_debugregs> for CommonDebugRegs {
34+
fn from(kvm_regs: kvm_debugregs) -> Self {
35+
Self {
36+
dr0: kvm_regs.db[0],
37+
dr1: kvm_regs.db[1],
38+
dr2: kvm_regs.db[2],
39+
dr3: kvm_regs.db[3],
40+
dr6: kvm_regs.dr6,
41+
dr7: kvm_regs.dr7,
42+
}
43+
}
44+
}
45+
#[cfg(kvm)]
46+
impl From<&CommonDebugRegs> for kvm_debugregs {
47+
fn from(common_regs: &CommonDebugRegs) -> Self {
48+
kvm_debugregs {
49+
db: [
50+
common_regs.dr0,
51+
common_regs.dr1,
52+
common_regs.dr2,
53+
common_regs.dr3,
54+
],
55+
dr6: common_regs.dr6,
56+
dr7: common_regs.dr7,
57+
..Default::default()
58+
}
59+
}
60+
}
61+
#[cfg(mshv3)]
62+
impl From<DebugRegisters> for CommonDebugRegs {
63+
fn from(mshv_regs: DebugRegisters) -> Self {
64+
Self {
65+
dr0: mshv_regs.dr0,
66+
dr1: mshv_regs.dr1,
67+
dr2: mshv_regs.dr2,
68+
dr3: mshv_regs.dr3,
69+
dr6: mshv_regs.dr6,
70+
dr7: mshv_regs.dr7,
71+
}
72+
}
73+
}
74+
#[cfg(mshv3)]
75+
impl From<&CommonDebugRegs> for DebugRegisters {
76+
fn from(common_regs: &CommonDebugRegs) -> Self {
77+
DebugRegisters {
78+
dr0: common_regs.dr0,
79+
dr1: common_regs.dr1,
80+
dr2: common_regs.dr2,
81+
dr3: common_regs.dr3,
82+
dr6: common_regs.dr6,
83+
dr7: common_regs.dr7,
84+
}
85+
}
86+
}

src/hyperlight_host/src/hypervisor/vm.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use std::fmt::Debug;
1818

1919
use super::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
2020
use crate::Result;
21+
use crate::hypervisor::regs::CommonDebugRegs;
2122
use crate::mem::memory_region::MemoryRegion;
2223

2324
/// Trait for single-vCPU VMs. Provides a common interface for basic VM operations.
@@ -40,9 +41,18 @@ pub(crate) trait Vm: Send + Sync + Debug {
4041
fn fpu(&self) -> Result<CommonFpu>;
4142
/// Set the FPU registers of the vCPU
4243
fn set_fpu(&self, fpu: &CommonFpu) -> Result<()>;
43-
/// xsave
44-
#[cfg(crashdump)]
44+
45+
/// Get xsave
46+
#[allow(dead_code)]
4547
fn xsave(&self) -> Result<Vec<u8>>;
48+
/// Set xsave
49+
fn set_xsave(&self, xsave: &[u32; 1024]) -> Result<()>;
50+
51+
/// Get the debug registers of the vCPU
52+
#[allow(dead_code)]
53+
fn debug_regs(&self) -> Result<CommonDebugRegs>;
54+
/// Set the debug registers of the vCPU
55+
fn set_debug_regs(&self, drs: &CommonDebugRegs) -> Result<()>;
4656

4757
/// Map memory region into this VM
4858
///

0 commit comments

Comments
 (0)