ACPI基础——ASL语言

简介

ASL的全称是ACPI Source language。

在ACPI基础中已经有介绍过ASL语言,它是用来描述硬件信息以及相关硬件操作给OS使用的表达式。

简单来说,ASL可以看成是类似C语言的计算机语言,不过它功能更加的单一。不过虽然功能单一,但是因为涉及到各种各样的硬件,所以实际上需要记忆的东西会非常多,并且还在不断的变多。

目前ACPI的最新版本是6.1版本,相关的SPEC可以在http://www.uefi.org/specifications中下载到。

ASL现在作为BIOS/UEFI的一部分,它包含在BIOS的源代码里面,在https://code.csdn.net/jiangwei0512/edk2-udk2017.git这个GIT仓库中可以下载的UEFI的代码,搜索后缀是asl的文件可以找到源代码。由于edk2-udk2017是开源的代码,里面包含的硬件相关的东西很少,所以能够找到的asl文件并不多,不过实际使用的UEFI中,asl文件要多很多。

在编译BIOS的时候,会使用iasl编译器来编译ASL源代码,下面是一些使用到的工具(也包含了iasl):

ACPI基础——ASL语言_第1张图片

BIOS/UEFI中也有相关的ACPI操作的接口,它最终会将ACPI相关的内容放到内存的某段空间中,并将指向该区域的指针传递给OS。

OS使用这里的内容来操作获取硬件信息并操作相关的硬件。

这样的好处是,OS不需要直接去与底层硬件沟通,它只要直接操作这些ASL生成的内容就可以了。

另一个好处是,只要支持ACPI,不管OS是Windows还是Linux,都可以完成与硬件交互,也就是OS Independent。

上图中的acpidump.exe可以用来打印上述提到的那段内存空间:

ACPI基础——ASL语言_第2张图片

以上是截图的一部分,实际上它包含很多的内容。

OS就是要解析这些信息,它们也是我们写的ASL最终成为的内容。

通过Windows下的RW.exe工具,可以看到该机器下的ASL语言:

ACPI基础——ASL语言_第3张图片

基本上一般情况下我们很难看到多少ASL语言的实例,所以这是我们能够得到的很少的几个学习素材之一。

 

基本语法

ASL语言中需要掌握的东西分为下面的几个部分:

1. ASL表达式。ASL的表达式很简单,就个句式,不像C语言那样有有声明变量、声明函数啊等很多的形式;

2. 操作符。ASL定义了很多的操作符,它像是C语言中的关键字和函数名的合体,需要记忆;

3. ACPI预留的对象。这一部分是真正的难点,在ACPI SPEC中,定义了对应各种硬件的对象,它们的命名大多以_开头,且数量非常的多,需要很熟悉ACPI规范以及各种硬件设备才能真正了解这些预留对象。

 

表达式

ASL的表达式,简单来说就一句话:

Operator FixedList VariableList

Operator是ACPI中规定的操作符,在ACPI6.1版本中一共有148个,SPEC中有专门的章节来介绍它们,下面是截取的一角:

ACPI基础——ASL语言_第4张图片

FixedList是一组可选的变量,用()括起来。

VariableList也是一组可选的变量,用{}括起来。

当上述三个部分都存在的时候就很像C语言中的函数了。不过它跟函数还是有些不同的,事实上有一个操作符Method是用来定义ACPI中的函数的,它比C语言中的函数更广义。

另外需要说明ASL表达式是部分大小写的,无论大小写在编译时都被转换成了大写。

下面是一个例子:

DefinitionBlock ("Dsdt.aml", "DSDT", 1, "INTEL ", "OVMF    ", 4) {
  //
  // System Sleep States
  //
  // We build S3 and S4 with GetSuspendStates() in
  // "OvmfPkg/AcpiPlatformDxe/Qemu.c".
  //
  Name (\_S0, Package () {5, 0, 0, 0}) // Working
  Name (\_S5, Package () {0, 0, 0, 0}) // Soft Off
  // 后略
}

这里DefinitionBlock是一个Operator(事实上它是ASL的入口),()里面包含若干个变量,{}里面也包含若干变量,这里可以看到ASL表达式是可以嵌套的。

Name另一个Operator,它用来为对象命名,它不带{}。

 

操作符

前面已经提到了操作符。它就是表达式的开始。

由于操作符太多,不可能在这里一一介绍。

这里选择几个比较常见的进行说明。

 

Name

  Name (\_S0, Package () {5, 0, 0, 0}) // Working

Name的作用是定义一个变量。

它带两个FixedList,分别是(名称,对象)。

这里就是定义了一个Package,它的名字是_S0。

这里有几点需要说明:

1. “\”是根命名空间。ASL中有不同的命令空间,“\”是起始命名空间,有一些操作符会开辟新的命名空间;还有一个符号“^”表示上一层命名空间;

2. ASL中变量的名称都是固定的4个字节大小,不包括“\”,不满4个字节的,后面用“_”补全;

3.“_”开头的是规范预留的名称,虽然名称是预留了,但是定义并没有,我们写ASL的时候需要将它们补全(当然前提是我们需要用它);

4. 对象可以有不同的数据类型,ASL下有很多的数据类型,它们通过不同的操作符创建,这里就使用了Package这个操作符来创建Package类型的对象;

 

Package

Package () {5, 0, 0, 0}

Package用来定义一组数据。

它带有一个可选的FixedList和一个可选的VariableList(虽说可选但是一般都会用,不然数据怎么定义),格式是(数据个数) {具体数据}。

这里需要注意几点:

1. 数据个数如果是空的,则编译器会通过计算后面的具体数据来得到值;

2. 具体数据可是实际的数据对象,也可以是对象引用——就是用Name定义的对象的名称;
 

预留对象

这个太大了,就不在这里讲了。

 

补充——ASL中的数据类型

前面的介绍中多次ASL中的数据类型,这里统一说明下。

ASL中的数据类型大多通过操作符生成,但是像整数和字符串这样的也可以直接写。

下面是ASL中的所有类型:

1. 未初始化

2. Buffer:由操作符Buffer创建;

3. Buffer Field:Buffer中的成员,由操作符CreateBitFiled等一系列的CreateXXXFiled操作符创建;

4. Debug Object:可以输出到系统Debug口的对象;

5. Device:设备或者总线对象,由操作符Device创建;

6. Event:时间同步对象,由操作符Event创建;

7. Field Unit:在Operation Region中,使用Filed等操作符创建,是地址空间的一部分(portion of an address space);

8. Integer:整型;

9. Integer Constant:有如下的几个:ONE(1),ONES(全FF),ZERO(0),REVISION(版本号),它们本身就是操作符;

10. Method:可执行的方法,由Method操作符创建;

11. Mutex:同步互斥锁对象,由Mutex操作符创建;

12. Object Reference:对象引用,就是Name中的名称;

13. Operation Region:表示地址空间中的一段区域,由OperationRegion操作符创建;

14. Package:ASL对象集合,由Package操作符创建;

15. Power Resource:Power Resource描述对象,由PowerResource操作符创建;

16. Processor:处理器描述对象,现在不再使用了,用Device代替了;

17. String:字符串;

18. Thermal Zone:温度区域描述符,由ThermalZone操作符创建;

 

你可能感兴趣的:(UEFI开发基础)