Note: Access SMBIOS in Kernel of Windows

因為老闆說要給部門做一個簡單的talk, 鑑於目前同事多數是 Junior level, 而公司從事的還是x86為主的硬體生意, 所以決定中秋過完的部門週會上, 簡單介紹一下SMBIOS 的來由與存取方法, 讀資料過程還是有新的收穫, 學到如何kernel 使用wmi

開始做一些研究, 找到一些舊的資料, 基本上SMBIOS 真的開始全面導入是 v2.3.1之後, Win95 就開始使用PNPBIOS 界面提供 SMBIOS的支援, 但是直到 1999年Microsoft 才開始加入 Design for Windows Logo 認證裡面(from PC 99 Design guide), 不過強制需求應該是從Windows XP SP2/Windows 2003 Server SP1 開始引入了mssmbios.sys, 在WinHEC 2005有Release了一個文件 smbios.doc

該文件解釋了mssmbios.sys的一些行為,  基本上是基於WMI機制等於內部做了MOF宣告, 然後會去parsing smbios table資料, 並且存在 registry path 下"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Mssmbios\Data"

因為基於WMI, 所以它提供XP SP2與之後版本的user/kernel mode 的 wmi 存取, 為了更簡便使用user mode 還透過增加GetSystemFirmwareTable() API (from Windows 2003 server sp1), 而kernel mode 則從Vista 開始 多了 AuxKlibGetSystemFirmwareTable

kernel wmi 則是透過 IoWmiOpenBlock(), IoWMIQueryAllData(), “SMBIOS_DATA_GUID" 去取得, 這還要看一下 driver load order, 否則貿然在kernel driver使用應該會出問題

廣告

Note: SMBIOS/ACPI 觀察

這兩天因為要跟同事介紹 SMBIOS 所以重新把之前寫的code 拿出來測試一下, 公司配給我一台Asus Laptop 發現一件有趣的事情, ACPI 仍然可以在E/F Segment 內被找到 RSDP, 但是 SMBIOS 的 ESP 卻已經移掉, 這件事情讓我感覺蠻奇怪的

所以就查了一下SMBIOS v3.0規格內寫的是 Non-UEFI system 還是需要 在F Segment 內提供ESP呀, ACPI 猜想也是, 搞不太懂 ASUS 為啥一個拔掉一個還留著, 理論上為了最大相容性, 應該是都留著會比較好, 雖然他是UEFI only 的設計了, 但是我看過 WINCE一個詭異的設計是透過UEFI bootloader 去支援APIC mode 就是只在開機階段透過UEFI bootloader 去parsing ACPI table 然後自己切 Interrupt mode 到APIC mode其他部份保持WINCE本來的樣子

Note: Device Instance Order of PCI/PCI-e

遇到需要客制化NIC 是指定 NIC1,  NIC2的客制需求, 但是有些人的想法竟然是進OS再去改設定改變 Device Order, 這真是讓我覺的不能接受, 不能接受的原因不是因為這樣掉到我頭上, 而是這樣會變成生產安裝需要多一道程序,這代表工時與成本增加, 最重要是客戶是否使用會有困擾, 不太可能PC出貨後, 都不重新安裝OS, 那是否客戶也需要記得如果改變特定的Device Instance Order, 按客戶提案需求也不見得吻合

直覺這樣的需求應該是透過ACPI 來設定, 但是許久沒做BIOS工作後, 看了ACPI Spec. 沒看到可以做的方法, 跟老闆討論說Dell 有這樣改, 查了一下果然Dell 有於2010年提案並於同年12月正式成為 PCI Firmware Specification Revision 3.1 (need member) 的一部分,

看了一下 Linux 關於這個功能的實現, 發現早於2008年SMBIOS 2.6.0 就有Type 41 可以做這個功能

如果沒有這兩個機制, 變成就必須HW設計時注意PCI的BUS順序了

Note: Intel ME disable

目前Intel 平台已經全部導入ME(Management Engine)的設計, 也因為配合現在安全需求會有一個TEE的執行環境, 所以Intel 開始推他的SGX(Software Guard Extensions), 而要執行TEE Application跟OS溝通勢必要有一個RPCs溝通的管道, 系統內通常會載入一個專門的Driver負責跟TEE環境溝通, 而配合一般使用者環境會有它搭配的SDK開發, 而其中有一個環節是Intel DAL(dynamic application Loader)這是設計來讓載入有效簽名的Java Applet 到 Intel ME (from ME 7.1 support), 因此它需要跟 ME/TEE等東西打交道

本來上面講的東西Intel 不太對外公佈細節, 畢竟越少談, 越不容易被人找到漏洞, 不過這幾年也陸續傳出被發現各種資安漏洞如Intel-SA-0073/Intel-SA-0075/Intel-SA-0086 , 又被攻擊說因為ME不公開也是有資安疑慮, 變成某些國防使用會有不可預知的風險等等, 不知道是不是如此, Intel 把DAL Host Interface 就公開在Github上了, 算是踏出一小步

那這個有啥用呢, 用處就是搭配 me-disable 這個Linux 上的code 可以參考做出其他環境的版本, 而且因為有Intel DAL Host Interface的資料,  可以更清楚他的Command定義 可以從原碼中找到透過 “MKHI_GEN_GROUP_ID", “GEN_SET_MFG_MRST_AND_HALT_CMD" 這個命令去Reset & Halt ME的

這個功能是實際上對一般人無用但是對很多從事x86產業的OEM/ODM廠商來說, 就算是基本工具了, 因為ME啟動的情況下, 透過他的PCH會把某些東西鎖住, 無法實際操作, 這個設計也是因為安全需求, 但是Intel當初又不願意公開細節, 畢竟總是有更新系統Firmware的時刻, 多數廠商目前都採用各種奇怪的手法或是乾脆不更新某塊區塊了.

Intel 這個版本已經把Windows 下 User Application 如何找到Driver interface跟下指令的部份完全公開

Update: Sept. 08 2018

A Windows ME Disable by Myself
ME_Disable

ref.
Secret of Intel Management Engine by Igor Skochinsky

Wikipedia – Intel Active Management Technology

 

Note:Auto-Recovery for Windows System Boot crash

現在這個年代只討論 UEFI, Legacy BIOS 也可以做但是透過Customization Bootloader會更好一點,  簡單想法是透過NVRAM 存一個Boot Count, 個人偏好 RTC的CMOS空間, 當然要寫再Flash 也不是不行這個東西不是為了頻繁開關機的環境下設計的, 所以不會有頻繁擦寫Flash 的問題 後來想到本來UEFI 就有一個Monotonic Counter 設計來給Secure Boot用的, 等於是做一個簡化類似的東西, 但是配合自己系統改變

然後在系統內裝一個Agent, 最好是一個Automation啟動的Service 讓它負責抹除Boot Count, 個人會設計啟動一個Thread在系統啟動差不多3~5秒後才抹除確保系統不是開機到一半當掉 XD

然後透過BIOS 在BDS前去讀取該變數, 譬如累加到3次, 代表已經開機三次不成功, 這時BDS跳到選擇做Recovery的Partition 啟動, 讓它自動進入Recovery 步驟
or 是透過PXE去啟動系統 直接網路Recovery

類似下面這個

Make your own automatic Windows restore partition
IT Geek: How to Network Boot (PXE) the WinPE Recovery Disk with PXElinux v5 & Wimboot

Note: SW SMI in Kernel driver

在研究Windows 上要做一個SW_SMI的操作, 要先解決一個Buffer交換的問題, 看起來只有下面這個方法可以配置對應的Memory, 讓SMI emitter 去配置然後給SMM Handler 使用的樣子

MmAllocatePagesForMdlEx

想法是利用一個Driver 透過IOCTL 讓User Application去發起動作, 然後SMI Handler 需要透過Register 收到Buffer Address, 分別有32bits/64Bits 的不同
Windows 下面Driver 透過MmAllocatePagesFormMdlEx 去配置一個連續的記憶體區塊, 可能4K~64K就足夠一般使用, 或是1M? for BIOS update?