UEFI Driver編寫

最近有想在UEFI SHELL下實現所有設備的測試和訪問,而且要做的平臺通用性,UEFI的protocol很好支持,但是很多硬件的驅動是在PEI階段或者沒有加入規範,於是按照driver的形式寫這些驅動,需要調用的時候去找這些driver的GUID來調用,這樣整個調用框架不變,只要每次加載不同平臺的driver就可以。有點類似linux的思路,下面代碼均載錄EDK SHELL。


1、首先,定義一個GUID,這個GUID是唯一的,並且不能重複,以後就是通過GUID來找這個Driver。

#define EFI_CPU_ARCH_PROTOCOL_GUID \
  { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } }

2、然後定義一個方法的集合,比如EnableInterrupt、DisableInterrupt。這裏的EnableInterrupt、DisableInterrupt是函數指針,具體的實現後面會講到

typedef struct _EFI_CPU_ARCH_PROTOCOL   EFI_CPU_ARCH_PROTOCOL;

///
/// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
/// Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt
/// vectors and exception vectors, reading internal processor timers, resetting the processor, and
/// determining the processor frequency.
///
struct _EFI_CPU_ARCH_PROTOCOL {
  EFI_CPU_FLUSH_DATA_CACHE            FlushDataCache;
  EFI_CPU_ENABLE_INTERRUPT            EnableInterrupt;
  EFI_CPU_DISABLE_INTERRUPT           DisableInterrupt;
  EFI_CPU_GET_INTERRUPT_STATE         GetInterruptState;
  EFI_CPU_INIT                        Init;
  EFI_CPU_REGISTER_INTERRUPT_HANDLER  RegisterInterruptHandler;
  EFI_CPU_GET_TIMER_VALUE             GetTimerValue;
  EFI_CPU_SET_MEMORY_ATTRIBUTES       SetMemoryAttributes;
  ///
  /// The number of timers that are available in a processor. The value in this 
  /// field is a constant that must not be modified after the CPU Architectural 
  /// Protocol is installed. All consumers must treat this as a read-only field.
  ///
  UINT32                              NumberOfTimers;
  ///
  /// The size, in bytes, of the alignment required for DMA buffer allocations. 
  /// This is typically the size of the largest data cache line in the platform. 
  /// The value in this field is a constant that must not be modified after the 
  /// CPU Architectural Protocol is installed. All consumers must treat this as 
  /// a read-only field.  
  ///
  UINT32                              DmaBufferAlignment;
};

3、定義好方法後,可以用InstallProtocolInterface,把driver具體實現掛接上去。

  //
  // Install CPU Architectural Protocol
  //
  Status = gBS->InstallProtocolInterface (
                  &mHandle,
                  &gEfiCpuArchProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &mCpuArchProtocol
                  );


其中

mHandle :如果爲NULL,則系統會自動生成一個Handle,加入到系統Handle鏈表裏

gEfiCpuArchProtocolGuid:即是開始定義的GUID

EFI_NATIVE_INTERFACE:系統參數,只有這一種類型

mCpuArchProtocol:driver的具體實現,具體定義如下

//
// The Cpu Architectural Protocol that this Driver produces
//
EFI_CPU_ARCH_PROTOCOL       mCpuArchProtocol = {
  FlushCpuDataCache,
  EnableInterrupt,
  DisableInterrupt,
  GetInterruptStateInstance,
  Init,
  RegisterInterruptHandler,
  GetTimerValue,
  SetMemoryAttributes,
  1,
  4,
};

然後EnableInterrupt,DisableInterrupt都是函數名,定義了具體的方法如下:

/**
  This function enables interrupt processing by the processor.

  This function implements EnableInterrupt() service of CPU Architecture Protocol.
  This function enables interrupt processing by the processor. This function is
  used to implement the Boot Services RaiseTPL() and RestoreTPL().

  @param  This              The EFI_CPU_ARCH_PROTOCOL instance.

  @retval EFI_SUCCESS       Interrupts are enabled on the processor.
  @retval EFI_DEVICE_ERROR  Interrupts could not be enabled on the processor.

**/
EFI_STATUS
EFIAPI
EnableInterrupt (
  IN EFI_CPU_ARCH_PROTOCOL          *This
  )
{
  EnableInterrupts ();
  return EFI_SUCCESS;
}

掛接後,每次Load這個Driver就可以,通過標準方法HandleProtocol來調用了。這樣就實現了一個Driver的編寫。


4、總結

1、Driver先要定義一個GUID,和方法的集合,然後再用InstallProtocolInterface掛接,之後Load到內存後就可以被系統調用了

2、這樣定義的Driver都可以用標準接口調用,而且BIOS中已經包含大部分的驅動,這樣在測試時,只要調用定義好的GUID,而Driver根據不同的

      平臺適配。

3、還有問題就是UEFI還有很多總線類的驅動沒有定義的很詳細,比如SVID,LPC等?


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章