On 23/02/2024 13:09, Paolo Bonzini wrote:
> The address translation logic in get_physical_address() will currently
> truncate physical addresses to 32 bits unless long mode is enabled.
> This is incorrect when using physical address extensions (PAE) outside
> of long mode, with the result that a 32-bit operating system using PAE
> to access memory above 4G will experience undefined behaviour.
> Instead, truncation must be applied to the linear address. Because
> this truncation is diffent between 32- and 64-bit modes, the series
> opts to split 32- and 64-bit modes to separate MMU indices, which is
> the simplest way to ensure that, for example, a kernel that runs both
> 32-bit and 64-bit programs looks up the correct address in the
> (64-bit) page tables.
>
> Furthermore, when inspecting the code I noticed that the A20 mask is
> applied incorrectly when NPT is active. The mask should not be applied
> to the addresses that are looked up in the NPT, only to the physical
> addresses. Obviously no hypervisor is going to leave A20 masking on,
> but the code actually becomes simpler so let's do it.
>
> Patches 1 and 2 fix cases in which the addresses must be masked,
> or overflow is otherwise invalid, for MMU_PHYS_IDX accesses.
>
> Patches 3 and 4 introduce separate MMU indexes for 32- and 64-bit
> accesses.
>
> Patch 5 fixes the bug, by limiting the masking to the 32-bit MMU indexes.
>
> Patches 6 and 7 further clean up the MMU functions to centralize
> application of the A20 mask and fix bugs in the process.
>
> Tested with kvm-unit-tests SVM tests and with an old 32-bit Debian image.
>
> Paolo Bonzini (7):
> target/i386: mask high bits of CR3 in 32-bit mode
> target/i386: check validity of VMCB addresses
> target/i386: introduce function to query MMU indices
> target/i386: use separate MMU indexes for 32-bit accesses
> target/i386: Fix physical address truncation
> target/i386: remove unnecessary/wrong application of the A20 mask
> target/i386: leave the A20 bit set in the final NPT walk
>
> target/i386/cpu.h | 46 +++++++++++++++++++-----
> target/i386/cpu.c | 9 +++--
> target/i386/tcg/sysemu/excp_helper.c | 52 +++++++++++++---------------
> target/i386/tcg/sysemu/misc_helper.c | 3 ++
> target/i386/tcg/sysemu/svm_helper.c | 27 +++++++++++----
> 5 files changed, 92 insertions(+), 45 deletions(-)
Thank you for putting in the work to fix this all up!
I confirm that this patch series resolves the issue that I originally
observed in https://gitlab.com/qemu-project/qemu/-/issues/2040 and that
Windows 10 32-bit is able to boot with PAE enabled and memory over 4G.
Tested-by: Michael Brown <mcb30@ipxe.org>
Thanks,
Michael