diff mbox

RFC: ACPI, HPET._CRS, MacOSX vs. WinXP

Message ID 20140117211015.GB18752@ERROL.INI.CMU.EDU
State New
Headers show

Commit Message

Gabriel L. Somlo Jan. 17, 2014, 9:10 p.m. UTC
On Fri, Jan 10, 2014 at 05:13:11PM +0100, Igor Mammedov wrote:
> > On Fri, Jan 10, 2014 at 01:37:14PM +0100, Paolo Bonzini wrote:
> > > Il 09/01/2014 22:44, Gabriel L. Somlo ha scritto:
> > > > 1. hardcode "IRQNoFlags(){2, 8}" and require -no-hpet to prevent XP
> > > >    from bluescreening. Basically, this means we don't support XP on
> > > >    a VM where HPET is enabled.
> > > > 
> > > > 2. conditionally insert "IRQNoFlags(){2, 8}" if _OSI("Darwin") returns
> > > >    0xFFFFFFFF, [...] if we want to run OS X on piix+smp
> > > >    (all other combinations of (piix vs. q35) x (up vs.  smp) work fine
...
> there is harder route to get a clue why XP BSODs,
> one can use AMLI debugger to see what is happening in XP on boot
> http://msdn.microsoft.com/en-us/library/windows/hardware/ff537808%28v=vs.85%29.aspx
> that was how I found out about not supported ConcatenateResTemplate first.

After doing a bit of research, here's what I was able to find out:

1. "IRQNoFlags {2, 8}" was a mistake/typo I made early on, real Apple
   hardware (and *only* Apple hardware) has "IRQNoFlags {0, 8}" included
   with HPET._CRS

2. Both 0 and 8 are already spoken for, by the system timer (TMR), and
   by the RTC, respectively.

3. WinXP will also bluescreen on QEMU if HPET._CRS has "IRQNoFlags {0, 8}"
   added; in fact, it will bluescreen if *any* IRQNoFlags statement is
   included with the HPET DSDT node, as far as I was able to tell.

4. I acpidump-ed the DSDT on a bunch of machines, including a MacPro5,1,
   a MacBookPro2,2, a MacBookPro9,1, a Dell Latitude D630, and a Dell R410.
   Here's what I found:

     - All Macs (and only Macs) have IRQNoFlags {0, 8} in HPET._CRS.
     - my Dells (and I suspect most non-Apple machines) don't have
       IRQNoFlags in HPET_CRS at all.

     - On Macs, there's no TMR DSDT node at all.
     - My Latitude D630 laptop has a TMR node, with IRQNoFlags {2} in _CRS
     - the R410 also has a TMR node, with IRQNoFlags {0} in _CRS.

     - On Macs, RTC has no IRQNoFlags in its _CRS
     - Both my dells have IRQNoFlags {8} in RTC._CRS

5. I was able to boot XPsp2 on the MacBookPro2,2 straight from the DVD
   with a zeroed-out hard drive. It installs and works fine, and when
   I pull up the Device Manager, neither the RTC or the TMR devices have
   any IRQs listed under Properties/Resources.
   What is even more interesting, the HPET does NOT show up in the device
   tree *at all* !!!

6. On the MacBookPro9,1, XP bluescreens during install, in a similar
   mannner to how it bluescreens on QEMU if HPET._CRS contains IRQNoFlags.
   Bootcamp doesn't support anything older than Windows 7 on those machines,
   so I don't think there's anything I can do to get XP running and look
   at the device tree on that machine.

7. On QEMU, XP does indeed show the HPET alongside the TMR and RTC in
   its device tree, obviously without any IRQ resources under properties,
   since the only way it boots is if HPET._CRS doesn't include IRQNoFlags.

8. Windows 7, while it boots and runs fine when HPET._CRS contains
   IRQNoFlags, will show an unresolved IRQ conflict between the HPET and
   the RTC in the device tree. Commenting out IRQNoFlags from the RTC
   in QEMU does NOT solve that (still shows up as a conflict in the
   device tree).

9. I followed Igor's advice and ran a debug session, but unlike with
   ConcatenateResTemplate, XP didn't choke on AML byte code itself, but
   appears to die of a memory access violation:

     *** Fatal System Error: 0x0000007e (0x...)
     ...
     Probably caused by: ACPI.sys (ACPI!AcpiArbCrackPRT+113)

     80527bdc cc       int 3

   Poking around with various !amli debugger commands does not show
   anything AML-related as abnormal, so I think the problem is that
   either XP specifically expects the HPET._CRS buffer to be of a
   certain hardcoded size (which doesn't include any extra room for
   IRQNoFlags), or attempts to somehow process the values given via
   IRQNoFlags (0 and 8) in ways that cause it to then kill itself.

   Hard to tell without knowing more about XP internals (e.g., without
   XP kernel and/or acpi.sys source code).

At this point, conditionally inserting IRQNoFlags {0,8} only for OS X
sounds less of a hack and more like the right thing to do. I would be
comfortable using ConcatenateResTemplate since XP never gets a chance
to attempt to interpret that bytecode, which gets exercised only by
the _OSI("Darwin") branch. I tested this, and both XP and OSX seem
happy with it.

Please let me know what you think.

Thanks,
--Gabriel

Comments

Paolo Bonzini Jan. 20, 2014, 11:57 a.m. UTC | #1
Il 20/01/2014 12:58, Michael S. Tsirkin ha scritto:
> I think at this point I agree.
> 
> I think the hack looking for the SMC device is safer than _OSI: OSPMs
> are known to do crazy things when they see _OSI, such as assuming they
> need to try and emulate the OS probed.

Source?

Paolo
Michael S. Tsirkin Jan. 20, 2014, 11:58 a.m. UTC | #2
On Fri, Jan 17, 2014 at 04:10:16PM -0500, Gabriel L. Somlo wrote:
> On Fri, Jan 10, 2014 at 05:13:11PM +0100, Igor Mammedov wrote:
> > > On Fri, Jan 10, 2014 at 01:37:14PM +0100, Paolo Bonzini wrote:
> > > > Il 09/01/2014 22:44, Gabriel L. Somlo ha scritto:
> > > > > 1. hardcode "IRQNoFlags(){2, 8}" and require -no-hpet to prevent XP
> > > > >    from bluescreening. Basically, this means we don't support XP on
> > > > >    a VM where HPET is enabled.
> > > > > 
> > > > > 2. conditionally insert "IRQNoFlags(){2, 8}" if _OSI("Darwin") returns
> > > > >    0xFFFFFFFF, [...] if we want to run OS X on piix+smp
> > > > >    (all other combinations of (piix vs. q35) x (up vs.  smp) work fine
> ...
> > there is harder route to get a clue why XP BSODs,
> > one can use AMLI debugger to see what is happening in XP on boot
> > http://msdn.microsoft.com/en-us/library/windows/hardware/ff537808%28v=vs.85%29.aspx
> > that was how I found out about not supported ConcatenateResTemplate first.
> 
> After doing a bit of research, here's what I was able to find out:
> 
> 1. "IRQNoFlags {2, 8}" was a mistake/typo I made early on, real Apple
>    hardware (and *only* Apple hardware) has "IRQNoFlags {0, 8}" included
>    with HPET._CRS
> 
> 2. Both 0 and 8 are already spoken for, by the system timer (TMR), and
>    by the RTC, respectively.
> 
> 3. WinXP will also bluescreen on QEMU if HPET._CRS has "IRQNoFlags {0, 8}"
>    added; in fact, it will bluescreen if *any* IRQNoFlags statement is
>    included with the HPET DSDT node, as far as I was able to tell.
> 
> 4. I acpidump-ed the DSDT on a bunch of machines, including a MacPro5,1,
>    a MacBookPro2,2, a MacBookPro9,1, a Dell Latitude D630, and a Dell R410.
>    Here's what I found:
> 
>      - All Macs (and only Macs) have IRQNoFlags {0, 8} in HPET._CRS.
>      - my Dells (and I suspect most non-Apple machines) don't have
>        IRQNoFlags in HPET_CRS at all.
> 
>      - On Macs, there's no TMR DSDT node at all.
>      - My Latitude D630 laptop has a TMR node, with IRQNoFlags {2} in _CRS
>      - the R410 also has a TMR node, with IRQNoFlags {0} in _CRS.
> 
>      - On Macs, RTC has no IRQNoFlags in its _CRS
>      - Both my dells have IRQNoFlags {8} in RTC._CRS
> 
> 5. I was able to boot XPsp2 on the MacBookPro2,2 straight from the DVD
>    with a zeroed-out hard drive. It installs and works fine, and when
>    I pull up the Device Manager, neither the RTC or the TMR devices have
>    any IRQs listed under Properties/Resources.
>    What is even more interesting, the HPET does NOT show up in the device
>    tree *at all* !!!
> 
> 6. On the MacBookPro9,1, XP bluescreens during install, in a similar
>    mannner to how it bluescreens on QEMU if HPET._CRS contains IRQNoFlags.
>    Bootcamp doesn't support anything older than Windows 7 on those machines,
>    so I don't think there's anything I can do to get XP running and look
>    at the device tree on that machine.
> 
> 7. On QEMU, XP does indeed show the HPET alongside the TMR and RTC in
>    its device tree, obviously without any IRQ resources under properties,
>    since the only way it boots is if HPET._CRS doesn't include IRQNoFlags.
> 
> 8. Windows 7, while it boots and runs fine when HPET._CRS contains
>    IRQNoFlags, will show an unresolved IRQ conflict between the HPET and
>    the RTC in the device tree. Commenting out IRQNoFlags from the RTC
>    in QEMU does NOT solve that (still shows up as a conflict in the
>    device tree).
> 
> 9. I followed Igor's advice and ran a debug session, but unlike with
>    ConcatenateResTemplate, XP didn't choke on AML byte code itself, but
>    appears to die of a memory access violation:
> 
>      *** Fatal System Error: 0x0000007e (0x...)
>      ...
>      Probably caused by: ACPI.sys (ACPI!AcpiArbCrackPRT+113)
> 
>      80527bdc cc       int 3
> 
>    Poking around with various !amli debugger commands does not show
>    anything AML-related as abnormal, so I think the problem is that
>    either XP specifically expects the HPET._CRS buffer to be of a
>    certain hardcoded size (which doesn't include any extra room for
>    IRQNoFlags), or attempts to somehow process the values given via
>    IRQNoFlags (0 and 8) in ways that cause it to then kill itself.
> 
>    Hard to tell without knowing more about XP internals (e.g., without
>    XP kernel and/or acpi.sys source code).
> 
> At this point, conditionally inserting IRQNoFlags {0,8} only for OS X
> sounds less of a hack and more like the right thing to do. I would be
> comfortable using ConcatenateResTemplate since XP never gets a chance
> to attempt to interpret that bytecode, which gets exercised only by
> the _OSI("Darwin") branch. I tested this, and both XP and OSX seem
> happy with it.
> 
> Please let me know what you think.
> 
> Thanks,
> --Gabriel

I think at this point I agree.

I think the hack looking for the SMC device is safer than _OSI: OSPMs
are known to do crazy things when they see _OSI, such as assuming they
need to try and emulate the OS probed.


> diff --git a/hw/i386/acpi-dsdt-hpet.dsl b/hw/i386/acpi-dsdt-hpet.dsl
> index dfde174..0cf7fbf 100644
> --- a/hw/i386/acpi-dsdt-hpet.dsl
> +++ b/hw/i386/acpi-dsdt-hpet.dsl
> @@ -38,14 +38,21 @@ Scope(\_SB) {
>              }
>              Return (0x0F)
>          }
> -        Name(_CRS, ResourceTemplate() {
> -#if 0       /* This makes WinXP BSOD for not yet figured reasons. */
> -            IRQNoFlags() {2, 8}
> -#endif
> +        Name(RESP, ResourceTemplate() {
>              Memory32Fixed(ReadOnly,
>                  0xFED00000,         // Address Base
>                  0x00000400,         // Address Length
>                  )
>          })
> +        Name(RESI, ResourceTemplate() {
> +            IRQNoFlags() {0, 8}     // Mac OS X only
> +        })
> +        Method(_CRS, 0) {
> +            If (LEqual(\_OSI("Darwin"), 0xFFFFFFFF)) {
> +                Return (ConcatenateResTemplate(RESP, RESI, Local0))
> +            } else {
> +                Return (RESP)
> +            }
> +        }
>      }
>  }
Igor Mammedov Jan. 20, 2014, 12:03 p.m. UTC | #3
On Fri, 17 Jan 2014 16:10:16 -0500
"Gabriel L. Somlo" <gsomlo@gmail.com> wrote:

> On Fri, Jan 10, 2014 at 05:13:11PM +0100, Igor Mammedov wrote:
> > > On Fri, Jan 10, 2014 at 01:37:14PM +0100, Paolo Bonzini wrote:
> > > > Il 09/01/2014 22:44, Gabriel L. Somlo ha scritto:
> > > > > 1. hardcode "IRQNoFlags(){2, 8}" and require -no-hpet to prevent XP
> > > > >    from bluescreening. Basically, this means we don't support XP on
> > > > >    a VM where HPET is enabled.
> > > > > 
> > > > > 2. conditionally insert "IRQNoFlags(){2, 8}" if _OSI("Darwin") returns
> > > > >    0xFFFFFFFF, [...] if we want to run OS X on piix+smp
> > > > >    (all other combinations of (piix vs. q35) x (up vs.  smp) work fine
> ...
> > there is harder route to get a clue why XP BSODs,
> > one can use AMLI debugger to see what is happening in XP on boot
> > http://msdn.microsoft.com/en-us/library/windows/hardware/ff537808%28v=vs.85%29.aspx
> > that was how I found out about not supported ConcatenateResTemplate first.
> 
> After doing a bit of research, here's what I was able to find out:
> 
> 1. "IRQNoFlags {2, 8}" was a mistake/typo I made early on, real Apple
>    hardware (and *only* Apple hardware) has "IRQNoFlags {0, 8}" included
>    with HPET._CRS
> 
> 2. Both 0 and 8 are already spoken for, by the system timer (TMR), and
>    by the RTC, respectively.
> 
> 3. WinXP will also bluescreen on QEMU if HPET._CRS has "IRQNoFlags {0, 8}"
>    added; in fact, it will bluescreen if *any* IRQNoFlags statement is
>    included with the HPET DSDT node, as far as I was able to tell.
> 
> 4. I acpidump-ed the DSDT on a bunch of machines, including a MacPro5,1,
>    a MacBookPro2,2, a MacBookPro9,1, a Dell Latitude D630, and a Dell R410.
>    Here's what I found:
> 
>      - All Macs (and only Macs) have IRQNoFlags {0, 8} in HPET._CRS.
>      - my Dells (and I suspect most non-Apple machines) don't have
>        IRQNoFlags in HPET_CRS at all.
> 
>      - On Macs, there's no TMR DSDT node at all.
>      - My Latitude D630 laptop has a TMR node, with IRQNoFlags {2} in _CRS
>      - the R410 also has a TMR node, with IRQNoFlags {0} in _CRS.
> 
>      - On Macs, RTC has no IRQNoFlags in its _CRS
>      - Both my dells have IRQNoFlags {8} in RTC._CRS
> 
> 5. I was able to boot XPsp2 on the MacBookPro2,2 straight from the DVD
>    with a zeroed-out hard drive. It installs and works fine, and when
>    I pull up the Device Manager, neither the RTC or the TMR devices have
>    any IRQs listed under Properties/Resources.
>    What is even more interesting, the HPET does NOT show up in the device
>    tree *at all* !!!
> 
> 6. On the MacBookPro9,1, XP bluescreens during install, in a similar
>    mannner to how it bluescreens on QEMU if HPET._CRS contains IRQNoFlags.
>    Bootcamp doesn't support anything older than Windows 7 on those machines,
>    so I don't think there's anything I can do to get XP running and look
>    at the device tree on that machine.
> 
> 7. On QEMU, XP does indeed show the HPET alongside the TMR and RTC in
>    its device tree, obviously without any IRQ resources under properties,
>    since the only way it boots is if HPET._CRS doesn't include IRQNoFlags.
> 
> 8. Windows 7, while it boots and runs fine when HPET._CRS contains
>    IRQNoFlags, will show an unresolved IRQ conflict between the HPET and
>    the RTC in the device tree. Commenting out IRQNoFlags from the RTC
>    in QEMU does NOT solve that (still shows up as a conflict in the
>    device tree).
> 
> 9. I followed Igor's advice and ran a debug session, but unlike with
>    ConcatenateResTemplate, XP didn't choke on AML byte code itself, but
>    appears to die of a memory access violation:
> 
>      *** Fatal System Error: 0x0000007e (0x...)
>      ...
>      Probably caused by: ACPI.sys (ACPI!AcpiArbCrackPRT+113)
> 
>      80527bdc cc       int 3
> 
>    Poking around with various !amli debugger commands does not show
>    anything AML-related as abnormal, so I think the problem is that
>    either XP specifically expects the HPET._CRS buffer to be of a
>    certain hardcoded size (which doesn't include any extra room for
>    IRQNoFlags), or attempts to somehow process the values given via
>    IRQNoFlags (0 and 8) in ways that cause it to then kill itself.
> 
>    Hard to tell without knowing more about XP internals (e.g., without
>    XP kernel and/or acpi.sys source code).
> 
> At this point, conditionally inserting IRQNoFlags {0,8} only for OS X
> sounds less of a hack and more like the right thing to do. I would be
> comfortable using ConcatenateResTemplate since XP never gets a chance
> to attempt to interpret that bytecode, which gets exercised only by
> the _OSI("Darwin") branch. I tested this, and both XP and OSX seem
> happy with it.
> 
> Please let me know what you think.
> 
> Thanks,
> --Gabriel
> 
> diff --git a/hw/i386/acpi-dsdt-hpet.dsl b/hw/i386/acpi-dsdt-hpet.dsl
> index dfde174..0cf7fbf 100644
> --- a/hw/i386/acpi-dsdt-hpet.dsl
> +++ b/hw/i386/acpi-dsdt-hpet.dsl
> @@ -38,14 +38,21 @@ Scope(\_SB) {
>              }
>              Return (0x0F)
>          }
> -        Name(_CRS, ResourceTemplate() {
> -#if 0       /* This makes WinXP BSOD for not yet figured reasons. */
> -            IRQNoFlags() {2, 8}
> -#endif
> +        Name(RESP, ResourceTemplate() {
>              Memory32Fixed(ReadOnly,
>                  0xFED00000,         // Address Base
>                  0x00000400,         // Address Length
>                  )
>          })
> +        Name(RESI, ResourceTemplate() {
> +            IRQNoFlags() {0, 8}     // Mac OS X only
> +        })
> +        Method(_CRS, 0) {
> +            If (LEqual(\_OSI("Darwin"), 0xFFFFFFFF)) {
> +                Return (ConcatenateResTemplate(RESP, RESI, Local0))
Isn't Local0 an optional?
Since it's not used for anything then just omit it.

> +            } else {
> +                Return (RESP)
> +            }
> +        }
>      }
>  }
Michael S. Tsirkin Jan. 20, 2014, 12:08 p.m. UTC | #4
On Mon, Jan 20, 2014 at 12:57:50PM +0100, Paolo Bonzini wrote:
> Il 20/01/2014 12:58, Michael S. Tsirkin ha scritto:
> > I think at this point I agree.
> > 
> > I think the hack looking for the SMC device is safer than _OSI: OSPMs
> > are known to do crazy things when they see _OSI, such as assuming they
> > need to try and emulate the OS probed.
> 
> Source?
> 
> Paolo

For example, this one
http://article.gmane.org/gmane.comp.bios.coreboot.seabios/7235

exacept use the corrected values for IRQNoFlags.
It basically says "if we enabled Apple SMC let's
assume we also want IRQNoFlags in HPET _CRS.
Paolo Bonzini Jan. 20, 2014, 12:16 p.m. UTC | #5
Il 20/01/2014 13:08, Michael S. Tsirkin ha scritto:
>>> > > 
>>> > > I think the hack looking for the SMC device is safer than _OSI: OSPMs
>>> > > are known to do crazy things when they see _OSI, such as assuming they
>>> > > need to try and emulate the OS probed.
>> > 
>> > Source?
>> > 
>> > Paolo
> For example, this one
> http://article.gmane.org/gmane.comp.bios.coreboot.seabios/7235

No, not source code.

Source for "OSPMs do crazy things when they see _OSI".

Paolo
Gabriel L. Somlo Jan. 20, 2014, 6:54 p.m. UTC | #6
On Mon, Jan 20, 2014 at 01:16:02PM +0100, Paolo Bonzini wrote:
> Il 20/01/2014 13:08, Michael S. Tsirkin ha scritto:
> >>> > > I think the hack looking for the SMC device is safer than _OSI: OSPMs
> >>> > > are known to do crazy things when they see _OSI, such as assuming they
> >>> > > need to try and emulate the OS probed.
> 
> Source for "OSPMs do crazy things when they see _OSI".

After a bit more digging, I believe this has to do with the fact that
OSPM is responsible for define _OSI, and referencing it from e.g. the
HPET._CRS method when it's NOT defined (e.g. by a misbehaving OSPM)
results in all sorts of unpleasantness.

In fact, looking on the MacBookPro, we see the following:

DefinitionBlock ("dsdt.aml", "DSDT", 1, "APPLE ", "MacBookP", 0x00090001)
{
    ...
    Field (GNVS, AnyAcc, Lock, Preserve) {
        OSYS,   16,
        ...
    }
    ...
    Scope (\_SB) {
        Method (_INI, 0, NotSerialized) {
            Store (0x07DC, OSYS)
            If (CondRefOf (\_OSI, Local0)) {
                If (_OSI ("Darwin")) {
                    Store (0x2710, OSYS)
                }
                If (\_OSI ("Linux")) {
                    Store (0x03E8, OSYS)
                }
                If (\_OSI ("Windows 2009")) {
                    Store (0x07D9, OSYS)
                }
                If (\_OSI ("Windows 2012")) {
                    Store (0x07DC, OSYS)
                }
            }
        }
        ...
    }
    ...

So, basically, they give OSYS a default value, then *if* _OSI is
defined by a well-behaved OSPM, they use it to give OSYS a more
useful, specific value. CondRefOf is used to avoid a fatal error
in case _OSI does not exist.

And later:

                Device (HPET) {
                    Name (_HID, EisaId ("PNP0103"))
                    Name (_CID, EisaId ("PNP0C01"))
                    Name (BUF0, ResourceTemplate () {
                        IRQNoFlags () {0}
                        IRQNoFlags () {8}
                        Memory32Fixed (ReadWrite,
                            0xFED00000,         // Address Base
                            0x00000400,         // Address Length
                            _Y16)
                    })
                    Method (_STA, 0, NotSerialized) {
                        If (LGreaterEqual (OSYS, 0x07D1)) {
                            If (HPAE) {
                                Return (0x0F)
                            }
                        } Else {
                            If (HPAE) {
                                Return (0x0B)
                            }
                        }
                        Return (0x00)
                    }
                    ...
                }

Which begins to explain why, on the MBP2,2 I didn't see the HPET show
up in the XP device tree at all ! :)

I.e., I wonder if XP actually defines _OSI (my inner gambling addict
says it probably does not).

Long story short, we could use CondRefOf as an intermediary wrapper
around _OSI to avoid referencing SMC._STA from within HPET.CRS...

Not sure we want to "complicate" the rest of the HPET (e.g. return
different values for bit2, "show device in acpi u/i" depending on
_OSI, the way Apple machines do).

Thanks,
--Gabriel
Michael S. Tsirkin Jan. 20, 2014, 8:23 p.m. UTC | #7
On Mon, Jan 20, 2014 at 01:16:02PM +0100, Paolo Bonzini wrote:
> Il 20/01/2014 13:08, Michael S. Tsirkin ha scritto:
> >>> > > 
> >>> > > I think the hack looking for the SMC device is safer than _OSI: OSPMs
> >>> > > are known to do crazy things when they see _OSI, such as assuming they
> >>> > > need to try and emulate the OS probed.
> >> > 
> >> > Source?
> >> > 
> >> > Paolo
> > For example, this one
> > http://article.gmane.org/gmane.comp.bios.coreboot.seabios/7235
> 
> No, not source code.
> 
> Source for "OSPMs do crazy things when they see _OSI".
> 
> Paolo

Ah, that one.

For example, this msdn article at microsoft.com:
http://msdn.microsoft.com/en-us/library/windows/hardware/gg463275.aspx
"How to Identify the Windows Version in ACPI by Using _OSI"

at the end it states:
	the operating system makes features available based on the
	string argument to the _OSI method.


The ACPI spec states this in a more verbose form:
5.7.2 _OSI (Operating System Interfaces)

	 OSPM can choose to expose new functionality
	based on the _OSI argument string. That is, OSPM can use the strings
	passed into _OSI to ensure
	compatibility between older platforms and newer operating systems by
	maintaining known
	compatible behavior for a platform.


The concern therefore is that if bios only queries
OSI for Darwin and not other OSes, some OSPM will assume
it's a macbook hardware and do something stupid.
Michael S. Tsirkin Jan. 20, 2014, 8:31 p.m. UTC | #8
On Mon, Jan 20, 2014 at 01:54:15PM -0500, Gabriel L. Somlo wrote:
> On Mon, Jan 20, 2014 at 01:16:02PM +0100, Paolo Bonzini wrote:
> > Il 20/01/2014 13:08, Michael S. Tsirkin ha scritto:
> > >>> > > I think the hack looking for the SMC device is safer than _OSI: OSPMs
> > >>> > > are known to do crazy things when they see _OSI, such as assuming they
> > >>> > > need to try and emulate the OS probed.
> > 
> > Source for "OSPMs do crazy things when they see _OSI".
> 
> After a bit more digging, I believe this has to do with the fact that
> OSPM is responsible for define _OSI, and referencing it from e.g. the
> HPET._CRS method when it's NOT defined (e.g. by a misbehaving OSPM)
> results in all sorts of unpleasantness.

No, that's not what I meant.
Responded to the original question with what my
real concern was.

> In fact, looking on the MacBookPro, we see the following:
> 
> DefinitionBlock ("dsdt.aml", "DSDT", 1, "APPLE ", "MacBookP", 0x00090001)
> {
>     ...
>     Field (GNVS, AnyAcc, Lock, Preserve) {
>         OSYS,   16,
>         ...
>     }
>     ...
>     Scope (\_SB) {
>         Method (_INI, 0, NotSerialized) {
>             Store (0x07DC, OSYS)
>             If (CondRefOf (\_OSI, Local0)) {
>                 If (_OSI ("Darwin")) {
>                     Store (0x2710, OSYS)
>                 }
>                 If (\_OSI ("Linux")) {
>                     Store (0x03E8, OSYS)
>                 }
>                 If (\_OSI ("Windows 2009")) {
>                     Store (0x07D9, OSYS)
>                 }
>                 If (\_OSI ("Windows 2012")) {
>                     Store (0x07DC, OSYS)
>                 }
>             }
>         }
>         ...
>     }
>     ...
> 
> So, basically, they give OSYS a default value, then *if* _OSI is
> defined by a well-behaved OSPM, they use it to give OSYS a more
> useful, specific value. CondRefOf is used to avoid a fatal error
> in case _OSI does not exist.

Good to know, thanks for the info.

> And later:
> 
>                 Device (HPET) {
>                     Name (_HID, EisaId ("PNP0103"))
>                     Name (_CID, EisaId ("PNP0C01"))
>                     Name (BUF0, ResourceTemplate () {
>                         IRQNoFlags () {0}
>                         IRQNoFlags () {8}
>                         Memory32Fixed (ReadWrite,
>                             0xFED00000,         // Address Base
>                             0x00000400,         // Address Length
>                             _Y16)
>                     })
>                     Method (_STA, 0, NotSerialized) {
>                         If (LGreaterEqual (OSYS, 0x07D1)) {
>                             If (HPAE) {
>                                 Return (0x0F)
>                             }
>                         } Else {
>                             If (HPAE) {

and where does HPAE come from?

>                                 Return (0x0B)
>                             }
>                         }
>                         Return (0x00)
>                     }
>                     ...
>                 }
> 
> Which begins to explain why, on the MBP2,2 I didn't see the HPET show
> up in the XP device tree at all ! :)
> 
> I.e., I wonder if XP actually defines _OSI (my inner gambling addict
> says it probably does not).

This document says it does:
http://msdn.microsoft.com/library/windows/hardware/gg463275

> Long story short, we could use CondRefOf as an intermediary wrapper
> around _OSI to avoid referencing SMC._STA from within HPET.CRS...

I'm not sure why it's a problem to refer to SMC._STA
but if it is, we can just patch in another variable
in the HPET scope instead of _OSI.

> Not sure we want to "complicate" the rest of the HPET (e.g. return
> different values for bit2, "show device in acpi u/i" depending on
> _OSI, the way Apple machines do).
> 
> Thanks,
> --Gabriel

They seem to clear this bit for linux?
No idea why they do this - want to try looking into
linux source to figure out?
Gabriel L. Somlo Jan. 20, 2014, 9:25 p.m. UTC | #9
On Mon, Jan 20, 2014 at 10:31:56PM +0200, Michael S. Tsirkin wrote:
> > And later:
> > 
> >                 Device (HPET) {
> >                     ...
> >                     Method (_STA, 0, NotSerialized) {
> >                         If (LGreaterEqual (OSYS, 0x07D1)) {
> >                             If (HPAE) {
> >                                 Return (0x0F)
> >                             }
> >                         } Else {
> >                             If (HPAE) {
> 
> and where does HPAE come from?

e.g, on the MBP2,2:

    OperationRegion (RCRB, SystemMemory, 0xFED1C000, 0x4000)
    Field (RCRB, DWordAcc, Lock, Preserve)
    {
        Offset (0x1000),
        Offset (0x3000),
        Offset (0x3404),
        HPAS,   2,
            ,   5,
        HPAE,   1,
        ...
    }

i.e., I think it's something similar to how VEND and PRD are
checked in HPET._STA on qemu and seabios to decide whether to
return 0x00 or 0x0F.

> For example, this msdn article at microsoft.com:
> http://msdn.microsoft.com/en-us/library/windows/hardware/gg463275.aspx
> "How to Identify the Windows Version in ACPI by Using _OSI"
> 
> at the end it states:
>       the operating system makes features available based on the
>       string argument to the _OSI method.

The full text of that goes:

 "Implementation Note
  Place the routine that identifies the operating system in an _INI method
  under the \_SB scope so that _OSI can run as early as possible. This
  placement is important because the operating system makes features
  available based on the string argument to the _OSI method."

It all depends on what the document's author meant by "the operating
system" which "makes features available". Because somewhere earlier in
the document they say:

 "Recent versions of the ACPI spec have extended the use cases of
  the _OSI method beyond host operating system version identification.
  However, Windows supports _OSI only for the use of identifying the host
  version of Windows that is running on the system."

So my interpretation would be "call _OSI early during some _INI method
under the \_SB scope, so you know how to tweak the various other ACPI
nodes and methods". Kinda like the Apple OSYS example.

So I got curious, and looked through the DSDT.dsl on my other machines.
Both Dells also have \_SB._INI methods which liberally check _OSI, like
e.g. from my Dell R410 server:

        Name (TOOS, 0x00)
        Method (INIC, 0, NotSerialized) {
            If (CondRefOf (_OSI, Local0)) {
                If (\_OSI ("Windows 2001")) {
                    Store (0x05, TOOS)
                }

                ...

                If (\_OSI ("Linux")) {
                    Store (0x01, TOOS)
                }
            } Else {
                Store (\_OS, Local0)
                Store (SCMP (Local0, "Microsoft Windows NT"), Local1)
                If (Not (Local1)) {
                    Store (0x04, TOOS)
                } Else {
                    Store (SCMP (Local0, "Microsoft Windows"), Local2)
                    If (Not (Local2)) {
                        Store (0x02, TOOS)
                    } Else {
                        Store (SCMP (Local0, "Microsoft WindowsME:Millennium    Edition"), Local3)
                        If (Not (Local3)) {
                            Store (0x03, TOOS)
                        }
                    }
                }
            }
        }

My Dell D630 laptop also does it. I'm wondering if there is any
non-apple, non-dell hardware that does NOT do this. This feels to
me like "circumstantial evidence" in favor of my interpretation
above, but see below...

> I'm not sure why it's a problem to refer to SMC._STA
> but if it is, we can just patch in another variable
> in the HPET scope instead of _OSI.

Not a problem per se; just that, being relatively new to ACPI, I wasn't
strongly in favor or against either of the two possible ways to do this.

I didn't even know about _OSI until Paolo mentioned it somewhere earlier
in the conversation, so my only hammer used to be:

  If (CondRefOf(\_SB.PCI0.ISA.SMC))

to determine whether to include IRQNoFlags in HPET._CRS or not. Now that
I know about _OSI, tying the HPET to the SMC feels a bit hacky. Of
course, if you're right and it's bad voodoo to call _OSI, then it may
yet be the lesser of two evils.

It's just that all DSDTs I have access to (apple and dell) already do
call _OSI with impunity, so I'm not sure just how bad the voodoo is...

> > Not sure we want to "complicate" the rest of the HPET (e.g. return
> > different values for bit2, "show device in acpi u/i" depending on
> > _OSI, the way Apple machines do).
> 
> They seem to clear this bit for linux?
> No idea why they do this - want to try looking into
> linux source to figure out?

According to the ACPI docs, the bit is labeled "show device in the u/i",
and at least on XP, the only side effect is listing the HPET in the
device tree or not, sort-of like a "hidden bit". I'll check the linux
source to see if anything is done with that bit, and if so, what.

Thanks,
--Gabriel
Paolo Bonzini Jan. 21, 2014, 10:33 a.m. UTC | #10
Il 20/01/2014 22:25, Gabriel L. Somlo ha scritto:
> 
>  "Implementation Note
>   Place the routine that identifies the operating system in an _INI method
>   under the \_SB scope so that _OSI can run as early as possible. This
>   placement is important because the operating system makes features
>   available based on the string argument to the _OSI method."
> 
> It all depends on what the document's author meant by "the operating
> system" which "makes features available". Because somewhere earlier in
> the document they say:
> 
>  "Recent versions of the ACPI spec have extended the use cases of
>   the _OSI method beyond host operating system version identification.
>   However, Windows supports _OSI only for the use of identifying the host
>   version of Windows that is running on the system."

I read that as referring to things like _OSI("3.0 Thermal Model").  It
means (the way I read it) that Windows will not publish that kind of
_OSI string.

I think it is safe to assume that no OSPM will do those crazy things
with OS-defined _OSI strings (it's quite plausible that they do it with
feature _OSI strings).

First, because IMHO it is completely insane.

Second, because the current DSDT would also be theoretically broken with
an OSPM that does strange things with _OSI.  We never call _OSI, so the
OSPM could presume that it should "disable all features".

Paolo
Michael S. Tsirkin Jan. 21, 2014, 11:02 a.m. UTC | #11
On Tue, Jan 21, 2014 at 11:33:00AM +0100, Paolo Bonzini wrote:
> Il 20/01/2014 22:25, Gabriel L. Somlo ha scritto:
> > 
> >  "Implementation Note
> >   Place the routine that identifies the operating system in an _INI method
> >   under the \_SB scope so that _OSI can run as early as possible. This
> >   placement is important because the operating system makes features
> >   available based on the string argument to the _OSI method."
> > 
> > It all depends on what the document's author meant by "the operating
> > system" which "makes features available". Because somewhere earlier in
> > the document they say:
> > 
> >  "Recent versions of the ACPI spec have extended the use cases of
> >   the _OSI method beyond host operating system version identification.
> >   However, Windows supports _OSI only for the use of identifying the host
> >   version of Windows that is running on the system."
> 
> I read that as referring to things like _OSI("3.0 Thermal Model").  It
> means (the way I read it) that Windows will not publish that kind of
> _OSI string.

Exactly, I read it that way too.

> I think it is safe to assume that no OSPM will do those crazy things
> with OS-defined _OSI strings (it's quite plausible that they do it with
> feature _OSI strings).
> 
> First, because IMHO it is completely insane.

Insane, yes.
This is however what windows does and this is what microsoft document
explicitly says.

> Second, because the current DSDT would also be theoretically broken with
> an OSPM that does strange things with _OSI.  We never call _OSI, so the
> OSPM could presume that it should "disable all features".
> 
> Paolo

We restrict ourselves to a very small subset of the spec
that seems to work well everywhere, and
so far OSPMs seem to assume that's what no _OSI means.
Paolo Bonzini Jan. 21, 2014, 11:05 a.m. UTC | #12
Il 21/01/2014 12:02, Michael S. Tsirkin ha scritto:
> > I think it is safe to assume that no OSPM will do those crazy things
> > with OS-defined _OSI strings (it's quite plausible that they do it with
> > feature _OSI strings).
> > 
> > First, because IMHO it is completely insane.
> 
> Insane, yes.
> This is however what windows does and this is what microsoft document
> explicitly says.

Yeah, that's what I would like a source for.  _How_ does Microsoft tweak
its ACPI implementation based on the set of feature bits that are
_OSI-probed?

But even that is not very important because...

> We restrict ourselves to a very small subset of the spec
> that seems to work well everywhere, and
> so far OSPMs seem to assume that's what no _OSI means.

... do we have reason to believe that adding _OSI("Darwin") will make
some OSPM *restrict* their features further?  I don't think so.

Besides being doubly insane to me, it contradicts the spec.  The spec
says that _OSI probes can be used by the OSPM to provide *more*
features, not less.  It says "OSPM can choose to expose new
functionality" based on the _OSI argument string.

So only Mac OS X has to be tested if we probe _OSI("Darwin").

Paolo
Michael S. Tsirkin Jan. 21, 2014, 11:38 a.m. UTC | #13
On Mon, Jan 20, 2014 at 04:25:18PM -0500, Gabriel L. Somlo wrote:
> On Mon, Jan 20, 2014 at 10:31:56PM +0200, Michael S. Tsirkin wrote:
> > > And later:
> > > 
> > >                 Device (HPET) {
> > >                     ...
> > >                     Method (_STA, 0, NotSerialized) {
> > >                         If (LGreaterEqual (OSYS, 0x07D1)) {
> > >                             If (HPAE) {
> > >                                 Return (0x0F)
> > >                             }
> > >                         } Else {
> > >                             If (HPAE) {
> > 
> > and where does HPAE come from?
> 
> e.g, on the MBP2,2:
> 
>     OperationRegion (RCRB, SystemMemory, 0xFED1C000, 0x4000)
>     Field (RCRB, DWordAcc, Lock, Preserve)
>     {
>         Offset (0x1000),
>         Offset (0x3000),
>         Offset (0x3404),
>         HPAS,   2,
>             ,   5,
>         HPAE,   1,
>         ...
>     }
> 
> i.e., I think it's something similar to how VEND and PRD are
> checked in HPET._STA on qemu and seabios to decide whether to
> return 0x00 or 0x0F.
> 
> > For example, this msdn article at microsoft.com:
> > http://msdn.microsoft.com/en-us/library/windows/hardware/gg463275.aspx
> > "How to Identify the Windows Version in ACPI by Using _OSI"
> > 
> > at the end it states:
> >       the operating system makes features available based on the
> >       string argument to the _OSI method.
> 
> The full text of that goes:
> 
>  "Implementation Note
>   Place the routine that identifies the operating system in an _INI method
>   under the \_SB scope so that _OSI can run as early as possible. This
>   placement is important because the operating system makes features
>   available based on the string argument to the _OSI method."
> 
> It all depends on what the document's author meant by "the operating
> system" which "makes features available". Because somewhere earlier in
> the document they say:
> 
>  "Recent versions of the ACPI spec have extended the use cases of
>   the _OSI method beyond host operating system version identification.
>   However, Windows supports _OSI only for the use of identifying the host
>   version of Windows that is running on the system."
> 
> So my interpretation would be "call _OSI early during some _INI method
> under the \_SB scope, so you know how to tweak the various other ACPI
> nodes and methods". Kinda like the Apple OSYS example.
> 
> So I got curious, and looked through the DSDT.dsl on my other machines.
> Both Dells also have \_SB._INI methods which liberally check _OSI, like
> e.g. from my Dell R410 server:
> 
>         Name (TOOS, 0x00)
>         Method (INIC, 0, NotSerialized) {
>             If (CondRefOf (_OSI, Local0)) {
>                 If (\_OSI ("Windows 2001")) {
>                     Store (0x05, TOOS)
>                 }
> 
>                 ...
> 
>                 If (\_OSI ("Linux")) {
>                     Store (0x01, TOOS)
>                 }
>             } Else {
>                 Store (\_OS, Local0)
>                 Store (SCMP (Local0, "Microsoft Windows NT"), Local1)
>                 If (Not (Local1)) {
>                     Store (0x04, TOOS)
>                 } Else {
>                     Store (SCMP (Local0, "Microsoft Windows"), Local2)
>                     If (Not (Local2)) {
>                         Store (0x02, TOOS)
>                     } Else {
>                         Store (SCMP (Local0, "Microsoft WindowsME:Millennium    Edition"), Local3)
>                         If (Not (Local3)) {
>                             Store (0x03, TOOS)
>                         }
>                     }
>                 }
>             }
>         }
> 
> My Dell D630 laptop also does it. I'm wondering if there is any
> non-apple, non-dell hardware that does NOT do this. This feels to
> me like "circumstantial evidence" in favor of my interpretation
> above, but see below...

Yes, my server boxes don't have any _OSI in the DSDT.
Unlike laptop which really mostly cares about the
windows version that ships with it, these guys
sometimes care about running non windows OS-es.

It actually does call _OSI later, but in a way that has
no effect:
            Method (_STA, 0, NotSerialized)
            {
                Store (\_OS, Local0)
                Mid (Local0, Zero, 0x09, Local1)
                If (LEqual (Local1, "Microsoft"))
                {
                    If (CondRefOf (_OSI, Local2))
                    {
                        If (\_OSI ("Windows 2009"))
                        {
                            Return (0x0F)
                        }
                        Else
                        {
                            Return (Zero)
                        }
                    }
                    Else
                    {
                        Return (Zero)
                    }
                }
                Else
                {
                    Return (0x0F)
                }
            }

So this is a nice trick: it checks
prefix of _OS *then* calls _OSI.

Of course I'm not sure it won't crash if
_OS is shorter than 9 bytes but we can
write this more defensively.

> > I'm not sure why it's a problem to refer to SMC._STA
> > but if it is, we can just patch in another variable
> > in the HPET scope instead of _OSI.
> 
> Not a problem per se; just that, being relatively new to ACPI, I wasn't
> strongly in favor or against either of the two possible ways to do this.
> 
> I didn't even know about _OSI until Paolo mentioned it somewhere earlier
> in the conversation, so my only hammer used to be:
> 
>   If (CondRefOf(\_SB.PCI0.ISA.SMC))
> 
> to determine whether to include IRQNoFlags in HPET._CRS or not. Now that
> I know about _OSI, tying the HPET to the SMC feels a bit hacky. Of
> course, if you're right and it's bad voodoo to call _OSI, then it may
> yet be the lesser of two evils.


So assuming people don't want to tie this to SMC
(which I still like best) second best
I like the idea of looking at the prefix of _OS -
like code above does - then checking _OSI to make sure.
This way this won't affect microsoft or linux guests.
We probably call this in init though.
Could you find out what are _OS values for OSX?


> It's just that all DSDTs I have access to (apple and dell) already do
> call _OSI with impunity, so I'm not sure just how bad the voodoo is...

Not sure I trust what firmware developers do.  From what I saw they
basically ship it and then software has to find work arounds.

> > > Not sure we want to "complicate" the rest of the HPET (e.g. return
> > > different values for bit2, "show device in acpi u/i" depending on
> > > _OSI, the way Apple machines do).
> > 
> > They seem to clear this bit for linux?
> > No idea why they do this - want to try looking into
> > linux source to figure out?
> 
> According to the ACPI docs, the bit is labeled "show device in the u/i",
> and at least on XP, the only side effect is listing the HPET in the
> device tree or not, sort-of like a "hidden bit". I'll check the linux
> source to see if anything is done with that bit, and if so, what.
> 
> Thanks,
> --Gabriel
Michael S. Tsirkin Jan. 21, 2014, 11:44 a.m. UTC | #14
On Tue, Jan 21, 2014 at 12:05:21PM +0100, Paolo Bonzini wrote:
> Il 21/01/2014 12:02, Michael S. Tsirkin ha scritto:
> > > I think it is safe to assume that no OSPM will do those crazy things
> > > with OS-defined _OSI strings (it's quite plausible that they do it with
> > > feature _OSI strings).
> > > 
> > > First, because IMHO it is completely insane.
> > 
> > Insane, yes.
> > This is however what windows does and this is what microsoft document
> > explicitly says.
> 
> Yeah, that's what I would like a source for.  _How_ does Microsoft tweak
> its ACPI implementation based on the set of feature bits that are
> _OSI-probed?
> 
> But even that is not very important because...
> 
> > We restrict ourselves to a very small subset of the spec
> > that seems to work well everywhere, and
> > so far OSPMs seem to assume that's what no _OSI means.
> 
> ... do we have reason to believe that adding _OSI("Darwin") will make
> some OSPM *restrict* their features further?  I don't think so.
> 
> Besides being doubly insane to me, it contradicts the spec.  The spec
> says that _OSI probes can be used by the OSPM to provide *more*
> features, not less.  It says "OSPM can choose to expose new
> functionality" based on the _OSI argument string.

Ow come on. New functionality is there, OSPM sees we
probe for Darwin and tries to enable some broken emulation.

Since windows runs on mac hardware this won't surprise me at all.

> So only Mac OS X has to be tested if we probe _OSI("Darwin").
> 
> Paolo

If we limit this by testing _OS prefix first, then fine.
diff mbox

Patch

diff --git a/hw/i386/acpi-dsdt-hpet.dsl b/hw/i386/acpi-dsdt-hpet.dsl
index dfde174..0cf7fbf 100644
--- a/hw/i386/acpi-dsdt-hpet.dsl
+++ b/hw/i386/acpi-dsdt-hpet.dsl
@@ -38,14 +38,21 @@  Scope(\_SB) {
             }
             Return (0x0F)
         }
-        Name(_CRS, ResourceTemplate() {
-#if 0       /* This makes WinXP BSOD for not yet figured reasons. */
-            IRQNoFlags() {2, 8}
-#endif
+        Name(RESP, ResourceTemplate() {
             Memory32Fixed(ReadOnly,
                 0xFED00000,         // Address Base
                 0x00000400,         // Address Length
                 )
         })
+        Name(RESI, ResourceTemplate() {
+            IRQNoFlags() {0, 8}     // Mac OS X only
+        })
+        Method(_CRS, 0) {
+            If (LEqual(\_OSI("Darwin"), 0xFFFFFFFF)) {
+                Return (ConcatenateResTemplate(RESP, RESI, Local0))
+            } else {
+                Return (RESP)
+            }
+        }
     }
 }