it's already been pushed and reviewed

On Fri, Oct 2, 2026, 8:45 AM Persmule <[email protected]> wrote:

> Do you have any plan to upload this patch to https://review.coreboot.org/
> ? At least I can vote +1 for it as I have confirmed it working.
>
>
>
> On Thursday, October 1st, 2026 at 12:24 PM, Sebastian Müller <
> [email protected]> wrote:
>
> > Hi,
> > I think I found the actual problem, and it does not seem to be in
> > libgfxinit. That would also fit with the X301 test, where changing the
> > libgfxinit revision did not make any difference.
> >
> > In src/lib/hw-time-timer.adb the monotonic timer is imported like this:
> >
> >      procedure Timer_Monotonic_Get (MT : out Interfaces.C.long);
> >      pragma Import (C, Timer_Monotonic_Get, "timer_monotonic_get");
> >
> > The C side now uses:
> >
> >      struct mono_time {
> >              uint64_t microseconds;
> >      };
> >
> > and timer_monotonic_get() eventually does:
> >
> >      *mt = mono_counter.time;
> >
> > So the C function writes 8 bytes. You can also see that directly in the
> > disassembly:
> >
> >      mov %eax,(%ebx)
> >      mov %edx,0x4(%ebx)
> >
> > The problem is that on a 32-bit ramstage, Interfaces.C.long is only 4
> > bytes. GNAT allocates a 4-byte temporary, but the C function writes 8
> > bytes into it.
> >
> > As far as I can tell, the Ada declaration was correct when it was
> > originally added. The mismatch appeared later with commit b11f9f7e16
> > (timer: Switch mono_time to uint64_t, 2022-08-13), which changed the C
> > side to 64 bit without changing the Ada import.
> >
> > Without LTO this seems to work mostly by accident. Raw_Value_Min stays as
> > a separate function, has a fairly large stack frame, and the extra four
> > bytes happen to overwrite unused stack space.
> >
> > With LTO and GCC 15.2.0 the situation changes. The timer code gets
> > inlined, and in HW.Time.Ms_From_Now, HW.Time.Us_From_Now and
> > GMA.Panel.Wait_On the temporary ends up at 0xc(%esp) in a 16-byte stack
> > frame.
> >
> > That means the upper four bytes written by timer_monotonic_get()
> overwrite
> > the saved %ebx.
> >
> > When the function returns and restores %ebx, it restores the upper half
> of
> > the timer value instead of the original register value.
> >
> > That seems to be exactly what breaks the display probe.
> >
> > In the inlined Probe_Port code inside gma_gfxinit:
> >
> >      movzbl %al,%ebx
> >      cmpb   $0x0,0x4036320(%ebx)
> >      mov    %ebx,%eax
> >      call   to_panel
> >      movzbl %al,%eax
> >      call   panel__wait_on.part.0
> >      mov    %ebx,%edx
> >      call   display_probing__read_edid
> >
> > %ebx holds the port number.
> >
> > After Panel.Wait_On, %ebx is no longer the port. During early boot the
> > upper 32 bits of the microsecond counter are still zero, so %ebx
> > effectively becomes 0, which is Disabled.
> >
> > Read_EDID then subtracts one from the port, giving 0xff. The range check
> > fails, To_Display_Type falls through to its default case and returns DP,
> > and the DP path ends up using DP_Port'First, which is AUX channel A.
> >
> > That explains why it tries DDI_AUX_CTL_A instead of GMBUS pin 3, then
> > times out and eventually calls Panel.Off.
> >
> > It also explains why only the eighth probe is affected.
> >
> > For DP1-3, HDMI1-3 and VGA, To_Panel returns No_Panel, so Panel.Wait_On
> > exits before it reaches the timer code. The internal panel is the only
> one
> > that actually goes through the broken path.
> >
> > The fact that the X301 behaves the same way also makes sense then,
> because
> > this is shared timer code rather than something specific to one graphics
> > generation.
> >
> > The fix is simply to make the Ada declaration match the C type:
> >
> >      --  C declares this as `struct mono_time { uint64_t microseconds;
> }'.
> >      procedure Timer_Monotonic_Get (MT : out Word64);
> >
> > With that change, the generated code looks sane again. Raw_Value_Min is
> > called out of line, the 64-bit value comes back in eax:edx, and there is
> > no 4-byte temporary on the stack for the C function to overwrite.
> >
> > It also builds cleanly here for the hp/2170p with GCC 15.2.0 and LTO
> > enabled.
> >
> > As a small side effect, ramstage is about 500 bytes smaller with LTO and
> > around 240 bytes smaller without LTO.
> >
> > I cannot test the actual boot because I do not have a 2170p or X301 here.
> > The generated code makes the corruption pretty clear though.
> >
> > Could you test the patch on both machines with LTO enabled? That should
> > tell us whether this is indeed the bug you are seeing.
> > _______________________________________________
> > coreboot mailing list -- [email protected]
> > To unsubscribe send an email to [email protected]
> >
>
_______________________________________________
coreboot mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to