19.3.5. ASL 数据类型
ASL 提供了多种多样的数据类型和用于操作数据的运算符。它还提供了在与 ASL 运算符一起使用时,在这些数据类型之间进行显式和隐式转换的机制。
下表描述了每一种可用的 ASL 数据类型。
表 19.5 ASL 数据类型汇总
| ASL 数据类型 | 说明 |
|---|---|
| [Uninitialized] | 未分配类型或值。这是在方法执行开始时所有控制方法 LocalX 变量和未使用 ArgX 变量的类型,以及所有未初始化 Package 元素的类型。未初始化对象在作为 ASL 表达式中的源操作数使用之前,必须先进行初始化(通过 Store 或 CopyObject)。 |
| Buffer | 字节数组。未初始化的元素默认为零。 |
| Buffer Field | 使用 CreateBitField、CreateByteField、CreateWordField、CreateQWordField、CreateField 创建的缓冲区的一部分,或由 Index 运算符返回的部分。 |
| Debug Object | 调试输出对象。对一个对象进行格式化并将其打印到系统调试端口。如果调试未激活,则没有效果。 |
| Device | 设备或总线对象 |
| Event | 事件同步对象 |
| Field Unit (within an Operation Region) | 地址空间的一部分,按位对齐且粒度为 1 位。使用 Field、BankField 或 IndexField 创建。 |
| Integer | n 位小端无符号整数。在 ACPI 1.0 中,它是 32 位。在 ACPI 2.0 及更高版本中,它是 64 位。Integer(DWORD)标记表示只有低 32 位有意义,而 64 位整数的高 32 位必须为零(不要求屏蔽高位)。 |
| Integer Constant | 由 ASL 项“Zero”、“One”、“Ones”和“Revision”创建 |
| Method | 控制方法(可执行 AML 函数) |
| Mutex | 互斥同步对象 |
| Object Reference | 使用 RefOf、Index 或 CondRefOf 运算符创建的对象引用 |
| Operation Region | Operation Region(地址空间中的一个区域) |
| Package | 具有固定元素个数(最多 255 个)的 ASL 对象集合。 |
| Power Resource | Power Resource 描述对象 |
| Processor | 处理器描述对象 |
| RawDataBuffer | 字节数组。未初始化的元素默认为零。RawDataBuffer 不包含任何 AML 编码字节,只包含原始字节。 |
| String | 以空字符结尾的 ASCII 字符串。 |
| Thermal Zone | Thermal Zone 描述对象 |
注意
兼容性说明: 存储和操作对象引用的能力是在 ACPI 2.0 中引入的。在 ACPI 1.0 中,引用不能存储在变量中、作为参数传递,也不能从函数返回。
19.3.5.1. 数据类型转换概述
ASL 提供了两种机制,用于在运行时(AML 解释器执行期间)将对象从一种数据类型转换为另一种数据类型。第一种机制,显式数据类型转换,允许使用显式的 ASL 运算符将对象转换为不同的数据类型。第二种机制,隐式数据类型转换,当需要在数据对象被使用或存储之前将其转换为预期的数据类型时,由 AML 解释器调用。
以下通用规则适用于数据类型转换:
输入参数只要操作数类型与预期输入类型不匹配,就总是要进行隐式数据类型转换(也称为隐式源操作数转换)。
除显式数据转换运算符之外的所有运算符的输出(目标)参数,只要目标是一个现有的命名对象或命名字段,并且其类型与要存储的对象不同,就要进行隐式数据类型转换(也称为隐式结果对象转换)。
显式数据转换运算符的输出参数,以及引用方法局部变量或参数(LocalX 或 ArgX)的输出参数,不进行隐式类型转换。
这两种机制(显式和隐式转换)都将在后续章节中详细描述。
19.3.5.2. 显式数据类型转换
以下 ASL 运算符用于显式地将对象从一种数据类型转换为另一种:
ToBuffer
> 将 Integer、String 或 Buffer 转换为 Buffer 类型对象
ToDecimalString
> 将 Integer、String 或 Buffer 转换为 String 类型对象。该字符串包含源操作数十进制值的 ASCII 表示。
ToHexString
> 将 Integer、String 或 Buffer 转换为 String 类型对象。该字符串包含源操作数十六进制值的 ASCII 表示。
ToInteger
> 将 Integer、String 或 Buffer 转换为 Integer 类型对象。
ToString
> 直接复制并将 Buffer 转换为 String 类型对象。
以下 ASL 运算符用于复制和传输对象,并执行显式结果转换,使目标的类型与源对象的类型匹配:
CopyObject
> 显式地将操作数对象的副本存储到目标名称中。不执行隐式类型转换。(此运算符用于避免 ASL Store 运算符固有的隐式转换。)
19.3.5.3. 隐式数据类型转换
在执行 ASL 运算符期间,自动或隐式类型转换可能在两个不同时间发生。首先,可能需要将一个或多个源操作数转换为 ASL 运算符所期望的数据类型。其次,操作结果在存储到目标之前可能需要进行转换。(许多 ASL 运算符可以选择性地将其结果存储到由最后一个参数指定的对象中。对于这些运算符,如果指定了目标,则该行为与使用 Store 运算符将结果放入目标中的效果完全相同。)
这类数据转换由 AML 解释器在执行 AML 代码期间执行,统称为隐式操作数转换。如上文简要描述,隐式操作数转换有两种不同类型:
将源操作数从不匹配的数据类型转换为 ASL 运算符所需的正确数据类型,称为隐式源转换。当源操作数必须转换为运算符所期望的操作数类型时,会发生此转换。在 ASL 运算符能够继续执行之前,任意一个或所有源操作数都可能以这种方式被转换。
在操作结果存储到目标操作数之前,将其转换为目标操作数的现有类型,称为隐式结果转换。当目标是固定类型(例如命名对象或字段)时,会发生此转换。当存储到方法 Local 或 Arg 时,不执行也不需要转换,因为这些数据类型是可变类型(存储操作只是简单地覆盖任何现有对象及其现有类型)。
以下 ASL 运算符用于复制和传输对象,并对目标对象的现有类型执行隐式结果转换:
Store
> 将操作数对象的副本存储到目标名称中。如果目标名称是固定数据类型,则执行隐式结果转换(见上文)。但是,存储到方法局部变量和参数时不执行隐式转换,因此与使用 CopyObject 相同。
19.3.5.4. 隐式源操作数转换
在执行 ASL 运算符期间,每个源操作数由 AML 解释器按如下方式处理:
如果操作数的类型正是运算符所期望的类型,则不需要转换。
如果操作数类型不正确,则尝试将其转换为正确类型。
对于 Concatenate 运算符和逻辑运算符(LEqual、LGreater、LGreaterEqual、LLess、LLessEqual 和 LNotEqual),第一个操作数的数据类型决定第二个操作数所需的类型,并且仅对 Concatenate 而言,还决定结果对象的类型。(如有必要,第二个操作数将被隐式转换,以匹配第一个操作数的类型。)
如果无法转换,则中止正在运行的控制方法并发出致命错误。
每当源操作数包含的数据类型与运算符所期望的类型不同时,都会尝试进行隐式源转换。例如:
Store ("5678", Local1)
Add (0x1234, Local1, BUF1)
在上面的 Add 语句中,Local1 包含一个 String 对象,因此在 Add 操作继续之前,必须先将其转换为 Integer 对象。
在某些情况下,运算符可以接受多种类型的操作数(例如 Integer 和 String)。在这种情况下,将根据操作数的类型应用最高优先级的转换。下表描述了可用的源操作数转换。例如:
Store (Buffer (1) {}, Local0)
Name (ABCD, Buffer (10) {1, 2, 3, 4, 5, 6, 7, 8, 9, 0})
CreateDWordField (ABCD, 2, XYZ)
Name (MNOP, "1234")
Concatenate (XYZ, MNOP, Local0)
Concatenate 运算符的前两个参数可以接受 Integer、Buffer 或 String,而第一个参数的类型决定第二个参数将如何转换。在此示例中,第一个参数的类型是 Buffer Field(来自 CreateDWordField 运算符)。它应当被转换为什么:Integer、Buffer 还是 String?根据“对象转换规则”表,最高优先级的转换是 Integer。因此,以下两个对象都将被转换为 Integer:
XYZ (0x05040302)
MNOP (0x31, 0x32, 0x33, 0x34)
并且随后会被连接在一起,生成的类型和值将为:
Buffer (0x02, 0x03, 0x04, 0x05, 0x31, 0x32, 0x33, 0x34)
19.3.5.5. 隐式结果对象转换
对于所有会生成并存储结果值的 ASL 运算符(包括 Store 运算符),结果对象由 AML 解释器按如下方式处理和存储:
如果 ASL 运算符是显式转换运算符之一(ToString、ToInteger 等,以及 CopyObject 运算符),则不执行转换。(换句话说,结果对象会直接存储到目标中,并且会完全覆盖目标中已存储的任何现有对象。)
如果目标是方法局部变量或参数(LocalX 或 ArgX),则不执行转换,结果会直接存储到目标中。
如果目标是固定类型,例如命名对象或字段对象,则在存储之前会尝试将源转换为现有目标类型。
如果无法转换,则中止正在运行的控制方法并发出致命错误。
当运算符的结果被存储到固定类型对象中时,任何时候都可能发生隐式结果转换。例如:
Name (BUF1, Buffer (10))
Add (0x1234, 0x789A, BUF1)
由于 BUF1 是固定类型的 Buffer 命名对象,因此在将 Add 操作的 Integer 结果存储到 BUF1 之前,必须先将其转换为 Buffer。
19.3.5.6. 数据类型和类型转换
下表列出了可用的 ASL 数据类型,以及每种数据类型可用的数据类型转换(如果有)。每种数据类型的条目都进行了完整的交叉引用,同时显示该对象可以转换到的类型,以及所有其他可以转换为该数据类型的类型。
允许的转换同时适用于显式转换和隐式转换。
表 19.6 数据类型和类型转换
| ASL 数据类型 | 可隐式或显式转换为这些数据类型(按优先顺序) | 可从这些数据类型隐式或显式转换而来 |
|---|---|---|
| [未初始化] | 无。作为任何 ASL 语句中的源操作数使用时会导致致命错误。 | Integer, String, Buffer, Package, Object Reference |
| Buffer | Integer, String, Debug Object | Integer, String |
| Buffer Field | Integer, Buffer, String, Debug Object | Integer, Buffer, String |
| Debug Object | 无。作为任何 ASL 语句中的源操作数使用时会导致致命错误。 | Integer, String, Buffer, Package, Field Unit, Buffer Field |
| Device | 无 | 无 |
| Event | 无 | 无 |
| Field Unit(位于 Operation Region 中) | Integer, Buffer, String, Debug Object | Integer, Buffer, String |
| Integer | Buffer, Buffer Field, Field Unit, String, Debug Object | Buffer, String |
| Integer Constant | Integer, Debug Object | 无。并且,将任何对象存储到常量都是无操作,不是错误。 |
| Method | 无 | 无 |
| Mutex | 无 | 无 |
| Object Reference | 无 | 无 |
| Operation Region | 无 | 无 |
| Package | Debug Object | 无 |
| String | Integer, Buffer, Debug Object | Integer, Buffer |
| Power Resource | 无 | 无 |
| RawDataBuffer | 无 | 无 |
| Thermal Zone | 无 | 无 |
19.3.5.7. 数据类型转换规则
下表给出了每种允许的数据类型转换的详细数据转换规则。这些转换规则由 AML 解释器实现,并适用于所有转换类型——显式转换、隐式源转换以及隐式结果转换。
表 19.7 对象转换规则
| 从此数据类型的对象转换 | 到此数据类型的对象 | AML 解释器执行的操作 |
|---|---|---|
| Buffer | Buffer Field | 缓冲区的内容会被复制到 Buffer Field 中。如果缓冲区小于缓冲字段的大小,则进行零扩展。如果缓冲区大于缓冲字段的大小,则截断高位。兼容性说明:此转换最早在 ACPI 2.0 中引入。在 ACPI 1.0 中其行为未定义。 |
| Buffer | Debug Object | 每个缓冲区字节都显示为十六进制整数,以空格和/或逗号分隔。 |
| Buffer | Field Unit | 缓冲区的全部内容会被复制到 Field Unit 中。如果缓冲区的大小(按位计)大于 Field Unit 的大小,则将其分成若干片段并完整写入 Field Unit,低位片段优先。如果缓冲区(或分段后的最后一段)小于 Field Unit 的大小,则在写入之前进行零扩展。 |
| Buffer | Integer | 如果不存在整数对象,则创建一个新的整数。缓冲区的内容会被复制到 Integer 中,从最低有效位开始,持续复制直到缓冲区被完全复制——最多不超过 Integer 的最大位数。Integer 的大小由 Definition Block 表头中的 Revision 字段指示。Revision 字段值小于 2 表示 Integer 的大小为 32 位。大于或等于 2 的值表示 Integer 的大小为 64 位。如果缓冲区小于整数大小,则进行零扩展。如果缓冲区大于整数大小,则进行截断。不允许将零长度缓冲区转换为整数。 |
| Buffer | String | 如果不存在字符串对象,则创建一个新的字符串。如果字符串已存在,则将其完全覆盖,并按需要截断或扩展,以精确容纳转换后的缓冲区。缓冲区的全部内容会被转换为由两个字符组成的十六进制数字字符串,每个数字之间用一个空格分隔。零长度缓冲区将被转换为空(零长度)字符串。 |
| Buffer Field | [参见 Integer 和 Buffer 规则] | 如果 Buffer Field 小于或等于 Integer 的大小(按位计),则将其视为 Integer。否则,将其视为缓冲区。Integer 的大小由 Definition Block 表头中的 Revision 字段指示。Revision 字段值小于 2 表示 Integer 的大小为 32 位。大于或等于 2 的值表示 Integer 的大小为 64 位。(参见 Integer 和 Buffer 数据类型的转换规则。) |
| Field Unit | [参见 Integer 和 Buffer 规则] | 如果 Field Unit 小于或等于 Integer 的大小(按位计),则将其视为 Integer。如果 Field Unit 大于 Integer 的大小,则将其视为 Buffer。Integer 的大小由 Definition Block 表头中的 Revision 字段指示。Revision 字段值小于 2 表示 Integer 的大小为 32 位。大于或等于 2 的值表示 Integer 的大小为 64 位。(参见 Integer 和 Buffer 数据类型的转换规则。) |
| Integer | Buffer | 如果不存在缓冲区对象,则根据整数的大小创建一个新的缓冲区对象(32 位整数为 4 字节,64 位整数为 8 字节)。如果缓冲区对象已存在,则 Integer 会覆盖整个 Buffer 对象。如果该整数所需位数大于 Buffer 的大小,则在复制到 Buffer 之前先截断该整数。如果该整数包含的位数少于缓冲区的大小,则对 Integer 进行零扩展以填满整个缓冲区。 |
| Integer | Buffer Field | Integer 会覆盖整个 Buffer Field。如果整数小于缓冲字段的大小,则进行零扩展。如果整数大于缓冲字段的大小,则截断高位。兼容性说明:此转换最早在 ACPI 2.0 中引入。在 ACPI 1.0 中其行为未定义。 |
| Integer | Debug Object | 该整数显示为十六进制值。 |
| Integer | Field Unit | Integer 会覆盖整个 Field Unit。如果整数小于缓冲字段的大小,则进行零扩展。如果整数大于缓冲字段的大小,则截断高位。 |
| Integer | String | 如果不存在字符串对象,则根据整数的大小创建一个新的字符串对象(32 位整数为 8 个字符,64 位整数为 16 个字符)。如果字符串已存在,则将其完全覆盖,并按需要截断或扩展,以精确容纳转换后的整数。无论哪种情况,整个整数都会被转换为十六进制 ASCII 字符串。 |
| Package | Package | 如果不存在 Package 对象,则创建一个新的 Package 对象。如果 Package 已存在,则将其完全覆盖,并按需要截断或扩展,以精确容纳源 Package。目标 Package 中任何及所有现有的有效(非空)包元素都会被删除,并将源 Package 的全部内容复制到目标 Package 中。 |
| Package | Debug Object | Package 的每个元素都根据其类型显示。 |
| String | Buffer | 如果不存在缓冲区对象,则创建一个新的缓冲区对象。如果缓冲区对象已存在,则将其完全覆盖。如果字符串长于缓冲区,则在复制之前截断字符串。如果字符串短于缓冲区,则将缓冲区剩余字节置零。无论哪种情况,字符串都被视为缓冲区,其中每个 ASCII 字符串字符都复制到一个缓冲区字节中,包括空终止符。空(零长度)字符串将被转换为零长度缓冲区。 |
| String | Buffer Field | 字符串被视为缓冲区。如果该缓冲区小于缓冲字段的大小,则进行零扩展。如果缓冲区大于缓冲字段的大小,则截断高位。兼容性说明:此转换最早在 ACPI 2.0 中引入。在 ACPI 1.0 中其行为未定义。 |
| String | Debug Object | 每个字符串字符都显示为 ASCII 字符。 |
| String | Field Unit | 字符串的每个字符都会从第一个开始写入 Field Unit。如果 Field Unit 小于八位,则每个字符的高位都会丢失。如果 Field Unit 大于八位,则附加位会被置零。 |
| String | Integer | 如果不存在整数对象,则创建一个新的整数。整数初始化为值零,并将 ASCII 字符串解释为十六进制常量。每个字符串字符都被解释为十六进制值(‘0’-‘9’、‘A’-‘F’、‘a’-‘f’),从第一个字符作为最高有效数字开始,直到遇到第一个非十六进制字符、字符串结束,或达到整数大小为止(32 位整数为 8 个字符,64 位整数为 16 个字符)。注意:第一个非十六进制字符会无错误地终止转换,并且不允许使用“0x”前缀。不允许将空(零长度)字符串转换为整数。 |
19.3.5.8. 存储和复制对象的规则
下表列出了将对象存储到不同类型命名目标时执行的操作。ASL 提供以下类型的“存储”操作:
Store 运算符用于将对象显式存储到某个位置,并支持源对象的隐式转换。
许多 ASL 运算符可以选择性地将其结果存储到由最后一个参数指定的对象中。在这些运算符中,如果指定了目标,则该操作与使用 Store 运算符将结果放入目标完全相同。
CopyObject 运算符用于将对象的副本显式存储到某个位置,不支持隐式转换。
表 19.8 对象存储和复制规则
| 当把任意数据类型的对象存储到这种类型的目标位置时 | 此操作由 Store 运算符或任何带有目标操作数的 ASL 运算符执行 | 此操作由 CopyObject 运算符执行 |
|---|---|---|
| 方法 ArgX 变量 | 对象被复制到目标位置,不进行转换,但有一个例外。如果 ArgX 包含一个对象引用,则会发生自动解引用,并且对象会被复制到对象引用的目标,而不是覆盖 ArgX 的内容。 | 对象被复制到目标位置,不进行转换,但有一个例外。如果 ArgX 包含一个对象引用,则会发生自动解引用,并且对象会被复制到对象引用的目标,而不是覆盖 ArgX 的内容。 |
| 方法 LocalX 变量 | 对象被复制到目标位置,不进行转换。即使 LocalX 包含一个对象引用,它也会被覆盖。 | 对象被复制到目标位置,不进行转换。即使 LocalX 包含一个对象引用,它也会被覆盖。 |
| Field Unit 或 BufferField | 在应用隐式结果转换后,对象被复制到目标位置。 | Field 将永久保持其类型,不能被更改。因此,CopyObject 只能用于将 Integer 或 Buffer 类型的对象复制到字段。 |
| 命名数据对象 | 在应用隐式结果转换以匹配命名位置现有类型后,对象被复制到目标位置。 | 对象及其类型被复制到命名位置。 |
19.3.5.8.1. ArgX 对象
- 从 ArgX 参数读取
> * 对象引用 - 自动解引用,返回引用的目标。使用 DeRefOf 返回相同结果。 > > * Buffer - 返回 Buffer。可以创建指向该缓冲区的 Index、Field 或引用。 > > * Package - 返回 Package。可以创建指向该包的 Index 或引用。 > > * 所有其他对象类型 - 返回该对象。 > >
下表的方法调用示例:
MTHD (RefOf (Obj), Buf, Pkg, Obj)
表 19.9 从 ArgX 对象读取
| 参数 | MTHD ArgX 类型 | 对 ArgX 的读取操作 | 读取结果 |
|---|---|---|---|
| RefOf (Obj), | 对象 Obj 的引用 | Store (Arg0, …) | Obj |
| " | " | CopyObject (Arg0, …) | Obj |
| " | " | DeRefOf (Arg0) | Obj |
| Buf, | Buffer | Store (Arg1, ..) | Buf |
| " | " | CopyObject (Arg1, …) | Buf |
| " | " | Index (Arg1, …) | Index (Buf) |
| " | " | Field (Arg1, …) | Field (Buf) |
| Pkg | Package | Store (Arg2, …) | Pkg |
| " | " | CopyObject (Arg2, …) | Pkg |
| " | " | Index (Arg2, …) | Index (Pkg) |
| Obj | 所有其他对象类型 | Store (Arg3, …) | Obj |
| " | " | CopyObject (Arg3, …) | Obj |
存储到 ArgX 参数
对象引用对象 - 自动解引用,复制该对象并覆盖最终目标。
所有其他对象类型 - 复制该对象并覆盖 ArgX 变量。(对 Buffer 或 Package ArgX 参数的直接写入也只会简单地覆盖 ArgX)
表 19.10 写入 ArgX 对象
| ArgX 的当前类型 | 要写入的对象 | 对 ArgX 的写入操作 | 写入结果(在 ArgX 中) |
|---|---|---|---|
| RefOf (OldObj) | Obj(任意类型) | Store (…, ArgX) | RefOf (Obj 的副本) |
| " | " | CopyObject (…, ArgX) | RefOf (Obj 的副本) |
| 所有其他对象类型 | Obj(任意类型) | Store (…, ArgX) | Obj 的副本 |
| " | " | CopyObject (…, ArgX) | Obj 的副本 |
注
RefOf (ArgX) 返回对 ArgX 的引用。
19.3.5.8.2. LocalX 对象
- 从 LocalX 变量读取
> * 对象引用 - 如果执行的是 DeRefOf,则返回引用的目标。否则,返回该引用。 > > * 所有其他对象类型 - 返回该对象 > >
表 19.11 从 LocalX 对象读取
| 当前 LocalX 类型 | 对 LocalX 的读取操作 | 读取结果 |
|---|---|---|
| RefOf (Obj) | Store (LocalX, …) | RefOf (Obj) |
| " | CopyObject (LocalX, …) | RefOf (Obj) |
| " | DeRefOf (LocalX) | Obj |
| Obj(所有其他类型) | Store (LocalX, …) | Obj |
| " | CopyObject (LocalX, …) | Obj |
存储到 LocalX 变量
- 所有对象类型 - 首先删除 LocalX 中任何现有对象,然后存储该对象的一个副本。
表 19.12 写入 LocalX 对象
| 当前 LocalX 类型 | 要写入的对象 | 对 LocalX 的写入操作 | 写入结果(在 LocalX 中) |
|---|---|---|---|
| 所有对象类型 | Obj(任意类型) | Store (…, LocalX) | Obj 的副本 |
| " | " | CopyObject (…, LocalX) | Obj 的副本 |
19.3.5.8.3. 命名对象
从命名对象读取
对象引用 - 如果执行的是 DeRefOf,则返回引用的目标。否则,返回该引用。
所有其他对象类型 - 返回该对象
表 19.13 从命名对象读取
| 当前 NAME 类型 | 对 NAME 的读取操作 | 读取结果 |
|---|---|---|
| RefOf (Obj) | Store (NAME, …) | RefOf (Obj) |
| " | CopyObject (NAME, …)) | RefOf (Obj) |
| " | DeRefOf (NAME) | Obj |
| Obj(所有其他类型) | Store (NAME, …) | Obj |
| " | CopyObject (NAME, …) | Obj |
存储到命名对象
- 所有对象类型 - 首先删除 NAME 中任何现有对象,然后存储该对象的一个副本。Store 运算符将执行到 NAME 中现有类型的隐式转换。CopyObject 不执行隐式存储。
表 19.14 写入命名对象
| 当前 NAME 类型 | 要写入的对象 | 对 NAME 的写入操作 | 写入结果(在 NAME 中) |
|---|---|---|---|
| 任意(任意类型) | Obj(任意类型) | Store (…, NAME) | Obj 的副本(已转换以匹配 NAME 的现有类型) |
| " | " | CopyObject (…, NAME) | Obj 的副本(无转换) |