When a VM is destroyed (bhyvectl --destroy) while a vCPU thread is
handling an exit in bhyve, every call on the VM fails. vm_loop()
handles that for vm_run() and ends bhyve with BHYVE_EXIT_ERROR, but a
vCPU in the middle of an exit hits one of the assert(error == 0) in
emulate_inout() after its register update, or reports "Failed to
emulate instruction sequence" and returns VMEXIT_ABORT: bhyve dies of
SIGABRT and leaves a core. With a guest doing a lot of port I/O
(an IDE or legacy device, a serial console) a forced stop hits this
regularly.
Return an error from emulate_inout() instead of asserting, and on the
failure paths of the I/O and instruction emulation exits check whether
the VM is still there; if it is gone, exit with BHYVE_EXIT_ERROR as
vm_loop() does. A failure on a VM that still exists is reported and
aborts as before.
Signed-off-by: Wanpeng Qian <wanpengqian@gmail.com>
Sponsored by: keelos.dev