EventLog支持异常/报错/安全事件信息记录

功能描述:当风扇,键盘不在位/ 内存,硬盘有变化时,Setup界面记录事件信息,并根据 日期 时间 事件显示出来,也可以清除所有记录。

一、创建EventLog的Dxe Driver

事件日志的驱动包括四个部分:追加一条记录,删除记录,覆盖记录,得到下一条记录。
四个部分都涉及到链表的操作
定义一个链表的全局变量,该变量的数据代表当前记录,forwardLink表示指针指向前一个链表,backLink表示指针指向后一个链表。

LIST_ENTRY                            mEventLogList;
struct _LIST_ENTRY {
  LIST_ENTRY  *ForwardLink;
  LIST_ENTRY  *BackLink;
};

每一条记录的结构体包括,链表指针和内容(事件,日期,事件)

EFI_EVENT_LOG_DATA                    *EventLog;
typedef struct {
  UINT32                    Signature;
  LIST_ENTRY                Link;
  EVENT_LOG_ORGANIZATION    *Buffer;
} EFI_EVENT_LOG_DATA;
typedef struct {

  //
  //Log Header is optional, default is no header
  //
  UINT8   Type;
  UINT8   Length;

  UINT8   Year;
  UINT8   Month;
  UINT8   Day;
  UINT8   Hour;
  UINT8   Minute;
  UINT8   Second;
  UINT8   DataFormatType;
  UINT8   Data[8];
  //
  //Log Variable Data is optional
  //
} EVENT_LOG_ORGANIZATION;

1,追加一条记录

EventLog支持异常/报错/安全事件信息记录_第1张图片
追加记录使用插入头链表的方法,由图可以看出,追加记录的初始地址 = 当前记录初始地址+一条记录的大小

 CopyMem ((UINT8*) ((UINTN) EventLog->Buffer + NumBytes - OptionDataSize), OptionLogData, OptionDataSize);
 InsertTailList (&mEventLogList, &EventLog->Link);

2、删除全部记录

初始化链表就可以删除链表里的记录

InitializeListHead (&mEventLogList);

3、覆盖记录

先初始化再追加记录

InitializeListHead (&mEventLogList);
 CopyMem ((UINT8*) ((UINTN) EventLog->Buffer + NumBytes - OptionDataSize), OptionLogData, OptionDataSize);
 InsertTailList (&mEventLogList, &EventLog->Link);

4、读取下一条记录

1)得到第一条记录
2)一直查询直到匹配输入的一条记录,匹配成功返回下一条记录地址

 Link = mEventLogList.ForwardLink;
  while (Link != &mEventLogList) {
    EventLog = DATA_FROM_EFI_EVENT_LOG_THIS(Link);
    if (EventLog->Buffer == *EventListAddress) {
      Link = Link->ForwardLink;
      if (Link == &mEventLogList) {
        return EFI_NOT_FOUND;
      }
      
      EventLog = DATA_FROM_EFI_EVENT_LOG_THIS(Link);
      *EventListAddress = (VOID *) EventLog->Buffer;
      return EFI_SUCCESS; 
    }
    
    Link = Link->ForwardLink;
  }

5、安装DXE Driver的protocol,提供日志读写、删除、追加功能方法

ELPrivate->Signature                      = EVENT_LOG_SIGNATURE;
  ELPrivate->DevicePtr                      = NULL;
  ELPrivate->GPNVBase                       = (UINTN)mGPNVBase;
  ELPrivate->GPNVLength                     = GetGPNVSize ();
  ELPrivate->EventLogService.LogAddress     = (UINTN)mGPNVBase;
  ELPrivate->EventLogService.Write          = EfiWriteEventLog;
  ELPrivate->EventLogService.Clear          = EfiClearEventLog;
  ELPrivate->EventLogService.ReadNext       = EfiReadNextEventLog;
//  ELPrivate->EventLogService.DetectDevice   = FlashFdDetectDevice;
  ELPrivate->EventLogService.OverWrite      = EfiOverWriteEventLog;

  ELPrivate->Handle = NULL;
  Status = gBS->InstallProtocolInterface (
                  &ELPrivate->Handle,
                  &gEfiEventLogProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &(ELPrivate->EventLogService)
                  );

二、调用Event log Dxe Drivers

1)通过locateprotocol 得到驱动接口
2)调用 读取下一条记录的 遍历事件链表
3)事件链表值进行组合拼装成需要的格式,更新到Setup表格中

Time.Year   = BcdToDecimal8(EventLog->Year) + 2000;
        Time.Month  = BcdToDecimal8(EventLog->Month);
        Time.Day    = BcdToDecimal8(EventLog->Day);
        Time.Hour   = BcdToDecimal8(EventLog->Hour);
        Time.Minute = BcdToDecimal8(EventLog->Minute);
        Time.Second = BcdToDecimal8(EventLog->Second);

        ZeroMem(String, sizeof(String));
        UnicodeSPrint(String, sizeof (String), L"%04d/%02d/%02d           %02d:%02d:%02d",
                    Time.Year,Time.Month,Time.Day,Time.Hour,Time.Minute,Time.Second);
        StrRef = HiiSetString (mHiiHandle, 0, String, NULL);

        ZeroMem(String, sizeof(String));
        QueryTable (SELTypesTable, sizeof(SELTypesTable)/sizeof(TABLE_ITEM), EventLog->Type, String);
        Info = HiiSetString (mHiiHandle, 0, String, NULL);

        HiiCreateTextOpCode (StartOpCodeHandle, StrRef, STRING_TOKEN (STR_EMPTY), Info);

你可能感兴趣的:(BIOS,链表,数据结构)