標籤

2009年11月16日 星期一

讀寫SMRAM

http://bbs.pediy.com/showthread.php?t=84835



標 題: 【原創】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)


System Management Mode (SMM) is intended to be used for advanced power-management features and other operating-system-independent functions. The chipset is programmed to recognize many types of events and timeouts. When such an event occurs, the chipset asserts the SMI# input pin. At the next instruction boundary, the microprocessor saves its entire state and enters SMM.

一、概述
只有SMI才會引起進入SMM,處理器保護現場,切換到SMRAM裡的一個獨立位址空間執行SMM代碼,RSM指令會使系統返回到原來的正常模式。SMM相當於實模式,沒有特權級和位址映射,可定址4GB,可執行所有I/O和可用系統指令。
SMI優先順序在所有中斷裡最高。當處於SMM狀態,處理器不識別後繼的SMI請求,但第一個SMI請求可以被鎖存,並在系統退出SMM後被處理。
RSM指令只能在SMM狀態下執行,否則會產生操作符無效異常(exception)。RSMSMRAM裡的處理器內容存回處理器,接著把控制權還給被中斷程式。若處理器在SMRAM中偵測到無效狀態,會shut down並產生一特殊匯流排週期以標識該狀態。
當收到SMI時,若處理器處於HALT狀態,處理器從SMM返回會稍有不同,SMBASE位址也會有所改變。
 
二、SMRAM
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以上空間,DATASTACK可以在4GB的任何地方。
                                      寄存器初始值:
EFLAGS

0000 0002H

EIP

0000 8000H

CS

SMBase(default: 3000h)

DSESFSGSSS

0000H

CR0

Set PEEMTSPG to 0,其他不變

DR7

0400H


四、SMM中的中斷和exception
進入SMM後,所有HW中斷都被禁止(包括可遮罩硬體中斷、單步中斷、中斷點陷阱、NMISMIA20M中斷)。軟體中斷和exception能發生,但建議不要,否則可能會產生不可預料的後果。
NMI會被堵在SMI服務程式入口處,且只有第一個NMI會被鎖存並在退出SMM後被執行。但也可以通過使能INTR引腳並有效INTR的方式來在SMM中使能NMI。在一般情況下,NMI是不可嵌套的,但也有例外。若從NMI處理程式進入SMM,同時有收到新的NMI,就可以在退出SMM後實現嵌套,也就是在老的NMI處理程式裡處理新的NMI
 
五、在SMM裡保存FPU狀態
有時在SMM裡有必要保存FPU狀態,最安全的辦法是先置處理器於保護模式下再存FPU,儘管FSAVE可以以四種格式中任一種來存PFU內容。一般默認是在實模方式下進行,但若在非16位實模下發生SMI就必須進入保護模式執行FSAVEFRSTOR,否則無法正確保存和恢復相關FPU資訊。但存完FPU資訊後,SMI處理程式可以繼續在保護模式下執行,但建議其主要在16/32實模下運行。
 
六、SMM版本識別
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重啟
         若處理器在HALT狀態進入SMM,要在[SMBASE+FF02]處置自動HALT重啟標誌位元。SMI處理程式可將它清零或不予理睬,這樣返回時就相應地執行HLT指令後的下一條指令或仍回到HALT狀態。
自動HALT重啟標誌值


進入SMM後的值

退出SMM後標誌值

退出SMM狀態後處理器行為

0

0

1

1

0

1

0

1

返回到被中斷程式或任務的下一條指令
不可預料
返回到HLT指令後的下一條指令
回到HALT狀態

八、多處理器SMM注意事項


MP系統中任一處理器都要能回應SMI


每個處理器都有自己的SMRAM空間。


不同處理器的SMRAM可在同一記憶體空間重疊,但它們的狀態存儲區和動態資料存儲區卻要彼此獨立,代碼和靜態資料可共用。


SMI處理程式要為每個處理器初始化SMBASE


處理器可通過自己的SMI引腳或從APIC介面收到的SMI來響應本地SMIAPIC介面可將SMI分給不同的處理器)。

edge trigger VS level trigger

http://hi.baidu.com/lzzscor/blog/item/b8a8591ccf40198287d6b6ac.html

邊緣觸發是指每當狀態變化時發生一個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

http://mlsx.xplore.cn/2006/01/12/what-difference-between-acpi-and-apic.html

很多人問道了什麼ACPI,什麼是APIC,他們有沒有關係?名字這麼相近。下面給出我對其的一些理解,具體的解釋可以查看內核文檔庫的內核參數文件:
/usr/src/`uname -r`/Documents/kernel-parameters.txt
ACPI
ACPI就是Advanced Configuration and Power Interface的縮寫,意思是「高級配置與電源接口」。這是英特爾、微軟和TOSHIBA共同開發的一種電源管理標準。
ACPI可實現以下功能:   
  1. 用戶可以使外設在指定時間開關;   
  2. 使用筆記本電腦的用戶可以指定計算機在低電壓的情況下進入低功耗狀態,以保證重要的應用程序運行;   
  3. 操作系統可以在應用程序對時間要求不高的情況下降低時鐘頻率;
  4. 操作系統可以根據外設和主板的具體需求為它分配能源;
  5. 在無人使用計算機時可以使計算機進入休眠狀態,但保證一些通信設備打開;
  6. 即插即用設備在插入時能夠由ACPI來控制。
不過,ACPI和其他的電源管理方式一樣,要想享受到上面這些功能,必須要有軟件和硬件的支援。在軟件方面,Windows 98及其後續產品和Windows 2000都對ACPI給予了全面的支援;而Linux的內核目前對此支援得並不是太理想。硬件方面比較麻煩,除了要求主板、顯卡和網卡等外設要支援 ACPI外,還需要機箱電源的配合。電源在提供5伏電壓給主板的同時,還必須使電流穩定在720毫安以上才可以,這樣它才能夠實現電腦的「睡眠」和「喚醒」。

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。
我們最常用到的是S3狀態,即Suspend to RAM(掛起到RAM)狀態,簡稱STR。顧名思義,STR就是把系統進入STR前的工作狀態數據都存放到RAM中去。

在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是工業標準,包括了軟件和硬件方面的規範。
APIC
APIC(高級可編程中斷控制器)對計算機來講有兩個作用,
  1. 管理IRQ的分配,可以把傳統的16個IRQ擴展到24個(傳統的管理方式叫PIC),以適應更多的設備。
  2. 管理多CPU。由於Nf2主板並不支援多CPU,所以,APIC關閉直接的影響是減少了可用的IRQ。
不過,如果板卡不是非常多的話,關閉 APIC對系統是沒有什麼影響的。
要實現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之間的交互了。大體的流程是這樣子的:



  1. oftware執行VMXON指令進入VMX operation
  2. 通過VM entries,VMM就可以進入VM的guest中(VMM通過VMLANCH和VMRESUME來觸發VM entry,並通過VM exits重新獲得控制權)
  3. VM exits將控制權轉移到由VMM定義的entry point(VMM可以採取適當的動作來觸發VM exit,然後再使用一個VM entry就可以返回到VM中)。
  4. 最後,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

關於1A0(IA32_MISC_ENABLE)以及199(IA32_PERF_CTL),198(IA32_PERF_STATUS),自己project的CPU一定有Spec可以看到的,如果沒有就向Intel的FAE要吧。
; 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

www.ufoit.com# g& @1 a# D/ {. u
計算機研發論壇,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#

http://www.ufoit.com/bbs/thread-103-1-4.html

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

http://www.mem.com.tw/technologyexploring_content.asp?sn=0701020591

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()

  函數名: 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)

http://www.delorie.com/djgpp/doc/libc/libc_326.html

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的問題

QUESTION:
如果fopen不用二進位方式打開,如:fopen(filename,"r"),只要檔案有一位元組為1Ah,fread函數會停止讀取。

ANS:

用fopen(filename,"rb")

註:讀取任意的png圖片,如果fopen採用"r"方式,則fread只能讀取5個位元組,因為png格式的圖片第六位元為1A。

2009年7月4日 星期六

如何開啟 Windows 中的自動登入

  1. 按一下 [開始],然後按一下 [執行]
  2. [開啟] 方塊中,輸入 Regedt32.exe,然後按下 ENTER。
  3. 在登錄中找出下列子機碼:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
  4. 按兩下 [DefaultUserName] 項目,輸入您的使用者名稱,然後按一下 [確定]
  5. 按兩下 [DefaultPassword] 項目,輸入您的密碼,然後按一下 [確定]注意:如果 DefaultPassword 值不存在,您必須新增該值。如果要新增這個值,請依照下列步驟執行:

    1. [編輯] 功能表上,按一下 [新增],然後指向 [字串值]
    2. 輸入 DefaultPassword,然後按 ENTER。
    3. 按兩下 [DefaultPassword]
    4. [編輯字串] 對話方塊中,輸入您的密碼,然後按一下 [確定]
    注意:如果沒有指定 DefaultPassword 字串,Windows 就會自動將 AutoAdminLogon 機碼的值從 1 (True) 變更為 0 (False),以停用 AutoAdminLogon 功能。

  6. [編輯] 功能表上,按一下 [新增],然後指向 [字串值]
  7. 輸入 AutoAdminLogon,然後按 ENTER。
  8. 按兩下 [AutoAdminLogon]
  9. [編輯字串] 對話方塊中,輸入 1,然後按一下 [確定]
  10. 結束 [登錄編輯程式]。
  11. 按一下 [開始],按一下 [關機],然後在 [註解] 文字方塊中輸入原因。
  12. 按一下 [確定] 以關閉您的電腦。
  13. 重新啟動您的電腦。現在,您已經可以自動登入。
注意 如果要略過 AutoAdminLogon 程序,並以不同的使用者身份登入,請在登出或 Windows 重新啟動之後,按住 SHIFT 鍵。

如果群組原則物件 (GPO) 或本機原則在伺服器上定義「登入標誌」,登錄變更將不會生效。當原則變更為不會影響伺服器時,這個功能就會如預期般運作。

http://support.microsoft.com/kb/324737/zh-tw

Corel Netwinder Memory Map-7C00

Corel Netwinder Memory Map-7C00

IDE I/O space

Address

Name

Width

Meaning

7C00.01F0

b[8]

IDE
you can do word and dword access to 01F0 for data transfer

7C00.0000,2,4,6

b[4]

DMA base and current address (4 channels)
read or write this address twice to set the 16 bit value

7C00.0001,3,5,7

b[4]

DMA base and current count (4 channels)
read or write this address twict to get/set the 16 bit value

7C00.0008

b (write)

DMA command
4=controller enable
0x10=rotating scheme
0x40=DRQ active low
0x80=DACK active hi

7C00.0008

b (read)

DMA status
1=channel 0 terminal count
2=channel 1 terminal count
4=channel 2 terminal count
8=channel 3 terminal count
0x10=channel 0 request
0x20=channel 1 request
0x40=channel 2 request
0x80=channel 3 request

7C00.0009

b (write)

DMA control
0,1,2,3=channel select
4=set request

7C00.000A

b (write)

DMA mask register
0,1,2,3=channel select
4=set mask bit

7C00.000B

b (write)

DMA mode register
0,1,2,3=channel select
transfer type: 4=write, 8=read
0x10=auto-initialize
0x20=decrement address
transfer mode:0=demand, 0x40=single, 0x80=block, 0xC0=cascade

7C00.000C

b (write)

clear the toggle address bit for 7C030000 & 7C030001

7C00.000D

b (write)

DMA hardware reset

7C00.000E

b (write)

DMA clear all mask bits

7C00.000F

b (write)

DMA set maks bits
1,2,4,8 for channels 0,1,2,3

7C00.0087, 83, 81,82

b

DMA page registers
8 bits that set the ISA address bits A23:16

7C00.040B

b

DMA extended mode
0,1,2,3=select channel
timing:0=compatible, 0x10=A type, 0x20-B type, 0x30=F type

7C00.0020

ICW1

b (write) (first write)

Irq Controller command (ICW1)
0x10 selects this register (ICW1), use 0 for the others
default is ok

7C00.0020

OCW2

b (write) (same addr)

Irq controller command (OCW2)
irq rotate modes

7C00.0020

OCW2

b (write) (same addr)

Irq controller command (OCW2)
8 selects this register
spcial mask mode, poll mode

7C00.0021

ICW2

b (write)

Irq init command (ICW2)
8-0xF8 sets high bits of interrupt vector

7C00.0021

ICW3

b (write) (same addr)

Irq init command (ICW3)
0-7 sets the link from Irq controller 2 into Irq controller 1

7C00.0021

ICW4

b (write) (same addr)

Irq init command (ICW4)
buffer and nest modes

7C00.0021

OCW1

b (write) (same addr)

Irq control reg (OCW1) (all further writes)
a 1 in a bit position masks that irq channel

7C00.04D0

b (write)

Irq edge/level control
a 1 in a bit position means level sensitve
a 0 means edge sensitive

Timers

Address

Name

Width

Meaning

7C00.0040,41,42

b (read twice)

Counter values
read/write the low-then-high bytes of the 16 bit timers 0,1,2

7C00.0040,41,42

b (read back)

Counter status
1=BCD count, 0=binary count
0xE reads back the mode selection bits
0x30 reads back the read/write selection status
0x80 reads back the OUT pin

7C00.0043

b (write)

Counter control (common to all three)
1=BCD count
0=count to end, 2=harware-retrigger one-shot, 4=rate generator, 6=square wave gen, 8=software-triggered strobe, 0xA=hardware triggered strobe
0=counter latch, 0x10=read write LSB in 7C03004x, 0x20=read/write MSB in 7C03004x, 0x30-read/write LSB then MSB in 7X03004x
0=select timer 0, 0x40=select timer 1, 0x80=select timer 2, 0xC0=select Counter Status readback

7C00.007B

s

Bios timer
a value written here will be decremented on every BCLK until 0

Misc

Address

Width

Meaning

7C00.0061

this looks incorrect!

b

NMI status/control
1=timer 2 enable
2=speaker enable
4=SERR NMI enable
8=IOCHK NMI enable
0x10=refresh on ISA bus
0x20=timer 2 output
0x40=IOCHK status
0x80=SERR status

7C00.0070

b

RTC address
0-0x7E=RTC address
0x80=NMI enable

7C00.0071

b

RTC data
first, set the RTC address (7C00.0070), then read/write the data (7C00.0071)

7C00.0810

b (write)

RTC CMOS RAM Proect 1
write this to block any writes to 0x20-0x2F of RTC space

7C00.0812

b (write)

RTC CMOS RAM Protect 2
write this to block any writes to 0x30-0x3F of RTC space

Super I/O Space

Address

Name

Width

Meaning

7C00.0378

b

Parallel port data

7C00.0379

b (read)

Parallel port print status
1=timeout
8=error-
0x10=select
0x20=paper jam
0x40=ack-
0x80=busy-

7C00.037A

b (write)

Parallel port control
1=strobe
2=auto feed
4=init-
8=select in
0x10=irq enable
0x20=set data direction to 'in'

7C00.037A

b (read)

Parallel port control swapper

7C00.037B

b

EPP address port

7C00.037C-F

b[4]

EPP dataports 0-3

7C00.03F8

BLL/BHL

b

UART divisor register; ! counts down from 24 MHz !
Note: the other UART is at 7C00.02F8

7C00.03F8

RBR/TBR

b

UART data reg: reads the rx byte, writes the tx byte

7C00.03F9

ICR

b

UART Irq control
1=rx data irq enable
2=tx buffer irq enable
4=rx status irq enable
8=handshake status irq enable

7C00.03FA

ISR

b (read)

UART Irq status
1=no irq pending, 0=irq pending
6=UART rx status, error bit set
4=rx data ready or FIFO nearly full
0xC=tx FIFO ready and waiting (timout occurred)
2=tx buffer ready
0=handshake status changed
0xC0=FIFO's enabled

7C00.03FA

UFR

b (write)

UART Fifo control
1=fifo enable
2=reset rx fifo
4=reset tx fifo
8=DMA mode select
0,0x40,0x80,0xC0 sets FIFO fill threshold

7C00.03FB

UCR

b

UART control reg
0=5 bit, 1=6 bit, 2=7 bit,3=8 bit data
4=two stop bits
8=enable parity
0x10=even parity
0x20=fixed parity
0x40=inhibit tx
0x80=enable access to baud-divisor

7C00.03FC

HCR

b

UART handshake control
1=DTR set
2=RTS set
4=loopback enabled
8=Irq enabled
0x10=internal loopback enabled

7C00.03FD

USR

b

UART status reg
1=rx data ready
2=overrun
4=parity error
8=no stop bit error
0x10=silent byte detect
0x20=tx buffer empty
0x40=tx empty
0x80=rx fifo error
any read clears the bits

7C00.03FE

HSR

b

UART handshake status
1=CTS changed
2=DSR changed
4=RI falling edge
8=DCD changed
0x10=CTS sense
0x20=DSR sense
0x40=RI sense
0x80=DCD sense

7C00.03FF

UDR

b

UART user register

7C00.0370

b

Super IO config register
write 0x87 twice to wake it up
write ext-config-register number
write 0xAA to lock it

7C00.0371

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-0x33f in the IO space.

Physical Address

Virtual Address

Width

Meaning

7c00.0330

E000.0330 (io: 330)

16b

Misc IO registers

338

b write

0x80=turns on the red power LED
0x20=clock to serial register; data should be valid on rising edge
0x10=data to serial register
8=done signal to 5204 Xilinx (modem PCI control chip)
4=fan on; when tri-stated, fan is on by default
2=green power LED

338

b read

1=do-it button is pushed

33a

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 7C00.0370)

Width

Data (at 7C00.0371)

2

b

CR02
1=soft reset

7

b

CR07
logical device number
write this number, and then program CR30-CR71
0=FDC (we don't use this)
1=parallel
2=serialUART
3=consoleUART
4=RTC
5=keyboard
6=IR
7=aux i/o
8=aux i/o

20

b (read)

CR20 device id
assert(id==0x97)

21

b (read)

CR21 rev
assert(rev==0x71)

22

b

CR22 section power down
1=floppy power up
4=IR power up
8=parallel power up
0x10=serialUART power up
0x20=consoleUART power up

23

b

CR23 auto-power-down
0=power on, 1=stop clock incl PLL's, 2=standby for auto-power-down, 4=stop clock PLLs running
0x10-0x38=timeout to auto-power-down

24

b

CR24 PnP modes
use default

25

b

CR25
1-0x40 set TRI mode ??

26

b

CR26
1=disable consoleUART legacy irq mode
2=disable serialUART legacy irq mode
4=disable parallel legacy irq mode
0x20=lock config registers

28

b

CR28
0=parallel port normal, 5=parallel port acts as FDC
0x10=enable irq sharing

29

b

CR29
PnP id setting

2A

b

CR2A option pin assignments
0=pin 3S1 is DRVDEN, 1=pin is GP10, 2=pin is 8042 p12, 3=pin is DSRC-
0=pin 39S1 is IRRXH, 4=pin is IRSL0, 8=pin is GP25, 0xC=pin is CTSC-
0=pin 40S1 is CIRRX, 0x10=pin is GP24, 0x20=pin is 8042 p13
also pins 56S and 57S

2B

b

CR2B more option pin assignments

2C

b

CR2C more option pin assignments

30

b

CR30 section enable
1=activate this device

31

b

CR31
1=enable i/o read
2=enable i/o decoding

60, 61

b

CR60, CR61 address
set i/o address, from 0x100...0xFF8, CR60 is high byte
use defaults

70

b

CR70 interrupt control
0-0xF selects interrupt channel

71

b

CR71 interrupt control
1=level trigger, 0=edge trigger

74

b

CR74 DMA select
0-3 selects DMA channel (parallel, IR only)

F0

b

CRF0 clock select
parallel:
4=standard printer port, 0=SPP mode, 1=EPP/SPP mode, 2=ECP mode, 3=ECP/EPP mode, 5=EPP/SPP mode, 7=ECP/EPP mode
UARTs:
0=clock source is 1.8MHz, 1=clock source is 2MHz, 2=clock source is 24MHz, 3=clock source is 14.8MHz
RTC:
1=lock ram 80-9F
2=lock ram A0-BF
4=lock ram C0-DF
8=lock ram E0-FF
0x10=select bank 1 of ram, 0x20=select bank 2 of ram
KBC:
1=kb reset speed up
0=kb clk is 6MHz, 0x40=kb clk is 8MHz, 0x80=kb clk is 12MHz, 0xC0=kb clk is 16MHz
IR:
1=enable IR bank selection
2=append hardware CRC in FIR mode
4=add 4 char delay during turn-around
8=add 4 char delay during turn-around

RTC data reg's

Register (at 7C00.0070)

Width

Data (at 7c00.0071)

0-9

b[10]

RTC (bank 0)
seconds, seconds alarm, minutes, minutes alarm, hours, hours alarm, day-of-week, day-of-month, month, year

A

b

RTC control (bank 0)
0=no irq, 1=4ms irq, 2=8ms irq, 7=2ms irq, 0xB=31.24ms irq, 0xC=62.5ms, 0xD=125ms, 0xE=250ms, 0xF=500ms
0x80=update in progress

B

b

RTC control (bank 0)
1=daylight savings
2=set 24 hour mode
4=use binary mode for time
0x10=enable update-flag
0x20=enable alarm
0x40=enable periodic interupt
0x80=disable timer updates

C

b

RTC status (bank 0)

D

b

RTC status (bank 0)
0x80=ram and time are valid

E-7F

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
input/output buffer

e000.0064

b(write)

Keyboard command
20=read command
60=write command
A4=test password
A5=load password
A6=enable password
A7=disable mouse
A8=enable mouse
A9,AB=interface test
AA=self test
AD=disable keyboard
AE=enable keyboard

e000.0064

b(read)

Keyboard status
1=output buffer full
2=input buffer full
8=command byte
0x10=no inhibit
0x20=mouse output buffer full
0x40=timout error
0x80=parity error

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
some commands: 0=get id; 0x10=set input format; 0x11=set input channel.....up to 0x29

251

b read

0x20=phone present & offhook
0x10=handset inserted
1=joystick timer finished; front panel slider is connected to joystick port

251

b write

init joystick timer

252

b

data register

254

b

control register
0x80=cmd write irq enable
0x40=cmd read irq enable
0x20=data write irq enable
0x10=data read irq enable
8=reset
4=dma1 irq enable
2=dma0 irq enable
1=int ack

255

b

status register
0x80=cmd write ready
0x40=cmd read full
0x20=data write ready
0x10=data read full
8=irq
4=dma1
2=dma0

25c

b

interrupt status

Ether10

This is a NE2000 clone, with some extensions in Bank3.

Virtual Address

Width

Meaning

e000.0300

b

command register
2=run, 1=stop controller
4=send packet
8=remote read, 0x10=remote write, 0x18=send packet,0x20=remoteDMA complete/abort
0,0x40,0x80,0xC0 sets the register bank

Bank 0

e000.0301

b (read)

DMA address lo
these two registers can be read to get the current local DMA address

e000.0301

b (write)

page start
the Page Start register sets the start page address of the receive buffer ring.

e000.0302

b (read)

DMA address hi

e000.0302

b (write)

page end
the Page Stop register sets the stop page address of the receive buffer ring.

e000.0303

b

boundary pointer
this register is used to prevent overwrite of the receive buffer ring; it is typically used as a pointer indicating the last receive buffer page the host has read.

e000.0304

b (read)

tx status
1=tx complete ok
4=collision
8=abort due to collisions
0x10=carrier lost
0x40=heartbeat miss
0x80=late collision

e000.0304

b (write)

tx page start
this register sets the start page address of the packet to the transmitted.

e000.0305

b (read)

collision count
the register records the number of collisions a node experiences during a packet transmission.

e000.0305

b (write)

tx byte count lo
these two registers set the byte counts of the packet to be transmitted.

e000.0306

b (read)

FIFO data
this register allows the host to examine the contents of the FIFO after loopback.

e000.0306

b (write)

tx byte count hi

e000.0307

b

irq status
1=rx data ready ok
2=tx data sent ok
4=rx data with error
8=tx data with error
0x10=rx data overflow
0x20=tally count overflow
0x40=remoteDMA done
0x80=reset state

e000.0308

b (read)

DMA address lo
these two registers contain the current address of remote DMA.

e000.0308

b (write)

remote start address lo
these two registers set the start address of remote DMA.

e000.0309

b (read)

DMA address hi

e000.0309

b (write)

remote start address hi

e000.030A

b (write)

remote byte count lo
these two registers set the data byte counts of remote DMA.

e000.030B

b (write)

remote byte count hi

e000.030C

b (read)

rx status
1=rx data ok
2=crc error
4=framing error
0x10=missed packet
0x20=broadcast or multicast rx
0x40=in monitor mode
0x80=collision detected

e000.030C

b (write)

rx config
1=accept bad packets
2=accept short packets (64 bytes)
4=accept broadcast
8=accept multicast
0x10=accept all addresses
0x20=monitor mode; packets not saved in ram

e000.030D

b (read)

frame align error count

e000.030D

b (write)

tx config
1=inhibit CRC append
0=normal, 2=int. loopback, 4=extern loopback
8=auto transmit disable
0x10=collisiton offset enable

e000.030E

b (read)

crc error count

e000.030E

b (write)

data config register
1=read Ether10 chip word wide
2=byte order
8=disable loopback mode
0x10=auto initialize send packet
0x20-0x60=FIFO thresh

e000.030F

b (read)

missed packet error count

e000.030F

b (write)

irq mask

Bank 1

e000.0301-6

b[5]

physical address
tthese registers contain my Ethernet node address and are used to compare the destination address of incoming packets for acceptation or rejection.

e000.0307

b

current page
this register points to the page address of the first receive buffer page to be used for packet reception.

e000.0308-F

b[8]

multicast address
these registers provide filtering bits of multicast addresses hashed by the CRC logic.

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

e000.030C

b (read)

rx config

e000.030D

b

tx config

e000.030E

b (read)

data config

e000.030F

b (read)

irq mask

Bank 3

e000.030A

b

hardware config register
0=UTP/twisted pair, 3=UTP/twisted pair with "quiet" signals
4=link ok
0x10=fast ram installed

all banks

e000.0310-7

b[8]

data buffer (nominally "remote DMA")

e000.0318

b (read)

resets the Ether10 chip


Top level of memory map