https://curl.se/
最近在工作上碰到有腳本使用 cURL來即時向 server請求資料,趁此紀錄一些其使用方法。
HTTP Request
-X 參數用來對 URL發出 HTTP request,後面帶入HTTP method。
-x 通過代理伺服器 PROXY_ADDRESS:PROXY_PORT使用 cURL。
https://curl.se/
最近在工作上碰到有腳本使用 cURL來即時向 server請求資料,趁此紀錄一些其使用方法。
-X 參數用來對 URL發出 HTTP request,後面帶入HTTP method。
-x 通過代理伺服器 PROXY_ADDRESS:PROXY_PORT使用 cURL。
官方網址:
https://stedolan.github.io/jq
最近工作上接觸到其他人寫的 script,使用 jq來將 curl所得到的 .json檔案解析成 .csv檔。
雖然目前只使用到 jq一點點功能,但還是趁此機會紀錄一下。
依照官網的範例,可透過 github的 api獲取 json格式的 jq最近 5個 commit資訊:
使用 jq過濾 json:
只取出第一個 commit的資訊:
取出所有 commit中的 sha資訊:
也可以使用 jqplay的網站來嘗試 jq的輸出結果:
參考網站:
Microsoft pe-format
Wiki Portable_Executable
osdev COFF
XPE Viewer
UEFI image都是遵循微軟所定義的 PE/COFF格式,PE/COFF的格式可以參考維基百科的這張
圖:
使用 EDK2的 CpuDxe.efi來觀察一下:
可以看到一開始的 0x40個 Byte,是 DOS Header,起始的開頭為"MZ"(0x4D 0x5A),在 EDK2 structure定義如下:
而 0x3C則定義了PE Signature的位置,長度為 4 Bytes。以 CpuDxe.efi來說,是在 0x000000B8的位置。可從 0x000000B8的位置看到"PE\0\0"(0x50 0x45 0x00 0x00)的 PE Signature。
而從 0x40到 0xb7的這段空間稱為 DOS Stub,以前為了與 DOS相容而遺留下的產物,現在則直
接全部都填上 0x00。
在 PE Signature之後是 COFF File Header,在 EDK2中的定義如下:
COFF File Header長度為 20 Bytes,將其獨立拿出來看:
| Offset | Size | Field | Value | Description |
|---|---|---|---|---|
| 0 | 2 | Machine | 0x8664 | 代表 x64系統使用。 |
| 2 | 2 | NumberOfSections | 0x0006 | Section Table 的數量。 |
| 4 | 4 | TimeDateStamp | 0x0 | |
| 8 | 4 | PointerToSymbolTable | 0x0 | |
| 12 | 4 | NumberOfSymbols | 0x0 | |
| 16 | 2 | SizeOfOptionalHeader | 0x00F0 | Optional Header的 size。 |
| 18 | 2 | Characteristics | 0x2022 | IMAGE_FILE_EXECUTABLE_IMAGE + IMAGE_FILE_LARGE_ADDRESS_AWARE + IMAGE_FILE_DLL |
緊接下來則是 Optional Header,其長度可以從 COFF File Header得知為 0xF0。
其分成 3個部分,Standard Fields、Windows Specific Fields和
Data Directories。
| Offset | Size | Field | Value | Description |
|---|---|---|---|---|
| 0 | 2 | Magic | 0x020B | PE32+格式。 |
| 2 | 1 | MajorLinkerVersion | 0x0E | |
| 3 | 1 | MinorLinkerVersion | 0x1D | |
| 4 | 4 | SizeOfCode | 0x0000BAE0 | code section的 size。 |
| 8 | 4 | SizeOfInitializedData | 0x00001AE0 | initialized data section的 size。 |
| 12 | 4 | SizeOfUninitializedData | 0x0 | uninitialized data section的 size。 |
| 16 | 4 | AddressOfEntryPoint | 0x00001268 | entry point對ImageBase的相對位址。 |
| 20 | 4 | BaseOfCode | 0x000002C0 | code section對ImageBase的相對位址。 |
| Offset | Size | Field | Value | Description |
|---|---|---|---|---|
| 24 | 8 | ImageBase | 0x0 | |
| 32 | 4 | SectionAlignment | 0x00000020 | section在記憶體中為 32 Bytes alignment。 |
| 36 | 4 | FileAlignment | 0x00000020 | section中的raw data為 32 Bytes alignment。 |
| 40 | 2 | MajorOperatingSystemVersion | 0x0 | |
| 42 | 2 | MinorOperatingSystemVersion | 0x0 | |
| 44 | 2 | MajorImageVersion | 0x0 | |
| 46 | 2 | MinorImageVersion | 0x0 | |
| 48 | 2 | MajorSubsystemVersion | 0x0 | |
| 50 | 2 | MinorSubsystemVersion | 0x0 | |
| 52 | 4 | Win32VersionValue | 0x0 | |
| 56 | 4 | SizeOfImage | 0x0000DC40 | Image的 size,包含所有 headers。 CpuDxe.efi的 size就是0xDC40。 |
| 60 | 4 | SizeOfHeaders | 0x000002C0 | DOS stub、PE Header和 section headers的 size總和。 |
| 64 | 4 | CheckSum | 0x0 | |
| 68 | 2 | Subsystem | 0x000B | 代表為 IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_ DRIVER。 |
| 70 | 2 | DLL Characteristics | 0x0 | |
| 72 | 8 | SizeOfStackReserve | 0x0 | |
| 80 | 8 | SizeOfStackCommit | 0x0 | |
| 88 | 8 | SizeOfHeapReserve | 0x0 | |
| 96 | 8 | SizeOfHeapCommit | 0x0 | |
| 104 | 4 | LoaderFlags | 0x0 | |
| 108 | 4 | NumberOfRvaAndSizes | 0x00000010 | Data Directories的數量。 |
| Offset | Size | Field | Value | Description |
|---|---|---|---|---|
| 112 | 8 | Export Table | 0x0 | |
| 120 | 8 | Import Table | 0x0 | |
| 128 | 8 | Resource Table | 0x0 | |
| 136 | 8 | Exception Table | 0x0 | |
| 144 | 8 | Certificate Table | 0x0 | |
| 152 | 8 | Base Relocation Table | 0x0000DBC0 | |
| 160 | 8 | Debug | 0x0 | |
| 168 | 8 | Architecture | 0x0 | |
| 176 | 8 | Global Ptr | 0x0 | |
| 184 | 8 | TLS Table | 0x0 | |
| 192 | 8 | Load Config Table | 0x0 | |
| 200 | 8 | Bound Import | 0x0 | |
| 208 | 8 | IAT | 0x0 | |
| 216 | 8 | Delay Import Descriptor | 0x0 | |
| 224 | 8 | CLR Runtime Header | 0x0 | |
| 232 | 8 | Reserved | 0x0 |
Optional Header的下個部份則為 Section Headers,其數量可以從 COFF File Header的
NumberOfSections讀出。
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 8 | Name | 8 Bytes的 ASCII字串,代表此 section的名字。 |
| 8 | 4 | VirtualSize | 此section在記憶體中的 size,如果大於 SizeOfRawData 則後面會填上 0x0。 |
| 12 | 4 | VirtualAddress | 此 section在記憶體中相對於 ImageBase的起始位址。 |
| 16 | 4 | SizeOfRawData | initialized date的 size。 |
| 20 | 4 | PointerToRawData | section raw data的 offset。 |
| 24 | 4 | PointerToRelocations | Relocation table的 offset。 |
| 28 | 4 | PointerToLinenumbers | Line Number table的 offset。 |
| 32 | 2 | NumberOfRelocations | Relocatione table的數量。 |
| 34 | 2 | NumberOfLinenumbers | Line Number table的數量。 |
| 36 | 4 | Characteristics | 32 Bits flag。 |
CpuDxe.efi可以使用 xpeviewer讀出 6個 sections:
| Section Name | Content |
|---|---|
| .text | Executable code |
| .rodata | Read-only initialized data |
| .data | Initialized data |
| .xdata | Exception information |
| .reloc | Image relocations |
UEFI 提供兩種主要的 service來操作及控制系統資源:
提供開機期間相關的系統服務,在 ExitBootServices()被呼叫之後就無法使用。
在 ExitBootServices()之後還可以使用,OS 需要其來完成一些系統資源的操作。
UEFI在 allocate記憶體的時候,會需要指定這段記憶體的 EFI_MEMORY_TYPE,來代表其使用目 的。EFI_MEMORY_TYPE也分成只在 ExitBootServices()前可以使用及在 ExitBootService ()後也 能使用。詳細 EFI_MEMORY_TYPE使用可參考 UEFI Specification。
在 EFI System Table 中主要有兩個服務會在 Runtime使用:
提供所有 Runtime Services的指標。
由 GUID/Pointer 配對組成,可以是提供給系統的 function pointer、data或 table, 像是 SMBIOS及 ACPI table的 entry point。
Runtime Services其中還有包含 Time Services的部分,讓 OS可以不用透過直接讀取硬體的方式 來取得系統的時間資訊。相關的 function有 GetTime()、SetTime()、GetWakeupTime()和 SetWakeupTime()。
在ExitBootServices()之後,OS會透過 SetVirtualAddressMap()提供其虛擬記憶體的資訊 來將 Runtime Services從實體記憶體定址到虛擬記憶體。ConvertPointer()提供 UEFI的程式本身來轉 換虛擬記憶體。在 SetVirtualAddressMap()轉址前,會先執行註冊EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE的 Event。
Variable的主要作用在於 OS Loader與 firmware之間傳遞資料,對於不同的 platform可能有不同
的實作,但其要能在 reset的時候也可以保存資料。
VariableName及 VariableGuid 用來命名不同的 Variable。VariableName通常是人讀得懂的文字
,也不用擔心其重複,還有 VariableGuid可以用來分別。
有三個主要的 Attributes需要注意:
在 System Reset之後 Variable依然可以保留。
代表只有在 ExitBootService()之前可以使用,之後的 GetVariable()及 GetNextVariable()都會無法找到。
有這個代表 BootService也要同時被設定, ExitBootServices()之後也能存取。
只有同時擁有 Nonvoliatile和 RuntimeService的 Variable可以在 ExitBootServices()之後使用 SetVariable()來寫入。而只有 RuntimeService的則是 read-only,原因是記憶體的控制權已經交 給了 OS。
沒什麼想寫的,有想法再回來補充。
相關文章:
使用 Virtualenv 開發 Python
先前都是使用 Virtualenv來建立 Python開發的虛擬環境,但在 Python後面的版本,其本身就內
建了虛擬環境的模組 venv。
PCI Enumeration是我做 BIOS這幾年還未跨過去的一道坎,也只是片段零碎地在 debug的過
程中摸索,看不清楚全貌。最近看了 "EDK II EFI Driver Writers Guide"的 "PCI Driver
Design Guidelines"覺得獲益良多,許多觀念在讀這章的過程中重新整理了一次,所以藉由這
機會來重頭 study EDK II中關於整個 PCI Enumeration的程式碼,打鐵趁熱。
Pci Enumeration 在 EDK II主要由 PCI Root Bridge Io Driver、PCI Bus Driver以及 PCI Driver
這三種 Driver來完成。這三者的主要工作與概念在"PCI Driver Design Guidelines"寫得很清
楚,就不著墨在這。而 PCI Driver又太多種,所以本篇目前只專注在 PCI Root Bridge Io Driver
及 PCI Bus Driver的程式碼上。
PCI Root Bridge Io Driver
從Entry Point InitializePciHostBridge開始看吧:
好,我承認第一段就有點卡關,Host Bridge跟 Root Bridge分別到底是什麼? 先看一下 PCI_HOST_BRIDGE_INSTANCE的結構:
PCI_HOST_BRIDGE_INSTANCE的結構裡含有 RootBridges的 Linked List,代表一個 Host Bridge 可能有一個至多個 Root Bridge。又從後面的註解可以看到,EDK在 PCI Enumeration的情況只考慮系統只會有一個 Host Bridge。 可以理解成 Host Bridge是比 Root Bridge還上層的東西。
翻開 PCI的 spec,可以看到 PCI Bus就是透過 Host Bridge來與系統上的 CPU及 Memory連接的。而到了 PCI Express, Host Bridge的功能就被包含在 Root Complex中。
Root Bridge的詳細描述可以在UEFI spec中找到,其是用以產生實體 PCI Bus的 chipset
component。一個 Host Bridge可以有一個或多個 Root Bridge。下列兩個 UEFI spec中提到的比較常見的系統範例。
只有一個 Root Bridge:
多個 Root Bridge:
UEFI spce也有多個 Host Bridge的系統範例,這裡就不貼出來了。在我先前的經驗只有碰過一
個 Host Bridge和一個 Root Bridge的情況,所以這兩個東西才會讓我如此困惑,有時候也會混
在一起說。
另外其中還提到,PCI Segment與 Host Bridge和 Root Bridge是不同的概念。PCI Segment指的
是共用相同 PCI Configuration Space的 PCI Bus之集合,最多能有 256個 Bus。Root Bridge
可能包含整個或是部分的 PCI Segment。Host Bridge若是有多個 Root Bridge,則很有可能有
多個 PCI Segment。
再回到第一段 code,其用意就是要知道系統中有幾個 Root Bridge,其中的方法是去掃 Bus 0 -
255,如果 Bus上有 Device,就表示 Root Bridge存在,而在掃的過程中要去扣除掉 PCI to
PCI Bridge所產生出來的 Bus。
當然,如果本來就是知道系統中有多少 Root Bridge,我也是看過直接 hard code的。
接下來 InitializePciHostBridge還會將每個 RB所用到的 MMIO及 IO透過 DXE service回報
給 GCD (Global Coherency Domain) ,讓系統來管理所能使用的 resource。
並在 Root Bridge Handle上安裝 PCI Root Bridge IO Protocol來讓之後的 PCI Bus Driver使用。
話說有天心血來潮,想要把自己某個 side project的資料夾名稱從大寫的 Config改成小寫的 config。 但手動改成小寫後,git status指令的狀態不會有任何變化,於是查了一下,發現可以使用 git mv 指令來達到我要的效果。
透過一個過渡的目錄名稱 ./config1來達到我要的效果。還有另一個好處是 git mv之後的檔案都是
git add/rm之後的狀態,接下來直接 commit就行了。
由於 git mv本身就是移動或重新命名檔案或目錄的命令,直接使用:
git 以為是要把當前的 ./Config移動到 ./config下,會出現 fail。
而改變檔案名稱的大/小寫是可以直接使用 git mv的:
補充:
git的大小寫名稱行為似乎是跟 OS的檔案系統本身是不是 case sensitive有關。
透過 git config能改變 git case sensitive的行為。
OS loader是一種特殊的 UEFI Application,用來讓系統從 firmware
環境轉換到 OS環境。
C/C++ 語言常使用 Macro 來預先定義一些常常用到的值或程式碼片段,讓整體的
程式看起來更簡潔。
X Macro是種 Macro更進階的使用「方法」,而不是另一種「功能」。所以只要有
支援定義 Macro功能的程式語言,也可以使用。
其透過 "#define"與 "#undef"來替換 "X"的定義可以達到各種神奇的效果。
以下是一種最簡單範例:
Output:
我在 LIST_OF_NAMES宣告由 "X()"組成的函數,這時的 "X"還沒有被定義。
在 "main()"中,才把 "X()"定義成使用 printf函數印出 name參數並呼叫
LIST_OF_NAMES。
如果將 LIST_OF_NAMES的 X Macro展開來寫,就會是這個樣子:
而 X Macro最妙的用法還在於可以替換"X"的定義,使其重複利用:
Output:
Chocolatey 可以讓 Windows以 command line的形式來安裝及管理軟體套件,類似
Linux使用的 APT。