小華的部落格: 2014

搜尋此網誌

網頁

星期四, 12月 25, 2014

開啟CMD.EXE並一次執行多個DOS指令的方式(Command Prompt and Batch file)

這篇文章是分享如何開啟CMD.EXE時並一次執行多個DOS指令的方式。

為什麼要分享這個冷知識?
因為現在是冬天了,所以很冷。

好吧,我承認這是個很無聊的一篇文章,大家就將就點看吧 :)

首先呢,我們都知道Command Prompt 是執行CMD.EXE後就會產生出來的一個畫面,那我們能不能寫個批次檔去執行CMD.EXE又可以執行很多筆指令呢? 答案是可以的,做法就是寫個批次檔,然後透過"雙引號"去把所有指令包起來,指令跟指令中間加入 && 就可以了:


   CMD.EXE  "指令1 && 指令2 && 指令3....&&指令n"

底下就是兩個批次檔的範例,批次檔內會去執行簡單的DOS指令,執行完畢後會出現一個Command Prompt停在那邊。





那大家可能會好奇我用在哪裡? 因為我使用SlickEdit 去編寫BIOS CODE,因為懶惰,所以想說我只要開啟 BUILD TIP底下任何一個檔案,然後按個鈕,我就可以進入到工作目錄並且設定好Visual Studio 的環境讓我可以直接Compiler code....就醬~




※ 上圖可以看到我在SlickEdit 內開啟了一個檔案,叫做NT32Pkg.dsc ,然後我設定了兩個快捷鈕,這兩個快捷鈕可以讓我選擇設定VS2012/VS2010的環境,按下去之後他會幫我呼叫設定環境的批次檔,環境設定好之後會直接幫我進入到NT32Pkg.dsc 目錄(E:\UDK2014.SP1\NT32Pkg),然後我就可以很方便地在Command Prompt內做我要做的事情了。

底下是我在那兩個快捷鍵內的設定值,有分成CMD.EXE的設定方式跟BATCH的方式,差別就只是在於呼叫CMD.EXE去做事情還是自己寫個批次檔,然後呼叫那個批次檔而已。

CMD.EXE的方式:
cmd /E:ON /V:ON /k  ""C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Tools\VsDevCmd.bat" && cd/d "%f\..""


BATCH FILE的方式(除了描述在快捷鈕之外,要多寫一個批次檔):
"C:\Apps\TEST.bat" %f

TEST.bat的內容:
@ECHO OFF
CALL "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Tools\VsDevCmd.bat"
cd/d "%1\.."
CMD.EXE 

上述中的%f 是SlickEdit內的參數,%f = 目前檔案的完整路徑。
以上面的範例來說:

    %f   = e:\UDK2014.SP1\Nt32Pkg\Nt32Pkg
 
最後,我承認科技使用來自於人的惰性,不然也不會有這個冷知識可以分享,哈~


星期二, 12月 23, 2014

Intel® UEFI Development Kit Debugger Tool (Intel UDK Debugger and OVMFPkg)

這篇文章是紀錄我自己架設 QEMU + OVMF + Intel UDK + WinDbg 環境的筆記。

QEMU : 他是一個Open Source的處理器仿真器與模擬器。
http://wiki.qemu.org/Main_Page
   
OVMF : 他是一個UEFI EDK2 codebase裡面的一個專案,用來讓UEFI BIOS可以跑在虛擬機器(Virtual Machine)上面,在這裡的範例就是跑在QEMU裡面。
http://tianocore.github.io/ovmf/

Intel UDK Debugger : 這是INTEL開發的一個Source Level Debugger,他需要配合WinDbg(微軟提供的)才能做除錯的動作。

Intel Uefi Development Kit Debugger Tool

下面這張圖是我實際的架設環境,我在Windows 8.1裡面安裝了Intel UDK跟WinDbg然後透過虛擬的COM Port來與 QEMU裡面的BIOS.BIN(OVMF.FD)溝通。


安裝與設定(Install and Setup)

STEP1 : Download UDK2014.SP1 ,OvmfPkg and OptionRomPkg

我是把它們一起放在E:\UDK2014.SP1; 然後先準備好Compiler環境,並產生OVMF.FD. (環境的部分請參考UDK2014與OVMF的說明)。

確定Compiler 環境沒問題後,跟隨下面步驟來產生UEFI BIOS ROM。

1).先產生 OVMF.FD
   a. E:\UDK2014.SP1>edksetup.bat
   b. E:\UDK2014.SP1>build -DDEBUG_ON_SERIAL_PORT=TRUE -DSOURCE_DEBUG_ENABLE

2). 在把OVMF.FD複製一份,並修改檔案名稱為bios.bin (rename)
   (我是放在 E:\UDK2014.SP1\Build\Ovmf3264\DEBUG_VS2012x86\FV\bios.bin)
    a.E:\UDK2014.SP1> cd E:\UDK2014.SP1\Build\Ovmf3264\DEBUG_VS2012x86\FV
    b.E:\UDK2014.SP1\Build\Ovmf3264\DEBUG_VS2012x86\FV> copy OVMF.FD bios.bin

STEP2: 安裝(Install) WinDbg 
STEP3: 安裝Virtual Serial Port,你可以選擇Com0Com或是VSPD(Virtual Serial Port Driver),因為Com0Com 是免費(Free),另一個要破解(VSPD v7.2),所以我這邊就只介紹Com0Com 就好,破解版的我就自己知道就好這邊就不介紹了。

1) 先執行一個Cmd.exe with Admin (管理者權限)
   bcdedit -set TESTSIGNING ON
2)重新開機 (Reboot)
3) 安裝Com0Com 2.2.2.0 (For Windows 8.1/Win7 x64 bit) 

4) 執行 "C:\Program Files (x86)\com0com\setupc.exe",並在畫面中輸入下面指令:

    Command > Install PortName=COM6 PortName=COM7

5) 確認設備管理員(Device Manager)內有成功安裝driver,並且No yellow bang.


STEP4: 安裝(Install) Intel UDK v1.4 
※如果你是Windows 8.1 ,請設定相容性=Windows 7 (Compatibility mode=Windows 7)
 

1) 安裝過程中會指定WinDbg安裝目錄跟COM port Number,你也可以安裝完畢後,再去修改他的設定檔案(Config File):

"C:\Program Files (x86)\Intel\Intel(R) UEFI Development Kit Debugger Tool\SoftDebugger.ini"
  
底下是我實作時候的設定:
COM6 = Intel UDK
COM7 = QEMU

2) 安裝後,修改SoftDebugger.ini 加入以及修改底下的描述(RED COLOR)
"C:\Program Files (x86)\Intel\Intel(R) UEFI Development Kit Debugger Tool\SoftDebugger.ini"
[Debug]
Debug=1

[Debug Port]
Channel = Serial
Port = COM6
FlowControl = 0   
BaudRate = 115200
Server = 

STEP5:  執行Intel UDK Debugger,他會叫出WinDbg
STEP6: 執行QEMU 並且載入UEFI BIOS (Load BIOS.bin)

E:\UDK2014.SP1\Build\Ovmf3264\DEBUG_VS2012x86\FV>"C:\Program Files\qemu\qemu-system-x86_64.exe" -L . -serial COM7



如果有不清楚的部分,可以參考INTEL相關資料。







星期五, 12月 19, 2014

VC++ 可轉散發套件(Redistributable Package)


這篇文章只是要告訴大家可轉散發套件(VC++ Redistributable Package是幹甚麼的?

1)首先呢,我先在我的Win7 64 bit OS底下安裝VS2008 ,安裝時順便選擇我要裝x64 compiler,這樣子我的開發環境就會有VS2008 32 bit/64 bit compiler 功能!

2) 接著,我建立一個新的VC++空專案(VC++-->General-->Empty Project),裡面加入我自己的C 語言Source code (Tmake.c 跟Tmake.h),然後再專案屬性的地方先設定Win32 (Right click Project -->Properties ,在Platform 的地方選"Win32")

3) 先產生一次32 bit的應用程式,他會產生再輸出目錄 『Debug\Tmake.exe』

4) 接著,修改專案屬性,改選擇x64 ((Right click Project -->Properties ,在Platform 的地方選"x64"),如果你沒看到x64可以選擇,就是在安裝VisualStudio時沒選擇x64 compiler選項

5) 然後再產生一次 64 bit的應用程式,他會產生在輸出目錄『x64\Debug\Tmake.exe』

完成了步驟5之後,我就會有兩個執行檔,分別是32 bit版本跟64 bit版本。

底下是我的開發環境 (產生執行檔,但是拿到別台去執行)

OS: Windows 7 64 bit
Visual Studio 2008

底下是我的執行環境 (這台機器上面執行我自己寫的程式)

OS : Windows 8.1 64 bit
Visual Studio 2012/2013



    [圖1]  32 bit/64 bit 的主要差別除了暫存器之外就是在於 Calling Convention (呼叫慣例)

所以大家可以看到,我在Win7開發拿到另一台Win8.1 上面執行,而在Win8.1中我只安裝了Visual Studio 2012/2013這兩個版本,但是我的Win7開發時是Visual Studio 2008開發的。

所以,當我在Win8.1底下不管是執行32 bit 版本的Tmake.exe 或是  64 bit 版本的Tmake.exe 我都得到了相同的錯誤訊息。

ERROR MESSAGE:  因為應用程式檔設定不正確,所以無法啟動


[圖 2] 無論32/64 bit 都得到相同的錯誤訊息


假如你看到類似這種錯誤訊息時,只要去安裝可轉發套件,把需要的檔案補足在你的電腦中理論上問題就會消失了,但是 "你要找的到正確的版本的可轉發套件" (後面會講找不到時的解決方式)。


底下版本是VS2008 version v9.0.30729

底下版本是VS2008 v9.0.30729.6161 (比上面的還新一點)

Microsoft Visual C++ 2008 Service Pack 1 Redistributable Package MFC Security Update


另外,你可以在安裝完畢後,從System Event Log看到你到底安裝了甚麼版本:

Windows Installer 已安裝該產品。產品名稱: Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.6161。產品版本: 9.0.30729.6161。產品語言: 1033。製造商: Microsoft Corporation。安裝成功或錯誤狀態: 0

如果,你安裝完畢後還不能執行的話,那就是版本不同!  


如果你從System Event Log 查看,也會看到類似下面的錯誤訊息:

"D:\TmakeJpg\Debug\Tmake.exe" 的啟用內容產生失敗。 找不到依存組合 Microsoft.VC90.DebugCRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="9.0.21022.8"。

意思是說你執行Tmake.exe的電腦內的所能提供的執行環境跟這個應用程式內所要求的版本不同; 從上面的範例可以知道我安裝的都是v9.0.30729.xxxx 但是這個應用程式需要的是9.0.21022.8,這個時候,你有幾個解決方式。

方式1: 從開發的機器上把需要的檔案複製到執行的機器上的Windows\System32 底下
需要的檔案需要配合你的應用程式的類型來複製對應的檔案,例如:

Release Build 64 bit(x64):  
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\Amd64\Microsoft.VC90.CRT 
Release Build 32 bit(Win32):  
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT 

msvcm90.dll
msvcp90.dll
msvcr90.dll
Microsoft.VC90.CRT.manifest

Debug Build 64 bit(x64):
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\amd64\Microsoft.VC90.DebugCRT

Debug Build 32 bit(Win32):
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC90.DebugCRT

msvcm90d.dll
msvcp90d.dll
msvcr90d.dll
Microsoft.VC90.DebugCRT.manifest

方式2 : 把前面這些需要的檔案打包變成xxx.exe 再一起拿去執行的電腦安裝與執行.

請參考: http://msdn.microsoft.com/en-us/library/ms235291(v=vs.80).aspx
              http://msdn.microsoft.com/en-us/library/aa260978%28VS.60%29.aspx

方式3: 在專案屬性中選擇使用靜態MFC Library. (Win32/X64都要設定一次) 再重新編譯執行檔就可以了。



結論 :

 VC++的轉散發套件就是給『跟你開發環境不同』的人去補足需要的Library/DLL之後,才能順利執行你所開發的應用程式。

所以,程式開發者可以選擇『自己打包好所需要的檔案』後再提供給使用者免去使用者無法執行的窘境,或是使用者自己無法執行應用程式時去安裝對應的『轉散發套件』。

[註] 我的測試程式後來採用方式3解決問題! 系統就算不安裝VC++的轉散發套件也沒問題。


星期四, 10月 23, 2014

WMI ACPI

今天要整理的筆記是WMI ACPI
       
     在BIOS工程師中,對於WMI ACPI應該大家都有玩過,因為許多的OEM都是開發一些OS端的應用程式,然後再透過WMI 這種方式去跟BIOS的ACPI ASL CODE做溝通,以達到可以讀取Thermal 資訊/EC 資訊/ BIOS Setup Utility 資訊....etc.

   
在網路上或是微軟的相關文件中,你可以看到主要的架構在於wmiacpi.sys 跟acpi.sys 之間的溝通,對於BIOS工程師來說,如果要去提供這種介面就不得不參考微軟的wmi acpi白皮書上面介紹的內容了,底下是微軟文件的說明:

http://msdn.microsoft.com/en-us/library/windows/hardware/dn614028(v=vs.85).aspx

這份文件中主要的概念有幾個:

1. 他跟你說有一個MOF(Managed Object Format) 是用來給 WMI Core使用的,所以他有個資料庫管理這些MOF檔案;當上層的APP跟WMI Core溝通時,他要去這個資料庫撈對應的MOF資訊,從MOF資訊中取得一些資訊後,才知道怎麼跟你的ACPI溝通!
2.溝通的那個ACPI Device有一個特別的PNPID,也就是PNP0C14 ! 所以BIOS工程師要宣告一個ACPI Device然後底下定義_HID , "PNP0C14" 這樣子才能夠溝通~
3.Wmi Core 溝通的方式就請自行看這篇文章,像是如何透過GUID找到ACPI _WDG內比對GUID然後找到兩個字元後,再去看Flag屬性是否是Method,然後去執行相關的ACPI Method...之類的資訊,因為這些資訊已經在網路上很多,大家也應該熟悉了,這邊就不多描述。 底下是對_WDG對應時的C語言格式:

typedef struct
{
     GUID guid;             // GUID that names data block
     union
     {
         CHAR ObjectId[2];  // 2-character ACPI ID  (Data Blocks and Methods)
         struct 
         {
             UCHAR NotificationValue;  // Byte value passed by event handler control method
             UCHAR Reserved[1];
         } NotifyId;
    }
     USHORT InstanceCount;  // Number of separate instances of data block
     USHORT Flags;          // Flags
};
上面的C結構會對應倒ASL的_WDG 內的定義:
   Name(_WDG, Buffer() {
        0x6a, 0x0f, 0xBC,....//GUID
        66, 65,              // Object ID (BA) (兩個字元"BA",可能會組成WQBA或是WMBA,看Flag)
        3,                   // Instance Count (有幾筆Data items)
        0x01,                // Flags (決定他是不是Method...之類的屬性來決定WQXX/WMXX...etc)
        
    }) 


那大家可能會問說,你不說運作原理那你要說甚麼?

一般BIOS工程師在Debug時一般就是利用這些運作原理去追ACPI 來找出問題點,一般大家會比較忽略說,那上層的MOF是怎麼加進去資料庫的? 所以這邊會對這部分做一個簡單的說明。在說明之前,我們先看看下面這張圖:


Vbscript :    代表的就是上層APP可以透過像是VBScript/C#....etc之類的去開發你的APP。
Wmi Core :  會去撈MOF 資訊跟Acpi.sys溝通(透過WmiAcpi.sys) 。
ACPI ASL :  你要宣告PNP0C14 ,然後有個Name Object 叫做 _WDG (上面圖畫錯了,懶得改了)。
BIOS Function: 然後透過ACPI ASL的相關Method來實做一些BIOS CODE,像是發個SMI去取得一些資訊,再透過WMI_ACPI ASL往回傳給上層APP...etc.。


Installation wmi acpi方式有兩種:

方式1: MOF包在DLL,並註冊到Registry
1. 增加上述說的那些ASL CODE到你的BIOS

2. 建立一個MOF.DLL (類似OS動態連結檔,不過裡面沒有任何OBJ只有MOF資料)
    a. 建立wmiacpi.rc 跟wmiacpi.def 檔案
    b. 透過VS2010/2012/2013 的link.exe 將他變成wmiacpi.dll 裡面沒有obj,只有 MOF資料

wmiacpi.rc 內容:

#include <windows.h>
#include <ntverp.h>

#define VER_FILETYPE            VFT_DLL
#define VER_FILESUBTYPE         VFT_UNKNOWN
#define VER_FILEDESCRIPTION_STR         "Resource only DLL containing MOF for ASL code"
#define VER_INTERNALNAME_STR            "wmimof"
#define VER_ORIGINALFILENAME_STR        "wmimof.DLL"

#include "common.ver"

//
// WMIACPI.SYS requires that the mof resource be named MofResource

MofResource MOFDATA wmiacpi.bmf


wmiacpi.def 的內容就只有一行: 
LIBRARY wmiacpi.dll

    c. link command : 

rc /fo"%OUTDIR%\wmiacpi.res" wmiacpi.rc

link /OUT:"%OUTDIR%\wmiacpi.dll" /NOLOGO /DLL "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" 

"ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEF:"wmiacpi.def" %OUTDIR%\wmiacpi.res /MANIFEST /ManifestFile:"%OUTDIR%

\wmiacpi.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /PDB:"%OUTDIR%\wmiacpi.pdb" /TLBID:1 /NOENTRY /DYNAMICBASE 

/NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE


3. 複製MOF.DLL檔案到%windir%\system32 (也就是C:\Windows\System32)

4. 在Registry 的HKEY_LOCAL_MACHINE\CurrentControlSet\Services\WmiAcpi底下新增MofImagePath,然後裡面的值指向 "C:\Windows\System32\MOF.DLL"
5. 重新開機,然後OS偵測到PNP0C14之後就會自動安裝WmiAcpi.sys 然後會去Registry 找到你包在MOF.DLL內的資料,之後用你的APP來透過WMI Core去存取你的ACPI ASL.


※ 這邊說的MOF.DLL就是你透過link.exe 建立出來的檔案,請自行變更你的名稱

方式2: MOF包在ACPI ASL,等發送特定IRP時回給Wmi Core.

1. 增加上述說的那些ASL CODE到你的BIOS

2. 建立一個MOF.BMF (MOF的Binary格式,副檔名隨便給因為你可以在Compiler時指定副檔名)

3. 透過 wmimofck.exe 產生.x 檔案,在把他的內容包到ACPI ASL之中.

a. 首先先在_WDG內定義一個專屬MOF的GUID(切記不能改變GUID值) 

   Name(_WDG, Buffer() { 
       .
       // This GUID for returning the MOF data
       0x21, 0x12, 0x90, 0x05, 0x66, 0xd5, 0xd1, 0x11, 0xb2, 0xf0, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, //
       66, 65,        // Object ID (BA)  這兩個字元可以自己改,但是要對應到WQXX.
       1,                 // Instance Count 
       0x00,          // Flags    
   })

b.將Wmiacpi.x 內容複製貼上到Name Object "WQBA"

  Name(WQBA), Buffer(){"MOF Binary data from Wmiacpi.x"}

4. 重新開機,然後OS偵測到PNP0C14之後就會自動安裝WmiAcpi.sys 然後會發送特定的IRP,然後ACPI那邊會回給WMI CORE MOF的資訊~

在這兩中方式中,都需要把wmiacpi.mof 檔案先經過一個工具叫做mofcomp.exe compiler
而這個wmiacpi.mof 檔案的內容就是你在微軟文件那邊看到的,例如:

class WMIEvent : __ExtrinsicEvent
{
};


[WMI,
 Locale("MS\\0x409"),
 Description("This class contains the definition of the package used in other classes"),
 guid("{ABBC0F60-8EA1-11d1-00A0-C90629100000}")
]
class Package
{
    [WmiDataId(1),
     read, write,
     Description("16 bytes of data")
    ] uint8 Bytes[16];

};
...

然後經過mofcomp.exe compiler之後,會產生一個MOF binary 檔案,我把他叫做wmiacpi.bmf。

而這個wmiacpi.bmf 可以經過另一個工具wmimofck.exe 來產生c file / c header file ,如果你想自己寫一個Wmi driver時,可以透過這種方式把來幫助你產生一些需要的程式碼,也可以透過wmimofck.exe來產生VBScript 的Sample code(自動產生),所以當然也可以透過wmimofck.exe來產生一堆HEX 文字檔來方便你把MOF binary資料包進去ACPI ASL之中。

底下是我的批次檔,用來測試用的,分享給大家參考~






※ 這邊使用到的資訊都是來自於微軟的相關文件,有興趣請自行查詢!

需要用到的工具:
Windows WDK內的wmimofchk.exe (我是安裝WDK for win7 ,目前最新版是WDK 8.1)

Reference 

http://msdn.microsoft.com/en-us/library/windows/hardware/dn614028(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff542012(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff554794(v=vs.85).aspx

星期二, 9月 16, 2014

EDK2/EDKII Python Build Tool 兩三事 (Build.py)

EDK2 Python Build Tool 兩三事

最近因為工作需要,所以不得已逼自己去把EDK2 Python Build source code看完,看完後順便整理一下一些小重點,以免過陣子自己又忘記了。

     1)EDK_GLOBAL 
     這種定義的Macro只能給EDK1 driver使用,因為他會去檢查.inf 內的
     INF_VERSION  = 0x00010005 ,如果大於或是等於這個值就是當成EDK2,如果找不到這個值就會當成是EDK1。

因為不好用,所以就隨手改了一下CODE,讓他通吃EDK1 + EDK2 + FDF + DSC + DEC + INF

   2) Build Rule and Package rule
   在EDK2 中,他把EDK1原本的Build Rule & Package Rule 分別描述成:
        Tools_def.txt 
        Build_Rule.txt
        [Rule.$(Arch).$(ModuleType] 

好不好用看個人,不過如果你要支援原本EDK1 Package Rule時那就對不起啦,你要修改Python source code,不然你做不到。  例如說底下的EDK1 的COMPONENT_TYPE = FILE原本對應到某個Package Rule,但是在EDK2內不支援就是不支援,除非自己改python source code.

[Defines]
BASE_NAME               = xxxxx
FILE_GUID                   = 126A4D6A-C404-4200-8779-F327A4A79087
COMPONENT_TYPE  = FILE
BUILD_TYPE               = MAKEFILE

   3) Python v.s SQL
   Python build tool 只是拿SQL當成是存放他收集到的資料的一個地方,然後在另一個地方就可以去撈資料庫內的資訊然後寫對應的CODE去分析要幹嘛,所以rebuild的時候最好把這個資料庫暫存檔案刪除。 EX: Conf\.cache\build.db

   4) GenSection & GenFFS
   以前EDK1的這兩個工具也整合進去Python Build tool內了,所以想了解FDF是怎麼產生FV或是FD的人就請自行研究,不過他是另一隻Tool叫做GenFds.py。

   5) AutoGen.c v.s AutoGen.h
   偷偷產生的檔案用來存放一些PCD操作/有用到的PCD Value,GUID 定義跟一些偷塞的include... 如果是給PCD database使用的,他還會塞Dynamic PCD給PCD 資料庫當成初始化值。

    另外,Library 只會產生AutoGen.h 不會產生AutoGen.c,因為Library通常會跟某個Driver Link,所以等到真正要去產生Module make時,才會去檢查Library 內用到的GUID/PCD ,然後產生在Module's AutoGen.c內。

    6) Hard code
    恩,很多東西都寫死在Python build tool內,像是nmake command 要增加修改時就要改一改他,不過也是個好處,就是我可以偷加很多東西在裡面,然後不給你source code...哈!!!

   7) 產生執行檔
    .py  轉成 .exe 方式我自己再用的有兩種,一種是py2Exe不過版本過舊已經不能支援了,所以我採用EDK2 所建議的cx_Freeze 去轉換,轉換時還要搭配你的Python 版本,目前我看到的codebase內使用的是Python 2.7.3,所以應該以這個為主吧! 底下是EDK2 建議的方式:

Using cx_Freeze 4.2.3 with Python 2.7.2
Using cx_Freeze 3.0.3 with Python 2.5.4

  8) 嗯...有想到再說~


     
   




星期三, 2月 12, 2014

Python v.s UEFI EDK2 (EDKII)

這篇文章主要是幫自己紀錄一下學習EDK2 build process時的前置準備動作有哪些,後面會陸陸續續把這篇文章補齊,所以先留下個紀錄吧~

學習方式

    對於EDK2來說最大的轉變就是我一直提到的Build process,我常跟我周遭朋友說如果你要學好BIOS或是其他大型軟體專案,中間的『眉角』就是要把大型專案的學習方式分成:

     BUILD + CODE

當你有辦法分辨以及分開學習時,你才可以精準的掌握住甚麼是BUILD? 甚麼是CODE?
舉例來說,BUILD的部分就是屬於build rule/compiler rule/package rule ,簡單的說就是透過一些方式來把程式碼產生成binary,依照一些特定的layout來產生成一個BIOS ROM image;至於CODE的部分就屬於程式語言,像是C語言,組合語言的學習! 你唯有了解彼此之間的關係,你才能掌握關鍵處! 這也是我常跟朋友開玩笑說,你真的會"build+code"嗎?!

至於BUILD PROCESS的概念中,我也常常教導朋友去思考為什麼要這樣子做? 他解決了甚麼問題? 有沒有其他方式? 因此我常常由一個批次檔的概念外加一些淺而易懂的範例來讓他們知道說原來BUILD PROCESS原理是如此簡單,不過我沒打算在這邊寫詳細的解說,因為配合著畫圖邊解釋效果比較佳,如果大家有興趣又剛好在業界遇到我時再來跟我討論吧! ^^

所以記得,學習的方式就是BUILD + CODE分開來學!!!

前置動作
   有鑑於EDK2 BUILD PROCESS主要的部分已經改成Python 2.5/2.7開發,美其名是為了跨平台而準備,但是實際上卻沒有達成!  畢竟,EDK2在x86中並沒有拿Python 將所有win32 的工具重新寫一次,導致在x86平台中有一部分的python tool跟一部份的win32 tool,所以只能說『某些BUILD TOOLS』跨平台而已! 但是木已成舟,所以現在的x86上就變成了這個怪胎情況了!

   雖然我不討厭Python,但也不是擁護者,因為跨平台方式有很多種,他也不是最好的一種! 但是因為EDK2都選擇了Python,所以我也要強迫自己來學習他,秉持著工欲善其事,必先利其器的方式,我們先把除錯工具安裝好,以方便我們去分析與研究EDK2's Build.py

那有哪些東西要先安裝呢? 我個人偏好Visual Studio,因此我選擇了VS2010+PTVS 來當作是Debugger,安裝簡單! 當然你也可以選擇使用Eclipse Classic IDE + PyDev 的除錯方式 (感謝鳥公司John大大傾囊教學)!

所以如果你也想學Python,請跟著我一起安裝:

1. VS2010

2. Python tool for Visual Studio
https://pytools.codeplex.com/

3. Python 2.7.6 (目前EDK2還沒支援到Python 3.x,建議是安裝2.5.x/2.7.x)
http://www.python.org/download/releases/2.7.6/

Eclipse Classic IDE+PyDev

VS2010+PTVS


(未完待續...)










星期二, 1月 21, 2014

文字檔格式真多,那怎麼去區別ASCII/Big5/UTF-16/UTF-8呢?




以前處理一些字幕檔的時候,慢慢的累積了一些區別文字檔編碼的經驗,這邊就分享一下個人經驗,不過經驗歸經驗不一定正確,所以各位就將就點看,把他當成是解決你問題的一個進入點,然後再去搜尋相關知識來解決各位遇到的問題吧!

首先,我們先討論一下文字檔到底是啥? 其實不管是甚麼檔案,儲存的時候都是BINARY資料,差別就在於讀取檔案的人想要如何呈現給你看而已~

例如:

執行檔=二進制資料   , OS 讀取表頭判定他可以被執行,然後執行他!
文字檔=二進制資料   , Editor 讀取他然後依照一些編碼原則判定他,然後再去字型檔撈出字型顯示給你看!

所以啦,這篇文章要說的就是模擬一下如果我寫了一個Editor,我要怎麼區別不同的編碼格式!

從上面的圖中可以看到,一開始的時候我會先去讀取兩個位元組,這是因為Unicode(UTF-16)檔案會有一個標記來標記他是Unicode存取方式是Big Endian還是Little Endian (低位元組在記憶體低位址, x86常用) ,所以大家可以把UEFI 中的.uni 用16進制編輯器打開來看看,就會看到檔案最開頭有這個標記可以用來判斷~

如果沒有這個標記的檔案,我們就可以判斷為他可能是ASCII/UTF-8/Big-5的編碼方式,因為Big5是兩個位元組組成,他有他一定的規範,所以可以由這些規範來判別字元是不是Big5或只是單純ASCII的一個位元組而已~

除此之外,還有一個UTF-8比較討厭,因為UTF-16是固定兩個位元組儲存一個字元,所以像是英文"A"就會是0x0041 ,高位元組永遠是0x00,所以為了節省空間所以變成了可變位元組的編碼,因此一個字元可能由1~6 bytes組成,看樣子還有機會繼續延伸咧~

因此可以參考Wiki上的UTF-8的對應方式去判讀一個字元由幾個Bytes組成。

例如: 中文字 [這]
這=E9 80 99 (UTF-8)

第一個位元組的二進制是1110 1001前面的'1'代表全部是3 bytes,而後面的每個位元組的bit7:6就是對應Wiki上說的欄位表示  10xx xxxx, 10xx,xxxx

所以取出來的xxxx xxxxxx xxxxxx 
                            |       |              |____   011001    19
                            |       |____________   000000    0
                            |_________________  1001        9

U+9019 就是unicode的中文字 [這],所以UTF-8 也算是再重新編碼後的一種unicode表示碼!

不知道舉的這些例子看倌們能否了解?!

因為這不是我的專長,我是寫BIOS的,以上是經驗談~ Orz



星期二, 1月 07, 2014

UEFI Gop driver and PlatformGopPolicy

最近在除錯我自己從無到有DIY出來的EDKI codebase的問題,所以在這邊留一下筆記來記錄一下UEFI Gop driver遇到的問題~

問題描述: 
由於我們的系統比較特別,有eDP Panel 跟LVDS Panel(銷庫存),所以外掛了一顆eDP-LVDS IC,導致點亮VGA的方式變得複雜了點,另外我的CODEBASE目前還很陽春,所以只支援UEFI mode,也就是我要直接上UEFI GopDriver,而執行到UEFI Gop Driver後系統就當機了,為了這個問題所以把這隻Gop driver 反組譯,然後大致追了一下,然後把追CODE的筆記紀錄在下面!

筆記:
1) 他是一個EFI driver model driver,所以從DriverBinding Start()追進去看他做了甚麼事情
2) 底下是我整理的資料,因為沒有他的Source code,完全靠反組譯去猜測出底下的順序與動作,所以僅供參考,並不一定正確!
3)Root cause: 還不清楚,還在追...哈!

DriverBinding->Start()
{
   1..asm{RDTSC};
   2.ProgramIGD();
        a. OpenProtocol(Pciio) //準備用來讀取PCI Regs
        b. Pciio->Attributes(Enable BusMatser,MMIO,IOBASE) //啟動IGD設備
        c. OpenProtocol(DevicePath) 
        d.LocateProtocol (PlatformGopPolicy) //要求Platform firmware(也就是BIOS)提供VBT/Lid/Dock 的資訊
        e. PlatformGopPolicy->GetVbt(Address,Size);
        f. Config/Read IGD PCI Regs (DeviceId,RevisionId...etc)
        g.Read  Pch DeviceId and RevisionId.
        h.Init MMIO regs   // 目前還找不到相關文件說明這些暫存器在幹嘛
        i.Out 0x3c2,0x67
        j.Config MMIO regs 
        k. PlatformGopPolicy->PlatformLidStatus()
        l.  PlatformGopPolicy->PlatformDockStatus() if PlatformGopPolicy's revision > 0x0001 otherwise, ignore it.
        m.Create DDEV LinkedList (Display Device) //應該是參考Vbt去建立出來的資訊 CRT->eDP->EFP1->EFP2->EFP3
        n.Walk DDEV LinkedList to find out predefined DDEV and then try to enable it. (Hangup here.) //我當機在這裡
        o.Others //還沒追...應該是去產生一些protocol (EDID,brightness...etc) 或是devicepath 
   3.asm{RDTSC};
}

4)會被產生出來的Protocol掛自Child Handle上: 
a.DevicePath (09576E91-6D3F-11D2-8E39-00A0C969723B)
b.Undocument protocol (39487C79-236D-4666-87E5-09547CAAE1BC) : 不知道是幹嘛的...
c.EdidDiscovered (1C0C34F6-D380-41FA-A049-8AD06C1A66AA): 用來表示於顯示設備使用這個EDID.
d.GraphicOutput(9042A9DE-23DC-4A38-96FB-7ADED080516A):用來顯示影像
e.EdidActiveProtocol(BD8C1056-9F36-44EC-92A8-A6337F817986) : 正在顯示的設備使用這個EDID

如果SizeOfEdid !=0 代表EDID資料應該是有效的,應該可以檢查此Handle上面有沒有EDID Protocol來得到顯示設備的EDID,就像是Legacy 時呼叫INT 10h.