@@ -26,17 +26,16 @@ use mshv_bindings::LapicState;
2626#[ cfg( gdb) ]
2727use mshv_bindings:: { DebugRegisters , hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT} ;
2828use 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" ) ]
3836use 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" ) ]
4241use 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