bloggerads

2014年12月30日 星期二

C# : virtual + override or (virtual) + new

關鍵字是用來決定哪些成員要使用子類別中的定義

//      A a = new B(); //virtuall - new example
//
//                     A  ------------->  print (Call A)
//                     |
//    ------------->   B                  print (Call B)
//   

namespace virtual_new
{
    public class A
    {
         public virtual void print() { Console.WriteLine("Call A"); } // virtual here is not necessary!
    }
    
    public class : A
    {
         public new void print() { Console.WriteLine("Call B");  }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            A a = new B();
            a.print();  // Output: Call A
        }
    }
}

2014年12月10日 星期三

C++ Compiler : g++ 指令介紹

以下提供一些g++指令參數解釋,基本上就是用來生成執行檔/dll檔/obj檔

# Generate file.o

g++ -c file.cpp  

# Generate Assembly : file.s 

g++ -S file.cpp  

# Convert file.o to file_dll.dll (需要先把cpp檔做成obj檔再來轉成dll檔)

g++ -shared file.o -o file_dll.dll 

# Generate file.exe

g++ file.cpp  -o file 

# Generate file.exe from object and cpp files

g++ file.cpp  obj.o -o file 

# Generate main.exe from dll and cpp files

g++ file_dll.dll main.cpp -o main

# Alternative solution to generate main.exe from file_dll.dll  and main.cpp ,  -L. means current dir

g++ -L. -lfile_dll main.cpp -o main 

# Show all the warning
gcc -Wall -o main main.c

# Warning as error
gcc -Wall -Werror -o main main.c

2014年11月7日 星期五

ATA: Security Erase flow

ATA 清理硬碟的command有兩種:
  1. Trim command: 06h
  2. Security Erase command: F4h
最安全的方式是對碟機下security erase command, 才可以保證把舊硬碟送人後資料不會被扒出來。

這邊介紹security erase command flow, 往往市面上的軟體都需要熱插拔碟機,但這邊提供的方法不需要,因此可以適用在PCIe AHCI SSD上

步驟如下:

1. 用ATA Set feature command通知碟機將Comreset 轉成Hardware reset (因為開機Bios會對你的碟機下Security freeze lock讓碟機變成state machine:frozen state。如果不這樣做就得先熱插拔碟機才能讓碟機回到state machine:not frozen, 才可以下security erase)

下法就是透過Set feature command (EFh), feature=0x90 and count=0x06,來disable software setting preservation
這樣之後我們下的Comreset才會被轉成 hardware reset, 讓碟機回到not frozen state


2. 接著透過 port reset 或 HBA reset 發出 COMRESET

3. 下security erase command之前要先設定密碼 (也就是提升權限才能下這個command,最後security erase也會一併erase掉這個密碼)

就是以下這三步驟:
  1. SECURITY SET PASSWORD: F1h
  2. SECURITY_ERASE_PREPARE: F3h
  3. SECURITY_ERASE_UNIT: F4h
通常SSD幾秒內就完成碟機的erase(基本上還是要看碟機廠商怎麼做),傳統轉盤的碟機就會比較久甚至有些是天荒地老的久XD.

2014年10月25日 星期六

C/C++一些經驗談

一些雜談,提供個人Coding 的經驗

1. 無窮迴圈的例子: 沒有注意宣告的變數範圍上限或邏輯錯誤而溢位產生無窮迴圈
  1. for (unsigned char x=0; x<=0xff; x++) ;
  2. for (unsigned char x=0xff; x>=0; x--) ;
2. 宣告雙指標的時機
用指標來管理記憶體,而雙指標(指標的指標)就是用指標管理指標
實務上在函式間傳遞指標的位址時, 就必需要傳遞指標的指標。舉個記憶體管理的例子,假如我有一串link list如下p1~p6,就可以透過雙指標pp start/pp tail指定鏈結串鏈其中一段的起始節點位址(&p2)和尾部節點位址的(&p5), 而PP start/ PP tail就是雙指標的型態

2014年9月26日 星期五

C 結構(structure) 的一些注意事項 (C89 / C99 / 對齊,Alignment)

1. 結構變數初值給定

首先,先宣告一個結構型態, 接下來再介紹兩種初值給定方法(C99/C89):
+  struct test
+  {
+    const char* cap;
+    unsigned char data_0;
+    int data_1;  
+  };

support C99 mode (現在新版本的GCC都有support C99 mode 的結構變數初值給定方法。 這種方法的優點是未來如果結構調整變數的位置,宣告變數初值不用跟著調整):

+  struct test node = 
+  {
+      .cap="first", 
+      .data_0=10,
+      .data_1=5
+  };

以下是傳統(C89 mode)的寫法 (很可惜的是目前Watcom C版本(1.9)尚未支援C99 mode結構變數的初值給定方法),所以還是用舊有的寫法:

+  struct test node = 
+ {
+      "first",   // cap
+      10,       // data_0
+      5          // data_1
+  };

2. 結構內變數對齊(alignment)的問題

2014年7月25日 星期五

在DOS下寫程式常會用到的中斷 (to DOS愛好者)

現在還在用Dos的人其實不少只是比較不顯眼 :P ,就我知道幾乎所有的x86系統在開發過程中,還是以Dos tool來驗證chipset問題。(畢竟誰會這麼閒重新在UEFI shell上開發以前在Dos下沒問題的程式XD)

我也是Dos的愛用者,開發過的Dos測試程式比在其他作業系統上的測試程式多得多,寫程式的功力也是從這邊開始練起。

基本上使用Watcom若是default使用protect mode, 那麼寫Dos程式幾乎跟在windows上感覺差不多,但是Watcom可以透過inline assembly神不知鬼不覺地使用原始 real mode 的中斷。

由於中斷很多,這篇僅列出我常使用的中斷給大家參考:

1. Access PCI configuration: INT 1A

提供範例函數來讀取PCI cfg data:
+
+  //Author: Martin Lee
+   const unsigned char PCI_FUNCTION_ID= 0xB1;
+   const unsigned char READ_CONFIG_DWORD 0x0A
+   
+   DWORD READ_PCI_CONFIG_DWORD(WORD BDF, WORD index)
+   {
+   
+      DWORD data;
+       __asm
+       {
+       // 1AB109 INT 1A - PCI BIOS v2.0c+ - READ CONFIGURATION WORD
+       // BH = bus number
+       // BL = device/function number (bits 7-3 device, bits 2-0 function)
+       // ECX = dword read
+       mov     BX,  BDF
+       mov     di,  index
+       mov     ah,  PCI_FUNCTION_ID
+       mov     al,  READ_CONFIG_DWORD
+       int     1ah
+       mov     data, ecx
+       }
+       return data;
+   }

2. 對碟機做讀寫: INT 13

3. 設定螢幕的顏色游標什麼的: INT 10 (Watcom有很多內建的函數可以使用,使用上方便又美觀), 像我這個介面就完全是呼叫Watcom 的library做的

(待續)

2014年6月27日 星期五

ATA overview

想要寫一支Driver來控制硬碟發送ATA command,必須了解三份Spec
  1. ATA (AT Attachment): 這是一份軟體的spec,定義了command的種類
  2. AHCI or IDE : 這是controller的spec, 說明如何控制controller發出ATA command給碟機
  3. SATA :定義HW(phy)的行為,如power management及一些encoding/decoding, Link規則...等等 
這邊列舉一些常見的ATA command, 並以我開發的tool, 下圖,來介紹一些常見的command。



  • 25h: Read DMA ext: 傳統的Read
  • 35h: Write DMA ext: 傳統的Write
  • 60h: Read FDMA Queued :這就是 NCQ read
  • 61h: Write FDMA Queued :NCQ write
  • ECh: Identify : 這個command帶有512Byte的table,用來提供host查詢碟機的能力
  • E0h: Standby Immediately: 用於斷碟機電前, host發此命令告訴碟機
  • EFh: Set feature: host可以透過這個command來開啟碟機一些能力,如Partial/Slumber...
  • 06h: Data Set Management :這就是Trim command,用來告訴碟機哪些LBA是無效的資料請碟機刪掉。這個command對SSD尤其重要,若沒有這個command, SSD firmware 裡的GC(Garbage Collection)將不會回收一些無效的LBA而導致硬碟用久後效能低落
  • 92h: Download Microcode: 碟機廠家用此command來update 碟機內部的firmware


2014年6月12日 星期四

UEFI : Boot Service: HandleProtocol () / OpenProtocol (), LocateHandle() / LocateHandleBuffer()


     在寫UEFI code的時候,常常需要找到某個特定的handle, 然後打開這個handle底下特定的Protocol。如找到某個Pci Controller Handle, 然後打開他底下的gEfiPciIoProtocolGuid, 之後才能順利access此controller的Pci Space/Mem Space, 使用的方法不外乎是呼叫Boot Service所提供的HandleProtocol () / OpenProtocol (), LocateHandle() / LocateHandleBuffer()。

這幾個function說明如下:

■ HandleProtocol():

Queries a handle to determine if it supports a specified protocol.
The HandleProtocol() function is still available for use by old EFI applications and drivers. However, all new applications and drivers should use OpenProtocol() in place of HandleProtocol().

注意spec有說明HandleProtocol ()這個function應該要由OpenProtocol()來取代。因為它其實是長這樣的

EFI_STATUS
HandleProtocol (
IN EFI_HANDLE Handle,
IN EFI_GUID *Protocol,
OUT VOID **Interface
)
{
return OpenProtocol (
          Handle,
          Protocol,
          Interface,
          EfiCoreImageHandle,
          NULL,
          EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
          );
}

■ OpenProtocol()

Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the handle, it opens the protocol on behalf of the calling agent. This is an extended version of the EFI boot service HandleProtocol().

■ LocateHandle() / ■ LocateHandleBuffer() <== 這個比較常用!!

先分別看兩個的原型

typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_HANDLE_BUFFER) (
          IN EFI_LOCATE_SEARCH_TYPE SearchType,
          IN EFI_GUID * Protocol OPTIONAL,
          IN VOID *SearchKey OPTIONAL,
          IN OUT UINTN *NumberHandles,
          OUT EFI_HANDLE **Buffer
);
typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_HANDLE) (
          IN EFI_LOCATE_SEARCH_TYPE SearchType,
          IN EFI_GUID * Protocol OPTIONAL,
          IN VOID *SearchKey OPTIONAL,
          IN OUT UINTN *BufferSize, // On input, the size in bytes of Buffer. On output, the size in bytes of the array returned in Buffer (if the buffer was large enough) or the size, in bytes, of the buffer needed to obtain the array (if the buffer was not large enough).
          OUT EFI_HANDLE * Buffer // The buffer in which the array is returned
);

Description

The LocateHandle() function returns an array of handles that match the SearchType request. If the input value of BufferSize is too small, the function returns EFI_BUFFER_TOO_SMALL and updates BufferSize to the size of the buffer needed to obtain the array.

兩者差別在LocateHandle()需要自己”分配allocate”跟釋放Buffer。而LocateHandleBuffer() 使用者僅需釋放Buffer,allocate buffer 由此函式做掉

2014年6月9日 星期一

Demonstrate how macro CR works

在UEFI的code裡看到很多這樣的用法, 所以追根究底把它弄懂。用法是: 如果傳進一個函數裡面是某個結構成員的位址,可以用這個巨集回推出主結構的起始位址。 

+    /*    
+    原始定義: 
+    #define _CR(Record, TYPE, Field) 
+          ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))
+      
+    用途: 由結構成員的位址求得整個結構的起始位址
+    
+    Record:該成員的位址
+    TYPE:該成員所屬結構的型態
+    Field:該成員
+    (CHAR8 *) (Record):該TYPE結構成員的實際位址
+    (CHAR8 *) &( ( (TYPE *) 0)->Field):該成員在結構中的相對偏移量
+    
+    兩個做相減之後便可取得結構頭的位址,最後以(TYPE *)作強制轉換。
+    
+    */
+
+    #define _CR(Record, TYPE, Field)   
+      ((TYPE *) ((char *) (Record) - (char *) &( ((TYPE *)0)->Field)) )
+    
+    typedef struct _MyStru {
+            char a;
+            char b;
+            char c;
+    } MY_TYPE;
+    
+    void main()
+    {
+      MY_TYPE *pd;
+        
+      printf("Find pd address by CR: %X \n", _CR(&(pd->c), MY_TYPE, c) );
+      printf("pd address: %X \n", pd );  
+    }

2014年5月29日 星期四

makefile example in windows

path
|
+--scr
|   +--a.txt
|   +--b.txt
|
+--dest


@IF EXIST "src" (
@ECHO src exist
)

REM set current path to variable
@set current=%cd%
@cd %current%/src

REM Don't show command in screen by add @
@

REM Show something
@ECHO Show Something..

REM Copy a a.txt from src folder to dest folder
cp src/a.txt dest

REM Copy all files from src folder to dest
cp -r src/* dest

REM Jum To Tag
@GOTO EXIT
:EXIT

REM create a new folder
mkdir NewFolder

2014年5月26日 星期一

PCI 相關spec 隨手紀錄 (To Be Continued)

# Type 0 PCI header register介紹
讀外插PCI controller的option Rom需先enable option rom access(ERBAR.bit0=1)
=>先將Expansion Rom BAR bit0設為1再access Expansion Rom BAR address(option rom address)

Bios階段enable MMIO access(command.bit1=1), enable IO access(command.bit0=1) 以及打開Bus Master(command.bit2=1)讓device可以主動發出memory cycle

# Configuration Space accessing

1. 如果是寫DOS的程式,透過 Int 1A 可以 access 超過 0xff 這個範圍

2. CF8, CFC方法: (發 IO transaction)
Read 就是Write address to 0xCF8, Read Dword data from 0xCFC 
Write 就是Write address to 0xCF8, Write Dword data to 0xCFC 



+  // 示範Read, Author: Martin Lee
+  DWORD ReadPci( CFG_ADDRESS  addr)
+  {
+      DWORD val;
+      DWORD daddr = addr.all | BIT(31);
+      WORD  oport = 0xcf8;
+      WORD  iport = 0xcfc;
+      
+      __asm{
+      mov eax, daddr
+      mov  dx, oport
+      out  dx, eax
+      mov  dx, iport
+      in  eax, dx
+      mov DWORD ptr val, eax
+      }
+      return val;
+  }

3. 直接MMIO accessing: (發 Memory transaction)
這個方法必須找到MMIO base address(x86通常都會在E000_0000H,這個位址沒有絕對要看chipset的romsip決定)來算出真正Bus/Device/Function/Register的位址,
                                                            
MMIO Address = MMIO_BASE_Addr + { bus number[27:20], device number[19:15], function number[14:12], extended register number[11:8], register number[7:2], offset [1:0] }.

#define PCIEX_BASE_ADDRESS   0xe0000000 
#define PCIE_CFG_ADDR(bus, dev, func, reg) \
((UINTN)(PCIEX_BASE_ADDRESS + ((bus) << 20) + ((dev) << 15) + ((func) << 12) + (reg) ))

# About PCI to PCI bridge:





2014年5月24日 星期六

SATA Power Management

SATA PHY有四種state, 需要注意回到PHYRDY的時間有沒有follow spec
  1. PHYRDY
  2. Partial:  <10us
  3. Slumber: <10ms
  4. DevSleep: <20ms
發動的時機有兩種: HIPM / DIPM,一個是Host主動發起,一個是device主動發。

想知道這個碟機有support什麼樣的power management能力可以看Identify table

 Word 76, bit 9: Support HIPM
 Word 76, bit 14: Support Device auto slumber
 Word 78, bit 3: Support DIPM
 Word 78, bit 8: Support DEVSLP
 Word 79, bit 3: Enable DIPM
 Word 79, bit 8: Enable DEVSLP

以下是控制AHCI controller來做HIPM/DIPM實驗:

HIPM:

  Partial:
  • PxCMD &= (~CMD_ASP) //mute bit 27
  • PxCMD |= CMD_ALPE //set bit 26
  • PxSCTL.IPM =0 // mute bit 11~8

 Slumber:
  • PxCMD |= CMD_ALPE | CMD_ASP //set bit 26 & bit 27
  • PxSCTL.IPM =0 // mute bit 11~8

發個ATA command來trigger, 然後Check PxSSTS.IPM 就知道有沒有成功


DIPM:

 發ATA command(Set Feature, EFh) 開啟碟機這項功能


2014年4月26日 星期六

IDE (Integrated Drive Electronics) controller

IDE是早期用來控制碟機的spec, 目前已完全被AHCI所取代。

Q: 為什麼還是要學IDE protocol呢?
A: 因為Intel目前為止的設計,還是保留著支援IDE的彈性,在一些老系統(如xp)也只有IDE driver。通常都會讓使用者自行透過Bios選項將AHCI controller切換成IDE controller,這時Driver/Bios的控制硬碟方式就要改成IDE,所以還是有學習的價值。

Q: Why not default use IDE in modern PC?
A: IDE原理是控制IO register去下ATA command,除了速度慢以外。最大問題是他的設計是古老的思維而限制住他未來擴充的彈性,因此在2003年Intel release AHCI 用以取代IDE。

+ 本文開始 +

spec請參考以下這三分。古老的spec設計通常都比較簡單易懂
  1. PCI IDE Controller Specification Revision  1.0    3/4/94
  2. Programming Interface for Bus Master IDE Controller Revision  1.0     5/16/94
  3. Information Technology - AT Attachment - 8 ATA/ATAPI Command Set 
一個IDE controller規定了四個channel, 基本上有兩種mode, Compatibility and Native。

Compatibility mode:
  • 固定的IO register(Primary cmd/ctrl = 0x1f0~0x1f7/0x3f6, Secondary cmd/ctrl = 0x170~0x177/0x376)位址和固定的IRQ(14, 15)。
Native mode:
  • 由系統來assign: Primary cmd/ctrl = bar#0/bar#1, Secondary cmd/ctrl = bar#2/bar#3, 
需要注意的是control register 的位址是 ctrl port + 2

Q: 如何知道現在這個IDE是Compatibility or Native?
A: 在PCI header, Base-Class(09h), Sub-Class(0Ah), Interface:(0Bh) 定義了class code, 如果programmable indicator 不是fixed,operating mode可由程式來填入改變

Programmable Indicator: Indicate if controller support both mode (1), or fixed mode(0)
Operating Mode: Determine mode (0: compatibility, 1: native) 
Q: 如何找到硬碟插在哪個channel上並且發送ATA command?
A: 可以透過設定device register的bit 4, 然後看status是否回0x50來判斷channel上是否有device, 


接著請參考ATA spec定義的欄位,填寫要發的 command


Q: Bus Master code怎麼寫?
A: Bar#4 給定了Bus Master IO base address, 剩下的部分請參考圖,和原文spec step by step, 照做就可以把code寫出來了。


注意Command Register的Bit 3(read/write control), 下read command 時 bit3要設為 1, write command 時 bit3設為 0
programming bus master IDE, 請參考以下原文
3.1. Standard Programming Sequence
To initiate a bus master transfer between memory and an IDE DMA slave device, the following steps are required:

1) Software prepares a PRD Table in system memory. Each PRD is 8 bytes long and consists of an address pointer to the starting address and the transfer count of the memory buffer to be transferred. In any given PRD Table, two consecutive PRDs are offset by 8-bytes and are aligned on a 4-byte boundary.


2) Software provides the starting address of the PRD Table by loading the PRD Table Pointer Register . The direction of the data transfer is specified by setting the Read/Write Control bit. Clear the Interrupt bit and Error bit in the Status register.


3) Software issues the appropriate DMA transfer command to the disk device.


4) Engage the bus master function by writing a '1' to the Start bit in the Bus Master IDE Command Register for the appropriate channel.


5) The controller transfers data to/from memory responding to DMA requests from the IDE device.


6) At the end of the transfer the IDE device signals an interrupt.


7) In response to the interrupt, software resets the Start/Stop bit in the command register. It then reads the controller status and then the drive status to determine if the transfer completed


successfully.




2014年4月14日 星期一

PCIe Capability (0x10)



列出常參考的部分:


# Offset 0x0C (Link Capabilities)
=> Link能力
# Offset 0x10 (Link Control)
=> 電源控制 bit[1:0]: ASPM, 00b(Disabled) / 01b(L0s) / 10b(L1) /11b(L0s+L1)

# Offset 0x12 (Link Status)

=> 速度 bit[3:0]: 1=>Gen1(2.5GT), 2=>Gen2(5GT), 3=>Gen3(8GT), Gen1/Gen2採8b/10b編碼,實際速度約打8折
=> 寬度 bit[9:4]: 1/2/4/8/16=>x1/x2/x4/x8/x16 lane



2014年4月5日 星期六

AHCI (Advanced Host Controller Interface)

AHCI是PC架構下常見的儲存裝置控制器,透過AHCI我們可以將ATA command以SATA的形式發送給device。

一個AHCI controller最多可以implement 32個port,AHCI spec厲害的地方是定義了NCQ command。也就是host可以先發送最多32個command給device, 由device來決定要先做哪個command。近年來拜NAND flash快速發展所賜, 配上NCQ command,硬碟終於可以跑到接近SATA 3所定義的物理極速600MB/s。請參考下面這張TOSHIBA 120G的SSD跑分


焦點拉回spec,AHCI在PC架構上是一個PCI 或PCIe controller, 他的class code是Rx[B:9]=0x010601。

MMIO base address定義在PCI CFG header就Bar#4,在開機時,Bios會依照AHCI spec要求assign 一個align to 8KB的MMIO的base address。access MMIO address 可以看到General Host Control Registers(0~0xFF) + port0~31 (每個port range為0x80)這兩大部分


從GHC registers我們可以知道這個controller的能力如這個AHCI controller implement哪些port可以讓software使用,發生中斷的原因以及透過這些register做Global host reset。

至於對某個port上的硬碟發command最主要是透過port control registers來辦到。透過port的register我們也可以發port reset這種局部reset來命令此port的SATA phy重新link。

Q: 如何對port發command?
A: 首先先把記憶體宣告好,把要發的command以 command FIS型態填在宣告的記憶體上,如果是帶資料的command則還需要把PRD Table描述好,並將其指到一個準備傳送或接收資料的記憶體位址(注意必須是Word aligned)。最後去set PxCI,command就可以發到碟機了。

最後附上精心製作的AHCI register表,祝大家都可以寫出屬於自己的AHCI driver


Overall Registers layout

PRDT layout



2014年4月1日 星期二

EBDA (Extended BIOS Data Area)

這篇是說明在Legacy Bios中,如何動態申請memory的規範。

第一次碰到Option Rom,我對使用記憶體第一個想法就是, 難道不能用Malloc這類的函式嗎? 答案是不行,因為在boot的階段是沒有C函式庫可以用的。因此要使用memory存放資料就必須透過EBDA所定義的規範從640KB內抓一快記憶體來用。

定義幾個欄位:
[40:13]: EBDA的起始位址, 單位是KB, 欄位是一個Word
[40:13] ] = EBDA的長度, 單位是KB, 欄位是一個Byte
[40:0E] = EBDA的起始segment, 欄位是一個Word

<範例> 申請 2KB的記憶體位址

step 1. 程式先去讀出以上這三個欄位的位址
  • [40:13] = 27Ch (KB) = 9F000h
  • [9F00:0] = 4
  • [40:0E] = 9F00h
step 2. 將EBDA起始位址下移2KB, 並在EBDA起始的第一個Byte加上2
  • [40:13] = 27Ch (KB) -2 = 27Ah (KB) = 9E800h
  • [9E80:0] = 4+2= 6
  • [40:0E] = 9E80h 

2014年3月23日 星期日

Bios Boot Spec

以下的內容僅適用在Legacy Bios, 早期的Bios (Legacy Bios)都是在軟體中斷下作文章。在UEFI的架構下很多都已不適用了。但因為CSM模組一直都還在,也就是還有人在使用所以是值得學習和了解的。

IPL:
  •  IPL 指的是可以啟動載入並執行作業系統的裝置。他包含了像是 Floppy, Hard drives, CD-ROM, PCMCIA conrtollers/cards, PnP Cards, Legacy cards 甚至像是 Network, Serial port, Parallel port 等等可開機的實體或虛擬裝置。
  •  所有的 IPL 可以被歸類成下列三種
  •  1. BAID
  •  2. PnP Card (可再細分為 BCV 和 BEV 兩種裝置)
  •  3. Legacy IPL Device
int 19h: 選擇用哪種裝置開機 (如光碟機, 硬碟, 網卡等等)
  •  是 80x86 的 BIOS 中斷之一(又稱冷開機中斷),  
  •  This vector is taken after the POST in order to attempt to load and
  •  execute any bootstrap code on diskette or hard disk.
  • 在呼叫之後,它會根據 IPL Priority 中的裝置,呼叫其 Boot handler
BAIDs:
  •  A BIOS Aware IPL Device is any device that can boot an O/S, but requires the BIOS to have specific code to support it.
  •  (No Option ROM, 通常啟動的程式碼內建於 INT 19h (BIOS Bootstrap loader) 的服務之中)
BEV:
  •  A Bootstrap Entry Vector is a pointer that points to code inside an option ROM that will directly load an O/S. The BEV resides in a PnP option ROM Expansion Header. (for LAN )
BCV:
  •  A Boot Connection Vector is a pointer that points to code inside the option ROM that will perform device initialization, detect if a peripheral (such as a SCSI hard drive) is attached, and optionally hook INT 13h. 
IPL table (boot type): (int 19h)
  •  Floppy
  •  HDD → BCV table inside
  •  CD-ROM
  •  BEV #1
  •  BEV #2
BCV table (enumerate storage): (int 13h)
  •  SATA/PATA 
  •  Cards/EMMC
  •  USB
  •  BCV #1
  •  BCV #2

2014年3月22日 星期六

UEFI : Shell Command

首先要準備一個USB隨身碟,將Shell.efi, Bootx64.efi, ShellX64.efi 放到EFI\BOOT這個資料夾

先進到 Bios 選單關掉 secure boot. (若Bios本身就不支援secure boot則這步可省略)

開機Bios自己會到EFI\BOOT\目錄下執行shell, 接著會看到像是下面這個Device mapping table:

fs0: // file system 0
blk0:
blk1:

# 進入隨身碟
Shell>fs0:

# 檢查目錄裡的檔案(-b代表一頁一頁顯示)
fs0:\>ls -b

fs0:\>cd -b

# 查詢指令
fs0:\? -b


*** 好用的 EFI tool ***

UDK2014內含有許多APP可以直接在EFI shell下使用,如
EdkShellBinPkg\ 的 HexEdit.efi, Edit.efi,...等等

2014年3月19日 星期三

ASCII table

因為常在DOS下寫測是程式,總是會加上一些ASCII做的文字方塊,每次都是寫code再一邊查ASCII。
乾脆把表放上來,方便參考

這張圖片取自網站(This photo is originally from the website as follow):
https://commons.wikimedia.org/wiki/File:Ascii-codes-table.png
http://www.theasciicode.com.ar/ascii-printable-characters/lowercase-letter-h-minuscule-ascii-code-104.html

2014年3月6日 星期四

Assembly : 設定 register的 bit為0 or 1

1. 將 eax 的 bit 3 清為 0  

+         test   eax,  1  shl  3
+         jz      @f
+         xor    eax,  1  shl  3
+  @@:                             ;; eax bit 3 is 0 now

2. 將 eax 的 bit 3 設為 1       

+    or     eax,  1  shl  3


2014年3月5日 星期三

SATA Spec

1. 介紹SATA的四個Layer:


•Application Layer:  
  • Overall  ATA  command  execution

•Transport Layer:  
  • Placing control information and data to be transferred between the host and device in a packet/frame (FIS)

•Link Layer:  
  • Taking data from the constructed  frames, encoding  or  decoding each byte using 8b/10b, and inserting control characters such that the 10-bit stream of data may be decoded correctly

•Physical Layer: 
  • Transmitting and receiving the encoded information as a serial data stream on the wire
2. Primitive
    用來控制和提供串列線路的狀態,由4個Byte所組成

3. BURST:  
  • OOB signaling is a pattern of ALIGNP primitives or Dwords composed of D24.3 characters and idle time and is used to initialize the Serial ATA interface (由特定的Primitive或4個D24.3所組成)
4. OOB信號:
  • COMRESET (Originate from Host)/ COMINIT (Originate from Device)
  • COMWAKE (for both host & device)
  • Consists of 6 bursts with different time gap

5. Speed negotiation:



6. SATA FIS:





UEFI C coding stytle

最近接觸UEFI的code, 她是C語言架構所組成並使用VC++或DDK來compiler,coding上跟C幾乎是一樣。但是Intel工程把C的指標發揮到淋漓盡致, coding style很漂亮,所以我寫這篇文章: UEFI C Coding style,用來練習這種coding方式

UEFI Bios 定義許的protocol夾雜許多callback function的prototype。目的是固定函數的輸入輸出型態使其成為spec的一部分,然後將protocol 傳給所需要的driver使用

我也來學學UEFI的方式寫個C程式來試試

#include <cstdio>

int add( int x, int y ) {
   return x+y;
}
int add2( int x ) {
   return x+2;
}

typedef int (*ADD_CALLBACK)(int, int);
typedef int (*ADD2_CALLBACK)(int);

//
// Protocol type of Service
//
typedef struct
{
    unsigned char rev;
    ADD_CALLBACK AddCallBack;
    ADD2_CALLBACK Add2CallBack;    
}SERVICES;

int 
main ()
{
    SERVICES gPS = {0, add, add2};
    //(&gPS)->AddCallBack=add;
    //(&gPS)->Add2CallBack=add2;
    printf("%d\n", (&gPS)->AddCallBack(1,2));
    printf("%d\n", (&gPS)->Add2CallBack(3));

   return 0;
}

2014年1月22日 星期三

Change Code::Blocks theme

1. 關閉 Code::Blocks

2. 到http://wiki.codeblocks.org/index.php?title=Syntax_highlighting_custom_colour_themes 將此網頁提供的XML檔案新增到本地,並複製成一個.config檔

3. 找到 Code::Blocks提供的執行檔 cb_share_config.exe, 填好以下的欄位點Transfer再點Save
  • Source configuration file:  填入step 2存的.config檔位置
  • Destination configuration file: 填入Code::Blocks預設.conf 路徑 (C:\Users\(Your_Name)\AppData\Roaming\CodeBlocks)

2014年1月3日 星期五

WATCOM C 使用教學

Watcom官網download watcom編譯器 (1.9版, 2010),安裝完後會在"開始"出現IDE的圖示, 開啟它


先到File->New Project新增一個project (預設為noname),然後選你要編譯成哪種環境下執行的應用程式。我主要是用Watcom編譯DOS程式,而且我要直接跑在protect mode上,因此選擇DOS - 32 bit。至於要用哪種方法進入32位元,我比較常選的是PMODE/W  Executable(.exe), 這個執行檔執行時會自行先進入protect mode。
另一個選擇是 DOS/4GW Executable(.exe), 編譯成這個執行檔則程式的運行是寄生在DOS/4GW下,因此必須把dos4gw.exe放在同個目錄下程式才能正確執行。


 環境選擇好了就在白色處點右鍵,加入你寫的.c/.h/.cpp/.hpp檔


最後點選紅色框框處來執行,若編譯沒問題,就會產生一個noname.exe檔案了


完成。