仓库源文

.. Kenneth Lee 版权所有 2020

:Authors: Kenneth Lee :Version: 1.0

AML工作原理快速调研


前两天邀请人做这个文档的Review:

in nek:评审邀请:Linux内核软件架构基础

有读者告诉我我对AML的理解有误。我找我们做BIOS的兄弟确认了一把,把逻辑链放在这里 。

先定义一下问题:ACPI是一种定义BIOS和OS之间接口的方法。和其他一些方法,比如 Device Tree(简称DTS),不同,ACPI支持函数接口,也就是说,OS可以通过“调用”接口 给出的函数实现功能。这种所谓的“调用”,有几种可能:

  1. BIOS中给定一个数据结构,整体描述了一个函数,这个函数本身就是CPU的本地汇编。 BIOS把整个数据接口传递到OS管理的内存空间,OS直接调用这个空间中的函数。

  2. BIOS中给定一个数据结构,整体描述了一个函数,这个函数本身就是CPU的本地汇编。 这个数据结构留在BIOS控制的内存中,传递给OS一个指针,OS远程调用这个指令的地址 ,完成请求。

  3. BIOS中实现了一个本地函数,然后把这个函数的位置和格式告知OS,OS通过一个统一的 接口把函数的标识和请求的参数传递给BIOS,BIOS内部完成调用,然后把结果通知OS。

  4. BIOS给定一个数据结构,整体描述了一个函数,用一种平台无关的格式标识,这个数据 结构整体提供给OS,OS上有一个解释器,解释执行这个平台无关的格式,实现对功能的 执行。

用图来表达,区别如下:

    .. figure:: _static/aml调用1.jpg

严格来说,前两个方案没有什么区别,内存这东西,都是一样的内存。什么你的我的,其 实都是我的!:)我们差不多就可以了。

我自己不是做BIOS的,这部分的理解是做BIOS的兄弟给我介绍的,当时我的理解是第二种 形式。但这位读者告诉我,这个理解不对,所以我回去再咨询了几个做BIOS的兄弟,他们 给了我另外一些可以确认的证据,我通过这个文档把这些证据摆出来。

首先看定义,这里是一个DSDT中实现的AML的定义:::

    Method (_STA, 0, NotSerialized)  // _STA: Status
    {
        If ((TPEN == One))
        {
            Return (0x0F)
        }
        Else
        {
            Return (Zero)
        }
    }

我们直接看它的DSDT编译结果:::

    0000a670: 0800 0000 005c 5f53 422e 5350 4930 0079  .....\_SB.SPI0.y
    0000a680: 00a4 5242 5546 1415 5f53 5441 00a0 0a93  ..RBUF.._STA....
    0000a690: 5450 454e 01a4 0a0f a103 a400 1048 065f  TPEN.........H._
    0000a6a0: 5342 5f5b 8240 0649 5049 3008 5f48 4944  SB_[.@.IPI0._HID

可以看到_STA函数访问了TPEN,这个参数是直接在DSDT表中的,至少说明一点,至少在呈 现为DSDT表形态的时候,这是一个解释形的语言,而不是被编译成了二进制。

我们再找一个证据,这个是BIOS的同事推荐给我的一个文档: https://acpica.org/sites/acpica/files/asl_tutorial_v20190625.pdf,其中的表述如 下:

    .. figure:: _static/aml.jpg

这说明OS中是存在一个解释器,AML是一个类似Java的Bincode,通过解释器建立数据结构 ,从而可以解释执行。

所以我们的逻辑碎片只剩下最后一环:看看Linux内核中的具体实现:

内核对这个函数的调用是这样的:::

    status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
    if (ACPI_SUCCESS(status) && sta)
            return 1;

acpi_evaluate_integer()实际调用acpi_evaluate_object()。这个实现在 ./drivers/acpi/acpica/nsxfeval.c中,其最终的实现是这个函数: acpi_ns_evaluate(info)->acpi_ps_execute_method(info)->acpi_ps_parse_aml(),跟踪 进去,就可以看到针对每个opcode的执行过程。

换句话说,内核中确实带了一个解释器来执行这个函数,至于这个函数的bincode到底在 BIOS的内存空间中还是已经拷贝到内核的内存空间中,这个已经不重要了。

老实说,我个人对UEFI和ACPI的编程风格素来没有好感,简直就是反人类,这回跟踪完这 个AML的实现,我更没有好感了。但谁让它在服务器领域发展的时间长呢。这个世界就是这 么无奈。这也告诉我们当架构师的:

  1. 技术优美抵不过资源投入,虽然两者都是控制要素,但前者难暴力投入,后者可以

  2. 架构前期不要作妖,前期再轻微的决定,后面都是要生要死的大限制。