On Fri, 20 Jun 2025 18:01:08 +0100
Peter Maydell <peter.mayd...@linaro.org> wrote:

> On Fri, 20 Jun 2025 at 16:15, Igor Mammedov <imamm...@redhat.com> wrote:
> >
> > Reading QEMU_CLOCK_VIRTUAL is thread-safe.
> >
> > with CLI
> >  -M q35,hpet=on -cpu host -enable-kvm -smp 240,sockets=4
> > patch makes WS2025 guest, that was able to boot in 4/2min, to boot in 
> > 2/1min.
> >
> > Signed-off-by: Igor Mammedov <imamm...@redhat.com>
> > ---
> >  hw/timer/hpet.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
> > index 0fd1337a15..1ebd715529 100644
> > --- a/hw/timer/hpet.c
> > +++ b/hw/timer/hpet.c
> > @@ -681,6 +681,8 @@ static void hpet_init(Object *obj)
> >
> >      /* HPET Area */
> >      memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", 
> > HPET_LEN);
> > +    memory_region_enable_lockless_ro_io(&s->iomem);
> > +    s->iomem.disable_reentrancy_guard = true;
> >      sysbus_init_mmio(sbd, &s->iomem);  
> 
> Is this sequence possible?
While unlikely (what I observe from Linux/Windows guest,
they enable timer 1st and only then start readers),
but yes it still possible.

The more convoluted is the switch into disabled state, where
1:
  reader is already in enabled branch and preempted before
  reading clock:  
          case HPET_COUNTER:
            if (hpet_enabled(s)) {
               <yield>
               cur_tick = hpet_get_ticks(s);
2:
  writer saves s->hpet_counter = <now>

3:
  reader resumes and reads newer 'now'

4:
  on next counter read, reader switches to disabled branch
  and sees timer jump back to older s->hpet_counter value.
  and that shouldn't happen.

for this to work s->hpet_counter needs to catch up
the latest read timer value.

Let me try and see what could be done with it.

> 
> thread A
>    takes the BQL
>    enters hpet_ram_write() for HPET_CFG to set ENABLE
>    executes s->config = new_val (setting the ENABLE bit in it)
>    context switch before it gets to the point of setting
>      s->hpet_offset
> 
> thread B
>    enters hpet_ram_read() for HPET_COUNTER (which it can now
>     do because it doesn't need the BQL)
>    hpet_enabled() returns true (it tests s->config)
>    calls hpet_get_ticks which adds hpet_offset to the clock,
>      but hpet_offset has not been correctly set by A yet
> 
> thanks
> -- PMM
> 


Reply via email to