Hello,

David Bidner, le mer. 07 oct. 2026 05:21:39 +0200, a ecrit:
> When an AP starts, apboot32 loads the null IDT with
> 
>       mov     apboot_idt_ptr, %ebx
>       lidt    (%ebx)
> 
> The first instruction loads the contents of apboot_idt_ptr, which is zero,
> so lidt then loads the pseudo-descriptor from DS:0.  The AP is running with
> the early per-CPU segment base of -KERNELBASE (0x40000000), so that is
> linear address 0x40000000, i.e. physical address 0x40000000.
> 
> That physical address is RAM only when the guest has more than 1 GiB.  On a
> two-CPU i386 PAE machine with 512 or 1024 MiB it is the start of the PCI
> hole, the AP never retires lidt, and the BSP spins forever in the unbounded
> "Waiting for AP 1" loop in mp_desc.c.  With 1280 MiB or more the read lands
> in RAM and the AP happens to continue.
> 
> Load the address instead, matching the amd64 path:
> 
>       movl    $apboot_idt_ptr, %ebx
>       lidt    (%ebx)
> 
> so that the null pseudo-descriptor (limit 0, base 0) is read from
> apboot_idt_ptr itself.

Heh! Nice typo :)

Thanks for noticing,
Samuel

> Tested by booting a two-CPU i386 PAE QEMU/KVM guest at 512, 1024 and
> 1536 MiB: before this change the 512 and 1024 MiB guests hang in
> "Waiting for AP 1", after it they reach userland with the AP online.  A
> single-CPU i386 guest and two-CPU amd64 guests at the same sizes are
> unaffected.  Only i386 PAE boot-to-userland was exercised; no long-running
> behaviour was tested.
> ---
>  i386/i386/cpuboot.S | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/i386/i386/cpuboot.S b/i386/i386/cpuboot.S
> index fd3d6323..b939100a 100644
> --- a/i386/i386/cpuboot.S
> +++ b/i386/i386/cpuboot.S
> @@ -214,7 +214,7 @@ apboot32:
>       movw    %ax, %gs
>  
>       /* Load null Interrupt descriptor table */
> -     mov     apboot_idt_ptr, %ebx
> +     movl    $apboot_idt_ptr, %ebx
>       lidt    (%ebx)
>  
>       /* Enable local apic in xAPIC mode */

Reply via email to