diff mbox series

[v5,5/7] hw/isa/vt82c686: Work around missing level sensitive irq in i8259 model

Message ID cd0b323bb88df202e36014f950c0eb13a9fafd54.1677628524.git.balaton@eik.bme.hu
State New
Headers show
Series Pegasos2 fixes and audio output support | expand

Commit Message

BALATON Zoltan March 1, 2023, 12:17 a.m. UTC
MorphOS sets the ISA PIC to level sensitive mode but QEMU does not
support that so this causes a freeze if multiple devices try to raise
a shared interrupt. Work around it by lowering the interrupt before
raising it again if it is already raised. This could be reverted when
the i8259 model is fixed.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 hw/isa/vt82c686.c | 9 +++++++++
 1 file changed, 9 insertions(+)

Comments

Bernhard Beschow March 1, 2023, 6:49 a.m. UTC | #1
Am 1. März 2023 00:17:11 UTC schrieb BALATON Zoltan <balaton@eik.bme.hu>:
>MorphOS sets the ISA PIC to level sensitive mode but QEMU does not
>support that so this causes a freeze if multiple devices try to raise
>a shared interrupt. Work around it by lowering the interrupt before
>raising it again if it is already raised. This could be reverted when
>the i8259 model is fixed.
>
>Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>---
> hw/isa/vt82c686.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
>diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
>index 018a119964..3e44a51f92 100644
>--- a/hw/isa/vt82c686.c
>+++ b/hw/isa/vt82c686.c
>@@ -549,6 +549,7 @@ struct ViaISAState {
>     PCIDevice dev;
>     qemu_irq cpu_intr;
>     qemu_irq *isa_irqs_in;
>+    uint16_t isa_irqs_state;
>     ViaSuperIOState via_sio;
>     MC146818RtcState rtc;
>     PCIIDEState ide;
>@@ -636,6 +637,14 @@ static void via_isa_set_pci_irq(void *opaque, int irq_num, int level)
>             pic_level |= pci_bus_get_irq_level(bus, i);
>         }
>     }
>+    /* FIXME: workaround for i8259: level sensitive irq not supported */
>+    if ((s->isa_irqs_state & BIT(pic_irq)) && pic_level) {
>+        qemu_irq_lower(s->isa_irqs_in[pic_irq]);
>+    } else if (pic_level) {
>+        s->isa_irqs_state |= BIT(pic_irq);
>+    } else {
>+        s->isa_irqs_state &= ~BIT(pic_irq);
>+    }

Let's not clutter the device model with workarounds which quickly snowball into unmaintainable code. Please fix the i8259 instead.

>     /* Now we change the pic irq level according to the via irq mappings. */
>     qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level);
> }
BALATON Zoltan March 1, 2023, 11:27 a.m. UTC | #2
On Wed, 1 Mar 2023, Bernhard Beschow wrote:
> Am 1. März 2023 00:17:11 UTC schrieb BALATON Zoltan <balaton@eik.bme.hu>:
>> MorphOS sets the ISA PIC to level sensitive mode but QEMU does not
>> support that so this causes a freeze if multiple devices try to raise
>> a shared interrupt. Work around it by lowering the interrupt before
>> raising it again if it is already raised. This could be reverted when
>> the i8259 model is fixed.
>>
>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>> ---
>> hw/isa/vt82c686.c | 9 +++++++++
>> 1 file changed, 9 insertions(+)
>>
>> diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
>> index 018a119964..3e44a51f92 100644
>> --- a/hw/isa/vt82c686.c
>> +++ b/hw/isa/vt82c686.c
>> @@ -549,6 +549,7 @@ struct ViaISAState {
>>     PCIDevice dev;
>>     qemu_irq cpu_intr;
>>     qemu_irq *isa_irqs_in;
>> +    uint16_t isa_irqs_state;
>>     ViaSuperIOState via_sio;
>>     MC146818RtcState rtc;
>>     PCIIDEState ide;
>> @@ -636,6 +637,14 @@ static void via_isa_set_pci_irq(void *opaque, int irq_num, int level)
>>             pic_level |= pci_bus_get_irq_level(bus, i);
>>         }
>>     }
>> +    /* FIXME: workaround for i8259: level sensitive irq not supported */
>> +    if ((s->isa_irqs_state & BIT(pic_irq)) && pic_level) {
>> +        qemu_irq_lower(s->isa_irqs_in[pic_irq]);
>> +    } else if (pic_level) {
>> +        s->isa_irqs_state |= BIT(pic_irq);
>> +    } else {
>> +        s->isa_irqs_state &= ~BIT(pic_irq);
>> +    }
>
> Let's not clutter the device model with workarounds which quickly snowball into unmaintainable code. Please fix the i8259 instead.

Do you have an idea how? I don't know PC hardware well so it's not likely 
I can do that in one day and breaking PIC model would affect a lot of 
machines among them some production critical ones. Adding this workaround 
here only affects pegasos2 and the only partially modeled likely not used 
fuloong2e board (which is mostly there because it was there before and 
good to keep it to be able to test this device model with another machine) 
and I can test these two but not all the others using i8259. So I think 
for this release this is the best we can do and if somebody more 
knowledgeable about PC hardware fixes the i8259 PIC model later this can 
be easily reverted. It's not a big clutter so unless you can show this 
breaks something I'd rather have it to keep MorphOS usable on pegasos2 
with sound and network or USB. If you can prove this breaks something we 
could drop it but not based on opinion or feelengs only some evidence.

Regards,
BALATON Zoltan

>>     /* Now we change the pic irq level according to the via irq mappings. */
>>     qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level);
>> }
>
>
David Woodhouse March 1, 2023, 11:52 a.m. UTC | #3
On Wed, 2023-03-01 at 12:27 +0100, BALATON Zoltan wrote:
> On Wed, 1 Mar 2023, Bernhard Beschow wrote:
> > Am 1. März 2023 00:17:11 UTC schrieb BALATON Zoltan <balaton@eik.bme.hu>:
> > > MorphOS sets the ISA PIC to level sensitive mode but QEMU does
> > > not
> > > support that so this causes a freeze if multiple devices try to
> > > raise
> > > a shared interrupt. Work around it by lowering the interrupt
> > > before
> > > raising it again if it is already raised. This could be reverted
> > > when
> > > the i8259 model is fixed.
> > > 
> > > Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
> > > ---
> > > hw/isa/vt82c686.c | 9 +++++++++
> > > 1 file changed, 9 insertions(+)
> > > 
> > > diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
> > > index 018a119964..3e44a51f92 100644
> > > --- a/hw/isa/vt82c686.c
> > > +++ b/hw/isa/vt82c686.c
> > > @@ -549,6 +549,7 @@ struct ViaISAState {
> > >      PCIDevice dev;
> > >      qemu_irq cpu_intr;
> > >      qemu_irq *isa_irqs_in;
> > > +    uint16_t isa_irqs_state;
> > >      ViaSuperIOState via_sio;
> > >      MC146818RtcState rtc;
> > >      PCIIDEState ide;
> > > @@ -636,6 +637,14 @@ static void via_isa_set_pci_irq(void
> > > *opaque, int irq_num, int level)
> > >              pic_level |= pci_bus_get_irq_level(bus, i);
> > >          }
> > >      }
> > > +    /* FIXME: workaround for i8259: level sensitive irq not
> > > supported */
> > > +    if ((s->isa_irqs_state & BIT(pic_irq)) && pic_level) {
> > > +        qemu_irq_lower(s->isa_irqs_in[pic_irq]);
> > > +    } else if (pic_level) {
> > > +        s->isa_irqs_state |= BIT(pic_irq);
> > > +    } else {
> > > +        s->isa_irqs_state &= ~BIT(pic_irq);
> > > +    }
> > 
> > Let's not clutter the device model with workarounds which quickly
> > snowball into unmaintainable code. Please fix the i8259 instead.
> 
> Do you have an idea how? 

Let's start by understanding the problem completely. The i8259 *does*
support level-triggered interrupts. Look at the checks for s->elcr in
hw/intc/i8259.c, in pic_set_irq()...

    if (s->elcr & mask) {
        /* level triggered */
        if (level) {
            s->irr |= mask;
            s->last_irr |= mask;
        } else {
            s->irr &= ~mask;
            s->last_irr &= ~mask;
        }
    } else {
        /* edge triggered */


 ... and in pic_intack() ...


    /* We don't clear a level sensitive interrupt here */
    if (!(s->elcr & (1 << irq))) {
        s->irr &= ~(1 << irq);
    }


What qemu typically has an issue with is *shared* level-triggered
interrupts. But that would cause a level to be "forgotten" if another
input asserts and then deasserts the IRQ while one input thinks it's
holding it asserted. And I don't see how your workaround above would
have helped in that situation.

Are you sure the PIC ELCR is actually set for the lines you're having
trouble with? Is that something the Pegasos SmartFirmware would have
done, and MorphOS is expecting to inherit but isn't actually setting up
for itself?
BALATON Zoltan March 1, 2023, 1:18 p.m. UTC | #4
On Wed, 1 Mar 2023, David Woodhouse wrote:
> On Wed, 2023-03-01 at 12:27 +0100, BALATON Zoltan wrote:
>> On Wed, 1 Mar 2023, Bernhard Beschow wrote:
>>> Am 1. März 2023 00:17:11 UTC schrieb BALATON Zoltan <balaton@eik.bme.hu>:
>>>> MorphOS sets the ISA PIC to level sensitive mode but QEMU does
>>>> not
>>>> support that so this causes a freeze if multiple devices try to
>>>> raise
>>>> a shared interrupt. Work around it by lowering the interrupt
>>>> before
>>>> raising it again if it is already raised. This could be reverted
>>>> when
>>>> the i8259 model is fixed.
>>>>
>>>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>>>> ---
>>>> hw/isa/vt82c686.c | 9 +++++++++
>>>> 1 file changed, 9 insertions(+)
>>>>
>>>> diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
>>>> index 018a119964..3e44a51f92 100644
>>>> --- a/hw/isa/vt82c686.c
>>>> +++ b/hw/isa/vt82c686.c
>>>> @@ -549,6 +549,7 @@ struct ViaISAState {
>>>>      PCIDevice dev;
>>>>      qemu_irq cpu_intr;
>>>>      qemu_irq *isa_irqs_in;
>>>> +    uint16_t isa_irqs_state;
>>>>      ViaSuperIOState via_sio;
>>>>      MC146818RtcState rtc;
>>>>      PCIIDEState ide;
>>>> @@ -636,6 +637,14 @@ static void via_isa_set_pci_irq(void
>>>> *opaque, int irq_num, int level)
>>>>              pic_level |= pci_bus_get_irq_level(bus, i);
>>>>          }
>>>>      }
>>>> +    /* FIXME: workaround for i8259: level sensitive irq not
>>>> supported */
>>>> +    if ((s->isa_irqs_state & BIT(pic_irq)) && pic_level) {
>>>> +        qemu_irq_lower(s->isa_irqs_in[pic_irq]);
>>>> +    } else if (pic_level) {
>>>> +        s->isa_irqs_state |= BIT(pic_irq);
>>>> +    } else {
>>>> +        s->isa_irqs_state &= ~BIT(pic_irq);
>>>> +    }
>>>
>>> Let's not clutter the device model with workarounds which quickly
>>> snowball into unmaintainable code. Please fix the i8259 instead.
>>
>> Do you have an idea how?
>
> Let's start by understanding the problem completely. The i8259 *does*
> support level-triggered interrupts. Look at the checks for s->elcr in
> hw/intc/i8259.c, in pic_set_irq()...
>
>    if (s->elcr & mask) {
>        /* level triggered */
>        if (level) {
>            s->irr |= mask;
>            s->last_irr |= mask;
>        } else {
>            s->irr &= ~mask;
>            s->last_irr &= ~mask;
>        }
>    } else {
>        /* edge triggered */
>
>
> ... and in pic_intack() ...
>
>
>    /* We don't clear a level sensitive interrupt here */
>    if (!(s->elcr & (1 << irq))) {
>        s->irr &= ~(1 << irq);
>    }
>
>
> What qemu typically has an issue with is *shared* level-triggered
> interrupts. But that would cause a level to be "forgotten" if another
> input asserts and then deasserts the IRQ while one input thinks it's
> holding it asserted. And I don't see how your workaround above would
> have helped in that situation.
>
> Are you sure the PIC ELCR is actually set for the lines you're having
> trouble with? Is that something the Pegasos SmartFirmware would have
> done, and MorphOS is expecting to inherit but isn't actually setting up
> for itself?

No, it works with other guests like Linux and AmigaOS that use PIC as set 
up by the firmware but MorphOS tries to use it in level sensitive mode and 
likely has an IRQ handler which expects this to work. This is where I've 
debugged it and came to this workaround:

https://lists.nongnu.org/archive/html/qemu-ppc/2023-02/msg00403.html

When booting MorphOS with -d unimp I see these logs:

i8259: level sensitive irq not supported
i8259: level sensitive irq not supported

which is I guess when it tries to set it for both PICs. (If you want to 
try this MorphOS iso is downloadable and instructions how to boot it is 
here: http://zero.eik.bme.hu/~balaton/qemu/amiga/#morphos

Regards,
BALATON Zoltan
David Woodhouse March 1, 2023, 2:05 p.m. UTC | #5
On Wed, 2023-03-01 at 14:18 +0100, BALATON Zoltan wrote:
> > Are you sure the PIC ELCR is actually set for the lines you're having
> > trouble with? Is that something the Pegasos SmartFirmware would have
> > done, and MorphOS is expecting to inherit but isn't actually setting up
> > for itself?
> 
> No, it works with other guests like Linux and AmigaOS that use PIC as set 
> up by the firmware but MorphOS tries to use it in level sensitive mode and 
> likely has an IRQ handler which expects this to work. This is where I've 
> debugged it and came to this workaround:
> 
> https://lists.nongnu.org/archive/html/qemu-ppc/2023-02/msg00403.html
> 
> When booting MorphOS with -d unimp I see these logs:
> 
> i8259: level sensitive irq not supported
> i8259: level sensitive irq not supported
> 
> which is I guess when it tries to set it for both PICs. (If you want to 
> try this MorphOS iso is downloadable and instructions how to boot it is 
> here: http://zero.eik.bme.hu/~balaton/qemu/amiga/#morphos


Wow. Even looking at the PIIX3 datasheet from 1996, That 'Edge/Level
Bank Select (LTIM)' bit was documented as 'This bit is disabled. Its
function is replaced by the Edge/Level Triggerede Control (ELCR)
Registers.

We've been able to set the edge/level on a per-pin basis ever since the
ELCR was introduced with the IBM PS/2, I think.

It isn't a *correct* fix without a little bit more typing, but does
this make it work?

diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index 17910f3bcb..36ebcff025 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -246,6 +246,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
             if (val & 0x08) {
                 qemu_log_mask(LOG_UNIMP,
                               "i8259: level sensitive irq not supported\n");
+                s->elcr = 0xff;
             }
         } else if (val & 0x08) {
             if (val & 0x04) {
BALATON Zoltan March 1, 2023, 6:01 p.m. UTC | #6
On Wed, 1 Mar 2023, David Woodhouse wrote:
> On Wed, 2023-03-01 at 14:18 +0100, BALATON Zoltan wrote:
>>> Are you sure the PIC ELCR is actually set for the lines you're having
>>> trouble with? Is that something the Pegasos SmartFirmware would have
>>> done, and MorphOS is expecting to inherit but isn't actually setting up
>>> for itself?
>>
>> No, it works with other guests like Linux and AmigaOS that use PIC as set
>> up by the firmware but MorphOS tries to use it in level sensitive mode and
>> likely has an IRQ handler which expects this to work. This is where I've
>> debugged it and came to this workaround:
>>
>> https://lists.nongnu.org/archive/html/qemu-ppc/2023-02/msg00403.html
>>
>> When booting MorphOS with -d unimp I see these logs:
>>
>> i8259: level sensitive irq not supported
>> i8259: level sensitive irq not supported
>>
>> which is I guess when it tries to set it for both PICs. (If you want to
>> try this MorphOS iso is downloadable and instructions how to boot it is
>> here: http://zero.eik.bme.hu/~balaton/qemu/amiga/#morphos
>
>
> Wow. Even looking at the PIIX3 datasheet from 1996, That 'Edge/Level
> Bank Select (LTIM)' bit was documented as 'This bit is disabled. Its
> function is replaced by the Edge/Level Triggerede Control (ELCR)
> Registers.
>
> We've been able to set the edge/level on a per-pin basis ever since the
> ELCR was introduced with the IBM PS/2, I think.
>
> It isn't a *correct* fix without a little bit more typing, but does
> this make it work?
>
> diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
> index 17910f3bcb..36ebcff025 100644
> --- a/hw/intc/i8259.c
> +++ b/hw/intc/i8259.c
> @@ -246,6 +246,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
>             if (val & 0x08) {
>                 qemu_log_mask(LOG_UNIMP,
>                               "i8259: level sensitive irq not supported\n");
> +                s->elcr = 0xff;

This works too. I guess the log can be then removed too. Could you submit 
a proper patch or you want me to do that so we can drop the workaround for 
it? Thanks for looking into it.

Regards,
BALATON Zoltan

>             }
>         } else if (val & 0x08) {
>             if (val & 0x04) {
>
>
>
>
Bernhard Beschow March 1, 2023, 8:58 p.m. UTC | #7
Am 1. März 2023 14:05:31 UTC schrieb David Woodhouse <dwmw2@infradead.org>:
>On Wed, 2023-03-01 at 14:18 +0100, BALATON Zoltan wrote:
>> > Are you sure the PIC ELCR is actually set for the lines you're having
>> > trouble with? Is that something the Pegasos SmartFirmware would have
>> > done, and MorphOS is expecting to inherit but isn't actually setting up
>> > for itself?
>> 
>> No, it works with other guests like Linux and AmigaOS that use PIC as set 
>> up by the firmware but MorphOS tries to use it in level sensitive mode and 
>> likely has an IRQ handler which expects this to work. This is where I've 
>> debugged it and came to this workaround:
>> 
>> https://lists.nongnu.org/archive/html/qemu-ppc/2023-02/msg00403.html
>> 
>> When booting MorphOS with -d unimp I see these logs:
>> 
>> i8259: level sensitive irq not supported
>> i8259: level sensitive irq not supported
>> 
>> which is I guess when it tries to set it for both PICs. (If you want to 
>> try this MorphOS iso is downloadable and instructions how to boot it is 
>> here: http://zero.eik.bme.hu/~balaton/qemu/amiga/#morphos
>
>
>Wow. Even looking at the PIIX3 datasheet from 1996, That 'Edge/Level
>Bank Select (LTIM)' bit was documented as 'This bit is disabled. Its
>function is replaced by the Edge/Level Triggerede Control (ELCR)
>Registers.
>
>We've been able to set the edge/level on a per-pin basis ever since the
>ELCR was introduced with the IBM PS/2, I think.
>
>It isn't a *correct* fix without a little bit more typing, but does
>this make it work?
>
>diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
>index 17910f3bcb..36ebcff025 100644
>--- a/hw/intc/i8259.c
>+++ b/hw/intc/i8259.c
>@@ -246,6 +246,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
>             if (val & 0x08) {
>                 qemu_log_mask(LOG_UNIMP,
>                               "i8259: level sensitive irq not supported\n");
>+                s->elcr = 0xff;

Thanks so much, David! You're a genious...

Best regards,

Bernhard

>             }
>         } else if (val & 0x08) {
>             if (val & 0x04) {
>
>
>
David Woodhouse March 1, 2023, 9:53 p.m. UTC | #8
On Wed, 2023-03-01 at 19:01 +0100, BALATON Zoltan wrote:
> 
> > It isn't a *correct* fix without a little bit more typing, but does
> > this make it work?
> > 
> > diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
> > index 17910f3bcb..36ebcff025 100644
> > --- a/hw/intc/i8259.c
> > +++ b/hw/intc/i8259.c
> > @@ -246,6 +246,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
> >              if (val & 0x08) {
> >                  qemu_log_mask(LOG_UNIMP,
> >                                "i8259: level sensitive irq not supported\n");
> > +                s->elcr = 0xff;
> 
> This works too. I guess the log can be then removed too. Could you submit 
> a proper patch or you want me to do that so we can drop the workaround for 
> it? Thanks for looking into it.


Happy for you to do the rest of the typing ... :)

So, *ideally* I think you need to introduce a new field in the
PICCommonState which records the status of the LTIM bit. And fix up the
vmstate_pic_common in hw/intc/i8259_common.c to save and restore that
(with versioning for upgrade/downgrade).

Then you find those places which currently check the bit for the
specific pin in s->elcr, and make them something like:

--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -133,7 +133,7 @@ static void pic_set_irq(void *opaque, int irq, int level)
     }
 #endif
 
-    if (s->elcr & mask) {
+    if (s->ltim || (s->elcr & mask)) {
         /* level triggered */
         if (level) {
             s->irr |= mask;

It *might* be that you should make the LTIM behaviour optional, so that
only certain incarnations of the i8259 actually get it at all and it
*wouldn't* take effect if a guest tried to set it, which is what the
PIIX3 datasheet implies. But I suspect we can get away without that.
BALATON Zoltan March 1, 2023, 10:47 p.m. UTC | #9
On Wed, 1 Mar 2023, David Woodhouse wrote:
> On Wed, 2023-03-01 at 19:01 +0100, BALATON Zoltan wrote:
>>
>>> It isn't a *correct* fix without a little bit more typing, but does
>>> this make it work?
>>>
>>> diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
>>> index 17910f3bcb..36ebcff025 100644
>>> --- a/hw/intc/i8259.c
>>> +++ b/hw/intc/i8259.c
>>> @@ -246,6 +246,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
>>>              if (val & 0x08) {
>>>                  qemu_log_mask(LOG_UNIMP,
>>>                                "i8259: level sensitive irq not supported\n");
>>> +                s->elcr = 0xff;
>>
>> This works too. I guess the log can be then removed too. Could you submit
>> a proper patch or you want me to do that so we can drop the workaround for
>> it? Thanks for looking into it.
>
>
> Happy for you to do the rest of the typing ... :)

I don't mind the typing but this is quite a bit more involved than I 
expected. You've lost me at the vmstate stuff which I don't quite know how 
to change or test. If these were stored as bits in an ISW1 register as 
described by the docs I've looked at now then no change in migration would 
be needed but this isn't how it seems to be in QEMU so I give up on that 
in this case. Could you please do the typing then?

Thank you,
BALATON Zoltan

> So, *ideally* I think you need to introduce a new field in the
> PICCommonState which records the status of the LTIM bit. And fix up the
> vmstate_pic_common in hw/intc/i8259_common.c to save and restore that
> (with versioning for upgrade/downgrade).
>
> Then you find those places which currently check the bit for the
> specific pin in s->elcr, and make them something like:
>
> --- a/hw/intc/i8259.c
> +++ b/hw/intc/i8259.c
> @@ -133,7 +133,7 @@ static void pic_set_irq(void *opaque, int irq, int level)
>     }
> #endif
>
> -    if (s->elcr & mask) {
> +    if (s->ltim || (s->elcr & mask)) {
>         /* level triggered */
>         if (level) {
>             s->irr |= mask;
>
> It *might* be that you should make the LTIM behaviour optional, so that
> only certain incarnations of the i8259 actually get it at all and it
> *wouldn't* take effect if a guest tried to set it, which is what the
> PIIX3 datasheet implies. But I suspect we can get away without that.
>
>
David Woodhouse March 2, 2023, 8:59 a.m. UTC | #10
On Wed, 2023-03-01 at 23:47 +0100, BALATON Zoltan wrote:
> On Wed, 1 Mar 2023, David Woodhouse wrote:
> > On Wed, 2023-03-01 at 19:01 +0100, BALATON Zoltan wrote:
> > > 
> > > > It isn't a *correct* fix without a little bit more typing, but does
> > > > this make it work?
> > > > 
> > > > diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
> > > > index 17910f3bcb..36ebcff025 100644
> > > > --- a/hw/intc/i8259.c
> > > > +++ b/hw/intc/i8259.c
> > > > @@ -246,6 +246,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
> > > >              if (val & 0x08) {
> > > >                  qemu_log_mask(LOG_UNIMP,
> > > >                                "i8259: level sensitive irq not supported\n");
> > > > +                s->elcr = 0xff;
> > > 
> > > This works too. I guess the log can be then removed too. Could you submit
> > > a proper patch or you want me to do that so we can drop the workaround for
> > > it? Thanks for looking into it.
> > 
> > 
> > Happy for you to do the rest of the typing ... :)
> 
> I don't mind the typing but this is quite a bit more involved than I 
> expected. You've lost me at the vmstate stuff which I don't quite know how 
> to change or test. If these were stored as bits in an ISW1 register as 
> described by the docs I've looked at now then no change in migration would 
> be needed but this isn't how it seems to be in QEMU so I give up on that 
> in this case. Could you please do the typing then?

Yeah, it is a bit weird that we store the ICW1 byte in *separate*
elements of persistent state, each of *them* a uint8_t which holds only
a single bit of ICW1:

            s->init4 = val & 1;
            s->single_mode = val & 2;
            s->ltim = val & 8;

Still, it's a pattern that's easy enough to follow.

As for the rest of the typing, I'd basically done the bulk of it
already when showing how to adjust the existing (s->elcr&mask) checks;
there was only one more of those to type.

And then the vmstate part is basically just a cut and paste of the bit
in docs/devel/migration.rst which tells you exactly how to do it.

Patch follows. It builds, but I'll let you do the actual testing,
including migration to/from the new version, checking with
scripts/analyze-migration.py that the ltim is there when it should be,
and isn't when it shouldn't, and any other review feedback.
BALATON Zoltan March 2, 2023, 9:46 p.m. UTC | #11
On Thu, 2 Mar 2023, David Woodhouse wrote:
> On Wed, 2023-03-01 at 23:47 +0100, BALATON Zoltan wrote:
>> On Wed, 1 Mar 2023, David Woodhouse wrote:
>>> On Wed, 2023-03-01 at 19:01 +0100, BALATON Zoltan wrote:
>>>>
>>>>> It isn't a *correct* fix without a little bit more typing, but does
>>>>> this make it work?
>>>>>
>>>>> diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
>>>>> index 17910f3bcb..36ebcff025 100644
>>>>> --- a/hw/intc/i8259.c
>>>>> +++ b/hw/intc/i8259.c
>>>>> @@ -246,6 +246,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
>>>>>              if (val & 0x08) {
>>>>>                  qemu_log_mask(LOG_UNIMP,
>>>>>                                "i8259: level sensitive irq not supported\n");
>>>>> +                s->elcr = 0xff;
>>>>
>>>> This works too. I guess the log can be then removed too. Could you submit
>>>> a proper patch or you want me to do that so we can drop the workaround for
>>>> it? Thanks for looking into it.
>>>
>>>
>>> Happy for you to do the rest of the typing ... :)
>>
>> I don't mind the typing but this is quite a bit more involved than I
>> expected. You've lost me at the vmstate stuff which I don't quite know how
>> to change or test. If these were stored as bits in an ISW1 register as
>> described by the docs I've looked at now then no change in migration would
>> be needed but this isn't how it seems to be in QEMU so I give up on that
>> in this case. Could you please do the typing then?
>
> Yeah, it is a bit weird that we store the ICW1 byte in *separate*
> elements of persistent state, each of *them* a uint8_t which holds only
> a single bit of ICW1:
>
>            s->init4 = val & 1;
>            s->single_mode = val & 2;
>            s->ltim = val & 8;
>
> Still, it's a pattern that's easy enough to follow.
>
> As for the rest of the typing, I'd basically done the bulk of it
> already when showing how to adjust the existing (s->elcr&mask) checks;
> there was only one more of those to type.
>
> And then the vmstate part is basically just a cut and paste of the bit
> in docs/devel/migration.rst which tells you exactly how to do it.
>
> Patch follows. It builds, but I'll let you do the actual testing,
> including migration to/from the new version, checking with
> scripts/analyze-migration.py that the ltim is there when it should be,
> and isn't when it shouldn't, and any other review feedback.

I've tested that it fixes the problem with MorphOS on pegasos2 and checked 
that a migration file created while at the firmware, before MorphOS sets 
ltim does not have the subsection while migrate after MorphOS boot has it:

                 {
                     "name": "single_mode",
                     "type": "uint8",
                     "size": 1
                 },
                 {
                     "name": "elcr",
                     "type": "uint8",
                     "size": 1
                 }
             ],
             "subsections": [
                 {
                     "vmsd_name": "i8259/ltim",
                     "version": 1,
                     "fields": [
                         {
                             "name": "ltim",
                             "type": "uint8",
                             "size": 1
                         }
                     ]
                 }
             ]
         },
         {
             "name": "i8259",
             "instance_id": 1,
             "vmsd_name": "i8259",
             "version": 1,
             "fields": [
                 {
                     "name": "last_irr",
                     "type": "uint8",
                     "size": 1
                 },

A migration file saved from the qemu-system-x86_64 default pc machine also 
lacks the subsection so it should not affect migration there unless 
something sets the bit. Is this enough testing or should I try something 
else? I've updated the commit message but did not change the comment.

Regards,
BALATON Zoltan
diff mbox series

Patch

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 018a119964..3e44a51f92 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -549,6 +549,7 @@  struct ViaISAState {
     PCIDevice dev;
     qemu_irq cpu_intr;
     qemu_irq *isa_irqs_in;
+    uint16_t isa_irqs_state;
     ViaSuperIOState via_sio;
     MC146818RtcState rtc;
     PCIIDEState ide;
@@ -636,6 +637,14 @@  static void via_isa_set_pci_irq(void *opaque, int irq_num, int level)
             pic_level |= pci_bus_get_irq_level(bus, i);
         }
     }
+    /* FIXME: workaround for i8259: level sensitive irq not supported */
+    if ((s->isa_irqs_state & BIT(pic_irq)) && pic_level) {
+        qemu_irq_lower(s->isa_irqs_in[pic_irq]);
+    } else if (pic_level) {
+        s->isa_irqs_state |= BIT(pic_irq);
+    } else {
+        s->isa_irqs_state &= ~BIT(pic_irq);
+    }
     /* Now we change the pic irq level according to the via irq mappings. */
     qemu_set_irq(s->isa_irqs_in[pic_irq], pic_level);
 }