自己動手寫DSDT系列教程1-ASL(ACPI Source Language)基礎篇

寫在前面的話,鄙人不是一個主板BIOS開發工作者,以下對ASL的理解僅僅來源於http://www.acpi.info/上的ACPI Specification文檔。因此難免會出現不少錯誤的理解,以及錯誤的觀點,希望大家諒解以及糾正。
    首先,不得不說一下DSDT(Differentiated System Description Table)。什麼是DSDT呢?其實它屬於ACPI其中的一個表格,而ACPI是Advanced Configuration & Power Interface的縮寫,高級配置和電源接口,從文字上就可以理解ACPI是一系列的接口,這個接口包含了很多表格,所以DSDT即是其中的一張表格同時也是一些接口。所以不難想象ACPI主要的功能就是提供操作系統一些服務以及提供一些訊息給操作系統使用。DSDT自然也不例外。ACPI的一個特色就是專有一門語言來編寫ACPI的那些表格。它就是ASL(ACPI Source Language)也就是這盤文章的主角,ASL經過編譯器編譯後,就變成了AML(ACPI Machine Language),然後由操作系統來執行。既然ASL是一門語言,那就有它的準則。

ASL準則:
1、變量命名不超過4個字符,且不能以數字開頭。聯想一下看到過的DSDT代碼看看,絕對不會超過。
2、Scope形成作用域,概念類似於數學中的集合{}。有且僅有一個根作用域,所以DSDT都以


DefinitionBlock ("xxxx", "DSDT", 0x02, "xxxx", "xxxx", xxxx)
{


開始,同時以


}


結束。這個就是根作用域。xxxx參數依次表示輸出文件名、OEMID、表ID、OEM版本。第三個參數根據第二個參數指定,如上面所示。如果是"DSDT"就一定是0x02,其他參數都可以自由修改。
3、以“_”字符開頭的函數和變量都是系統保留的,這就是爲什麼反編譯某些AML以後得到的ASL出現_T_X,重新編譯的時候會出現警告。
4、Method定義函數,函數可以定義在Device下或者Scope下,但是不能脫離Scope定義單獨的函數,所以不會有這種情況出現。


Method (xxxx, 0, NotSerialized)
{
......
}
DefinitionBlock ("xxxx", "DSDT", 0x02, "xxxx", "xxxx", xxxx)
{
......
}


5、根作用域下有\_GPE,\_PR,\_SB,\_SI,\_TZ五個作用域。\_GPE就是ACPI的事件處理,\_PR處理器,\_SB所有的設備和總線。\_SI系統指示燈。_TZ熱區,用於讀取某些溫度。不同屬性的東西放在對應的作用域下。例如:
設備Device (PCI0)放在Scope (\_SB)裏面


Scope (\_SB)
{
    Device (PCI0)
    {
        ....
    }
    ....
}


CPU相關的信息放在Scope (_PR)


Scope (_PR)
{
    Processor (CPU0, 0x00, 0x00000410, 0x06)
    {
        ....
    }
    ....
}


Scope (_GPE)放着相關的事件處理


Scope (_GPE)
{
    Method (_L0D, 0, NotSerialized)
    {
        ....
    }
    ....
}


乍一看不是函數嗎?當然函數也可以放在這裏。但是請注意函數名“_”開頭,是系統保留的函數。
6、Device(xxxx)也可看做是一個作用域
7、符號“\”引用根作用域,“^”引用上級作用域
8、ASL中沒有運算符,+-*/=是不會出現了,但是有等價的函數。
9、函數最多可以傳遞8個參數,在函數裏用Arg0~Arg7表示,不可以自定義。
10、函數最多可以用8個局部變量,用Local0~Local7,不用定義,但是需要初始化才能使用,也就是一定要有一次賦值操作。

ASL常用的數據類型:
Integer(整數)、String(字符串)、Event(事件)、Buffer(數組)、Package(對象集合)
ASL定義變量:
例如:
Name(TEST,0)//定義一個整數
Name(MSTR,"ASL")//定義一個字符串


Name (_PRW, Package (0x02)
                {
                    0x0D,
                    0x03
                })


//定義一個Package
可以發現定義變量的時候不需要顯式聲明其類型
ASL賦值方法:
有且僅有一個,Store(a,b)如
Store(0,Local0)//Local0=0
Store(Local0,Local1)//Local0=Local1

ASL運算函數:
上面提到ASL沒有運算符號,但是有運算函數
Add 整數相加
And 整數於
Decrement 整數自減1
Divide 整數除法
Increment 整數自增1
Mod 整數求餘
Multiply 整數相乘
ShiftLeft 左移
ShiftRight 右移
Subtract 整數減法
Or 或
Not 取反
Nor 異或
等等,具體請查閱ACPI Specification
舉例如下:


Add(1, 2, Local0) //Local0 = 1 + 2
And(0x11, 0x22, Local0) //Local0 = 0x11 & 0x22
Divide(10, 9, Local1, Local0) //Local0 = 10 / 9, Local1 = 10 % 9
Mod (10, 9, Local0) //Local0 = 10 % 9
Multiply(1, 2, Local0) //Local0 = 1 * 2
ShiftLeft(1, 20, Local0) // Local0 = 1 << 20
ShiftRight(0x10000, 4, Local0) // Local0 = 0x10000 >> 4
Subtract(2, 1, Local0) //Local0 = 2 - 1
Or(0x01, 0x02, Local0) //Local0 = 0x01 | 0x02
Not(0x00,Local0) //Local0 = ~(0x00)
Nor(0x11, 0x22, Local0) //Local0 = ~(0x11) & ~(0x22)


ASL邏輯運算:
LAnd 邏輯與
LEqual 邏輯相等
LGreater 邏輯大於
LGreaterEqual 邏輯大於等於
LLess 邏輯小於
LLessEqual 邏輯小於等於
LNot 邏輯反
LNotEqual 邏輯不等於
LOr 邏輯或


Store (LAnd(1, 1), Local0) //Local0 = 1 & 1
Store (LEqual(1, 1), Local0) //Local0 = (1 == 1)
Store (LGreater(1, 2), Local0) //Local0 = (1 > 2)
Store (LGreaterEqual(1, 2), Local0) //Local0 = (1 >= 2)
Store (LLess(1, 2), Local0) //Local0 = (1 < 2)
Store (LLessEqual(1, 2), Local0) //Local0 = (1 <= 2)
Store (LNot(0), Local0) //Local0 = !0
Store (LNotEqual(0, 1), Local0) //Local0 = (0 != 1)
Store (LOR(0, 1), Local0) //Local0 = (0 | 1)


不難發現邏輯運算只會有兩種結果0或者1。

ASL函數的定義:
1、定義函數


Method(TEST)
{}


2、定義有兩個輸入參數的函數,以及使用局部變量Local0~Local7


Method(MADD,2)
{
    Store(Arg0, Local0)
    Store(Arg1, Local1)
    Add(Local0, Local1, Local0)
}


實現了兩個參數的加法運算,因此傳入的參數一定要隱式整形數。
3、定義帶返回值的函數


Method(MADD,2)
{
    Store(Arg0, Local0)
    Store(Arg1, Local1)
    Add(Local0, Local1, Local0)
    Return (Local0)
}


例子爲自定義加法的實現。函數實現如同系統函數Add一樣的相加
Store(MADD(1,2), Local0) //Local0 = 1 + 2
4、定義可序列化的函數


Method(MADD, 2, Serialized)
{
Store(Arg0, Local0)
Store(Arg1, Local1)
Add(Local0, Local1, Local0)
Return (Local0)
}


這個有點類似於多線程同步的概念,也就是說,當函數聲明爲Serialized,內存中僅能存在一個實例。一般應用在函數中創建一個對象。應用舉例說明:


Method(TEST, Serialized)
{
    Name(MSTR,"I will sucess"
}


如果這樣子聲明TEST這個函數,那麼在兩個地方同時調用這個函數


Device (Dev1)
{
     TEST()
}
Device (Dev2)
{
     TEST()
}


如果先執行Dev1的TEST,Dev2中的TEST將等待Dev1中的TEST函數執行完畢再執行。如果聲明爲


Method(TEST, NotSerialized)
{
Name(MSTR,"I will sucess"
}


那麼將在其中一個Devx調用TEST的時候,另外一個調用失敗,當它試圖創建相同的字符串MSTR的時候。

ASL流程控制:
和常見的高級語言一樣,ASL也有與之對應的控制流程語句。
Break
BreakPoint
Case
Continue
Default
Else
ElseIf
If
Return
Stall
Switch
While
(一)分支控制If, ElseIf, Else, Switch, Case
1、If用法介紹
例如下面的語句判斷一下當前系統的接口是不是Darwin,如果是把OSYS = 0x2710


If (_OSI ("Darwin"))
{
    Store (0x2710, OSYS)
}


2、ElseIf、Else用法介紹,如果系統結構不是Darwin,另外如果系統不是Linux,那麼OSYS = 0x07D0


If (_OSI ("Darwin"))
{
    Store (0x2710, OSYS)
}
ElseIf (_OSI ("Linux"))
{
    Store (0x03E8, OSYS)
}
Else
{
    Store(0x07D0, OSYS)
}


3、Switch, Case, Defaule, BreakPoint示例


Switch(Arg2)
{
    Case(1)
    {
If(LEqual(1, Arg1)
{
    Return (1)
}
BreakPoint
    }
    Case(2)
    {
        ....
        Return (2)
    }
    Default
    {
        BreakPoint
    }
}


Switch可以看做是一系列If....Else的集合。BreakPoint相當於斷點,意味着退出當前Swtich
(二)循環控制While,Break,Continue以及暫停Stall示例


Store(10, Local0)
While (LAnd (0x00, Local0))
{
    Decrement (Local0)
    Stall (32)
}


Local0等於10,如果Local0邏輯於0不爲真,Local0自減1,暫停32us,所以這段代碼延時10 * 32 = 320 us。

累了,今天就寫到這裏,有了這些基礎,鄙人覺得現在大部分論壇壇友對着DSDT的時候就不會是發呆又發呆,至少可以明白些少語句了。


原文出自:http://bbs.pcbeta.com/viewthread-944566-1-1.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章