Skip to content

Commit 2cc8da2

Browse files
authored
mshv: use VP register page for RIP/RAX writes in run_vcpu (#1366)
* 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> * Pr feedback Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent 6db12d2 commit 2cc8da2

1 file changed

Lines changed: 49 additions & 20 deletions

File tree

  • src/hyperlight_host/src/hypervisor/virtual_machine/mshv

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

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ 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,
3333
hv_partition_synthetic_processor_features, hv_register_assoc,
@@ -36,7 +36,8 @@ use mshv_bindings::{
3636
};
3737
#[cfg(feature = "hw-interrupts")]
3838
use mshv_bindings::{
39-
hv_interrupt_type_HV_X64_INTERRUPT_TYPE_FIXED, hv_register_name_HV_X64_REGISTER_RAX,
39+
HV_X64_REGISTER_CLASS_GENERAL, hv_interrupt_type_HV_X64_INTERRUPT_TYPE_FIXED,
40+
hv_register_name_HV_X64_REGISTER_RAX, set_gp_regs_field_ptr,
4041
};
4142
#[cfg(feature = "hw-interrupts")]
4243
use mshv_ioctls::InterruptRequest;
@@ -219,16 +220,30 @@ impl VirtualMachine for MshvVm {
219220
let instruction_length = io_message.header.instruction_length() as u64;
220221
let is_write = io_message.header.intercept_access_type != 0;
221222

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()))?;
223+
// mshv, unlike kvm, does not automatically increment RIP.
224+
if let Some(page) = self
225+
.vcpu_fd
226+
.get_vp_reg_page()
227+
.filter(|p| unsafe { (*p.0).isvalid != 0 })
228+
{
229+
// SAFETY: The register page is valid (isvalid checked
230+
// above) and populated after a vcpu run intercept.
231+
unsafe {
232+
(*page.0).__bindgen_anon_1.__bindgen_anon_1.rip =
233+
rip + instruction_length;
234+
(*page.0).dirty |= 1 << HV_X64_REGISTER_CLASS_IP;
235+
}
236+
} else {
237+
self.vcpu_fd
238+
.set_reg(&[hv_register_assoc {
239+
name: hv_register_name_HV_X64_REGISTER_RIP,
240+
value: hv_register_value {
241+
reg64: rip + instruction_length,
242+
},
243+
..Default::default()
244+
}])
245+
.map_err(|e| RunVcpuError::IncrementRip(e.into()))?;
246+
}
232247

233248
// VmAction::Halt always means "I'm done", regardless
234249
// of whether a timer is active.
@@ -253,13 +268,27 @@ impl VirtualMachine for MshvVm {
253268
} else if let Some(val) =
254269
super::super::x86_64::hw_interrupts::handle_io_in(port_number)
255270
{
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()))?;
271+
if let Some(page) = self
272+
.vcpu_fd
273+
.get_vp_reg_page()
274+
.filter(|p| unsafe { (*p.0).isvalid != 0 })
275+
{
276+
let vp_reg_page = page.0;
277+
set_gp_regs_field_ptr!(vp_reg_page, rax, val);
278+
// SAFETY: page is valid (isvalid checked above).
279+
unsafe {
280+
(*vp_reg_page).dirty |=
281+
1 << HV_X64_REGISTER_CLASS_GENERAL;
282+
}
283+
} else {
284+
self.vcpu_fd
285+
.set_reg(&[hv_register_assoc {
286+
name: hv_register_name_HV_X64_REGISTER_RAX,
287+
value: hv_register_value { reg64: val },
288+
..Default::default()
289+
}])
290+
.map_err(|e| RunVcpuError::Unknown(e.into()))?;
291+
}
263292
continue;
264293
}
265294
}

0 commit comments

Comments
 (0)