QEMU crashes when an interrupt is triggered whose descriptor is not in physical memory
Host environment
- Operating system: Arch Linux
- OS/kernel version: Linux pc 6.7.5-arch1-1 #1 SMP PREEMPT_DYNAMIC Sat, 17 Feb 2024 14:02:33 +0000 x86_64 GNU/Linux
- Architecture: x86_64
- QEMU flavor: qemu-system-i386
- QEMU version: 8.2.50 (built from Git commit da96ad4a)
- QEMU command line:
./qemu-system-i386 -drive format=raw,file=test.bin
Emulated/Virtualized environment
- Operating system: Custom, see additional information section.
- OS/kernel version: N/A
- Architecture: x86
Description of problem
When an interrupt is triggered whose descriptor is mapped but not in physical memory, QEMU crashes with the following message:
**
ERROR:../system/cpus.c:524:bql_lock_impl: assertion failed: (!bql_locked())
Bail out! ERROR:../system/cpus.c:524:bql_lock_impl: assertion failed: (!bql_locked())
Aborted (core dumped)
The given code triggers the bug by moving the IDT's base address, but it can also be triggered by any other method of moving the IDT's physical memory location, f.ex paging. With KVM enabled, this specific example loops forever instead of crashing, but if the code is altered to use paging, an internal KVM error is reported and the VM is paused.
Steps to reproduce
- Assemble the code listed below using NASM:
nasm test.asm -o test.bin - Run the code using
qemu-system-i386 -drive format=raw,file=test.bin. Note that the given code only triggers the bug if the guest has 2 gigabytes or less of physical memory. - QEMU crashes.
Additional information
NASM assembly of the code used:
bits 16
org 0x7c00
_start:
; Disable interrupts and load new IDT
cli
o32 lidt [idtdesc]
; Descriptor for INT 0 is in nonexistent physical memory, which crashes QEMU.
int 0x00
idtdesc:
dw 0x3ff ; Limit: 1 KiB for IDT
dd 0x80000000 ; Base: 2 GiB
; Like most BIOSes, SeaBIOS requires this magic number to boot
times 510-($-$$) db 0
dw 0xaa55