Page 1 of 1

[Solved] LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 4:26 pm
by kzinti
I am in the process of integrating LAI (https://github.com/managarm/lai) into my OS and have run into an issue. It appears there is no DSDT table in my firmware and LAI needs it.

This is under QEMU. Firmware is OVMF. I have enumerated all tables from the RSDT and from the XSDT. In both cases I do not find any DSDT table.

LAI complains with "unable to find ACPI DSDT." in lai_create_namespace().

Is there a trick / workaround to this?

Image of log here: https://ibb.co/dp5fTt5

Re: LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 4:38 pm
by devc1
I can confirm to you that there is a dsdt in OVMF.

The DSDT pointer is located in the FADT Table (Signature 'FACP') Not with the SDT Array.

When you find the FADT, Check if the ACPI revision is 2 (in the R/XSDT) if yes (This is the case with OVMF) then you can use the 64 Bit X_Dsdt Pointer in the FADT, if the revision is 1 then use the 32 Bit Dsdt pointer.

Re: LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 4:41 pm
by devc1
Check if you have the latest versions of OVMF, otherwise there is a problem with your usage of the LAI library.
Personnaly, I prefered to create my own ACPI driver, but this takes alot of time,.

Every ACPI compatible firmware has a DSDT.

Re: LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 4:45 pm
by kzinti
It appears that the DSDT is indeed in the FADT. This means that my "obvious/trivial" implementation for laihost_scan() doesn't work. My implementation needs to know to look for the DSDT behind the FADT. Interesting.

Here is what I have:

Code: Select all

template <typename T>
static void* laihost_scan(const T& rootTable, std::string_view signature, int index)
{
    int count = 0;
    for (auto address : rootTable)
    {
        const auto table = (acpi::Table*)(laihost_map(address, sizeof(acpi::Table)));
        MTL_LOG(Debug) << "ACPI Table: " << table->GetSignature();
        if (table->GetSignature() == signature)
        {
            if (index == count)
            {
                laihost_map(address, table->length); // TODO: is this required? can we do better?
                return table;
            }

            ++count;
        }
    }

    return nullptr;
}

void* laihost_scan(const char* signature, size_t index)
{
    if (g_xsdt)
        return laihost_scan(*g_xsdt, signature, index);
    else
        return laihost_scan(*g_rsdt, signature, index);
}
I need to update this code to check for 'DSDT' and look inside the FADT instead of naively looping the XSDT.

I'll give this a try, thanks!

Re: LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 4:47 pm
by devc1
You're welcome !

Re: LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 4:56 pm
by kzinti
devc1 wrote:When you find the FADT, Check if the ACPI revision is 2 (in the R/XSDT) if yes (This is the case with OVMF) then you can use the 64 Bit X_Dsdt Pointer in the FADT, if the revision is 1 then use the 32 Bit Dsdt pointer.
Shouldn't we be checking the revision number in the FADT table (as opposed to the R/XSDT)?

It seems safest to check the size of the FADT table before accessing X_DSDT.

Re: [Solved] LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 6:39 pm
by devc1
You should check the value in the RSDP (I said RSDT by error) to determine if you have an XSDT or a legacy RSDT, to enumerate SDTs you should know the size of the pointers, 32 bits for RSDT and 64 bits for XSDT.

If the revision field is set to 2 then use the XSDT and 64 bit pointers.

You can test the compatibility of your OS with these 2 revisions by running on OVMF and SeaBIOS (Normal QEMU w Legacy ACPI).

These are my structures:
The XRSDP struct is apended with the RSDP.

Code: Select all

typedef struct _ACPI_RSDP_DESCRIPTOR{ 
         char Signature[8]; 
         char Checksum; 
         char OEMId[6]; 
         char Revision; 
         UINT32 RsdtAddress; 
 } ACPI_RSDP_DESCRIPTOR; 
  
 typedef struct _ACPI_EXTENDED_RSDP_DESCRIPTOR { 
     ACPI_RSDP_DESCRIPTOR RsdpDescriptor; 
     UINT32 Length; 
     UINT64 XsdtAddress; 
     char ExtendedChecksum; 
     char Reserved[3]; 
 } ACPI_EXTENDED_RSDP_DESCRIPTOR;

typedef struct _ACPI_RSDT{ 
     ACPI_SDT Sdt; 
         UINT32 SdtPtr[];//[(hdr.length - sizeof(hdr)) / 4]; 
 } ACPI_RSDT; 
  
 typedef struct _ACPI_XSDT{ 
     ACPI_SDT Sdt; 
     UINT64 SdtPtr[]; //[(hdr.length - sizeof(hdr)) / 8]; 
 } ACPI_XSDT;

Re: [Solved] LAI / QEMU / OVMF - No DSDT table

Posted: Fri Sep 30, 2022 11:18 pm
by kzinti
Sure. This seems unrelated to my issue and this thread.

Re: LAI / QEMU / OVMF - No DSDT table

Posted: Sat Oct 01, 2022 1:26 pm
by devc1
It seems safest to check the size of the FADT table before accessing X_DSDT.
this is not needed, just check if you have an XSDT if yes then you can use the X_Dsdt field along with other fields from ACPI 2.0+.

Re: [Solved] LAI / QEMU / OVMF - No DSDT table

Posted: Sat Oct 01, 2022 2:30 pm
by nexos
I agree with kzinti. Don't trust what firmware hands you.

Re: [Solved] LAI / QEMU / OVMF - No DSDT table

Posted: Sat Oct 01, 2022 7:46 pm
by kzinti
nexos wrote:I agree with kzinti. Don't trust what firmware hands you.
Indeed, never trust the firmware.