c46f68bd7d
For PC-relative translation blocks, env->eip changes during the execution of a translation block, Therefore, QEMU must be able to recover an instruction's PC just from the TranslationBlock struct and the instruction data with. Because a TB will not span two pages, QEMU stores all the low bits of EIP in the instruction data and replaces them in x86_restore_state_to_opc. Bits 12 and higher (which may vary between executions of a PCREL TB, since these only use the physical address in the hash key) are kept unmodified from env->eip. The assumption is that these bits of EIP, unlike bits 0-11, will not change as the translation block executes. Unfortunately, this is incorrect when the CS base is not aligned to a page. Then the linear address of the instructions (i.e. the one with the CS base addred) indeed will never span two pages, but bits 12+ of EIP can actually change. For example, if CS base is 0x80262200 and EIP = 0x6FF4, the first instruction in the translation block will be at linear address 0x802691F4. Even a very small TB will cross to EIP = 0x7xxx, while the linear addresses will remain comfortably within a single page. The fix is simply to use the low bits of the linear address for data[0], since those don't change. Then x86_restore_state_to_opc uses tb->cs_base to compute a temporary linear address (referring to some unknown instruction in the TB, but with the correct values of bits 12 and higher); the low bits are replaced with data[0], and EIP is obtained by subtracting again the CS base. Huge thanks to Mark Cave-Ayland for the image and initial debugging, and to Gitlab user @kjliew for help with bisecting another occurrence of (hopefully!) the same bug. It should be relatively easy to write a testcase that performs MMIO on an EIP with different bits 12+ than the first instruction of the translation block; any help is welcome. Fixes: |
||
---|---|---|
.. | ||
alpha | ||
arm | ||
avr | ||
cris | ||
hexagon | ||
hppa | ||
i386 | ||
loongarch | ||
m68k | ||
microblaze | ||
mips | ||
nios2 | ||
openrisc | ||
ppc | ||
riscv | ||
rx | ||
s390x | ||
sh4 | ||
sparc | ||
tricore | ||
xtensa | ||
Kconfig | ||
meson.build |