rust-osdev/acpi

AML: Incorrect read_region/write_region handling

alnyan opened this issue · 0 comments

While working with real DSDT and comparing reads/writes to what ACPICA does, I found out there are several issues with how reads/writes to regions are done:

  • Incorrect calculation of final access addresses/IO ports: typically, ***_region does let address = (region_base + offset), which is incorrect, because we're trying to add bytes (region_base) to bits (offset) here, which yields incorrect addresses
  • Not sure if this is intended behavior, but when the address isssue is fixed, the functions allow misaligned access to memory/IO, e.g. trying to read_u32(0xdaf9dfe5)

I caught these issues while running AML of ThinkPad T430 DSDT, specifically, it has the following code (excerpt):

    OperationRegion (MNVS, SystemMemory, 0xDAF9D018, 0x1000)
    OperationRegion (SMI0, SystemIO, 0xB2, 0x01)

    Field (SMI0, ByteAcc, NoLock, Preserve)
    {
        APMC, 8
    }

    Field (MNVS, AnyAcc, NoLock, Preserve)
    {
        Offset (0xFC0),
        CMD, 8,
        ERR, 32,
        PAR0, 32,
        PAR1, 32,
        PAR2, 32,
        PAR3, 32
    }

    Mutex (MSMI, 0x07)
    Method (SMI, 5, NotSerialized)
    {
        Acquire (MSMI, 0xFFFF)

        CMD = Arg0
        ERR = 0x01
        PAR0 = Arg1
        PAR1 = Arg2
        PAR2 = Arg3
        PAR3 = Arg4
        APMC = 0xF5

        While ((ERR == 0x01))
        {
            Sleep (0x01)
            APMC = 0xF5
        }

        Release (MSMI)
    }

    Method (VUPS, 0, NotSerialized)
    {
        SMI (0x01, 0x01, 0x02, 0x00, 0x00)
    }

This code seems to be intended to generate a SMI for some graphics card management stuff, but when testing, it actually got stuck waiting for ERR to become != 0x01.

When comparing addresses of reads/writes generated by the acpi crate and what ACPICA does, I found out:

  • ACPICA only does byte accesses there, so misalignment is not a problem (and the region's AnyAcc allows this)
  • ACPICA accesses addresses 0xdaf9dfd8..0xdaf9dfe9, while the acpi crate accesses 0xdafa4e18..0xdafa4ea0