Aaron Li's Blog

In solitude, where we are least alone.

一名萌新程序员


Press on avatar to see the blogs.

ASL语言学习(4)- OpRegion 实战

续上三篇,这一篇实战一下与BIOS C代码结合的内存修改。
ASL语言学习(1)- 基本语法,作用域
ASL语言学习(2)- Debug,常用操作符
ASL语言学习(3)- 隐式转换,Method调用

Reference:

ACPI Source Language (ASL) Tutorial

ACPI Source Language (ASL) Reference

OperationRegion 的运用方式

OperationRegion是ASL中最常用的关键字之一,在第一篇文章中也讲过。

我们可以通过OperationRegion实现内存修改、寄存器修改等功能,这里实战一下与BIOS C代码结合的内存修改。

代码部分

ASL 示例如下(这是生成一个Fibonacci数列的递推):

    OperationRegion (TEST, SystemMemory, 0xA5A5A5A5, 0xA5A5A5A5)
    Field (TEST, ByteAcc, NoLock, Preserve) {
      ITER, 32,  // Iteration
      //
      // 16 bit x 32 = 1024 bits.
      //
      IBUF, 512, // Buffer
    }
    Method(EXEC, 0, Serialized) {
      Name (BUFF, Buffer(64){0}) //64 bytes = 512 bits.
      // BUFF[0] = 1
      // BUFF[1] = 1
      Store (0x1, Index(BUFF, 0))
      Store (0x1, Index(BUFF, 2))
      Store (2, Local0)
      // BUFF[i] = BUFF[i-2] + BUFF[i-1]
      // i in [2, ITER) -- Local0
      While (LLess(Local0, ITER)) {
        Multiply (Local0, 2, Local1) // 1 Word = 2 Byte
        Store (DerefOf(Index(BUFF, Subtract(Local1, 3))),Local2)        // BUFF[i-2] higher byte
        ShiftLeft (Local2, 8, Local2)
        Add (Local2, DerefOf(Index(BUFF, Subtract(Local1, 4))), Local2) // BUFF[i-2] lower byte

        Store (DerefOf(Index(BUFF, Subtract(Local1, 1))),Local3)        // BUFF[i-1] higher byte
        ShiftLeft (Local3, 8, Local3)
        Add (Local3, DerefOf(Index(BUFF, Subtract(Local1, 2))), Local3) // BUFF[i-1] lower byte

        Add (Local2, Local3, Local4)

        Store (And(Local4, 0xFF), Index(BUFF, Local1))                  // BUFF[i] lower byte
        ShiftRight(Local4, 8, Local4)
        Store (And(Local4, 0xFF), Index(BUFF, Add(Local1, 1)))          // BUFF[i] higher byte
        Increment (Local0)
      }
      Store (BUFF, IBUF)
    }

C语言部分简单描述下流程:

1) 在内存中Allocate一段Runtime可以访问的buffer

typedef struct {
  UINT32                Iteration;
  UINT16                Buffer[0x20];
} ACPI_TEST_BUFFER;

Status = gBS->AllocatePool (
                EfiRuntimeServicesData,
                sizeof (ACPI_TEST_BUFFER),
                (VOID **) &mAcpiTestBuffer
                );
ZeroMem (mAcpiTestBuffer, sizeof (ACPI_TEST_BUFFER));
mAcpiTestBuffer->Iteration = 0x18;

2) Patch 这段buffer的地址和长度到ACPI Table中的OperationRegion关键字中。

参考Spec:https://uefi.org/specs/ACPI/6.5/20_AML_Specification.html#defopregion

通过检索如下关键字找到表中对应OperationRegion的Offset

// DefOpRegion := OpRegionOp NameString RegionSpace RegionOffset RegionLen
// OpRegionOp := ExtOpPrefix 0x80
// ExtOpPrefix := 0x5B
// RegionSpace := ByteData  (0x00 SystemMemory)
// RegionOffset := TermArg => Integer (0x0A)
// RegionLen := TermArg => Integer
// TermArg := ExpressionOpcode | [DataObject] | ArgObj | LocalObj
// DataObject := [ComputationalData] | DefPackage | DefVarPackage
// ComputationalData := ByteConst | WordConst | [DWordConst] | QWordConst | String | ConstObj | RevisionOp | DefBuffer
// DWordConst := DWordPrefix DWordData
// DWordPrefix := 0x0C

结合上述在Spec中找到的定义,我们要找的Binary为:

5B 80 54 45 53 54 00 0C A5 A5 A5 A5 0C A5 A5 A5 A5

并将其中的两个0xA5A5A5A5替换为mAcpiTestBuffer的地址和长度。

运行部分

我们find命令查看,可以看到我们allocate的buffer地址成功被patch到TEST中(000000006F342F18)。

- find TEST
                       \_SB.TEST Region       00000000e15c3ac6 007 [SystemMemory] Addr 000000006F342F18 Len 0044
- find EXEC
                       \_SB.EXEC Method       0000000053e75605 007 Args 0 Len 00A8 Aml 00000000ae51bb6e

执行结果(这是BIOS log):

# before execute
Dump data from 6F342F18, size: 0x44
6F338F18: 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
6F338F28: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
6F342F38: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
6F342F48: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
6F342F58: 00 00 00 00                                      | ....
# after execute and reset
Dump data from 6F342F18, size: 0x44
6F342F18: 18 00 00 00 01 00 01 00 02 00 03 00 05 00 08 00  | ................
6F342F28: 0D 00 15 00 22 00 37 00 59 00 90 00 E9 00 79 01  | ....".7.Y.....y.
6F342F38: 62 02 DB 03 3D 06 18 0A 55 10 6D 1A C2 2A 2F 45  | b...=...U.m..*/E
6F342F48: F1 6F 20 B5 00 00 00 00 00 00 00 00 00 00 00 00  | .o .............
6F342F58: 00 00 00 00                                      | ....

可以看到对应的内存被更改了。

一种错误示范

本来想图省事,用CreateWordField代替每个byte的读写和移位操作。

    Method(EXCE, 0, Serialized) {
      Name (BUFF, Buffer(64){0}) //64 bytes = 512 bits.
      // BUFF[0] = 1
      // BUFF[1] = 1
      Store (0x1, Index(BUFF, 0))
      Store (0x1, Index(BUFF, 2))
      Store (2, Local0)
      // BUFF[i] = BUFF[i-2] + BUFF[i-1]
      // i in [2, ITER)
      While (LLess(Local0, ITER)) {
        Multiply(Local0, 2, Local1) // 1 Word = 2 Byte
        // 这东西不能在while里面用
        CreateWordField (BUFF, Subtract(Local1, 4), IDX1)
        CreateWordField (BUFF, Subtract(Local1, 2), IDX2)
        CreateWordField (BUFF, Local1, IDX3)
        Add (IDX1, IDX2, IDX3)
        Increment (Local0)
      }
      Store (BUFF, IBUF)
    }

结果在While的第二个loop中,报错:

3ACPI BIOS Error (bug): Failure creating named object [\_SB.EXCE.IDX1], AE_ALREADY_EXISTS (20220331/dsfield-184)
3ACPI Error: AE_ALREADY_EXISTS, CreateBufferField failure (20220331/dswload2-477)
3ACPI Error: Aborting method \_SB.EXCE due to previous error (AE_ALREADY_EXISTS) (20220331/psparse-529)
3ACPI Error: AE_ALREADY_EXISTS, while executing \_SB.EXCE from AML Debugger (20220331/dbexec-163)
Evaluation of \_SB.EXCE failed with status AE_ALREADY_EXISTS

即Object不能重复定义。


目前就这么多了,记笔记的时候并没有写这么多,很多都是在整理的时候拓展的,希望能帮到有需要的人。

如果后面还有值得一记的东西,还会继续整理。

更早的文章

ASL语言学习(3)- 隐式转换,Method调用

本文介绍ASL语言的部分隐式转换与Method调用。

继续阅读
Top