bloggerads

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 );  
+    }