ASL語言
ASL的全稱是ACPI Source language,ASL現在作為BIOS/UEFI的一部分,它包含在BIOS的原始碼裡面。
BIOS/UEFI中也有相關的ACPI操作的介面,它最終會將ACPI相關的內容放到記憶體的某段空間中,並將指向該區域的指標傳遞給OS。OS使用這裡的內容來操作獲取硬體資訊並操作相關的硬體。這樣的好處是,OS不需要直接去與底層硬體溝通,它只要直接操作這些ASL生成的內容就可以了。另一個好處是,只要支援ACPI,不管OS是Windows還是Linux,都可以完成與硬體互動,也就是OS Independent。
一、ASL基本準則
作者:freevanx
- 變數命名不超過4個字元,且不能以數字開頭。
- 變數或者函式命名,不分大小寫。
- Scope形成作用域,概念類似於C++中的namespace,Java中的package。
- Method 或者 Function 定義函式,函式可以定義在 Device 下或者 Scope 下,但是不能脫離 Scope 定義 單獨的函式,也就是說,函式必須依附於物件(Scope or device)
- 以"_"字元開頭的函式,都是系統保留的,不得給自己的函式取這樣的名字
- ASL 中沒有運算子號(邏輯或者算術都是如此),但有與此等價的相應系統函式代替
- 符號“\”引用根作用域,“^”引用父級或稱上級作用域
- 作用域,或者稱路徑,有相對和絕對之分。相對作用域從當前作用域開始,向上延伸。也就是說在當 前作用域中使用函式和變數時,解析器會首先從當前作用域中尋找它的定義,如果找不到,則會從父級 或稱上級作用域中繼續尋找,一直找到當前作用域的 root 為止。絕對路徑,則從定義此變數或者函式的 root 作用域開始,一級級的寫下去,一直寫到此變數的作用域,作用域的引用使用符號“.”,例如 \SB.PCI0.ABCD 。
- 函式最多可傳遞 8 個引數,在函式裡用 Arg0~Arg7 引用,不可以自己定義名字
- 在函式中最多可以使用 8 個區域性變數,用 Local0~Local7 表示,不用定義,但是在把區域性變數的值 賦給其他變數之前,區域性變數必須是有效的值,也就是說,至少有一次把值賦給區域性變數的操作
- 宣告變數時不需要顯式宣告其型別,只學系統和應用型語言的童鞋可能會感到強大的不適應,而會 Perl 或者 Python 這類 Script 語言的童鞋則見怪不怪。
二、資料型別,賦值,基本運算
1. 資料型別 ASL 中支援的資料型別有:
- 整數- Integer,
- 字串 - String,
- 事件 - Event,
- 陣列 - Buffer,
- 物件集合 - Package
2. 定義變數
定義一個整數 Name(MYTS, 0)
定義一個字串 Name(TSTR, "Hello ASL")
3. 賦值
最常用的賦值函式只有一個,即 Store(),
如 Store(0x1234, Local0) // Local0 = 0x1234;
Store("Hello ASL", Local0) // Local0 = "Hello ASL"
4. 算術運算
算數運算的操作符如下圖所示,請牢記第一節列出的準則,千萬不要使用 + - * / 等符號計算 舉例如下:
- Add(3, 5, Local0) // Local0 = 3 +5
- And (0xF4, 0x39, Local0) // Local0 = 0xF4 & 0x39
- Divide(100, 9, Local1, Local0) // Local0 = 100/9, Local1 = 100 % 9
- Mod(100, 9, Local0) // Local0 = 100 % 9
- Multiply(34, 25, Local0) // Local0 = 34 * 25
- Nor(0x34, 0xF8, Local0) // Local0 = (~0x34) & (~0xF8),
- 無對應的操作符 Not(0x00, Local0) // Local0 = ~0x00
- Or(0x3F, 0xF4, Local0) // Local0 = 0x3F | 0xF4
- ShiftLeft(3, 6, Local0) // Local0 = 3 > 6
- Subtract(100, 24, Local0) // Local0 = 100 - 24
- Xor(0x3F, 0x90, Local0) // Local0 = 0x3F ^ 0x90
除了上面列出的使用方法之外,這些函式還會將計算結果通過返回值傳遞回來,這樣就方便一次連線很 長的算式。 例如: Store(Add(5, 4), Local0) // Local0 = 5 + 4
三、函式,
流程控制
1. 定義函式
Method(TMED) { }
2. 定義有兩個輸入引數的函式
Method(TMED, 2) { // Arg0 - 第一個輸入引數 // Arg1 - 第二個輸入引數 }
3. 在函式中使用區域性變數
Method(TMED, 2) {
Store(Arg0, Local0)
Store(Arg1, Local1)
Add(Local0, Local1, Local0)
}
4. 在函式中使用返回值
Method(TMED, 2) {
Store(Arg0, Local0)
Store(Arg1, Local1)
Add(Local0, Local1, Local0)
Return(Local0)
}
5. 呼叫函式 TMED(3, 5) 6. 儲存函式的返回值 Store(TMED(4, 5), TMPD)
Scope(_SB)
{
Device(LID0)
{
Name(_HID, EISAID("PNP0C0D"))
Method(_STA, 0, NotSerialized)
{
Return(Zero)
}
}
}
Name(_S0, Package(4) {Zero, Zero, Zero, Zero})
If(SS1)
{
Name(_S1, Package(4) {One, Zero, Zero, Zero})
}
If(SS3)
{
Name(_S3, Package(4) {0x05, Zero, Zero, Zero})
}
If(SS4)
{
Name(_S4, Package(4) {0x06, Zero, Zero, Zero})
}
Name(_S5, Package(4) {0x07, Zero, Zero, Zero})
Method(PTS, 1, NotSerialized)
{
If(Arg0)
{
\_SB.PCI0.LPCB.SPTS(Arg0)
\_SB.PCI0.NPTS(Arg0)
\_SB.SARM(Arg0)
\_SB.PCI0.LPCB.SIOS(Arg0)
}
}
Method(WAK, 1, NotSerialized)
{
\_SB.PCI0.LPCB.SWAK(Arg0)
\_SB.PCI0.NWAK(Arg0)
\_SB.PCI0.LPCB.S1RS(Arg0)
\_SB.PCI0.LPCB.SIOW(Arg0)
}
}
四、OperationRegion 的使用,IO,Memory,PCI,EC 讀寫
OperationRegion 是 ACPI 定義的一種操作 Register 方式,可以操作的 Register 包括 IO Memory PCI 等 等,ACPI 4.0 支援的 OperationRegion 共有以下幾種。此外,使用者還可以自己寫一個 ACPI 驅動,註冊自 己的 OperationRegion。
就當前來說,並不是上面所有的 OperationRegion 都受到支援且可以使用,一些 OperationRegion,受限 於編譯器,OS 下 AML 的 Interpreter 支援等等因素,是不能確定能夠在當前 ASL 中使用的,類似的 OperationRegion 有 CMOS,PCIBARTarget,IPMI,SMBus。另外,對於其他的一些 OperationRegion,ACPI Spec 有一些特殊的規定
- OS 必須保證 SystemIO OperationRegion 在任何情況下都可以使用
- OS 必須保證 PCI Root Bus 下的 PCI_Config OperationRegion 一定可用
- OS 必須保證,SystemMemory OperationRegion 在訪問通過 Memory Map Report 的 Memory 時,一定可 用。事實上,這一條就是說明,只要是在有效地址空間中的 Memory 訪問,OS 必須保證 Memory OperationRegion 可用
此外其他 OperationRegion,必須通過_Reg Method 去判斷,如果 OperationRegion 已經 connect,則此 時此 OperationRegion 可用,如果沒有 connect,或者已經 Disconnect,則不可通過此 OperationRegion 去訪問裝置的地址空間。
IO OperationRegion 接下來,將展示一個 IO OperationRegion 的使用,我們使用定義的 OperationRegion,將 debug code 輸出到 80 Port
//示例開始
OperationRegion (DBGP, SystemIO, 0x80, 4)
Field (DBGP, ByteAcc, Lock, Preserve)
{
P80L, 8
}
Store(0xA3, P80L)
// 輸出 A3 到 80 port
Memory OperationRegion
接下來,我們通過 Memory OperationRegion 展示一個相當好用函式。我們知道,對於 PCIe 裝置來說, 有兩種訪問方法,一種是通過傳統的 PCI 相容方式,另外一種是通過 MMIO,不但可以訪問 PCI 的 256 byte 的 PCI Space,而且可以訪問全部的 4K PCI space,那麼接下來,我們將展示這樣一組函式,他能夠讓 你在 ASL 裡面自由的訪問 PCI Express 的 Configuration Space。
//示例開始
#define PCIE_BASE 0xE0000000
Method (RDPB, 1) {
Add (Arg0, PCIE_BASE, Local0) // Add PCI Express MMIO base address
OperationRegion (PECF, SystemMemory, Local0, 0x1)
Field (PECF, ByteAcc, Nolock, Preserve) {
MCFG, 8 ,
}
Return (MCFG)
}
上面展示的函式是直接通過 MMIO 訪問 PCI Express 裝置的 configuration space,但是上面函式只適合 比較熟練的開發者使用,因為需要自己計算 PCIe 裝置的地址,那麼,我們把上面的函式稍微轉換一下, 變成下面的函式,這樣就夠直觀了。
// Arg0 - bus no
// Arg1 - dev no
// Arg2 - func no
// Arg3 - register offset
Method (RDPB, 4) {
ShiftLeft(Arg0, 20, Local0) // 計算 bus number PCIe address
Or(ShiftLeft(Arg1, 15), Local0, Local0) // 計算 device number PCIe address
Or(ShiftLeft(Arg2, 12), Local0, Local0) // 計算 function number PCIe address
Or(Arg3, Local0, Local0) // 計算 register,形成最終 PCIe address
Add (Arg0, PCIE_BASE, Local0) // Add PCI Express MMIO base address
OperationRegion (PECF, SystemMemory, Local0, 0x1)
Field (PECF, ByteAcc, Nolock, Preserve) {
MCFG, 8 ,
}
Return (MCFG)
}
有了上面的函式,我們可以直接在 ASL 讀某個 PCIe 裝置的一個 byte,例如,我們讀 PCI 裝置,bus 0, dev 31, func 3, register 0x40,可以使用如下語句:
Store(RDPB(0, 31, 3, 0x40), Local0)
上面是讀 PCIe Register 的函式,接下來,我們將上面的函式稍作修改,寫一個寫 byte 到 PCIe register 的函式。
// Arg0 - bus no
// Arg1 - dev no
// Arg2 - func no
// Arg3 - register offset
// Arg4 - value
Method (WRPB, 4) {
ShiftLeft(Arg0, 20, Local0) // 計算 bus number PCIe address
Or(ShiftLeft(Arg1, 15), Local0, Local0) // 計算 device number PCIe address
Or(ShiftLeft(Arg2, 12), Local0, Local0) // 計算 function number PCIe address
Or(Arg3, Local0, Local0) // 計算 register,形成最終 PCIe address
Add (Arg0, PCIE_BASE, Local0) // Add PCI Express MMIO base address
OperationRegion (PECF, SystemMemory, Local0, 0x1)
Field (PECF, ByteAcc, Nolock, Preserve) {
MCFG, 8 ,
}
Store(Arg4, MCFG)
}
可以使用以下語句,將一個 byte 寫入到 bus 0, dev 31, func 3, register 0x40
WRPB(0, 31, 3, 0x40, 5)
PCI_CONFIG OperationRegion
可以通過定義 PCI OperationRegion 來訪問 PCI 和 PCI Express 裝置的配置空間。不過,可以從 PCI OperationRegion 的定義看到,OperationRegion 本身只定義 Register 在 Configuration Space 的位置 和長度,但不能確定 PCI 裝置 bus number,device number,和 function number,所以也就不能確定設 備的地址。 ACPI 引入了其他一些 Method 來確定 ACPI 中 PCI 裝置的地址。 _SEG 函式定義 PCI 裝置的 Segment,在 x86 架構中來說,一般不使用_SEG,所有的 PCI 裝置預設都在 Segment 0. _BBN 函式定義 PCI Root Bridge 的 bus number,一般來說在 PCI Root Bridge 下定義_BBN(0),意指從 bus 0 開始。有 了 segment 和 bus,最後我們在 PCI 裝置下定義一個_ADR 屬性,確定此 PCI 裝置的 device number 和 function number,_ADR 的返回值中,高 16 位表示 device number,低 16 位表示 function number,接 下來將展示一段 sample code,讀寫 bus 0 ,device 29,function 1 USB controller 的 PCI Configuration Space
//示例開始
Name(_ADR, 0x001d0001) // Device (HI WORD)=29, Func (LO WORD)=1
OperationRegion(USBR, PCI_Config, 0xC4, 1)
Field(USBR, ANYACC, NOLOCK, PRESERVE) {
URES, 8
}
Method(TEMD) {
Store(3, URES)
}
EC OperationRegion
EC OperationRegion 是定義 EC Space 操作的,可以在 ASL 裡面定義 EC OperationRegion,直接讀寫 EC OperationRegion,OS 的 ACPI 或者 EC Driver 或將這些操作轉換為對 EC Space 的讀寫。根據 ACPI spec, 對於一個讀操作,driver 會向 EC 傳送 0x80 command 讀其中的 value,對於寫操作,driver 會向 EC 發 0x81 command 將一個 value 寫道 EC Space。接下來定義一個 EC OperationRegion,假設 EC Space offset 0x00 是 CPU 的溫度。
//示例開始
OperationRegion (ECF2, EmbeddedControl, 0x00, 0xFF)
Field (ECF2, ByteAcc, Lock, Preserve) {
CTMP, 8, //CPU Temp
}
Store(CTMP, Local0) // Read CPU temperature from EC Space
與上面其他 OperationRegion 不同的是,EC OperationRegion 並不是任何時刻都可以使用,所以我們要 follow ACPI spec,在同一 scope 中定義一個_Reg 屬性,來判斷 EC OperationRegion 是否可用
//示例開始
Name(ECON, 0) // Variable to remember EC
OperationRegion Status Method(_REG, 0x2) {
if(LEqual(Arg0, 0x03)) // Is it EC OperationRegion? Yes EC =3
{
If(Arg1) // Is OperationRegion Connect?
{
Store(0x01, ECON) // Available
}
Else // OperationRegion Disconnect
{
Store(0x00, ECON) // unavailable
}
}
}
相關文章
- 計算機語言:編譯型/解釋型、動態語言/靜態語言、強型別語言/弱型別語言計算機編譯型別
- Go語言————1、初識GO語言Go
- java語言屬於哪種語言Java
- 概念區別 【編譯型語言與解釋型語言、動態型別語言與靜態型別語言、強型別語言與弱型別語言】編譯型別
- 【Go語言入門系列】(八)Go語言是不是面嚮物件語言?Go物件
- go語言與c語言的相互呼叫GoC語言
- SQL語言(結構化查詢語言)SQL
- SQL語言基礎(資料控制語言)SQL
- 從高階語言到機器語言
- Python 語言特性:編譯+解釋、動態型別語言、動態語言Python編譯型別
- SQL語言SQL
- r語言R語言
- C語言C語言
- 計算機程式語言的分類,解釋型語言、編譯型語言、指令碼語言的關係計算機編譯指令碼
- 編譯型語言與解釋型語言編譯
- GO語言————2、GO語言環境安裝Go
- python語言與其他語言有什麼不同?Python
- 聊聊C語言/C++—程式和程式語言C語言C++
- 【R語言入門】R語言環境搭建R語言
- 獲取系統語言/當前 App支援語言APP
- 解釋型語言、編譯型語言 區別編譯
- NLP 與 NLU:從語言理解到語言處理
- 組合語言1 - 什麼是組合語言?組合語言
- C語言:一種高效、易學的程式語言C語言
- 【譯】Go語言宣告語法Go
- Go語言mapGo
- 組合語言組合語言
- C語言字串C語言字串
- PLSQL程式語言SQL
- go 語言切片Go
- sql程式語言SQL
- Protobuf 語言指南
- go 語言常量Go
- C語言(一)C語言
- go語言使用Go
- C語言: returnC語言
- C語言 typedefC語言
- 隻言片語