2021年5月17日 星期一

Beyond BIOS Note - CH3 UEFI Driver Model


Things should be made as simple as possible - but not simpler
- Albert Einstein

Driver initialization

Load Image

Driver image的檔案必須儲存於ROM、硬碟或網路等媒體裝置,當系統找到driver image時,
就可以透過 gBS->LoadImage() 將image加載至記憶體,而此Image必須符合PE/COFF 格式。

當gBS->LoadImage()執行後,系統就會為driver建立一個handle,這個handle被稱為
Image Handle,並且將一個 EFI_LOADED_IMAGE_PROTOCOL實體放在這handle下。
這時的driver還沒有執行(start),只存在於記憶體之中。

Image Handle
   └ ─ ─ ─ EFI_LOADED_IMAGE_PROTOCOL

Start Image

UEFI Driver Model 的driver 不能直接touch hardware,只能在本身的 Image Handle上
Install Protocol,且還必須安裝EFI_DRIVER_BINDING_PROTOCOL,有
EFI_DRIVER_BINDING_PROTOCOL 的Image Handle 則被稱為Driver Image Handle

若driver要能被unload,則必須實作EFI_LOADED_IMAGE_PROTOCOL 中的Unload() function。

Driver Image Handle
   └ ─ ─ ─ EFI_LOADED_IMAGE_PROTOCOL
   └ ─ ─ ─ EFI_DRIVER_BINDING_PROTOCOL
   └ ─ ─ ─ EFI_DRIVER_CONFIGURATION_PROTOCOL (optional)
   └ ─ ─ ─ EFI_DRIVER_DIAGNOSTICS_PROTOCOL (optional)
   └ ─ ─ ─ EFI_DRIVER_COMPONENT_NAME2_PROTOCOL (optional)

Host Bus Controllers

UEFI Driver Model driver 通常用來操作一至多個controller,而在driver與controller連接之
前,需要操作某些controller,這些controller稱為Host Bus Controller。

每個host bridge都表示成一個device handle,device handle中有 Device Path Protocol及
其IO抽象化操作的Protocol。以PCI Host Bus Controller為例,其提供PCI Host Bridge IO
Protocol。

PCI Host Bridge Device Handle
   └ ─ ─ ─ EFI_DEVICE_PATH_PROTOCOL
   └ ─ ─ ─ EFI_PCI_HOST_BRIDGE_IO_PROTOCOL

PCI Bus Driver可以連接在此PCI Host Bridge,並建立其child handle給每個系統中的PCI
device。而PCI Device Driver 則必須連接這些child handle並提供其抽象化IO操作給系統使用。

Device Drivers

Device Driver不允許建立新的device handle,只在現有的device handle上添加protocol。
其最常見的行為是在Bus driver所建立的handle上提供IO抽象化操作,例如Simple Text
Output、Simple Input、Block I/O及Simple Network Protocol。

Device Handle
   └ ─ ─ ─ EFI_DEVICE_PATH_PROTOCOL
   └ ─ ─ ─ EFI_XYZ_IO_PROTOCOL

    ↓ Start()   ↑ Stop()

Device Handle
   └ ─ ─ ─ EFI_DEVICE_PATH_PROTOCOL
   └ ─ ─ ─ EFI_XYZ_IO_PROTOCOL
   └ ─ ─ ─ EFI_BLOCK_IO_PROTOCOL

連接Device handle的Device Driver必須有Driver Binding Protocol在其本身的image handle上。

Driver Binding Protocol包含Supported ()、Start ()及Stop ()三個functions。
  • Supported ()
  • 功用為測試此driver是否支援特定controller。以上面的Device handle為例,driver
    可以檢查此device handle是否支援 Device Path Protocol及EFI_XYZ_IO_PROTOCOL。
    若 Supported()通過,driver就能透過 Start()來連接controller。

  • Start ()
  • driver透過Start() 在device handle上添加額外的IO protocol。以上面例子來看
    ,Block IO protocol就被建立在device handle上。

  • Stop ()
  • 相對於Start(),Stop() 用來終止driver對device handle的操作,並要負責將原來
    driver安裝在device handle 上的任何protocol移除。

Support ()、Start ()及Stop ()需呼叫OpenProtocol ()來取得protocol和CloseProtocol ()
來釋出Protocol。OpenProtocol ()及CloseProtocol ()會更新handle database,讓系統能追蹤
哪些protocol正在被使用。可透過OpenProtocolInformation ()來獲取component正在使用
protocol的相關列表。

Bus Drivers

Bus driver 負責對其 bus上的 child controller建立 device handle。
A、B、C、D和E代表此Bus controller 的child controller。其上的箭頭代表其parent controller
,如果此Bus controller 為 Host Bus Controller的話,則沒有parent controller。

    ↙
 Bus Controller

    ↓ Start()   ↑ Stop()

    ↙
 Bus Controller
    └ ─ A
    └ ─ B
    └ ─ C
    └ ─ D
    └ ─ E

Bus driver至少必須在其child handle上安裝IO抽象化操作的protocol(EFI_XYZ_IO_PROTOCOL),
若child handle代表physical device,則還需安裝DEVICE_PATH_PROTOCOL。Bus Specific
Driver Protocol為optional,在driver connect child controller時會使用到(Boot Service 的
ConnectController ())。

Child Device Handle
   └ ─ ─ ─ EFI_DEVICE_PATH_PROTOCOL
   └ ─ ─ ─ EFI_XYZ_IO_PROTOCOL
   └ ─ ─ ─ EFI_BUS_SPECIAL_DRIVER_OVERRIDE_PROTOCOL (optional)

Platform Components

driver 的connect與disconnect controller由platform firmware透過Boot Service
ConnectController()和DisconnectController()來決定,通常為UEFI Boot Manager
的一部分。

若platform想要執行系統檢測或安裝作業系統,則其會connect driver到所有可能的 boot
device。若platform想開機到預安裝好的作業系統,則其只需connect 該作業系統需要的
device及其所需的driver。

platform 也可以選擇安裝optional的 protocol Platform Driver Override Protocol,其作用與
Bus Specific Driver Protocol相同,但擁有更高的priority。

Hot Plug Event

當 Hot Plug Event因新增 device觸發時,Bus driver需要負責:
  1. 建立 device 的child handle
  2. 呼叫 ConnectController()

2021年5月13日 星期四

[Python] 將 Qt Designer的 .ui檔轉換成 .py檔

Qt Designer

PySide2

使用 pyside2-uic

pyside2-uic.exe <UI_FILE> -o <OUTPUT_FILE>

pyside2-uic預設安裝位置為%PYTHON_INSTALL_PATH%\Scripts\



PyQt5 & PyQt6

使用 pyuic5pyuic6

pyuic6.exe <UI_FILE> -o <OUTPUT_FILE>

pyuic5及 pyuic6預設安裝位置為%PYTHON_INSTALL_PATH%\Scripts\


2021年5月5日 星期三

建置 Windows Debugger(WinDbg) 環境 via Serial Cable

本篇文章參考
Debugging Tools for Windows

其他WinDbg相關細節
建置 Windows Debugger(WinDbg) 環境 via USB 3.0 cable

Setup Target Computer

1. 使用 Device Manager確認 COM port number。

2. 使用系統管理員權限開啟command prompt,並輸入以下命令
bcdedit /debug on
bcdedit /dbgsettings serial debugport:n baudrate:115200
n為 COM port number。

3. 重新開機。

Setup and Use WinDbg

1. 開啟WinDbg
(C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe)

2. 點選"File" > "Kernel Debugging"

3. 標籤頁切換到"COM",並輸入 HOST端所連接的 COM port number。

3. 按下確定,開始執行WinDbg

2021年4月27日 星期二

iASL - ASL Optimizing Compiler and Disassembler

參考網站
ACPICA

Errors, Warnings, and Remarks

-ve
只回報Error,忽略Warning及Remark。

編譯 DSDT0000.dsl時只回報 Error iasl.exe -ve DSDT0000.dsl

AML Disassembler

-d <f1 f2 ...>
反組譯 AML檔案回 ASL(*.dsl)

反組譯 DSDT0000.bin回 DSDT0000.dsl 的ASL檔案 iasl.exe -d DSDT0000.bin

-e <f1 f2 ...>
在反組譯AML時,會遇到有些 unresolve external control method,用以指定含有其
external control method的 AML檔

反組譯DSDT0000.bin時,指定 SSDT0000.bin及 SSD10000.bin為含有其
external control method的AML檔
iasl.exe -e SSDT0000.bin SSD10000.bin -d DSDT0000.bin

指定所有 SSD*.bin為含有DSDT0000.bin external control method的AML檔
iasl.exe -e SSD*.bin -d DSDT0000.bin

2021年4月13日 星期二

asl.exe - Microsoft ASL Compiler

參考網站
microsoft-asl-compiler

Windows在使用 ACPI table時,不是每次都從記憶體存取,而是暫存在其登錄檔,透過登錄檔
來存取。可以透過 regedit登錄檔編輯程式來讀取修改 ACPI的登錄檔,其路徑為
Computer\HKEY_LOCAL_MACHINE\HARDWARE\ACPI

而 Microsoft的 WDK提供 asl.exe可以用來取出或取代其中的 ACPI table。

/tab=<TabSig>
將 <TabSig>的 AML反組譯回 ASL檔案,<TabSig>可從 regedit查詢。

取出 DSDT.asl
asl.exe /tab=DSDT

取出所有 ACPI table並存成 ACPI.txt
asl.exe /tab=*

/nologo
不印出logo banner的訊息。

Example 1: without /nologo
asl.exe /tab=DSDT
Output 1:
Microsoft ACPI Source Language Assembler Version 5.0.0NT
Copyright (c) 1996,2014 Microsoft Corporation
Compliant with the ACPI 5.0 Specification

Example 2: with /nologo
asl.exe /nologo /tab=DSDT
Output 2:


/c
將 table存成 .bin檔

取出 DSDT的 AML並存成 DSDT0000.bin
asl.exe /c /tab=DSDT

ACPI-table-load usage


只能用於已存在在系統中的ACPI table

/loadtable
將ACPI table load進 registry中

將 AMLFile load進 registry中
asl.exe /loadtable [-v] [-d] <AMLFile>
-v: verbose mode
-d: 移除先前所 load的 AML檔

在 Windows下修改及替換 DSDT或SSDT table

1. 以DSDT為例,先使用 asl.exe將 DSDT的 AML從 registry取出
asl.exe /tab=DSDT /c
會得到 DSDT0000.BIN。

2. 使用 ASL compiler iasl.exe將 DSDT0000.bin 反組譯。
iasl.exe -d DSDT0000.bin
若是反組譯成功,就會產生 DSDT0000.dsl的 ASL檔。
有時會遇到缺少 external control method的情況導致反組譯失敗,這時就可以使用 -e
參數來 include包含 external control method的 AML檔。

EX: Include SSD0及 SSD1
iasl.exe -e SSD00000.bin SSD10000.bin -d DSDT0000.bin
或是使用 -fe來 include描述 external control method的檔案。

3. 依照需求修改 DSDT0000.dsl

EX: 在 DSDT0000.dsl中加入 Serial port的定義

DefinitionBlock ("", "DSDT", 2, "ACRSYS", "ACRPRDCT", 0x00000000)
{
    External (_GPE.HLVT, MethodObj)    // 0 Arguments
    External (_PR_.BGIA, UnknownObj)
    External (_PR_.BGMA, UnknownObj)
    External (_PR_.BGMS, UnknownObj)
......
    OperationRegion (SERP, SystemIO, 0x3F8, 0x8)
    Field (SERP, ByteAcc, NoLock, Preserve)
    {
      THRR, 8,
      , 8,
      , 8,
      , 8,
      , 8,
      LSRR, 8,
      MSRR, 8
    }

    Name (SS1, Zero)
    Name (SS2, Zero)
......

4. 使用 iasl.exe compile修改過的DSDT0000.dsl
iasl.exe -ve DSDT0000.dsl
成功後就會產生 DSDT0000.aml。
-ve為忽略 warning及 remark,只顯示error。

5. 將DSDT0000.aml load到 registry
asl.exe /loadtable DSDT0000.aml

6. 啟動 Windows test mode
bcdedit /set testsigning on
重新開機以後就能生效。

2021年3月29日 星期一

[Python] Nuitka - 將Python 打包成執行檔


官方網址
https://nuitka.net
https://github.com/Nuitka

Windows


使用Nuitka 將hello.py 打包
python -m nuitka --mingw64 hello.py
打包時會要求下載 C Caching tool及 MinGW64 C compiler。


打包成一個獨立資料夾
python -m nuitka --mingw64 --standalone hello.py
執行完後會產生 .build及 .dist, .dist就是可以用來單獨執行的資料夾。

2021年3月20日 星期六

The Blue Nowhere Developer Software Select


程式碼編輯器 (Code Editor)


Visual Studio Code
https://code.visualstudio.com

Buckup
Sublime Text
https://www.sublimetext.com

Notepad++
https://notepad-plus-plus.org


內容比較軟體


Beyond Compare
https://www.scootersoftware.com


Hex Editor


HxD
https://mh-nexus.de


Git GUI


TortoiseGit
https://tortoisegit.org


網頁瀏覽器 (Web browser)


Firefox
https://www.mozilla.org


壓縮軟體


7-Zip
https://www.developershome.com/7-zip/


映像檔掛接工具


Virtual CloneDrive
https://www.elby.ch/


檔案總管


Q-Dir
https://www.softwareok.com/


SSH Client


MobaXterm
https://mobaxterm.mobatek.net/

2020年11月27日 星期五

[X86] Protected Mode


參考來源:
Intel 64 and IA-32 Architectures Software Developer Manuals
AMD64 Architecture Programmer's Manual
The Intel Microprocessors by Barry B.Brey

相關文章:
Real Mode

Protected Mode相對於 Real Mode,可以定址到 1MB以上的記憶體空間,而原本的 segment register變成用以選擇 descriptor的 selector。
discriptor中描述 memory的 segment 位置、長度與access right。

Protected Mode下,segment register從 descriptor table中指定 descriptor,透過 descriptor
間接地指定 memory segment,相對於在 Real Mode下 segment register是直接指定 memory
segment。


Selectors and Descriptors

descriptor table分為兩種,GDT(Global Descriptor Table)及 LDT(Local Descriptor Table),
每個 descriptor table可以存放 8192個 descriptror。GDT可以被系統中所有程式使用,而
每個程式可能會有自己的 LDT。

descriptor 的格式如下圖,其長度為 8 bytes,所以 descriptor table最大的長度為
64K (8 * 8192)。

其中 Base Address代表segment的起始位址,為32-bit address,可定址到 4GB記憶體位址。
Segment Limit 則為 segment可定址的最高位址。若 Base Address為 0x00F00000而 Segment
Limit為0x000FF,此 segment的範圍就是 0x00F00000 - 0x00F000FF。

G (Granularity) flag沒有被設定,表示Segment Limit為 byte increment,segment的size為1 byte - 1M bytes (0x00001 - 0xFFFFF)。
若 G flag被設定,Segment Limit為 4k bytes increment,則 segment size就是 4k bytes - 4G bytes。

L (Long) bit 只在long mode有效,代表segment在64-bit mode下運行(L=1),或是在
compatibility mode下運行(L=0)。

AV (Available) bit 是給system software使用,代表此segment是否available。

D/B (Default Operation Size) 若D=0,則此 segment中的 instruction都預設使用 16-bit
offset address及register。若D=1,則預設使用32-bit offset address及register。

Type field描述此 segment如何在系統中運作及direction of growth,並根據 code和 data或
system descriptor而有不同的定義。


descriptor 是由segment register在descriptor table中指定。

13-bit index用以指定descriptor table 8192(2^13) decriptor的其中一個。
TI (table indicator)代表 GDT (TI=0)或者 LDT (TI=1)。
RPL (requested privilege level)為要求存取 memory segment的權限。其值 00權限最高,
通常稱為 ring0,11權限最低,通常稱為ring3。
Windows的kernel及driver使用ring0,而一般應用程式通常使用ring3。


Program-Invisible Registers

這些暫存器是隱藏起來,不能被軟體直接使用。像是每個segment register,都有其對應的
program-invisible register。

有些 segment register隱藏起來的部分通常被稱為 "descriptor cache"、 "shadow register"或
"cache memory",此 cache並非 CPU的 L1 L2 cache。
當 segment register指定 segment,segment的 base address、limit及 access right就會被
load進 invisible register。讓處理器可以頻繁的存取 segment而不用去訪問 descriptor table。

GDTR(global descriptor table register)與 IDTR(interrupt descriptro table register) 掌握 descriptor table的 base address與 limit。

LDT的segment會在GDT中的某個descriptor中描述,LDTR則會載入 LDT的 base address、limit
及 attribute。

TR (Task Register)中的selector為visible,而selector會指向GDT其中的TSS descriptor為當前
task的segment。而其invisible的部分cache descriptor的 base address、limit及attribute。

2020年11月19日 星期四

[ASM] Assembly 筆記


參考來源:
https://www.nasm.us/


Assembler Directives


BIST:Specifying Target Processor Mode

用來告訴 Assembler所要產生的程式碼是要在 16-bit mode或 32-bit mode下運行。
16-bit mode寫作 'BITS 16'而 32-bit mode為 'BITS 32'。若沒有指定則預設為32-bit mode。

USE16 and USE32
與BITS 功能相同,用以相容其他assembler。

MASM


.686 (32bit MASM only)

啟用 Pentium Pro的 nonprivileged指令集

.686P (32bit MASM only)

啟用 Pentium Pro所有指令集

.XMM (32bit MASM only)

啟用 SSE指令集

.MODEL (32bit MASM only)

初始 memory model

ASSUME

啟用檢查 register值


Pseudo Instructions


Pseudo Instructions假指令不是真正的 x86機器碼指令,而是給 compiler看的。

DB (and Friends):Declaring Initialized Data

DB, DW, DD, DT, DO, DY and DZ
用來宣告 data

宣告 1 byte data 0x55
db 0x55 ;just the byte 0x55

EQU:Defining Constants

定義某個符號的值,其之後不能被修改

定義 msglen為 'hello, world'字串的長度,其值為 12
message db 'hello, world'
msglen equ $-message

TIMES:Repeating Instructions or Data

TIMES前綴用來重複該 instruction或 data

宣告長度 64 bytes的 buffer
times 64 db 0 


Expressions


$ and $$

$代表此行的開頭位置,$$為此區段的開頭位置

jmp $ ;infinite loop

@@:

@B可以代表前個@@:位置,@F則代表後面@@:的位置。

2020年9月19日 星期六

DISM - Windows 映像檔佈署工具

DISM 是Windows下用以佈署映像檔的工具。

/Split-image

將 .wim檔分割為多個 WIM(.swm)檔案。以 /FileSize來指定 .swm檔的檔案大小上限。
/CheckIntegrity 用以偵測並追蹤 WIM檔案毀損狀況。

dism /Split-Image /ImageFile:"<WIM_PATH>" /SWMFile:"<SWM_PATH>"
/FileSize:<MB> [/CheckIntegrity]


分割 install.wim
在製作 Windows USB開機隨身碟時,會遇到 install.wim檔案大小大於 4GB的情況。
目前 UEFI系統只支援 FAT32格式,而 FAT32有單一檔案大小不能超過 4GB的限制,
所以如果要不透過其他工具直接製作 USB開機碟,可以將 install.wim分割成多個
檔案來避開限制,使用分割出的 .swm檔取代原本的 .wim檔。