Skip to content

Commit e5b2b39

Browse files
committed
mshv: use VP register page for RIP/RAX writes in run_vcpu
Replace set_reg() hypercalls with direct VP register page writes for the RIP increment on IO exits and the RAX write on IO-in (hw-interrupts). The VP register page is a shared memory page between userspace and the hypervisor that is picked up automatically on the next DISPATCH_VP, eliminating one hypercall per IO exit. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent a83ce8c commit e5b2b39

File tree

2 files changed

+38
-23
lines changed

2 files changed

+38
-23
lines changed

src/hyperlight_host/src/hypervisor/virtual_machine/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ pub enum RunVcpuError {
200200
GetDr6(HypervisorError),
201201
#[error("Increment RIP failed: {0}")]
202202
IncrementRip(HypervisorError),
203+
#[error("VP register page not available")]
204+
NoVpRegisterPage,
203205
#[error("Parse GPA access info failed")]
204206
ParseGpaAccessInfo,
205207
#[error("Unknown error: {0}")]

src/hyperlight_host/src/hypervisor/virtual_machine/mshv/x86_64.rs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,16 @@ use mshv_bindings::LapicState;
2626
#[cfg(gdb)]
2727
use mshv_bindings::{DebugRegisters, hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT};
2828
use mshv_bindings::{
29-
FloatingPointUnit, SpecialRegisters, StandardRegisters, XSave, hv_message_type,
30-
hv_message_type_HVMSG_GPA_INTERCEPT, hv_message_type_HVMSG_UNMAPPED_GPA,
29+
FloatingPointUnit, HV_X64_REGISTER_CLASS_IP, SpecialRegisters, StandardRegisters, XSave,
30+
hv_message_type, hv_message_type_HVMSG_GPA_INTERCEPT, hv_message_type_HVMSG_UNMAPPED_GPA,
3131
hv_message_type_HVMSG_X64_HALT, hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT,
3232
hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES,
33-
hv_partition_synthetic_processor_features, hv_register_assoc,
34-
hv_register_name_HV_X64_REGISTER_RIP, hv_register_value, mshv_create_partition_v2,
35-
mshv_user_mem_region,
33+
hv_partition_synthetic_processor_features, mshv_create_partition_v2, mshv_user_mem_region,
3634
};
3735
#[cfg(feature = "hw-interrupts")]
3836
use mshv_bindings::{
39-
hv_interrupt_type_HV_X64_INTERRUPT_TYPE_FIXED, hv_register_name_HV_X64_REGISTER_RAX,
37+
HV_X64_REGISTER_CLASS_GENERAL, hv_interrupt_type_HV_X64_INTERRUPT_TYPE_FIXED,
38+
hv_register_assoc, hv_register_value,
4039
};
4140
#[cfg(feature = "hw-interrupts")]
4241
use mshv_ioctls::InterruptRequest;
@@ -219,16 +218,23 @@ impl VirtualMachine for MshvVm {
219218
let instruction_length = io_message.header.instruction_length() as u64;
220219
let is_write = io_message.header.intercept_access_type != 0;
221220

222-
// mshv, unlike kvm, does not automatically increment RIP
223-
self.vcpu_fd
224-
.set_reg(&[hv_register_assoc {
225-
name: hv_register_name_HV_X64_REGISTER_RIP,
226-
value: hv_register_value {
227-
reg64: rip + instruction_length,
228-
},
229-
..Default::default()
230-
}])
231-
.map_err(|e| RunVcpuError::IncrementRip(e.into()))?;
221+
// mshv, unlike kvm, does not automatically increment RIP.
222+
// Write directly to the VP register page to avoid a
223+
// hypercall round-trip on every IO exit.
224+
{
225+
let page = self
226+
.vcpu_fd
227+
.get_vp_reg_page()
228+
.ok_or(RunVcpuError::NoVpRegisterPage)?;
229+
// SAFETY: The register page is a valid mmap'd page
230+
// from create_vcpu and is always populated after a
231+
// vcpu run returns an intercept message.
232+
unsafe {
233+
(*page.0).__bindgen_anon_1.__bindgen_anon_1.rip =
234+
rip + instruction_length;
235+
(*page.0).dirty |= 1 << HV_X64_REGISTER_CLASS_IP;
236+
}
237+
}
232238

233239
// VmAction::Halt always means "I'm done", regardless
234240
// of whether a timer is active.
@@ -253,13 +259,20 @@ impl VirtualMachine for MshvVm {
253259
} else if let Some(val) =
254260
super::super::x86_64::hw_interrupts::handle_io_in(port_number)
255261
{
256-
self.vcpu_fd
257-
.set_reg(&[hv_register_assoc {
258-
name: hv_register_name_HV_X64_REGISTER_RAX,
259-
value: hv_register_value { reg64: val },
260-
..Default::default()
261-
}])
262-
.map_err(|e| RunVcpuError::Unknown(e.into()))?;
262+
let page = self
263+
.vcpu_fd
264+
.get_vp_reg_page()
265+
.ok_or(RunVcpuError::NoVpRegisterPage)?;
266+
// SAFETY: same as the RIP write above.
267+
unsafe {
268+
(*page.0)
269+
.__bindgen_anon_1
270+
.__bindgen_anon_1
271+
.__bindgen_anon_1
272+
.__bindgen_anon_1
273+
.rax = val;
274+
(*page.0).dirty |= 1 << HV_X64_REGISTER_CLASS_GENERAL;
275+
}
263276
continue;
264277
}
265278
}

0 commit comments

Comments
 (0)