3.2.4异常处理
所有在对ACPICA子系统的请求的处理过程中发生的异常都以ACPI_STATUS为返回码返回到调用者。所有ACPICA的异常都是以“AE_”开头,例如,AE_OK表示请求执行成功。
所有异常处理都由调用者内联到ACPICA子系统接口中。对于以Acpi和AcpiOs开头的调用没有异常处理函数与之关联。
3.2.5 多任务和可重入
ACPICA子系统的所有组成部分都应该是可重入的并且支持多线程的。为了实现可重入和多线程,OSL必须根据特定的主操作系统的操作原语实现互斥访问接口,以保证能够正常使用同步和异常访问。尽管依赖与这写互斥访问接口的实现,然而ACPICA子系统的所有组成部分都是可重入和支持多线程的。AML翻译器是个例外。解释如下。
由于ACPI协议的约束,AML翻译器并发性的实现有很大的限制。协议规定在任意时间,最多只能有一个控制方法能够执行AML代码。如果一个控制方法执行时被阻塞(在一些限制条件下是可能发生的),其它的控制方法应该可以执行。不管怎样,可以说ACPI协议妨碍了控制方法的并发执行。因此,在ACPICA子系统的所有组成部分中,AML翻译器是单线程的。对与对控制方法的内部或者外部请求的串行化是由翻译器的前置部分完成的。
3.2.6 事件处理
词语“事件处理”宽泛的指在ACPICA子系统执行过程中的异步事件。这些事件包括:
- 由ACPI固定的和通用事件触发的SCI
- 执行ASL中的Notify关键字表示的控制方法而触发的通知事件
- 在执行控制方法的过程中,由于进入地址空间或者操作域而触发的事件
对于每个事件的描述以及ACPICA子系统对于这些事件的支持,下面将进行详细的描述。
3.2.6.1 固定事件
固定事件由ACPICA子系统默认事件处理handler处理,对于每个事件,可以安装单独的handler。只有设备驱动和系统服务需要安装此类的handler。
3.2.6.2通用事件
通用事件通常是通过执行与事件相关的控制方法来进行处理的。根据ACPI协议,每一级别的GPE都能有相应的控制方法与之对应。这些控制方法中,以_Exx为名字的是边沿触发方式,以_Lxx为名字的是电平触发方式。xx是以十六进制表示的GPE的级别(详见ACPI协议)。这个控制方法不会在SCI中断handler的上下文执行,但是会被主操作系统入队列以延后执行。
除了这种机制,对于不同级别的GPE可以有单独的handler,这不是强制性的,实际上,现在需要独立的GPE handler的设备只有ACPI EC。EC的驱动会为属于EC 的GPE安装独立handler。
如果GPE安装了handler,handler会使用优先级而不会使用_Exx/_Lxx控制方法。
还支持GPE块设备(GPE Block Devices)。根据需要,这些块嫩够被动态的安装和卸载。ACPICA子系统嫩够对GPE集中处理和分派,并且提供了必要的接口来安装和卸载GPE块设备。
3.2.6.3 通知事件
在执行控制方法过程中,Notify操作码的执行会形成ACPI通知事件。通知事件是基于ACPI对象的,这个对象必须是一个设备或者热区(thermal zone)。如果对这个设备安装了通知handler,在Notify操作码执行过程中,会在这个线程执行控制方法的上下文中执行这个handler。
通知handler由设备驱动和系统服务安装,这些系统服务知道那些设备和热区会收到通知事件。
3.2.7 地址空间和操作域
ASL源代码和相应的AML代码能够使用地址空间机制来操作不直接属于ASL scope的数据。例如,地址空间用于操作 CMOS RAM 和ACPI EC。有几个预定义的能够操作的地址空间,并且允许用户自定义定制空间。
操作系统软件(软件包含AML翻译器)允许通过ASL 操作域(OpRegion)结构操作各种地址空间。在创建OpRegion时,ASL程序员会定义能够被OpRegion 操作的界限(窗口大小)和地址空间。接着,为了方便使用在窗口中的地址,用fields中的字符串来代表这些地址。
3.2.7.1 安装地址空间handler
在运行时,在对地址空间安装了handler之后,ASL/AML代码才能使用地址空间。ACPICA使用者可以安装默认地址空间handler,或者通过接口AcpiInstallAddressSpaceHandler接口来安装地址空间handler。
每个地址空间是被特定的设备所拥有,因此,在设备的scope中对地址空间的引用都会被设备地址空间的handler处理。这个机制允许对同类地址空间安装多个地址空间/操作域handler。基于ACPI地址空间的范围规则(scoping rules),每个handler都是互斥的。例如,想象两个SMBus设备,一个基于EC,另一个基于PCI。每个SMBus设备都会向ASL声明地址空间,两个地址空间互不干扰。在这种情况下,可能需要两个设备驱动和两个完全不同的地址空间handler,每类SMbus设备一个handler。这个机制也适用于其它预定义的地址空间。例如,PCI配置空间对于每个PCI总线都是唯一的。在一个PCI总线的范围内创建域时,这个域仅能指代这个PCI总线。
地址空间handler必须安装在命名空间中被命名的对象上,或者安装在ACPI_ROOT_OBJECT上。对于维持命名空间的范围规则而言,这个要求是必须的。地址handler是为命名空间中拥有地址空间的对象安装的。需要操作地址空间的每一条ASL规则,每一个域都要在对象的scope中。
ACPICA使用者需要枚举命名空间并根据需要安装地址handler。
3.2.7.2ACPI相关的地址空间
ACPI协议会为如下类型地址定义地址空间:
- System I/O
- PCI Configuration Space
- System Management Bus (SMBus)
- Embedded Controller
- CMOS
- PCI Bar Target
- IPMI (ACPI 4.0)
- General Purpose I/O (ACPI 5.0)
- Generic Serial Bus (ACPI 5.0)
ACPICA子系统会为下面的地址空间实现默认的地址空间handler:
- System Memory
- System I/O
- PCI Configuration Space
调用AcpiInstallAddressSpaceHandler接口时,将ACPI_DEFAULT_HANDLER作为handler地址传递给接口,可以使用默认的地址空间handler。
其它预定义的地址空间(如EC和SMBus)没有默认的地址空间handler,因此,如果操作系统不提供地址空间handler,则这些地址空间是不能操作的。这些地址空间handler通常是由EC,SMBus和其它ACPI相关的设备驱动提供的。
3.2.7.3 设备驱动和AML共享资源
在某些情况下,ACPI相关的驱动和与驱动相关的ASL/AML代码之间需要共享设备寄存器、内存等资源。
ACPICA提供了一种机制,这种机制允许设备驱动拥有这些内存和寄存器,AML操作这些内存和寄存器时将会自动进入到驱动中。自定义地址空间handler会管理这些共享资源。
设备驱动和OSPM代码都能够为所有设备提供自定义地址空间handler,因此,驱动对这些寄存会进行互斥访问。ACPICA允许命名空间中的所有设备都有一个唯一的地址空间handler(对所有的ACPI地址空间)。当设备的ASL代码执行并操作寄存器或者内存时(通过操作域),将会使用设备驱动地址空间handler,此时,驱动能够完全控制共享资源。
注:当注册了自定义地址空间handler的设备的scope中的ASL在执行时,相应的自定义空间handler才会进行干预。这不会影响到命名空间中其它设备操作地址空间。例如,默认地址空间handler能够用于整个命名空间的I/O操作,包括安装了自定义handler的需要共享I/O端口的设备。
3.2.7.3.1 ASL共享资源实例
下面是一个ASL代码片段,这个代码片段定义并操作了 I/O操作域和几个共享I/O寄存器(COST和VREG)。
Scope (_SB)
{
Device (PCI0)
{
Name (_HID, EisaId ("PNP0A08")) // _HID: Hardware ID
Device (PS2K)
{
Name (_HID, EisaId ("PNP0303")) // _HID: Hardware ID
OperationRegion (PKBS, SystemIO, 0x60, 0x05)
Field (PKBS, WordAcc, Lock, Preserve)
{
COST, 16,
VREG, 16
}
Method (_AC0, 0, NotSerialized)
{
And (COST, 0xFFFF, COST)
Store (0x1234, VREG)
Or (COST, 0xFFF6, COST)
Store (COST, Debug)
Return (COST)
}
}
}
}
3.2.7.3.2自定义地址空间handler安装
为了能够陷入并操作上例中定义的寄存器,设备驱动需要获取ACPI命名空间中设备的handle,然后为这个设备安装一个自定义地址空间handler。一旦地址空间handler被安装,ASL/AML中所有通过COST和VREG I/O端口对PKBS操作域进行的操作将会转移到驱动中进行处理。
Status = AcpiGetHandle (NULL, "\\_SB.PCI0.PS2K", &ObjHandle);
Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_IO,
RegionHandler, RegionInit, MyContext);
if (ACPI_FAILURE (Status))
{
ACPI_EXCEPTION ((AE_INFO, Status,
"Could not install an OpRegion handler for PS2K device (%p)",
ObjHandle));
}
使用acpiexec工具并执行“hanlders”命令,可以看到对\_SB_.PCI0.PS2K自定义handler已经被安装。
- handlers
Operation Region Handlers at the namespace root:
SystemMemory (00) : User (00422A30) /* default acpiexec handler */
SystemIO (01) : User (00422A30) /* default acpiexec handler */
Operation Region Handlers for specific devices:
SystemIO (01) : User (00422280) Device Name: \_SB_.PCI0.PS2K
执行控制方法_AC0(它会操作在PKBS操作域中定义的I/O寄存器),可以看到\_SB_.PCI0.PS2K 的自定义系统I/0handler被使用多次:
- evaluate \_SB_.PCI0.PS2K._AC0
Evaluating \_SB_.PCI0.PS2K._AC0
ACPI: PCI0.PS2K SystemIO request at: 0x0000000000000060 [READ]
ACPI: PCI0.PS2K SystemIO request at: 0x0000000000000060 [WRITE]
ACPI: PCI0.PS2K SystemIO request at: 0x0000000000000062 [WRITE]
ACPI: PCI0.PS2K SystemIO request at: 0x0000000000000060 [READ]
ACPI: PCI0.PS2K SystemIO request at: 0x0000000000000060 [WRITE]
ACPI: PCI0.PS2K SystemIO request at: 0x0000000000000060 [READ]
[ACPI Debug] Integer 0x0000000000000000
ACPI: PCI0.PS2K SystemIO request at: 0x0000000000000060 [READ]
Evaluation of \_SB_.PCI0.PS2K._AC0 returned object 00323EC8, buffer length 10
[Integer] = 0000000000000000