玩转Mac OS之UEFI(二)----SimpleUefiLog

Simple_Uefi_Log

version:1.0.0

UefiLog.h



#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Protocol/SimpleFileSystem.h>

#define LOG_DEBUG(Format, ...) Log(DEBUG, __FILE__, __func__, __LINE__, Format, ##__VA_ARGS__)
#define LOG_TRACE(Format, ...) Log(TRACE, __FILE__, __func__, __LINE__, Format, ##__VA_ARGS__)
#define LOG_INFO(Format, ...) Log(INFO, __FILE__, __func__, __LINE__, Format, ##__VA_ARGS__)
#define LOG_WRAN(Format, ...) Log(WRAN, __FILE__, __func__, __LINE__, Format, ##__VA_ARGS__)
#define LOG_ERROR(Format, ...) Log(ERROR, __FILE__, __func__, __LINE__, Format, ##__VA_ARGS__)

typedef enum _LOG_LEVEL
{
    DEBUG = 1,
    TRACE,
    INFO,
    WRAN,
    ERROR
}LOG_LEVEL;

// 使用前初始化日志库
// Path  可以传入NULL,则log文件和程序同目录
// Path  非NULL时,需保证上级目录存在
EFI_STATUS
LogInit(
        IN CHAR16 *Path
        );

// 程序结束前调用,用来关闭打开的Log文件
VOID
LogClose(
         VOID
         );

VOID
SetShowLevel(
             BOOLEAN Is                // default 'true'
);

VOID
SetShowLine(
            BOOLEAN Is                // default 'true'
);

VOID
SetShowFuncName(
                BOOLEAN Is                // default 'true'
);

VOID
SetShowFileName(
                BOOLEAN Is                // default 'false'
);

VOID
SetShowTime(
            BOOLEAN Is                // default 'true'
);

VOID
Log(
    LOG_LEVEL level,
    CHAR8 *FileName,
    CHAR8 *FuncName,
    UINTN LineNum,
    CHAR16 *Format,
    ...
    );

UefiLog.c


#include "UefiLog.h"

#include <Library/BaseLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>

#include <Protocol/LoadedImage.h>
#include <Protocol/DevicePathToText.h>

#include <Guid/FileInfo.h>

#define MAX_MSG_SIZE  0x200

EFI_FILE_PROTOCOL *gFileHandle = NULL;
STATIC BOOLEAN ShowLevel = TRUE;
STATIC BOOLEAN ShowLine = TRUE;
STATIC BOOLEAN ShowFuncName = TRUE;
STATIC BOOLEAN ShowFileName = FALSE;
STATIC BOOLEAN ShowTime = TRUE;

VOID
SetShowLevel(
    BOOLEAN Is
)
{
    ShowLevel = Is;
}

VOID
SetShowLine(
    BOOLEAN Is
) 
{
    ShowLine = Is;
}

VOID
SetShowFuncName(
    BOOLEAN Is
)
{
    ShowFuncName = Is;
}

VOID
SetShowFileName(
    BOOLEAN Is
)
{
    ShowFileName = Is;
}

VOID
SetShowTime(
    BOOLEAN Is
)
{
    ShowTime = Is;
}

CHAR16 *
GetLevelString(
    LOG_LEVEL Level
)
{
    switch (Level)
    {
    case DEBUG:
        return L"[ DEBUG ]";
    case TRACE:
        return L"[ TRACE ]";
    case INFO:
        return L"[ INFO ]";
    case WRAN:
        return L"[ WARN ]";
    case ERROR:
        return L"[ ERROR ]";
    default:
        return L"[       ]";
        break;
    }
}

CHAR16 *
GetEfiTime(
    VOID
)
{
    EFI_TIME Time;
    EFI_STATUS Status;
    CHAR16 *TimeStr = NULL;
    Status = gRT->GetTime(
        &Time, 
        NULL
    );
    if (EFI_ERROR(Status))
    {
        Print(L"Get Time Failed: %r\n", Status);
        return L"1970-01-01 00:00:00";
    }

    TimeStr = CatSPrint(
        TimeStr,
        L"%d-%02d-%02d %02d:%02d:%02d",
        Time.Year,
        Time.Month,
        Time.Day,
        Time.Hour,
        Time.Minute,
        Time.Second
    );
    return TimeStr;
}

CHAR16 *
GetStrReplace(
    IN CHAR16 *Str,
    IN CHAR16 *OldStr,
    IN CHAR16 *NewStr
)
{
    UINTN LenStr;
    UINTN OldStrLen;
    UINTN Index = 0;
    CHAR16 *BStr = NULL;

    LenStr = StrLen(Str);
    OldStrLen = StrLen(OldStr);

    BStr = AllocatePool(LenStr);
    gBS->SetMem(
        BStr, 
        LenStr,
        0
    );

    for (Index = 0; Index < LenStr; Index++)
    {
        if (!StrnCmp(
            Str + Index, 
            OldStr, 
            OldStrLen
        ))
        {
            StrCat(
                BStr, 
                NewStr
            );
            Index += OldStrLen - 1;
        }
        else
        {
            StrnCat(
                BStr, 
                Str + Index, 
                1
            );
        }
    }

    StrCpy(
        Str, 
        BStr
    );

    return Str;
}

EFI_STATUS
GetCurrentPath(
    OUT CHAR16 **Path
)
{
    EFI_STATUS Status;
    EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol;
    EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToTextProtocol;
    
    Status = gBS->LocateProtocol(
        &gEfiDevicePathToTextProtocolGuid, 
        NULL, 
        (VOID **)&DevicePathToTextProtocol
    );
    if (EFI_ERROR(Status))
    {
        Print(L"Get DevicePathToTextProtocol Error: %r\n", Status);
        return Status;
    }

    Status = gBS->HandleProtocol(
        gImageHandle, 
        &gEfiLoadedImageProtocolGuid, 
        (VOID **)&LoadedImageProtocol
    );
    if (EFI_ERROR(Status))
    {
        Print(L"Get LoadedImageProtocol Error: %r\n", Status);
        return Status;
    }

    *Path = DevicePathToTextProtocol->ConvertDevicePathToText(
        LoadedImageProtocol->FilePath,
        TRUE,
        TRUE
    );

    return EFI_SUCCESS;
}

EFI_STATUS
OpenLogFile(
    OUT EFI_FILE_PROTOCOL **FileHandle,
    IN CHAR16 *Path
)
{
    EFI_STATUS Status;
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystemProtocol;
    EFI_FILE_PROTOCOL *Root = 0;

    Status = gBS->LocateProtocol(
        &gEfiSimpleFileSystemProtocolGuid,
        NULL,
        (VOID **)&SimpleFileSystemProtocol
    );

    if (EFI_ERROR(Status))
    {
        Print(L"Get SimpleFileSystemProtocol Error: %r\n", Status);
        return Status;
    }

    Status = SimpleFileSystemProtocol->OpenVolume(
        SimpleFileSystemProtocol,
        &Root
    );

    if (EFI_ERROR(Status))
    {
        Print(L"OpenVolume Failed : %r\n", Status);
        return Status;
    }

    Status = Root->Open(
        Root,
        FileHandle,
        Path,
        EFI_FILE_MODE_CREATE |
        EFI_FILE_MODE_WRITE |
        EFI_FILE_MODE_READ,
        0
    );

    if (EFI_ERROR(Status))
    {
        Print(L"Open File Failed : %r\n", Status);
        return Status;
    }

    return EFI_SUCCESS;
}


EFI_STATUS
LogInit(
    IN CHAR16 *Path
)
{
    EFI_STATUS Status;
    if (Path == NULL)
    {
        Status = GetCurrentPath(&Path);
        Path = GetStrReplace(Path, L".efi", L".log");
        if (EFI_ERROR(Status))
        {
            Print(L"GetCurrentPathError: %r\n", Status);
            return Status;
        }
    }

    Status = OpenLogFile(
        &gFileHandle, 
        Path
    );

    return Status;
}

EFI_STATUS
WriteData(
    IN VOID *Buffer,
    IN UINT64 BufferSize
)
{
    if (gFileHandle == NULL)
    {
        Print(L"Unknow File!\n");
        return EFI_UNSUPPORTED;
    }

    if (Buffer == NULL)
    {
        Print(L"Unknow Buffer!\n");
        return EFI_UNSUPPORTED;
    }

    if (BufferSize == 0)
    {
        Print(L"Unknow BufferSize!\n");
        return EFI_UNSUPPORTED;
    }

    EFI_STATUS Status;
    UINTN InfoBufferSize;
    EFI_FILE_INFO *FileInfo = NULL;

    Status = gFileHandle->GetInfo(
        gFileHandle,
        &gEfiFileInfoGuid, 
        &InfoBufferSize, 
        (VOID *)FileInfo
    );

    if (Status == EFI_BUFFER_TOO_SMALL)
    {
        FileInfo = AllocatePool(InfoBufferSize);
        Status = gFileHandle->GetInfo(
            gFileHandle,
            &gEfiFileInfoGuid,
            &InfoBufferSize,
            (VOID *)FileInfo
        );
    }

    if (EFI_ERROR(Status))
    {
        Print(L"Get File Info Failed: %r\n", Status);
        return Status;
    }

    Status = gFileHandle->SetPosition(
        gFileHandle,
        FileInfo->FileSize
    );

    if (EFI_ERROR(Status))
    {
        Print(L"Set Position Failed: %r\n", Status);
        return Status;
    }

    Status = gFileHandle->Write(
        gFileHandle,
        &BufferSize,
        Buffer
    );
    if (EFI_ERROR(Status))
    {
        Print(L"Write File Failed: %r\n", Status);
        return Status;
    }

    Status = gFileHandle->Flush(gFileHandle);

    if (EFI_ERROR(Status))
    {
        Print(L"Flush Data Failed: %r\n", Status);
        return Status;
    }
    return Status;
}

VOID
LogClose(
    VOID
)
{
    gFileHandle->Flush(gFileHandle);
    gFileHandle->Close(gFileHandle);
}

VOID
Log(
    LOG_LEVEL level,
    CHAR8 *FileName,
    CHAR8 *FuncName,
    UINTN LineNum,
    CHAR16 *Format,
    ...
)
{
    VA_LIST Marker;
    CHAR16 Buffer[MAX_MSG_SIZE];
    CHAR16 *Header = NULL;
    CHAR16 *Data = NULL;

    VA_START(
        Marker, 
        Format
    );
    UnicodeVSPrint(
        Buffer, 
        MAX_MSG_SIZE, 
        Format, 
        Marker
    );
    VA_END(Marker);

    if (ShowLevel)
    {
        Header = CatSPrint(
            Header, 
            L"%s ", 
            GetLevelString(level)
        );
    }

    if (ShowTime)
    {
        Header = CatSPrint(
            Header,
            L"%s ",
            GetEfiTime()
        );
    }

    if (ShowFileName)
    {
        Header = CatSPrint(
            Header,
            L"%a ",
            FileName
        );
    }

    if (ShowFuncName)
    {
        Header = CatSPrint(
            Header,
            L"%a ",
            FuncName
        );
    }

    if (ShowLine)
    {
        Header = CatSPrint(
            Header,
            L"%d ",
            LineNum
        );
    }

    if (Header == NULL)
    {
        Header = L"";
    }

    Data = CatSPrint(
        Data, 
        L"%s%s",
        Header,
        Buffer
    );

    Print(L"%s", Data);
    WriteData((VOID *)Data, StrLen(Data) * 2);
}

UefiLog是在UEFI环境下轻量级日志系统

1.

在使用宏定义前调用LogInit()进行初始化日志库
在程序退出前调用LogClose()关闭日志库

// 使用前初始化日志库
// Path  可以传入NULL,则log文件和程序同目录
// Path  非NULL时,需保证上级目录存在
EFI_STATUS
LogInit(
    IN CHAR16 *Path
);

2.

可以调用SetShowLevel()来选择是否显示日志级别
相关设置有 行数、函数名称、文件名、时间、日志级别
默认不显示文件名。

Test.c

//
// UefiLog
//
// test.c 
//
// UefiLog test Application
//

#include <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/PrintLib.h>
#include <Library/BaseLib.h>
#include "UefiLog/UefiLog.h"

EFI_STATUS
EFIAPI
UefiMain(
    IN EFI_HANDLE ImageHandle,
    IN EFI_SYSTEM_TABLE* SystemTable
)
{
    LogInit(NULL);
    LOG_DEBUG(L"Test:%r\n", EFI_SUCCESS);
    SetShowFileName(TRUE);
    LOG_ERROR(L"error:%r\n", EFI_LOAD_ERROR);
    SetShowLevel(FALSE);
    SetShowFileName(FALSE);
    SetShowFuncName(FALSE);
    SetShowLine(FALSE);
    SetShowTime(FALSE);

    CHAR8 Data[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    };

    UINTN Index = 0;

    for (Index = 0; Index < 512; Index++)
    {
        if (Index % 16 == 0)
        {
            LOG_DEBUG(L"%04X:   ", Index);
        }

        LOG_DEBUG(L"%02X  ", Data[Index]);

        if (Index % 16 == 15)
        {
            LOG_DEBUG(L"\n");
        }
    }
    LogClose();
    return EFI_SUCCESS;
}

3.

才疏学浅,能力有限,望指正!

4.

关注GitHub or 简书 不断更新中!

飞机票:SimpleUefiLog

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容