blob: 1a34672d30805ba5de8cf7c226b10d171e72a341 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
x86: 0.968
debug: 0.930
TCG: 0.890
architecture: 0.867
kernel: 0.797
device: 0.766
graphic: 0.732
performance: 0.720
boot: 0.632
i386: 0.602
peripherals: 0.588
socket: 0.573
semantic: 0.558
ppc: 0.555
mistranslation: 0.516
network: 0.478
permissions: 0.471
register: 0.457
PID: 0.450
vnc: 0.425
arm: 0.351
risc-v: 0.301
hypervisor: 0.292
assembly: 0.231
VMM: 0.222
user-level: 0.222
files: 0.191
KVM: 0.156
virtual: 0.092
x86 TCG incorrectly truncates physical addresses to 32 bits when PAE is enabled
Description of problem:
Originally observed as 32-bit Windows failing to boot on systems with RAM above 4G when using TCG (but working fine under KVM). Windows kernel debugger showed the kernel allocating a block of memory but somehow failing to create a page table mapping for it.
Bisection in QEMU produced the first bad commit as 4a1e9d4 ("target/i386: Use atomic operations for pte updates"), which changed the PTE accessing code from using e.g. `x86_ldq_phys()` to using `probe_access_full()` and `ldq_p()`.
Further deconstruction of the changes in this commit found that at some point during the boot, the value obtained from `ldq_p()` was completely different to the value obtained from `x86_ldq_phys()`. Debugging revealed that the underlying host addresses used by each method were exactly 4G apart, with the new method (`ldq_p()`) accessing a host location 4G below the correct address.
Inspection of the code revealed one place where addresses are truncated to 32 bits, which would cause this 4G offset: in `get_physical_address()` we have the code:
```
if (!(env->hflags & HF_LMA_MASK)) {
/* Without long mode we can only address 32bits in real mode */
out->paddr = (uint32_t)out->paddr;
}
```
This looks wrong, since PAE allows for physical addresses above 4G to be accessed without long mode. (This is the whole point of PAE.)
A quick experiment shows that commenting out the above block of code fixes the symptom and allows Windows 10 to boot with RAM above 4G.
I suspect that the test should be checking for PAE being enabled rather than long mode being enabled. (Enabling PAE is part of setting up the CPU for long mode, so it is impossible to be in long mode without PAE already enabled.)
Steps to reproduce:
Run the command given above.
|