2009年11月16日 星期一
讀寫SMRAM
標 題: 【原創】SMM Rootkit初步 - 讀寫SMRAM(帶你邁入CPU級Rootkit之門)
作 者: 木樁
時 間: 2009-03-29,14:37
鏈 接: http://bbs.pediy.com/showthread.php?t=84835
好吧,我承認標題有點誇大,不介意的都進來BS我把
就像 qihoocom 大俠說的,「SMM XX早就幾萬年前就不是什麼秘密了」,不過國內討論這個的到是鮮見,希望這篇文章能拋磚引玉吧。
之前看到rootkit.com上 Implementing SMM PS/2 Keyboard sniffer 那個代碼,狠狠震撼了一把。於是開始研究SMM,半月下來總算有些收穫。這裡將如何讀寫SMRAM的方法拿出來科普一下,希望更多人能邁入編寫SMM Rootkit的大門。
文章後面提供可以在VPC和VMware兩大虛擬機中運行的代碼,將演示如何在WinXP(SP2)中讀寫SMRAM。(本文只考慮最簡單的系統環境,不涉及 SMM Space Locked(D_LCK)=1 時無法讀寫SMRAM的情況)另外,按 Ivanov 大牛的說法,這種方法侷限性很大,只能在沒有執行 Intel 修補方案的主板上運用(感謝兩大VM模擬的都是I440BX )。
對硬件方面接觸尚淺,文中若有疏漏之處,歡迎指正。
--------------------------------------------------------------------------------------------------------
首先放下PCI相關的諸多知識,我用最短的篇幅敘述讀寫SMRAM的過程。希望這篇文章能帶你邁出SMM Rootkit的第一步。
首先說說什麼是SMM(System Management Mode)。System Management Mode Hack中說:SMM是專門為電源管理設計的執行規則。當進入SMM後,系統的各個部件可以被關閉或者使用最低的功耗。SMM獨立於其他的系統軟件,也可以被用在其他目的... 該文章中文版點這裡
瞭解SMM是什麼東西就夠了,這篇文章不會涉及太多SMM的東西。相反,讀寫SMRAM更需要的是PCI配置空間(PCI Configuration Space)方面的知識。
先講講兩個訪問PCI配置空間的I/O端口:CF8h 和 CFCh
通過向 CF8h 端口寫一個特殊的地址,我們就可以在 CFCh 端口上讀寫指定寄存器的值。這裡要讀的寄存器是位於配置空間偏移為 72h 的8bit寄存器——SMRAM (System Management RAM Control Register)
首先要介紹一下 CF8h 這個I/O端口。實際上 I/O CF8h 寫的是CONFIG_ADDRESS寄存器,所以 CF8h又叫CONFIG_ADDRESS。其佈局如下[1]:
名稱: CONFIG_ADDRESS寄存器結構.gif 查看次數: 1684 文件大小: 7.6 KB
按上圖格式,31位置1(enable),假設I440BX的北橋82443BX位於Bus: 0, Device:0, Func:0(後面將教你如何確定芯片類型以及取得這幾個值),這樣配置空間的基址就是0x80000000。
通過I/O指令向CF8h寫入0x80000000,就可以從 CFCh(CONFIG_DATA)中讀出82443BX配置空間偏移為0的一個DWORD值了。而這個DWORD的高低16位分別是VendorID和DeviceID,如圖:
名稱: PCI配置空間頭部_cut.gif 查看次數: 1675 文件大小: 8.9 KB
下面在我們去讀配置空間偏移為72h的SMRAM前,首先注意一個特性。不知道你注意到沒有,回頭看看CONFIG_ADDRESS的低2位,它們被定義為 0。且不談PCI規範上的大道理,說白了這個地方為0是為了限制你給出的地址——必須為4的整數倍。瞭解到這一點再看那個Register Number 就比較好理解了,原來這個寄存器編號和偏移是這麼對應的。
好了,那麼偏移為72h (01110010) 的SMRAM,最後兩位置零是70h (01110000),即位於編號為1C (11100)的寄存器上。所以只要向 CF8h 裡寫入0x80000070這個地址,此時從 CFCh 端口讀出的數據就是包含SMRAM的一個DWORD了。
名稱: 82443BX Register Map_SMRAM.gif 查看次數: 1686 文件大小: 24.2 KB
假設讀出來的數據為DWORD 380A0000h (00 00 0A 38),對照上面82443BX寄存器表可知:
代碼:
70h 00
71h 00
72h 0A SMRAM
73h 38 ESMRAMC
好了,SMRAM寄存器讀出來了,下面進入正題:如何將SMRAM內容映射到0xA0000。
從文獻[2]中瞭解到,只要D_OPEN=1時,對物理內存0xA0000的訪問會變成這樣:
名稱: SMRAM_D_OPEN.jpg 查看次數: 1684 文件大小: 23.0 KB
D_OPEN位在哪?SMRAM = 0Ah又代表什麼?根據文獻[1]記載,SMRAM的各位意義如下(關於SMRAM更詳細解釋,見文章末尾補充資料不部分):
代碼:
7 6 5 4 3 2 - 0
0 D_OPEN D_CLS D_LCK G_SMRAME C_BASE_SEG
| 1 010
|-> 我們就是要設置 D_OPEN = 1
原來的0Ah就是 0000 1010。只要第四位的D_LCK不為1,好了,向SMRAM寫入4Ah (0100 1010),於是飛躍光明之巔!
附帶程序中整個映射SMRAM過如下:
1. 首先遍歷PCI設備,找到I440BX的82443BX Host Bridge Controller。
(VMware Workstation 6.0.x中82443BX 的VendorID: 8086h DeviceID: 7190h)
(Virtual PC 2007 6.0.x 中82443BX 的VendorID: 8086h DeviceID: 7192h)
很幸運,這兩個虛擬機中,82443BX都位於Bus:0, Device:0, Func:0,所以PCI配置空間基址都是0x80000000。
2. 以I/O偽代碼為例,讀SMRAM:
out( CF8h, 80000070h ) // 還記得0x80000070怎麼來的嗎?
in( CFCh, eax ) // 讀出包含SMRAM的一個DWORD,如 380A0000h
shr eax, 10h // SMRAM的8bit在第三個字節處,右移16位(2字節)
// 此時AL中就是SMRAM內容了(0Ah)
3. 置D_OPEN為1,並且C_BASE_SEG設為010
(C_BASE_SEG在初始化時就是010了,不過為了防止意外,最好重設一下)
out( CF8h, 80000070h )
mov eax, 384A0000h // 寫回D_OPEN置1後的SMRAM(4Ah)
out( CFCh, eax )
4. 此時對物理內存0xA0000-0xBFFFF讀寫,就是在SMRAM中了。寫完試試D_OPEN=0隱藏看看,讀0xA0000是不是又回到顯存了?
注意:當SMM Space Lock(D_LCK)為1時,這種方法是無法修改SMRAM的,只能另闢蹊徑。
另外,關於讀出的SMRAM內容,一定會有人質疑0xA0000處真的是SMRAM?關於這點,可以去看看SMRAM的佈局http://www.sandpile.org/ia32/smm.htm。
我一般是通過7FF0h (EIP) 和7FF4h (EFLAGS) 這兩個DWORD判斷的(SMBASE默認是0xA0000):
> dump [000A7FC0 - 000A8000]
000A7FC0 00 00 00 00 28 00 00 00 00 04 00 00 F0 0F FF FF
000A7FD0 E1 BB 7E 81 83 A0 00 00 B2 00 00 00 00 00 00 00
000A7FE0 20 42 E6 F9 20 42 E6 F9 80 C2 A1 F9 E0 E0 6E 80
000A7FF0 47 8B A1 F9 46 02 00 00 00 90 03 00 31 00 01 80
EIP EFLAGS
引用:
補充資料:
這裡是 Intel 440BX AGPset: 82443BX Host Bridge Controller[1] 中關於SMRAM的詳細解釋:
名稱: SMRAM描述-System Management RAM Control Register.gif 查看次數: 1655 文件大小: 16.2 KB
名稱: 內容System Management RAM Control Register.gif 查看次數: 1651 文件大小: 81.5 KB
還有些相關知識,有時間再補上...
參考文獻:
[1] Intel 440BX AGPset: 82443BX Host Bridge Controller
http://download.intel.com/design/chi...s/29063301.pdf
[2] Shawn Embleton, Sherri Sparks, Cliff Zou.
SMM Rootkits: A New Breed of OS Independent Malware
[3] Loic Duflot, Daniel Etiemble, Olivier Grumelard.
Using CPU System Management Mode to Circumvent Operating System Security Functions
[4] Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide
http://www.intel.com/products/processor/manuals/
[5] A tool for FreeBSD to discover SMRAM on i440BX based motherboards
http://unix.derkeiler.com/Mailing-Li...att-0448/smm.c
測試環境:
Intel Pentium D 3.0GHz 雙核 + Virtual PC 2007(6.0.192.0) + WinXP(SP2)
Intel Pentium D 3.0GHz 雙核 + VMware Workstation (6.0.4-93057) + WinXP(SP2)
AMD Athlon 64 X2 Dual 4000+ + Virtual PC 2007(6.0.192.0) + WinXP(SP2)
Virtual PC 2007下的運行截圖:
名稱: VPC運行截圖.gif 查看次數: 1684 文件大小: 23.2 KB
由於手頭沒有I440BX的主板,無法使用真實機器測試。另外 AMD64 Architecture Programmer's Manual Volume 2: System Programming 也提及了SMM的相關細節,目前還沒有仔細看。
如果你在其他芯片組上測試成功,歡迎給我來信:upbit@126.com
ps: 忘補上一個開發庫了,程序裡用到了WinIO,可以到這裡http://www.internals.com/
WinIO這個開發庫附帶C和VB的例子,理論上我這裡給的代碼都能翻譯成C或VB的,有興趣的不妨試試
什麼是SYSTEM MANAGEMENT MODE (SMM)
一、概述
只有SMI才會引起進入SMM,處理器保護現場,切換到SMRAM裡的一個獨立位址空間執行SMM代碼,RSM指令會使系統返回到原來的正常模式。SMM相當於實模式,沒有特權級和位址映射,可定址4GB,可執行所有I/O和可用系統指令。
SMI優先順序在所有中斷裡最高。當處於SMM狀態,處理器不識別後繼的SMI請求,但第一個SMI請求可以被鎖存,並在系統退出SMM後被處理。
RSM指令只能在SMM狀態下執行,否則會產生「操作符無效」異常(exception)。RSM把SMRAM裡的處理器內容存回處理器,接著把控制權還給被中斷程式。若處理器在SMRAM中偵測到無效狀態,會shut down並產生一特殊匯流排週期以標識該狀態。
當收到SMI時,若處理器處於HALT狀態,處理器從SMM返回會稍有不同,SMBASE位址也會有所改變。
SMM時,處理器在SMRAM裡執行代碼和存儲資料,也用其來存儲系統管理資訊(如系統配置和power-down設備的特殊資訊)及OEM SPEC資訊。SMRAM被映射到物理空間,最大是4GB,默認是64KB,開始於物理空間裡的SMBASE(硬體RESET後,預設值是3000H)。
處理器在[SMBASE+8000H]尋找SMI處理程式的第一條指令。[SMBASE+FE00H]:[SMBASE+FFFFH]存放處理器狀態,即處理器的所有寄存器值。
SMRAM
SMBASE+FFFFH: Start of State Aave Area SMBASE+FE00H: |
SMI Handler Entry Point SMBASE+8000H: |
SMBASE+8000H
三、SMI執行環境
SMM與實模相似但有所不同,它可以定址4GB,加上「E」首碼就可以訪問1MB以上空間,DATA和STACK可以在4GB的任何地方。
寄存器初始值:
EFLAGS | 0000 0002H |
EIP | 0000 8000H |
CS | SMBase(default: 3000h) |
DS、ES、FS、GS、SS | 0000H |
CR0 | Set PE、EM、TS、PG to 0,其他不變 |
DR7 | 0400H |
四、SMM中的中斷和exception
進入SMM後,所有HW中斷都被禁止(包括可遮罩硬體中斷、單步中斷、中斷點陷阱、NMI、SMI和A
NMI會被堵在SMI服務程式入口處,且只有第一個NMI會被鎖存並在退出SMM後被執行。但也可以通過使能INTR引腳並有效INTR的方式來在SMM中使能NMI。在一般情況下,NMI是不可嵌套的,但也有例外。若從NMI處理程式進入SMM,同時有收到新的NMI,就可以在退出SMM後實現嵌套,也就是在老的NMI處理程式裡處理新的NMI。
有時在SMM裡有必要保存FPU狀態,最安全的辦法是先置處理器於保護模式下再存FPU,儘管FSAVE可以以四種格式中任一種來存PFU內容。一般默認是在實模方式下進行,但若在非16位實模下發生SMI就必須進入保護模式執行FSAVE和FRSTOR,否則無法正確保存和恢復相關FPU資訊。但存完FPU資訊後,SMI處理程式可以繼續在保護模式下執行,但建議其主要在16/32實模下運行。
31 18 17 16 15 0
Reserved | SMM版本標識 |
Bit 17 =1 : SMBASE重定位使能
Bit 16=1 : 支援I/O指令重啟
1)
SMBASE重定位
SMBASE默認是30000H,放在處理器內部的SMBASE寄存器裡,我們可以通過在[SMBASE+FEF8H]處設置SMBASE區來重定位SMRAM。後續SMI請求會在新位址處執行SMI處理程式和存放狀態記憶體(系統重啟後會把SMBASE寄存器又寫成30000H,但INIT不會改變它)。
若SMBASE重定位到1MB以上位址,實模下的軟體操作就不能初始化段寄存器到SMBASE。
SMBASE可用「E」首碼來訪問32位元位址大小。
2)
I/O指令重啟
就是允許從SMM狀態返回時從被中斷I/O指令處重新執行。I/O指令重啟區[SMBASE+FF00H]控制I/O指令重啟,值為FFH時允許重啟。但該I/O指令並不是造成SMI的原因。
若從I/O指令進入SMM又收到SMI,處理器會先處理新的SMI再重啟該I/O指令。
若處理器在HALT狀態進入SMM,要在[SMBASE+FF02]處置自動HALT重啟標誌位元。SMI處理程式可將它清零或不予理睬,這樣返回時就相應地執行HLT指令後的下一條指令或仍回到HALT狀態。
進入SMM後的值 | 退出SMM後標誌值 | 退出SMM狀態後處理器行為 |
0 0 1 1 | 0 1 0 1 | 返回到被中斷程式或任務的下一條指令 不可預料 返回到HLT指令後的下一條指令 回到HALT狀態 |
MP系統中任一處理器都要能回應SMI。
每個處理器都有自己的SMRAM空間。
不同處理器的SMRAM可在同一記憶體空間重疊,但它們的狀態存儲區和動態資料存儲區卻要彼此獨立,代碼和靜態資料可共用。
SMI處理程式要為每個處理器初始化SMBASE。
處理器可通過自己的SMI引腳或從APIC介面收到的SMI來響應本地SMI(APIC介面可將SMI分給不同的處理器)。
edge trigger VS level trigger
邊緣觸發是指每當狀態變化時發生一個io事件,條件觸發是只要滿足條件就發生一個io事件。
舉個讀socket的例子,假定經過長時間的沉默後,現在來了100個字 節,這時無論邊緣觸發和條件觸發都會產生一個read ready notification通知應用程序可讀。
應用程序讀了50個字節,然後重新調用api等待io事件。這時條件觸發的api會因為還有50個字節可讀從而立即返回用戶一個read ready notification。而邊緣觸發的api會因為可讀這個狀態沒有發生變化而陷入長期等待。
因此在使用邊緣觸發的api時,要注意每次都要讀到socket返回EWOULDBLOCK為止,否則
這個socket就算廢了。而使用條件觸發的api時,如果應用程序不需要寫就不要關注socket可寫的事件,否則就會無限次的立即返回一個write ready notification。
大家常用的select就是屬於條件觸發這一類,以前本人就犯過長期關注socket寫事件從而
CPU 100%的毛病。
恩,最近用poll也碰到了這個問題,呵呵。
ACPI VS APIC
很多人問道了什麼ACPI,什麼是APIC,他們有沒有關係?名字這麼相近。下面給出我對其的一些理解,具體的解釋可以查看內核文檔庫的內核參數文件:
/usr/src/`uname -r`/Documents/kernel-parameters.txt
ACPIACPI就是Advanced Configuration and Power Interface的縮寫,意思是「高級配置與電源接口」。這是英特爾、微軟和TOSHIBA共同開發的一種電源管理標準。
ACPI可實現以下功能:
- 用戶可以使外設在指定時間開關;
- 使用筆記本電腦的用戶可以指定計算機在低電壓的情況下進入低功耗狀態,以保證重要的應用程序運行;
- 操作系統可以在應用程序對時間要求不高的情況下降低時鐘頻率;
- 操作系統可以根據外設和主板的具體需求為它分配能源;
- 在無人使用計算機時可以使計算機進入休眠狀態,但保證一些通信設備打開;
- 即插即用設備在插入時能夠由ACPI來控制。
ACPI共有六種狀態,分別是S0到S5,它們代表的含義分別是:
- S0–實際上這就是我們平常的工作狀態,所有設備全開,功耗一般會超過80W;
- S1–也稱為POS(Power on Suspend),這時除了通過CPU時鐘控制器將CPU關閉之外,其他的部件仍然正常工作,這時的功耗一般在30W以下;(其實有些CPU降溫軟件就是利用這種工作原理)
- S2–這時CPU處於停止運作狀態,總線時鐘也被關閉,但其餘的設備仍然運轉;
- S3–這就是我們熟悉的STR(Suspend to RAM),這時的功耗不超過10W;
- S4–也稱為STD(Suspend to Disk),這時系統主電源關閉,但是硬盤仍然帶電並可以被喚醒;
- S5–這種狀態是最乾脆的,就是連電源在內的所有設備全部關閉,功耗為0。
在STR狀態下,電源仍然繼續為記憶體等最必要的設備供電,以確保數據不丟失,而其他設備均處於關閉狀態,系統的耗電量極低。一旦我們按下Power按鈕(主機電源開關),系統就被喚醒,馬上從RAM中讀取數據並恢復到STR之前的工作狀態。RAM的讀寫速度極快,因此我們感到進入和離開STR狀態所花費的時間不過是幾秒鐘而已;
而S4狀態,即 STD(掛起到HDD)與STR的原理是完全一樣的,只不過數據是保存在硬盤中。由於硬盤的讀寫速度比RAM要慢得多,因此用起來也就沒有STR那麼快了。 STD的優點是只通過軟件就能實現,比如Windows 2000就能在不支援STR的硬件上實現STD。
之前的電源管理是APM(Advanced Power Management),那麼ACPI和APM相比有什麼區別呢?
ACPI與APM比較
- APM 1.0&1.1:由BIOS執行電源管理;
- APM 1.2:操作系統定義電源管理時間,由BIOS負責執行;
- ACPI:BIOS收集硬件信息,定義電源管理方案;由操作系統負責執行。
- APM是一種軟件解決方案,因此是與操作系統有關的, 而ACPI是工業標準,包括了軟件和硬件方面的規範。
APICAPIC(高級可編程中斷控制器)對計算機來講有兩個作用,
- 管理IRQ的分配,可以把傳統的16個IRQ擴展到24個(傳統的管理方式叫PIC),以適應更多的設備。
- 管理多CPU。由於Nf2主板並不支援多CPU,所以,APIC關閉直接的影響是減少了可用的IRQ。
要實現SMP功能,我們使用的CPU必須具備以下要求:
CPU 內部必須內置APIC單元。Intel 多處理規範的核心就是高級可編程中斷控制器(Advanced Programmable Interrupt Controllers–APICs)的使用。CPU通過彼此發送中斷來完成它們之間的通信。通過給中斷附加動作(actions),不同的CPU可以在某種程度上彼此進行控制。每個CPU有自己的APIC(成為那個CPU的本地APIC),並且還有一個I/O APIC來處理由I/O設備引起的中斷,這個I/O APIC是安裝在主板上的,但每個CPU上的APIC則不可或缺,否則將無法處理多CPU之間的中斷協調。
APIC可能遇到的問題,很多這類問題可以通過BIOS更新來解決。
下面的是通過更改HAL類型來解決
CPU實際運行頻率與BIOS設定頻率不符
NF2的用戶大約有10%的會出現CPU實際運行頻率與BIOS設定頻率不符的問題。我們稱之為「頻率不對」。這種現象帶來的直接後果就是在測試3dmark或跑3D遊戲的時候,會感覺不流暢,也稱之為「頓」。
一般在更改BIOS設置後、更新驅動後重啟時,用測試軟件如Aida32、MBM5等可以看到CPU的運行頻率和你在BIOS裡設置得不一樣,而且差距很大。這個時候,用super pi測試CPU速度,會比平常花費時間長好幾秒,用3dmark跑測試,會比平常低幾百分甚至上千分。在3dmark中看到的CPU頻率,也與BIOS設定不符合。如果出現這種情況,則屬於我們所討論的「頻率不對」的問題。
不過,不是所有的3D遊戲「頓」都是這個原因。判斷的方法是:如果你只有個別遊戲「頓」,或者用上述軟件測試頻率正確,就不是此問題。
如果判斷確實屬此問題,解決的方法也很簡單,經過網友討論,只要關閉APIC功能即可。(注意,是APIC,不是ACPI)。
有一些服務器(比如IBM的,HP的),安裝LINUX時,會給出內核的錯誤,導致無法安裝,這個時候可以在安裝的時候輸入
linux acpi=off noapic
應該是安裝上的。
轉載請註明: 轉載自Linux|系統管理|WEB開發
2009年11月4日 星期三
Intel VMX
http://pengsunshine.blogspot.com/2008/03/intel-vmx.html
Intel提供了處理器級的VMX(Virtual-Machine Extensions),從硬件層面支持VT技術。本文及後續的幾篇文章將結合"Intel 64 and IA-32 Architectures Software developer's Manual (Volume 3B)"和自己使用Xen的經驗寫些東西,算是學習筆記吧,不足之處在所難免,哪位看到了希望能共同交流提高 (^_^)。
先看一下虛擬機的體系結構:Intel VMX的體系結構可劃分為兩層:VMM和VM。
- VMM(Virtual-Machine Monitors)作為host,具有對processor(s)和平台硬件的完全控制權限。它為guest提供VCPU(virtual processor)的抽象,並允許guest直接運行在邏輯處理器(logical processor)上。VMM具有對處理器資源、物理內存、中斷和IO的選擇控制的權利。(舉例:Xen就是一種VMM。)
- VM(Virtual-Machine)相應地作為guest,其實是提供了一種guest軟件環境:它維護一個棧,其中包含了OS和application software。其每個操作都獨立於其他的VM,並且使用由同一個物理平台所提供的對處理器、內存、硬盤、顯卡、IO訪問的統一接口。此外,這個棧並不知道VMM的存在。運行於VM中的軟件其權限是受限的,這樣才能保障VMM對整個平台資源的完全控制。(舉相應的例子:Xen上跑的Guest OS就是VM。)
下面來簡要介紹一下VMX operation。支持虛擬化的處理器其虛擬化相關的操作被稱為VMX operation 。它分為兩類:VMX root operation 和 VMX non-root operation 。通常來說,VMM 運行於 VMX root operation 而 guest 運行於 VMX non-root operation 。兩種operation之間的轉換被稱為VMX transitions:從root到non-root被稱為VM entries,而從non-root到root則稱為VM exits。簡單可如下圖所示:
處於VMX root operation的CPU其行為與在VMX operation之外是基本一樣的,最根本的不同之處在於其增加了一套新的VMX指令集,且能存儲到特定控制寄存器的值是有限的。而處於VMX non-root operation的CPU起行為是受限的,且經過了修改以幫助實現virtualization。與其普通的operation不同,特定的指令(包括新增的VMCALL指令)和事件將導致VM exits從而進入VMM:由於這些VM exits代替了以前正常的行為,所以在VMX non-root operation中的軟件的功能是受限的(也正是這種限制保證了VMM能夠始終具有控制處理器資源的能力)。
從 guest的角度,沒有任何一個Guest可見的位來指示一個邏輯處理器是否處於VMX non-root operation,這樣VMX就能保證guest並不知道其正在運行於一個VM中。即便是CPL(current privilege level)為0,VMX operation也給guest加了限制,這樣guest software就可以完全不必改變其原始的設計,這也簡化了VMM的開發。
現在就可以看一下VMM與Guest之間的交互了。大體的流程是這樣子的:
- oftware執行VMXON指令進入VMX operation
- 通過VM entries,VMM就可以進入VM的guest中(VMM通過VMLANCH和VMRESUME來觸發VM entry,並通過VM exits重新獲得控制權)
- VM exits將控制權轉移到由VMM定義的entry point(VMM可以採取適當的動作來觸發VM exit,然後再使用一個VM entry就可以返回到VM中)。
- 最後,VMM通過VMXOFF指令關閉自身並退出VMX operation
既然已經涉及到VMX指令,下面又引出一個非常重要的數據結構VMCS(Virtual-Machine Control Structure),這個數據結構在下文中還要非常詳細地介紹。對VMCS的訪問是由一組被稱作VMCS pointer(每個logical processor有一個VMCS pointer)的處理器狀態來管理的。VMCS pointer是一個64位的VMCS地址,可通過VMPTRST和VMPTRLD指令對其進行讀寫;VMM可以使用VMREAD、VMWRITE、 VMCLEAR指令對VMCS進行配置。對VMM所管理的每個VM,VMM可以使用不同的VMCS;且對VM中的每個logical processor(or vcpu),VMM也可以為每個vcpu使用不同的VMCS。
VMX operation需要處理器支持,那麼如何從軟件層面斷定一個處理器是否支持VMX operation:通過CPUID --- 如果CPUID.1:ECX.VMX[bit 5] = 1,那說明該CPU支持VMX operation。現有的VMX體系結構的設計具有良好的可擴展性,software可以使用一個VMX capability MSRs集來獲得VMX新增的擴展特性。
現在再來看看如何使能和進入VMX operation:進入VMX operation之前,system software通過設置CR4.VMXE[bit 13] = 1 來使能VMX,之後就可以通過VMXON指令來進入VMX operation。如果CR4.VMXE = 0,VMXON將導致一個invalid-opcode異常(#UD),而且一旦進入VMX operation,CR4.VMXE就無法在此中被清零;system software通過VMXOFF離開VMX operation,只有在VMX operation外部CR4.VMXE才能被清零。
VMXON由IA32_FEATURE_CONTROL MSR (MSR address 3AH)所控制,當一個logical processor被rest時,該MSR被清零。此MSR的相關位如下:
- Bit 0 is the lock bit. 若該位被清零,VMXON就會觸發一個general-protection exception;若該位被置1,向此MSR進行WRMSR也會觸發general-protection exception,直到a power up reset condition發生時該MSR才能被修改。系統BIOS可以通過該比特位來禁用VMX,若要打開VMX支持,BIOS必須設置該MSR的bit 0, bit 1, bit 2。
- Bit 1 enables VMXON in SMX operation. 若該位被清零,SMX operation中的VMXON將觸發一個general-protection exception。若在不同時支持VMX和SMX的logical processors上試圖設置該位,將會觸發general-protection exceptions。(若一個logical processor自從最後一次執行GETSEC[SENTER]為止GETSEC[SEXIT]還未被執行,則稱其in SMX operation)
- * Bit 2 enables VMXON outside SMX operation. 若該位被清零,在SMX operation外部進行VMXON將觸發一個general-protection exception。在不支持VMX的logical processors上試圖設置該位將觸發general-protection exceptions。(若一個logical processor還未執行GETSEC[SENTER]或最後一次執行過GETSEC[SENTER]後又執行了GETSEC[SEXIT],則稱其 outside SMX operation)
在執行VMXON之前,software應該分配出(保留)一塊4KB對齊的內存區域供logical processor用以支持VMX operation。這個內存區域就被稱為VMXON region。
最後,簡單說說VMX operation上的限制:VMX operation對processor operation作了一些限制,諸如:
- 在VMX operation中,處理器將對CR0和CR4的某些具體位填充固定值(CR0.PE, CR0.NE, CR0.PG, cR4.VMXE的值都必須為1)。如果這些位中任何一位的值並不是它應該的值,VMXON就會fail。在VMX operation中任何試圖使用CLTS, LMSW, MOV CR等指令改變這些位的值都將導致general-protection exception。VM entry或VM exit都無法將這些位的值設置為其不應該的值。(CR0.PE和CR0.PG的限制就說明了VMX operation必須處於paged protected mode,這也使得guest software無法運行於unpaged protected mode或real-address mode中)
- 若logical processor處於A20M mode,VMXON會fail。一旦處理器進入VMX operation, A20M的中斷就會被block,這樣VMX operation中A20M mode當然是不可能的了。
- 只要logical processor處於VMX root operation,INIT signal就會被block;在VMX non-root operation中它是不會被block的,此時INITs將觸發VM exits。
從源碼級別,Xen裡面的vmx.c描述的就是Intel VMX體系結構相關的VM Exits支持:對照著Intel的Manual可以找到Xen對其的具體實現。
2009年10月21日 星期三
Speed Step
; R9 m5 }% ^0 u9 q6 D計匠網論壇IA-32 ASDM volume 3也提到一點點,特別是1A0(IA32_MISC_ENABLE).
/ Y' s* D' A7 i+ |www.ufoit.com
! f& c, E/ n- [6 g5 p oBIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC對於Intel speedstep,我這裡摘抄一篇深圳頂星數碼的同志所發表一篇絕好的技術簡介文檔給你做參考。
1 V3 z' r& x1 s' i$ [0 }4 Q7 vBIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC
; S8 u0 |3 ?8 z2 m2 U( o& d* y H計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC
英特爾增強SpeedStep技術簡介BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC; V+ d7 i+ \3 Q6 J' t
來自:http://www.topstardigital.cn/TechIntro-14.htm
計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC# |8 ~% h8 i: F0 G' X
對於英特爾的SpeedStep節能技術,很多人可能已不再陌生。SpeedStep技術是一項旨在徹底區分台式機CPU與筆記本電腦專用CPU的性 能,並與系統運行速度有密切關係的新技術,原來的代號是「Geyserville」。簡單地說,採用SpeedStep技術的筆記本電腦,可以根據不同的 使用環境,對CPU的運行速度進行合理調整。SpeedStep技術的基本工作過程是:如果筆記本電腦使用的是外接電源,CPU將按照正常的主頻率及電壓 運行;當專用軟件檢測到筆記本電腦切換到電池電源供電時,將自動切換筆記本電腦CPU的主頻率及電壓至較低運行狀態;當筆記本電腦恢復使用外接電源 時,CPU又自動切換回到最高主頻率及正常電壓下工作,使之全速運行。從技術上分析可知,同一處理器工作時,運行速度越快,工作電壓越高,功耗也越大;相 反,處理器的運行速度降低後,工作電壓會降低,功耗和發熱量也會降低。 BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC, R, j- `: Y1 `, g" @% s
; _0 U4 k, v( R" g1 x8 }1 Z* [# r# m計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC在 去年(2003年),英特爾又推出了內部代號為「Geyserville III」的增強SpeedStep技術,首先在Pentium M處理器實現,支持的平台包括Odem和Motora等855系列芯片組。其與原有的SpeedStep主要有兩點區別:第一點,增強的 SpeedStep(簡稱EIST)使得原有的性能等級從兩階增加到多階,是的性能切換更加靈活,例如,1.4G Pentium 4M的有600M和1.4G兩檔,但是對於支持1.4G Pentium M處理器而言,就有600M、800M、1G、1.2G和1.4G五個頻率檔次。第二點,增強的SpeedStep可以直接通過對處理器的MSR寄存器編 程來實現頻率,大大減少了頻率切換時間,而原來的SpeedStep依賴於對Chipset的IO端口編程實現,所以切換延時較大。計匠網論壇/ L8 } I+ r! x
BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC/ b6 r# g/ m' B3 y. v4 l% ?8 E
下面我們簡單介紹一下對於SpeedStep的支持固件編程相關知識。計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC0 S, L3 M& R0 |) F' y( B I
www.ufoit.com, r, Q+ A4 ]9 K7 `9 u
我們知道,處理器的性能狀態是由離散的電壓和頻率對定義的。在不同的頻率和電壓下,處理器的執行性能也是不同。EIST提供了一個全新的方法來改變 CPU的性能狀態,這種方法本身是基於CPU MSR寄存器,而不是基於Chipset的,所以這種方法具有硬件軟件的轉變過渡時間少、系統設計簡單等特點。Intel的奔騰M處理器提供了兩個MSR 寄存器來實現EIST功能,一個是IA32_PERF_CTL和IA32_PERF_STS,我們通過寫IA32_PERF_CTL來實現CPU性能的狀 態轉變,主要是設置BUS_RATIO_SEL和VID_SEL位域。一旦設置完之後,CPU隨後馬上進行RATIO和VID的切換,如果在切換的過程中 間有新的值更新IA32_PERF_CTL寄存器,那麼,在CPU完成系統狀態切換之後,CPU馬上進行本次新的性能切換。
4 l/ a; U. ~& ]* ^. U計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC
* e3 f$ K9 U) |( W2 u) W: U 如果我們讀取IA32_PERF_CTL,這只表明上次更新所期望的CPU性能置,並不表示CPU的當前性能值,因為,如果CPU處在thermal throttle的過程中,那麼,CPU會暫停性能的切換,直到thermal throttle的結束。& O9 y8 V$ F1 L/ r) }( U
' h) f6 h1 }) _計匠網論壇 如果我們想確定CPU的當前性能狀態,我們可以通過讀取IA32_PERF_STS寄存器的值來確定。這個寄存器包括一些主要信息,如 BUS_RATIO_STS和VID_STS域表明當前的頻率和電壓值,這些信息是動態更新的。這個寄存器同樣也包括了系統BOOT時和系統所支持的最大 性能點。 BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC5 y* h- K: e1 \2 J& z
BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC) y7 P" I1 p' `* L, ]( g8 G
在Windows XP下,OS查找PSS表,找出其想進入的狀態,查找控制值,然後把控制值寫入控制寄存器中間。系統有兩種方式進入實現控制動作,一種是透過SMM模式進 行,一種是OSPM通過G3寄存器直接寫。到底是採用哪種方式依靠_PCT這個對象決定。而在_PCT內部,實際上是根據系統OSPM的性能確定返回哪種 控制方式的,也就是採用SMM Model和Processor Native Mode。BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC" F! L* n! u( ]
BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC9 F9 V3 m7 X6 F6 D5 u! q5 ?7 |
我們知道,OS是這樣實現處理器性能的控制的,首先,OSPM通過ACPI表得知系統支持的處理器狀態,然後OSPM根據其對於系統當前狀態的評估,確 定進入哪種處理器狀態。在確定進入何種狀態之後,OSPM決定這種方法是否是其支持的方法,否則回去調用CPU的驅動程序完成相關動作。一般OSPM直接 支持的方法就是IO之類的傳統方法。 計匠網論壇6 u o! B- @' o7 {
$ x; w2 X: {9 _! v3 M* \BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC 所 以,如果OSPM不是透過SMM去完成對於MSR的IA32_PERF_CTL和IA32_PERF_STS操作,那麼,OSPM必須去調用處理器的驅動 程序,驅動程序的存在必須告知ACPI,使得ACPI的_PCT的返回是直接對於IA32_PERF_CTL和IA32_PERF_STS操作,而這是依 賴於_PDC這個方法完成的,_PDC是OSPM用來告訴ACPI其是否支持直接對於IA32_PERF_CTL和IA32_PERF_STS操作,是 OSPM向ACPI傳遞消息的一種途徑。
# S3 c3 q0 o& R5 hwww.ufoit.com計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC% h' ^" P8 v4 U7 w' o
_FDC是OSPM在進行所有處理器操作之前首先調用的一個方法,這個方法有處理器的驅動程序向ACPI傳送一個DWORD的變量,這個變量包含由處理器 廠商定義的格式,對於不同處理器的能力。根據_FDC傳遞過來系統軟件支持的能力,ACPI調整_PCT和PSS方法。計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC5 @6 Y: p4 f' \/ \ e3 Q) V
; f$ E+ u" G" R' Y" X* z 支持Intel EIST的_FDC的工作原理是這樣的,缺省的,系統BIOS是採用IO地址映射的方式提供_PCT和_PSS的,也就是SMM方式操作CPU的MSR寄 存器直接對IA32_PERF_CTL和IA32_PERF_STS操作。如果沒有處理器驅動程序去調用_PDC這樣,通過系統ACPI、SMI服務例程 和處理器的服務程序,我們可以實現EIST所帶來的優點,達到性能和節電的兼顧。
2009年10月14日 星期三
PCI CLKRUN# & PCIE CLKREQ#
PCI設備的Pin定義上有CLOCK RUN這個Option信號.
PCI Express設備有定義CLOCK REQUEST這個Option信號.這兩個信號為了省電的目的而設的.
先看PCI的CLKRUN#,如下圖:
如果PCI Deivce A和B,某個或全部設備在工作時,會激活(low) CLKRUN#,HOST會檢測CLKRUN#是否在活動狀態,如果在活動狀態,那麼.就不驅動STOP PCI的信號給時鐘產生器(Clock generator).如果PCI Deivce A和B都不工作,就會不激活(High) CLKRUN#,HOST在檢測CLKRUN#狀態時,發現沒有任何PCI設備在活動當中.當幾個PCI CLK之後(一般四個左右),就會激活STOP PCI#,讓時鐘產生器放慢或停止產生PCI CLOCK給A和B。如果當A或B設備某一個設備需要處理數據,就會再次激活CLKRUN#,HOST檢測到CLKRUN#活動時,立即停止驅動STOP PCI,時鐘產生器就會立即恢復所有PCI的CLOCK。----當然這僅僅是一種平台的情況。
再看PCI Express CLKREQ#,如下圖:
如果A設備有支持CLKREQ#,那麼在A設備在需要時鐘時,就會驅動CLKREQ#,如果不需要,就不會再驅動CLKREQ#,B設備同理。當然PCIE的CLOCK控制多了幾個Option的信號,複雜一點。具體看SPEC。
詳細資料請翻閱PCI SPEC 3.0以及PCIE spec 2.0
2009年8月31日 星期一
PCIE ASPM
PCI-E專欄:PCI Express省電模式剖析 行動平台決戰電池續航力
新電子 2006 年 1 月號 238 期
文.Steve Kolokowsky/Trevor Davis
桌上型與筆記型電腦的演進永無止境,事實上,在討論筆記型電腦或桌上型電腦時,總是會出現 「更快」、「更輕巧」、或 「功能更強」等字眼。我們總是盤算下次何時為系統進行升級,希望在最快的電腦上讓應用程式發揮更大的效能...
桌上型與筆記型電腦的演進永無止境,事實上,在討論筆記型電腦或桌上型電腦時,總是會出現 「更快」、「更輕巧」、或「功能更強」等字眼。我們總是盤算下次何時為系統進行升級,希望在最快的電腦上讓應用程式發揮更大的效能。本文將討論PCI Express新開發的省電模式,此項優勢將協助PCI Express在行動平台方面的普及。
在先前的技術專文中闡述PCI Express存在的重要性,並指出此傳輸技術將全面改變桌上型與筆記型電腦的運作模式,然而有一個尚未討論的問題—那就是PCI Express技術的功耗問題。
行動運算有四大考量因素:記憶體、重量、儲存容量,以及電池續航力。記憶體通常是以Mb或Gb為計量單位,重量則是以盎司計算,儲存容量則以Gb為單位,而電池續航力則是以個人使用的狂熱程度來衡量。這之間的差別在於電池續航力的量測是很主觀的,因為每位使用者不同的使用方式都會影響電持續航力的測量結果。其他項目的量測都能做到相當客觀,例如80Gb硬碟機絕對就只有80Gb的容量;而它的重量是6.5磅,那就是6.5磅,一點也不會少算,但談到電池續航力,就有眾多量測的方法。
事實上,目前有許多不同的「業界標準」方法來測試電池續航力,圖1顯示戴爾電腦在量測搭載Intel Pentium III處理器的Dell Latitude筆記型電腦電池續航力時,其所產生的量測圖表。
圖1顯示戴爾電腦對其產品進行許多標準測試。現今數項主流電池續航力效能量測指標包括BWS BatteryMark、Winstone 2004 Battery-Mark及MobileMark 2002。在日本業界有其電池續航力檢測標準,也就是日本電子與資訊科技產業協會(JEITA)所制定的標準。想像一下在全球眾多廠商致力於延長電池續航力之際,PCI Express方面所產生的變化將會對他們的計畫產生怎樣的影響?
現今普遍致力於如何將筆記型電腦的尺寸變小,再加上大家對於電池續航力的見解與看法大相逕庭的情況之下,導致科技的運用必須著重於系統開發的焦點-電池續航力。設計業者已事先預知此種市場需求,因此當他們在開發PCI Express時就將這些限制納入考量。
PCI Express事先規畫省電效率
標準平行的PCI介面納入許多遵循PCI匯流排電源管理介面規格的省電功能,因此,除了根聯合體(Root Complex)之外,其他所有的PCIe裝置都必須支援這些省電功能。此外,PCIe定義一套名為主動式電源管理(Active State Power Management, ASPM)的機制。主動式電源管理則是進一步擴充PCI電源的管理規格。ASPM與標準PCI電源管理規格之間的主要差別在於ASPM是自動運作的機制。
以往的省電設計中,主機軟體必須與裝置控制器進行互動,相互協調出適合的省電設定。USB就是很好的例子,主機驅動程式必須告訴主機控制器停止傳送開始欄位(Start of Frame, SOF)封包,USB裝置才能切換至低耗電模式。當主機一旦停止傳送SOF封包,USB裝置的耗電量就會大幅降低,從500mA降低至500μA。但由於研判何時關閉這些連結埠的程序相當複雜,Windows主機軟體只有在整部個人電腦進入閒置狀態時,才會讓USB匯流排暫停運作。
另一方面,想像一下,主機在這些裝置進入閒置狀態時,才能關閉這些裝置的運作會是怎樣的狀況?例如除非移動滑鼠,否則滑鼠不會消耗任何電力;另一個例子是試圖存取外接式硬碟時,外接硬碟機才會被啟動。因此,桌上型電腦會變得比較安靜,筆記型電腦會變得更輕巧,而筆記型電腦的電池續航力也會延長一點。
PCIe的ASPM則是能做到接近這種的理想作法,ASPM不需要主機、裝置或者驅動程式的互動,就能自動控制連結狀態。因此,這種設計讓連結能在不論多短暫閒置時間也可立即切換至低耗電狀態。自動電源控制機制亦能縮短連結回覆至全面運作模式延遲時間。
PCIe定義五種電源模式,其中包括正常運作到完全關機模式:
.L0 — 正常運作
.L0s —連結待機
.L1 — 連結閒置
.L2 — 僅啟用輔助電源
.L3 — 關閉電源,裝置關機
PCI Express REV1.1基礎規格
.一個「Yes」的指令即表示須要支援(除非另有說明)、「On」及「Off」的指令表示需要時脈及電源輸送、「On / Off」表示一個設計選擇項目。
PCI Express連結電源管理狀況
L0—正常運作:在L0模式下,連結處在全線運作狀態,所有時脈都啟用,任何傳輸作業都在正常延遲速度下進行,所有裝置都必須支援這種模式。
L0s—連結待機:所有PCIe系統都必須支援L0s模式,在L0s模式中,時脈都維持運作,電源亦保持開啟狀態,但連結不會主動傳送資料。這也意謂著連結從L0s模式回覆正常模式的時候時,必須要重新啟動,但回覆過程的延遲相當短暫。裝置在從L0s回覆時有不同的延遲時間,但是其變幅相當小。連接功能暫存器中定義的L0s延遲範圍為64ns至4μs。
L0s有許多優點,由於不需要端點對端點的互動就能進入L0s模式,因此切換的速度相當快。由於時脈訊號依然保持運作狀態,因此離開的速度也相當快。此外,它能套用至連結的某一端(傳送或接收端),另一端仍能繼續運作。這意謂著系統從一端傳送資料時,在大多數的時間會自動獲得L0s的協助,但在送出訊框完成(FC)封包以及通知(ACK)封包時,連結就會被喚醒。L0s的缺點是時脈訊號一直呈現運作狀態,因此L0s模式會耗用不少電力。
傳送器僅須傳送Electrical Idle指令集,並將PCIe鏈路置於電力待機狀態,就能將接收端置入L0s模式。Electrical Idle指令集是少數在實體層中進行解譯名為Ordered Set的PCIe訊息。Ordered Set指令集長度有四個字元,因此要將連結置入L0s模式時,需要的時間為4×10bits×400ps= 16ns,因此這是相當短的延遲。
因此,從L0s回覆至正常模式也會相當地快,傳送器只須在連結上傳送幾個Fast Training Sequence(FTS)Ordered Sets的指令集,連結就會回覆至正常模式。而且,接收器可以指定要從範圍在1到255的L0s回覆所需的FTS數量。因此,其連結便可以在16ns至 4ms間從L0s回覆至正常的模式,實際時間則視接收器的功能以及時脈來源而定。
L1—低耗電待機模式:L1則是PCIe的一種選項功能,其省電效率遠超過L0s,但是缺點就是延遲時間較為長久。在L1模式中,PCIe參考時脈訊號維持不變,但PCIe裝置使用的內部相鎖迴路(PLL)則被關閉,這種設計讓省電效率得以超越L0s,但卻衍生出較長的延遲和較高的傳輸佔量 (Overhead)。當下游裝置切換至PCI電源管理模式(D1~D3)或是當裝置已準備好透過上述自動電源控制機制ASPM進入L1模式時(圖2),系統就會進入L1模式。由於連結的兩端都須參與作業,因此進入L1模式所涉及的端點對端點互動步驟比進入L0s模式還要多。圖3顯示進入L1模式所需進行的互動步驟。在這個例子中,下游連結埠被指示進入L1模式,並將負責管理傳輸作業。鏈路的其中一端或兩端都可以發出指令,讓鏈路從L0模式轉換至L1模式。
首先,下游連結埠的電源管理邏輯欄位要求進入L1模式,為了要進入L1模式,該連結埠必須:
.阻擋新的傳輸層封包(TLP)傳輸作業
.確定回覆緩衝區已清空資料
.確定已收到足夠的流量控制權限,以便能在每個虛擬通道(VC)與每種資料流上達到最高容量的傳輸
因此,當所有條件都符合的時候,其中下游的連結埠就會開始持續傳送一個PM Active State Request L1的資料鏈結層封包(DLLP),最後直到收到PM Request Ack DLLP為止。在此同時,在上游部份,當收到PM Active State Request L1 DLLP的時候,就會觸發一連串的事件,該連結埠必須:
.阻斷新的傳輸層封包(TLP)傳輸作業
.等待回傳緩衝區清空資料
.等待收到足夠的流量控制權限,以便能在每個虛擬通道(VC)與每種資料流上達到最高容量的傳輸
當上游元件符合所有條件的時後,就會開始傳送一個PM Request Ack DLLP,這個訊號會觸發下游元件轉移至L1模式,並且透過上述的程序使得連結切換至閒置狀態。當連結的上游端收到切換至電源閒置模式的訊號時,它就會進入電源閒置模式。
這種程序看似複雜,但全部都是由PCIe狀態機器負責執行,如果裝置支援L1 ASPM機制,主機軟體甚至完全不必執行任何作業。這就是PCIe電源管理技術的優點。連結的任何一端皆可以讓連結離開L1狀態(圖3),當裝置決定要離開L1模式時,就會開始傳送TS1指令集到連結的另一端。回覆程序會迅速回覆連結的時序,並確保連結的實際參數跟連結關閉時完全一樣,從L1模式回覆所需的時間不到64ms,這個過程的時間愈短代表連結消耗的電力愈少。
L2—輔助電源模式:除了關閉裝置上所有電源外,L2模式是耗電量最低的狀態。在L2模式中,所有裝置的時脈訊號都處在閒置狀態,只剩下用來偵測網路喚醒功能(WAKE)與信標(Beacon)事件的低頻時脈。系統只能利用VAUX為裝置提供電力。若WAKE被啟動時,VAUX則供應高達375mA的電流,若WAKE關閉時,VAUX則只供應20mA的電流,進入L2模式與進入L1模式非常類似,兩者間只有以下差異:
.L2無法透過ASPM來觸發,只能由主機來觸發
.L2模式進入協定會將連結切換至「L2_ready」 狀態。當主機看到下游連結處於L2模式時,就會移除VMAIN。
.裝置須要運用更多的電源關閉步驟來進入L2模式
等候狀態、連結層傳輸、通訊協定電源規畫等,這些都是為了延長電池續航力所需要的關鍵要素。可攜式電子產品節省電力的關鍵在於縮短產品處理作業上的時間,以及縮短元件之間傳輸作業的時間,如此,電子裝置在標準運作模式下的耗電量就愈低。更確切地說,可攜式裝置進出各種作業的速度愈快,省電效率就愈高。為達到這項目標,在開發裝置必須考量PCI Express的能力。
就目前而言,許多業者等候PCI Express大舉進軍桌上型電腦與伺服器產品,根據上述特別的考量因素,PCI Express一直在開發電源敏感度協定。因此,當看到設計業者及工程師將PCI Express視為注重電池續航力的高速資料連結理想介面時,也毋須覺得訝異。考慮到人們對於「更快」、「更輕巧」,以及「功能更強勁」的看法永遠無法一致,業者在開發未來的筆記型電腦與可攜式運算裝置之際,PCI Express必然成為資料連結的最佳選擇。
(本文作者任職於Cypress Semiconductor)
(詳細圖表請見新電子238期1月號)
http://patchwork.kernel.org/patch/42481/
The L0s state can be managed separately for each direction (upstream
direction and downstream direction) of the link. But in the current
implementation, those are mixed up. With this patch, L0s for each
direction are managed separately.
To maintain three states (upstream direction L0s, downstream L0s and
L1), 'aspm_support', 'aspm_enabled', 'aspm_capable', 'aspm_disable'
and 'aspm_default' fields in struct pcie_link_state are changed to
3-bit from 2-bit. The 'latency' field is separated to two 'latency_up'
and 'latency_dw' fields to maintain exit latencies for each direction
of the link. For L0, 'latency_up.l0' and 'latency_dw.l0' are used to
configure upstream direction L0s and downstream direction L0s
respectively. For L1, larger value of 'latency_up.l1' and
'latency_dw.l1' is considered as L1 exit latency.
Signed-off-by: Kenji Kaneshige
---
drivers/pci/pcie/aspm.c | 170 ++++++++++++++++++++++++++++++------------------
1 file changed, 107 insertions(+), 63 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Index: 20090818/drivers/pci/pcie/aspm.c
===================================================================
--- 20090818.orig/drivers/pci/pcie/aspm.c
+++ 20090818/drivers/pci/pcie/aspm.c
@@ -26,6 +26,13 @@
#endif
#define MODULE_PARAM_PREFIX "pcie_aspm."
+/* Note: those are not register definitions */
+#define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */
+#define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */
+#define ASPM_STATE_L1 (4) /* L1 state */
+#define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW)
+#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1)
+
struct aspm_latency {
u32 l0s; /* L0s latency (nsec) */
u32 l1; /* L1 latency (nsec) */
@@ -40,19 +47,20 @@ struct pcie_link_state {
struct list_head link; /* node in parent's children list */
/* ASPM state */
- u32 aspm_support:2; /* Supported ASPM state */
- u32 aspm_enabled:2; /* Enabled ASPM state */
- u32 aspm_capable:2; /* Capable ASPM state with latency */
- u32 aspm_default:2; /* Default ASPM state by BIOS */
- u32 aspm_disable:2; /* Disabled ASPM state */
+ u32 aspm_support:3; /* Supported ASPM state */
+ u32 aspm_enabled:3; /* Enabled ASPM state */
+ u32 aspm_capable:3; /* Capable ASPM state with latency */
+ u32 aspm_default:3; /* Default ASPM state by BIOS */
+ u32 aspm_disable:3; /* Disabled ASPM state */
/* Clock PM state */
u32 clkpm_capable:1; /* Clock PM capable? */
u32 clkpm_enabled:1; /* Current Clock PM state */
u32 clkpm_default:1; /* Default Clock PM state by BIOS */
- /* Latencies */
- struct aspm_latency latency; /* Exit latency */
+ /* Exit latencies */
+ struct aspm_latency latency_up; /* Upstream direction exit latency */
+ struct aspm_latency latency_dw; /* Downstream direction exit latency */
/*
* Endpoint acceptable latencies. A pcie downstream port only
* has one slot under it, so at most there are 8 functions.
@@ -84,7 +92,7 @@ static int policy_to_aspm_state(struct p
return 0;
case POLICY_POWERSAVE:
/* Enable ASPM L0s/L1 */
- return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
+ return ASPM_STATE_ALL;
case POLICY_DEFAULT:
return link->aspm_default;
}
@@ -278,36 +286,35 @@ static u32 calc_l1_acceptable(u32 encodi
return (1000 << encoding);
}
-static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state,
- u32 *l0s, u32 *l1, u32 *enabled)
+struct aspm_register_info {
+ u32 support:2;
+ u32 enabled:2;
+ u32 latency_encoding_l0s;
+ u32 latency_encoding_l1;
+};
+
+static void pcie_get_aspm_reg(struct pci_dev *pdev,
+ struct aspm_register_info *info)
{
int pos;
u16 reg16;
- u32 reg32, encoding;
+ u32 reg32;
- *l0s = *l1 = *enabled = 0;
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32);
- *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
- if (*state != PCIE_LINK_STATE_L0S &&
- *state != (PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S))
- *state = 0;
- if (*state == 0)
- return;
-
- encoding = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
- *l0s = calc_l0s_latency(encoding);
- if (*state & PCIE_LINK_STATE_L1) {
- encoding = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
- *l1 = calc_l1_latency(encoding);
- }
+ info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
+ /* 00b and 10b are defined as "Reserved". */
+ if (info->support == PCIE_LINK_STATE_L1)
+ info->support = 0;
+ info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
+ info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16);
- *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+ info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
}
static void pcie_aspm_check_latency(struct pci_dev *endpoint)
{
- u32 l1_switch_latency = 0;
+ u32 latency, l1_switch_latency = 0;
struct aspm_latency *acceptable;
struct pcie_link_state *link;
@@ -320,18 +327,24 @@ static void pcie_aspm_check_latency(stru
acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)];
while (link) {
- /* Check L0s latency */
- if ((link->aspm_capable & PCIE_LINK_STATE_L0S) &&
- (link->latency.l0s > acceptable->l0s))
- link->aspm_capable &= ~PCIE_LINK_STATE_L0S;
+ /* Check upstream direction L0s latency */
+ if ((link->aspm_capable & ASPM_STATE_L0S_UP) &&
+ (link->latency_up.l0s > acceptable->l0s))
+ link->aspm_capable &= ~ASPM_STATE_L0S_UP;
+
+ /* Check downstream direction L0s latency */
+ if ((link->aspm_capable & ASPM_STATE_L0S_DW) &&
+ (link->latency_dw.l0s > acceptable->l0s))
+ link->aspm_capable &= ~ASPM_STATE_L0S_DW;
/*
* Check L1 latency.
* Every switch on the path to root complex need 1
* more microsecond for L1. Spec doesn't mention L0s.
*/
- if ((link->aspm_capable & PCIE_LINK_STATE_L1) &&
- (link->latency.l1 + l1_switch_latency > acceptable->l1))
- link->aspm_capable &= ~PCIE_LINK_STATE_L1;
+ latency = max_t(u32, link->latency_up.l1, link->latency_dw.l1);
+ if ((link->aspm_capable & ASPM_STATE_L1) &&
+ (latency + l1_switch_latency > acceptable->l1))
+ link->aspm_capable &= ~ASPM_STATE_L1;
l1_switch_latency += 1000;
link = link->parent;
@@ -340,33 +353,48 @@ static void pcie_aspm_check_latency(stru
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
{
- u32 support, l0s, l1, enabled;
struct pci_dev *child, *parent = link->pdev;
struct pci_bus *linkbus = parent->subordinate;
+ struct aspm_register_info upreg, dwreg;
if (blacklist) {
/* Set enabled/disable so that we will disable ASPM later */
- link->aspm_enabled = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
- link->aspm_disable = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
+ link->aspm_enabled = ASPM_STATE_ALL;
+ link->aspm_disable = ASPM_STATE_ALL;
return;
}
/* Configure common clock before checking latencies */
pcie_aspm_configure_common_clock(link);
- /* upstream component states */
- pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled);
- link->aspm_support = support;
- link->latency.l0s = l0s;
- link->latency.l1 = l1;
- link->aspm_enabled = enabled;
-
- /* downstream component states, all functions have the same setting */
+ /* Get upstream/downstream components' register state */
+ pcie_get_aspm_reg(parent, &upreg);
child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
- pcie_aspm_get_cap_device(child, &support, &l0s, &l1, &enabled);
- link->aspm_support &= support;
- link->latency.l0s = max_t(u32, link->latency.l0s, l0s);
- link->latency.l1 = max_t(u32, link->latency.l1, l1);
+ pcie_get_aspm_reg(child, &dwreg);
+
+ /*
+ * Setup L0s state
+ *
+ * Note that we must not enable L0s in either direction on a
+ * given link unless components on both sides of the link each
+ * support L0s.
+ */
+ if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
+ link->aspm_support |= ASPM_STATE_L0S;
+ if (dwreg.enabled & PCIE_LINK_STATE_L0S)
+ link->aspm_enabled |= ASPM_STATE_L0S_UP;
+ if (upreg.enabled & PCIE_LINK_STATE_L0S)
+ link->aspm_enabled |= ASPM_STATE_L0S_DW;
+ link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
+ link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s);
+
+ /* Setup L1 state */
+ if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1)
+ link->aspm_support |= ASPM_STATE_L1;
+ if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1)
+ link->aspm_enabled |= ASPM_STATE_L1;
+ link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
+ link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
/* Save default state */
link->aspm_default = link->aspm_enabled;
@@ -379,8 +407,7 @@ static void pcie_aspm_cap_init(struct pc
*/
list_for_each_entry(child, &linkbus->devices, bus_list) {
if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
- link->aspm_disable =
- PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
+ link->aspm_disable = ASPM_STATE_ALL;
break;
}
}
@@ -409,19 +436,20 @@ static void pcie_aspm_cap_init(struct pc
}
}
-static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 state)
+static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
{
u16 reg16;
int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16);
reg16 &= ~0x3;
- reg16 |= state;
+ reg16 |= val;
pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
}
static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
{
+ u32 upstream = 0, dwstream = 0;
struct pci_dev *child, *parent = link->pdev;
struct pci_bus *linkbus = parent->subordinate;
@@ -429,20 +457,27 @@ static void pcie_config_aspm_link(struct
state &= (link->aspm_capable & ~link->aspm_disable);
if (link->aspm_enabled == state)
return;
+ /* Convert ASPM state to upstream/downstream ASPM register state */
+ if (state & ASPM_STATE_L0S_UP)
+ dwstream |= PCIE_LINK_STATE_L0S;
+ if (state & ASPM_STATE_L0S_DW)
+ upstream |= PCIE_LINK_STATE_L0S;
+ if (state & ASPM_STATE_L1) {
+ upstream |= PCIE_LINK_STATE_L1;
+ dwstream |= PCIE_LINK_STATE_L1;
+ }
/*
* Spec 2.0 suggests all functions should be configured the
* same setting for ASPM. Enabling ASPM L1 should be done in
* upstream component first and then downstream, and vice
* versa for disabling ASPM L1. Spec doesn't mention L0S.
*/
- if (state & PCIE_LINK_STATE_L1)
- pcie_config_aspm_dev(parent, state);
-
+ if (state & ASPM_STATE_L1)
+ pcie_config_aspm_dev(parent, upstream);
list_for_each_entry(child, &linkbus->devices, bus_list)
- pcie_config_aspm_dev(child, state);
-
- if (!(state & PCIE_LINK_STATE_L1))
- pcie_config_aspm_dev(parent, state);
+ pcie_config_aspm_dev(child, dwstream);
+ if (!(state & ASPM_STATE_L1))
+ pcie_config_aspm_dev(parent, upstream);
link->aspm_enabled = state;
}
@@ -673,7 +708,10 @@ void pci_disable_link_state(struct pci_d
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
link = parent->link_state;
- link->aspm_disable |= state;
+ if (state & PCIE_LINK_STATE_L0S)
+ link->aspm_disable |= ASPM_STATE_L0S;
+ if (state & PCIE_LINK_STATE_L1)
+ link->aspm_disable |= ASPM_STATE_L1;
pcie_config_aspm_link(link, policy_to_aspm_state(link));
if (state & PCIE_LINK_STATE_CLKPM) {
@@ -742,11 +780,17 @@ static ssize_t link_state_store(struct d
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pcie_link_state *link, *root = pdev->link_state->root;
- u32 state = buf[0] - '0';
+ u32 val = buf[0] - '0', state = 0;
- if (n < 1 || state > 3)
+ if (n < 1 || val > 3)
return -EINVAL;
+ /* Convert requested state to ASPM state */
+ if (val & PCIE_LINK_STATE_L0S)
+ state |= ASPM_STATE_L0S;
+ if (val & PCIE_LINK_STATE_L1)
+ state |= ASPM_STATE_L1;
+
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
list_for_each_entry(link, &link_list, sibling) {
2009年7月21日 星期二
存取記憶體 peekb()
功 能: 檢查存儲單元
用 法: char peekb (int segment, unsigned offset);
segment為段基地址,offset偏移地址。
程序例:
#include
#include
#include
int main(void)
{
int value = 0;
printf("The current status of your keyboard is:\n");
value = peekb(0x0040, 0x0017);
if (value & 1)
printf("Right shift on\n");
else
printf("Right shift off\n");
if (value & 2)
printf("Left shift on\n");
else
printf("Left shift off\n");
if (value & 4)
printf("Control key on\n");
else
printf("Control key off\n");
if (value & 8)
printf("Alt key on\n");
else
printf("Alt key off\n");
if (value & 16)
printf("Scroll lock on\n");
else
printf("Scroll lock off\n");
if (value & 32)
printf("Num lock on\n");
else
printf("Num lock off\n");
if (value & 64)
printf("Caps lock on\n");
else
printf("Caps lock off\n");
return 0;
}
http://baike.baidu.com/view/1983818.html?fromTaglist
2009年7月20日 星期一
取得檔案時間 "findfirst" (struct ffblk)
findfirst
Syntax
#include
int findfirst(const char *pathname, struct ffblk *ffblk, int attrib);
Description
This function and the related findnext (see section findnext) are used to scan directories for the list of files therein. The pathname is a wildcard that specifies the directory and files to search for (such as subdir/*.c), ffblk is a structure to hold the results and state of the search, and attrib is a combination of the following:
FA_RDONLY
Include read-only files in the search (Ignored.)
FA_HIDDEN
Include hidden files in the search
FA_SYSTEM
Include system files in the search
FA_LABEL
Include the volume label in the search
FA_DIREC
Include subdirectories in the search
FA_ARCH
Include modified files in the search (Ignored.)
If a file has flag bits that are not specified in the attrib parameter, the file will be excluded from the results. Thus, if you specified FA_DIREC and FA_LABEL, subdirectories and the volume label will be included in the results. Hidden and system files will be excluded.
Since findfirst calls DOS function 4eh, it is not possible to exclude read-only files or archive files from the results. Even if the FA_ARCH and FA_RDONLY bits are not specified in the attrib parameter, the results will include any read-only and archive files in the directory searched.
This function supports long file names.
The results of the search are stored in ffblk, which is extended when the LFN API (see section LFN) is supported. Fields marked LFN are only valid if the lfn_magic member is set to "LFN32".
struct ffblk {
char lfn_magic[6]; /* LFN: the magic "LFN32" signature */
short lfn_handle; /* LFN: the handle used by findfirst/findnext */
unsigned short lfn_ctime; /* LFN: file creation time */
unsigned short lfn_cdate; /* LFN: file creation date */
unsigned short lfn_atime; /* LFN: file last access time (usually 0) */
unsigned short lfn_adate; /* LFN: file last access date */
char ff_reserved[5]; /* used to hold the state of the search */
unsigned char ff_attrib; /* actual attributes of the file found */
unsigned short ff_ftime; /* hours:5, minutes:6, (seconds/2):5 */
unsigned short ff_fdate; /* (year-1980):7, month:4, day:5 */
unsigned long ff_fsize; /* size of file */
char ff_name[260]; /* name of file as ASCIIZ string */
}
Return Value
Zero if a match is found, nonzero if none found.
Portability
ANSI/ISO C No
POSIX No
Example
struct ffblk f;
int done = findfirst("*.exe", &f, FA_HIDDEN | FA_SYSTEM);
while (!done)
{
printf("%10u %2u:%02u:%02u %2u/%02u/%4u %s\n",
f.ff_fsize,
(f.ff_ftime >> 11) & 0x1f,
(f.ff_ftime >> 5) & 0x3f,
(f.ff_ftime & 0x1f) * 2,
(f.ff_fdate >> 5) & 0x0f,
(f.ff_fdate & 0x1f),
((f.ff_fdate >> 9) & 0x7f) + 1980,
f.ff_name);
done = findnext(&f);
}
2009年7月17日 星期五
fread() 遇到1Ah的問題
如果fopen不用二進位方式打開,如:fopen(filename,"r"),只要檔案有一位元組為1Ah,fread函數會停止讀取。
ANS:
用fopen(filename,"rb")
註:讀取任意的png圖片,如果fopen採用"r"方式,則fread只能讀取5個位元組,因為png格式的圖片第六位元為1A。
2009年7月4日 星期六
如何開啟 Windows 中的自動登入
- 按一下 [開始],然後按一下 [執行]。
- 在 [開啟] 方塊中,輸入 Regedt32.exe,然後按下 ENTER。
- 在登錄中找出下列子機碼:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
- 按兩下 [DefaultUserName] 項目,輸入您的使用者名稱,然後按一下 [確定]。
- 按兩下 [DefaultPassword] 項目,輸入您的密碼,然後按一下 [確定]。注意:如果 DefaultPassword 值不存在,您必須新增該值。如果要新增這個值,請依照下列步驟執行:
- 在 [編輯] 功能表上,按一下 [新增],然後指向 [字串值]。
- 輸入 DefaultPassword,然後按 ENTER。
- 按兩下 [DefaultPassword]。
- 在 [編輯字串] 對話方塊中,輸入您的密碼,然後按一下 [確定]。
- 在 [編輯] 功能表上,按一下 [新增],然後指向 [字串值]。
- 輸入 AutoAdminLogon,然後按 ENTER。
- 按兩下 [AutoAdminLogon]。
- 在 [編輯字串] 對話方塊中,輸入 1,然後按一下 [確定]。
- 結束 [登錄編輯程式]。
- 按一下 [開始],按一下 [關機],然後在 [註解] 文字方塊中輸入原因。
- 按一下 [確定] 以關閉您的電腦。
- 重新啟動您的電腦。現在,您已經可以自動登入。
如果群組原則物件 (GPO) 或本機原則在伺服器上定義「登入標誌」,登錄變更將不會生效。當原則變更為不會影響伺服器時,這個功能就會如預期般運作。
http://support.microsoft.com/kb/324737/zh-tw
Corel Netwinder Memory Map-7C00
Corel Netwinder Memory Map
Address | Name | Width | Meaning |
| | b[8] | IDE |
| | b[4] | DMA base and current address (4 channels) |
| | b[4] | DMA base and current count (4 channels) |
| | b (write) | DMA command |
| | b (read) | DMA status |
| | b (write) | DMA control |
| | b (write) | DMA mask register |
| | b (write) | DMA mode register |
| | b (write) | clear the toggle address bit for |
| | b (write) | DMA hardware reset |
| | b (write) | DMA clear all mask bits |
| | b (write) | DMA set maks bits |
| | b | DMA page registers |
| | b | DMA extended mode |
| ICW1 | b (write) (first write) | Irq Controller command (ICW1) |
| OCW2 | b (write) (same addr) | Irq controller command (OCW2) |
| OCW2 | b (write) (same addr) | Irq controller command (OCW2) |
| ICW2 | b (write) | Irq init command (ICW2) |
| ICW3 | b (write) (same addr) | Irq init command (ICW3) |
| ICW4 | b (write) (same addr) | Irq init command (ICW4) |
| OCW1 | b (write) (same addr) | Irq control reg (OCW1) (all further writes) |
| | b (write) | Irq edge/level control |
Timers
Address | Name | Width | Meaning |
| | b (read twice) | Counter values |
| | b (read back) | Counter status |
| | b (write) | Counter control (common to all three) |
| | s | Bios timer |
Misc
Address | Width | Meaning |
this looks incorrect! | b | NMI status/control |
| b | RTC address |
| b | RTC data |
| b (write) | RTC CMOS RAM Proect 1 |
| b (write) | RTC CMOS RAM Protect 2 |
Address | Name | Width | Meaning |
| | b | Parallel port data |
| | b (read) | Parallel port print status |
| | b (write) | Parallel port control |
| | b (read) | Parallel port control swapper |
| | b | EPP address port |
| | b[4] | EPP dataports 0-3 |
| BLL/BHL | b | UART divisor register; ! counts down from 24 MHz ! |
| RBR/TBR | b | UART data reg: reads the rx byte, writes the tx byte |
| ICR | b | UART Irq control |
| ISR | b (read) | UART Irq status |
| UFR | b (write) | UART Fifo control |
| UCR | b | UART control reg |
| HCR | b | UART handshake control |
| USR | b | UART status reg |
| HSR | b | UART handshake status |
| UDR | b | UART user register |
| | b | Super IO config register |
| | b | ext-config-register data |
Misc IO
Several IO points are accessed through the "general purpose" pins on the superIO chip. We have programmed these registers to be at 0x330-0x
Physical Address | Virtual Address | Width | Meaning |
| E000.0330 (io: 330) | 16b | Misc IO registers |
| | | |
| 338 | b write | 0x80=turns on the red power LED |
| 338 | b read | 1=do-it button is pushed |
| | b | 1=copy data from serial register to output pins: set to 1, then set to 0 |
The "serial register" mentioned above is an external 4 bit register which holds:
first-shifted-bit=reset the termerature chip
second-shifted-bit=enable the mono speaker (0 to mute the speaker)
third-shifted-bit=enable flash write
last-shifted-bit=turn on front panel green LED
Ext-config-register
Register (at | Width | Data (at |
2 | b | CR02 |
7 | b | CR07 |
20 | b (read) | CR20 device id |
21 | b (read) | CR21 rev |
22 | b | CR22 section power down |
23 | b | CR23 auto-power-down |
24 | b | CR24 PnP modes |
25 | b | CR25 |
26 | b | CR26 |
28 | b | CR28 |
29 | b | CR29 |
| b | CR |
2B | b | CR2B more option pin assignments |
| b | CR |
30 | b | CR30 section enable |
31 | b | CR31 |
60, 61 | b | CR60, CR61 address |
70 | b | CR70 interrupt control |
71 | b | CR71 interrupt control |
74 | b | CR74 DMA select |
F0 | b | CRF0 clock select |
RTC data reg's
Register (at | Width | Data (at |
0-9 | b[10] | RTC (bank 0) |
A | b | RTC control (bank 0) |
B | b | RTC control (bank 0) |
C | b | RTC status (bank 0) |
D | b | RTC status (bank 0) |
E | b[72] | RTC user ram (bank 0) |
80-F7 | b | see W83977AF manual |
Super IO (cont'd)
The SuperIO contains a separate microprocessor controlling the keyboard and mouse. Communications to/from it are through this narrow portal....
Virtual Address | Width | Meaning |
e000.0060 | b | Keyboard controller |
e000.0064 | b(write) | Keyboard command |
e000.0064 | b(read) | Keyboard status |
Sound
There are many "mixer" type functions which can be programmed in the sound chip; please refer to the data sheet.
Virtual Address | Width | Meaning |
E000.0250 (io: 250) | 16b | Wave Artist sound device |
250 | b | command register |
251 | b read | 0x20=phone present & offhook |
251 | b write | init joystick timer |
252 | b | data register |
254 | b | control register |
255 | b | status register |
| b | interrupt status |
This is a NE2000 clone, with some extensions in Bank3.
Virtual Address | Width | Meaning |
e000.0300 | b | command register |
Bank 0 | ||
e000.0301 | b (read) | DMA address lo |
e000.0301 | b (write) | page start |
e000.0302 | b (read) | DMA address hi |
e000.0302 | b (write) | page end |
e000.0303 | b | boundary pointer |
e000.0304 | b (read) | tx status |
e000.0304 | b (write) | tx page start |
e000.0305 | b (read) | collision count |
e000.0305 | b (write) | tx byte count lo |
e000.0306 | b (read) | FIFO data |
e000.0306 | b (write) | tx byte count hi |
e000.0307 | b | irq status |
e000.0308 | b (read) | DMA address lo |
e000.0308 | b (write) | remote start address lo |
e000.0309 | b (read) | DMA address hi |
e000.0309 | b (write) | remote start address hi |
e | b (write) | remote byte count lo |
e000.030B | b (write) | remote byte count hi |
e | b (read) | rx status |
e | b (write) | rx config |
e000.030D | b (read) | frame align error count |
e000.030D | b (write) | tx config |
e000.030E | b (read) | crc error count |
e000.030E | b (write) | data config register |
e | b (read) | missed packet error count |
e | b (write) | irq mask |
Bank 1 | ||
e000.0301-6 | b[5] | physical address |
e000.0307 | b | current page |
e000.0308-F | b[8] | multicast address |
Bank 2 | ||
e000.0301 | b (read) | page start |
e000.0301 | b (write) | current DMA addr 0 |
e000.0302 | b (read) | page stop |
e000.0302 | b (write) | current DMA addr 1 |
e000.0303 | b | remote next packet pointer |
e000.0304 | b (read) | tx page start address |
e000.0305 | b | local next packet pointer |
e000.0306 | b | address counter hi |
e000.0307 | b | address counter lo |
e | b (read) | rx config |
e000.030D | b | tx config |
e000.030E | b (read) | data config |
e | b (read) | irq mask |
Bank 3 | ||
e | b | hardware config register |
all banks | ||
e000.0310-7 | b[8] | data buffer (nominally "remote DMA") |
e000.0318 | b (read) | resets the Ether10 chip |