From: Subject: Re: [PATCH] vmd: handle the reset control register at 0xcf9 To: dv@sisu.io, mlarkin@nested.page Cc: ssnf@ssnf.xyz, tech@openbsd.org Date: Fri, 28 Aug 2026 01:01:32 +0000 > ...not sure the reset bits are right They are incorrect. I have corrected the values. Thanks for noticing. I tested against a old binary by mistake, sorry. I also updated vcpu_exit's comment to include EAGAIN. It was already a existing return value before this patch, at the SVM_VMEXIT_SHUTDOWN case. > and from my quick checking I think we need to implement reads of the > register. At least linux reads before it writes and I'm not sure the > consequence yet of not emulating that correctly. Linux just masks the read before writing back. It works as it as, because currently it simply reads 0xff. However, I see no benefit from reading this register. Not implementing might affect guests who probe 0xcf9 for presence, but I do not know of any that do that. Thanks for the feedback. diff --git usr.sbin/vmd/x86_vm.c usr.sbin/vmd/x86_vm.c index 1b5ade90f9b..2d2da13da92 100644 --- usr.sbin/vmd/x86_vm.c +++ usr.sbin/vmd/x86_vm.c @@ -45,6 +45,10 @@ typedef uint8_t (*io_fn_t)(struct vm_run_params *); #define LOWMEM_KB 576 #define MAX_PORTS 65536 +#define RST_CNT 0xcf9 +#define RST_CNT_SYS_RST 0x02 +#define RST_CNT_RST_CPU 0x04 +#define RST_CNT_RESET (RST_CNT_SYS_RST | RST_CNT_RST_CPU) io_fn_t ioports_map[MAX_PORTS]; @@ -52,7 +56,7 @@ int translate_gva(struct vm_exit*, uint64_t, uint64_t *, int); static int loadfile_bios(gzFile, off_t, struct vcpu_reg_state *); static int vcpu_exit_eptviolation(struct vm_run_params *); -static void vcpu_exit_inout(struct vm_run_params *); +static int vcpu_exit_inout(struct vm_run_params *); extern struct vmd_vm *current_vm; extern int con_fd; @@ -449,12 +453,16 @@ unpause_vm_md(struct vmd_vm *vm) * Parameters: * vrp: vcpu run parameters containing guest state for this exit */ -void +int vcpu_exit_inout(struct vm_run_params *vrp) { struct vm_exit *vei = vrp->vrp_exit; uint8_t intr = 0xFF; + if (vei->vei.vei_dir == VEI_DIR_OUT && + vei->vei.vei_port == RST_CNT && + (vei->vei.vei_data & RST_CNT_RESET) == RST_CNT_RESET) + return (EAGAIN); if (vei->vei.vei_rep || vei->vei.vei_string) { #ifdef MMIO_DEBUG log_info("%s: %s%s%s %d-byte, enc=%d, data=0x%08x, port=0x%04x", @@ -483,6 +491,7 @@ vcpu_exit_inout(struct vm_run_params *vrp) if (intr != 0xFF) vcpu_assert_irq(vrp->vrp_vm_id, vrp->vrp_vcpu_id, intr); + return (0); } /* @@ -503,12 +512,14 @@ vcpu_exit_inout(struct vm_run_params *vrp) * Return values: * 0: the exit was handled successfully * 1: an error occurred (eg, unknown exit reason passed in 'vrp') + * EAGAIN: the vm should be reset */ int vcpu_exit(struct vm_run_params *vrp) { int ret; + ret = 0; switch (vrp->vrp_exit_reason) { case VMX_EXIT_INT_WINDOW: case SVM_VMEXIT_VINTR: @@ -528,12 +539,10 @@ vcpu_exit(struct vm_run_params *vrp) case SVM_VMEXIT_NPF: case VMX_EXIT_EPT_VIOLATION: ret = vcpu_exit_eptviolation(vrp); - if (ret) - return (ret); break; case VMX_EXIT_IO: case SVM_VMEXIT_IOIO: - vcpu_exit_inout(vrp); + ret = vcpu_exit_inout(vrp); break; case VMX_EXIT_HLT: case SVM_VMEXIT_HLT: @@ -547,7 +556,7 @@ vcpu_exit(struct vm_run_params *vrp) log_debug("unknown exit reason 0x%x", vrp->vrp_exit_reason); } - return (0); + return (ret); } /*