作業是以 Dxe Driver 為主,故討論 Dxe 面。
SwSmi 的主要攻略技巧就是先鎖定幾項重點:
1. SMM Driver 機制
2. 如何將 Dxe Driver 送進 SMRAM
3. 如何 Register SwSmi Notification
4. 如何控制 SwSmi Notification
5. 如何產生 SwSmi
SMM Driver 和一般 Dxe Driver 不同的地方,就是 SMM Driver 會跑兩次。
第一次在 Dxe Phase,經用 EFI_SMM_BASE_PROTOCOL.InSmm () 先做驗證是否在 SMM Mode 下。
如果為 FALSE,則使用 Register () 函數執行第二次,這個函數可以看成是 SMM 下的 Driver Entry Point。
接著,在 SMM 下進入 Entry Point,再做 InSmm () 驗證,如果為 TRUE,則執行相關處理,抱括 SwSmiInputValue 的指定,利用 EFI_SMM_SW_DISPATCH_PROTOCOL 的 Register () 做函數綁定。
這部份很重要,因為 EFI_SMM_SW_DISPATCH_PROTOCOL 是由南橋 Bus 產生,所以當這邊有指定的 Value 填進 SMI Command Port 時,南橋偵測到就會觸發 SMI# 或是傳遞訊息。CPU 收到後,會有小小的 Delay (並不像書上寫的 "馬上",因為負責偵測 SMI 的組件並不一定就是接受 SMI 的組件),就會做 Function Callback,工程師就是在這塊做處理。
SmiInputValue 倒是好填,Command Port 指定就很麻煩,每個晶片組都不同,以前在寫 Win32 API 的經驗是 0xB2 for Intel ICH mostly,具體看那張板子什麼晶片組的吧....估計老師是做 AMD Chipset 的才會報 0xB0,這部份如果照單全收很容易『挫街』。
每個 codebase 都有自己的 SMI Cmd Port 定義的檔,ACPI Spec 也有,程式功夫一大抄,對 codebase 搜索強的自然吃香一點。
上面知道了,Trigger 就比較簡單,只要對特定的 SMI Cmd Port 填特定的值就行了。
進入到 SMM 後可用的服務被限制到很低,可用 SMMBASE 提供的 GetSmstLocation,拿到 SMM 的 System Table ,還是有一些東西可以用的,I/O Mem 存取之類。
比較需要注意的地方就是,因為 SMM 跨度十分廣,所以有可能 driver 存活得比自己的 producer 還久,故在使用 protocol 時務必注意,不要使用到跨度後會失效的 (例如 Boot Services 下的東西)。
另外目前了解到的知識是,如果想把 SMM 下的 driver unload,進到 SMM 解掉掛在上面的 dispatcher 就行了,如下:
mSwSmmDispatcher->UnRegister (mSwSmmDispatcher, mSwmSmmHandle); mPbSmmDispatcher->UnRegister (mPbSmmDispatcher, mPbmSmmHandle);
只是比較奇怪的是,在 DXE 下 register 的 SMM Base 竟然在 DXE 下解不掉,Handle 都對的。。。不緊張,未來搞懂再補充回來。
9/22 補充: 為何 SMM Base 在 DXE 下解不掉,原因是在 Unload 處我把他 Handle 下注冊的函數全 UnRegister 了,根據 EFI Spec,當一 Handle 下沒任何掛載時,它會被 Handle Database 回收,所以造成在 UnRegister SMM Base 時找不到 Handle
沒有留言:
張貼留言