Step to UEFI (130)NT32 模拟器中的 Debug Message 输出

一年多以前,提出了个奇怪的想法:是否可以在自己编写的Application中输出到 NT32 的模拟器LOG中?当时遇到的问题是,如果想直接输出必须调用 WinNtThunkDxe 这样的Protocol,而在定义Protocol的时候必须使用Windows.h 的头文件,但是 AppPkg 中无法做到这一点,最终找到的解决方法是修改gST->Reset 。但是很显然,这并非完美的解决方法【参考1】。

最近,忽然想起来,可以重新定义一个自己的 Protocol 头,只要需要用到的函数偏移正确,调用时放入正确的参数同样能正常工作。需要用到的最重要的 Protocol 结构体在  \UDK2017\Nt32Pkg\Include\Protocol\WinNtThunk.h :

typedef struct {
  UINT64                              Signature;

  //
  // Win32 Process APIs
  //
  WinNtGetProcAddress                 GetProcAddress;
  WinNtGetTickCount                   GetTickCount;
  WinNtLoadLibraryEx                  LoadLibraryEx;
  WinNtFreeLibrary                    FreeLibrary;

  WinNtSetPriorityClass               SetPriorityClass;
  WinNtSetThreadPriority              SetThreadPriority;
  WinNtSleep                          Sleep;

  WinNtSuspendThread                  SuspendThread;
  WinNtGetCurrentThread               GetCurrentThread;
  WinNtGetCurrentThreadId             GetCurrentThreadId;
  WinNtGetCurrentProcess              GetCurrentProcess;
  WinNtCreateThread                   CreateThread;
  WinNtTerminateThread                TerminateThread;
  WinNtSendMessage                    SendMessage;
  WinNtExitThread                     ExitThread;
  WinNtResumeThread                   ResumeThread;
  WinNtDuplicateHandle                DuplicateHandle;

  //
  // Wint32 Mutex primitive
  //
  WinNtInitializeCriticalSection      InitializeCriticalSection;
  WinNtEnterCriticalSection           EnterCriticalSection;
  WinNtLeaveCriticalSection           LeaveCriticalSection;
  WinNtDeleteCriticalSection          DeleteCriticalSection;
  WinNtTlsAlloc                       TlsAlloc;
  WinNtTlsFree                        TlsFree;
  WinNtTlsSetValue                    TlsSetValue;
  WinNtTlsGetValue                    TlsGetValue;
  WinNtCreateSemaphore                CreateSemaphore;
  WinNtWaitForSingleObject            WaitForSingleObject;
  WinNtReleaseSemaphore               ReleaseSemaphore;

  //
  // Win32 Console APIs
  //
  WinNtCreateConsoleScreenBuffer      CreateConsoleScreenBuffer;
  WinNtFillConsoleOutputAttribute     FillConsoleOutputAttribute;
  WinNtFillConsoleOutputCharacter     FillConsoleOutputCharacter;
  WinNtGetConsoleCursorInfo           GetConsoleCursorInfo;
  WinNtGetNumberOfConsoleInputEvents  GetNumberOfConsoleInputEvents;
  WinNtPeekConsoleInput               PeekConsoleInput;
  WinNtScrollConsoleScreenBuffer      ScrollConsoleScreenBuffer;
  WinNtReadConsoleInput               ReadConsoleInput;

  WinNtSetConsoleActiveScreenBuffer   SetConsoleActiveScreenBuffer;
  WinNtSetConsoleCursorInfo           SetConsoleCursorInfo;
  WinNtSetConsoleCursorPosition       SetConsoleCursorPosition;
  WinNtSetConsoleScreenBufferSize     SetConsoleScreenBufferSize;
  WinNtSetConsoleTitleW               SetConsoleTitleW;
  WinNtWriteConsoleInput              WriteConsoleInput;
  WinNtWriteConsoleOutput             WriteConsoleOutput;

  //
  // Win32 File APIs
  //
  WinNtCreateFile                     CreateFile;
  WinNtDeviceIoControl                DeviceIoControl;
  WinNtCreateDirectory                CreateDirectory;
  WinNtRemoveDirectory                RemoveDirectory;
  WinNtGetFileAttributes              GetFileAttributes;
  WinNtSetFileAttributes              SetFileAttributes;
  WinNtCreateFileMapping              CreateFileMapping;
  WinNtCloseHandle                    CloseHandle;
  WinNtDeleteFile                     DeleteFile;
  WinNtFindFirstFile                  FindFirstFile;
  WinNtFindNextFile                   FindNextFile;
  WinNtFindClose                      FindClose;
  WinNtFlushFileBuffers               FlushFileBuffers;
  WinNtGetEnvironmentVariable         GetEnvironmentVariable;
  WinNtGetLastError                   GetLastError;
  WinNtSetErrorMode                   SetErrorMode;
  WinNtGetStdHandle                   GetStdHandle;
  WinNtMapViewOfFileEx                MapViewOfFileEx;
  WinNtReadFile                       ReadFile;
  WinNtSetEndOfFile                   SetEndOfFile;
  WinNtSetFilePointer                 SetFilePointer;
  WinNtWriteFile                      WriteFile;
  WinNtGetFileInformationByHandle     GetFileInformationByHandle;
  WinNtGetDiskFreeSpace               GetDiskFreeSpace;
  WinNtGetDiskFreeSpaceEx             GetDiskFreeSpaceEx;
  WinNtMoveFile                       MoveFile;
  WinNtSetFileTime                    SetFileTime;
  WinNtSystemTimeToFileTime           SystemTimeToFileTime;

  //
  // Win32 Time APIs
  //
  WinNtLocalFileTimeToFileTime        LocalFileTimeToFileTime;
  WinNtFileTimeToLocalFileTime        FileTimeToLocalFileTime;
  WinNtFileTimeToSystemTime           FileTimeToSystemTime;
  WinNtGetSystemTime                  GetSystemTime;
  WinNtSetSystemTime                  SetSystemTime;
  WinNtGetLocalTime                   GetLocalTime;
  WinNtSetLocalTime                   SetLocalTime;
  WinNtGetTimeZoneInformation         GetTimeZoneInformation;
  WinNtSetTimeZoneInformation         SetTimeZoneInformation;
  WinNttimeSetEvent                   timeSetEvent;
  WinNttimeKillEvent                  timeKillEvent;

  //
  // Win32 Serial APIs
  //
  WinNtClearCommError                 ClearCommError;
  WinNtEscapeCommFunction             EscapeCommFunction;
  WinNtGetCommModemStatus             GetCommModemStatus;
  WinNtGetCommState                   GetCommState;
  WinNtSetCommState                   SetCommState;
  WinNtPurgeComm                      PurgeComm;
  WinNtSetCommTimeouts                SetCommTimeouts;

  WinNtExitProcess                    ExitProcess;

  WinNtSprintf                        SPrintf;

  WinNtGetDesktopWindow               GetDesktopWindow;
  WinNtGetForegroundWindow            GetForegroundWindow;
  WinNtCreateWindowEx                 CreateWindowEx;
  WinNtShowWindow                     ShowWindow;
  WinNtUpdateWindow                   UpdateWindow;
  WinNtDestroyWindow                  DestroyWindow;
  WinNtInvalidateRect                 InvalidateRect;
  WinNtGetWindowDC                    GetWindowDC;
  WinNtGetClientRect                  GetClientRect;
  WinNtAdjustWindowRect               AdjustWindowRect;
  WinNtSetDIBitsToDevice              SetDIBitsToDevice;
  WinNtBitBlt                         BitBlt;
  WinNtGetDC                          GetDC;
  WinNtReleaseDC                      ReleaseDC;
  WinNtRegisterClassEx                RegisterClassEx;
  WinNtUnregisterClass                UnregisterClass;

  WinNtBeginPaint                     BeginPaint;
  WinNtEndPaint                       EndPaint;
  WinNtPostQuitMessage                PostQuitMessage;
  WinNtDefWindowProc                  DefWindowProc;
  WinNtLoadIcon                       LoadIcon;
  WinNtLoadCursor                     LoadCursor;
  WinNtGetStockObject                 GetStockObject;
  WinNtSetViewportOrgEx               SetViewportOrgEx;
  WinNtSetWindowOrgEx                 SetWindowOrgEx;
  WinNtMoveWindow                     MoveWindow;
  WinNtGetWindowRect                  GetWindowRect;

  WinNtGetMessage                     GetMessage;
  WinNtTranslateMessage               TranslateMessage;
  WinNtDispatchMessage                DispatchMessage;

  WinNtGetProcessHeap                 GetProcessHeap;
  WinNtHeapAlloc                      HeapAlloc;
  WinNtHeapFree                       HeapFree;
  
  WinNtQueryPerformanceCounter        QueryPerformanceCounter;
  WinNtQueryPerformanceFrequency      QueryPerformanceFrequency;
  
} EFI_WIN_NT_THUNK_PROTOCOL;

修改之后的可以直接在 UEFI Application 中进行定义的结构体如下

typedef struct {
  UINT64                              Signature;
  //
  // Win32 Process APIs
  //
  UINTN API1[17];
  //
  // Wint32 Mutex primitive
  //
  UINTN API2[11];  
  //
  // Win32 Console APIs
  //
  UINTN API3[15];    
  //
  // Win32 File APIs
  //
  UINTN API41[16];  
  MyWinNtGetStdHandle                 GetStdHandle;
  UINTN API42[4];   
  MyWinNtWriteFile                    WriteFile;
  UINTN API5[6];   
  //
  // Win32 Time APIs
  //
  UINTN API6[10];   
  //
  // Win32 Serial APIs
  //
  UINTN API7[44];     
} MY_EFI_WIN_NT_THUNK_PROTOCOL;

 

这个结构体中,对我们有用的是  WinNtWriteFile   WriteFile  还有  WinNtGetStdHandle GetStdHandle。只要这两个的偏移正确即可进行调用。对于这两个函数,我们还需要重新改写一下原型,比如之前的定义为:

typedef
WINBASEAPI
BOOL
(WINAPI *WinNtWriteFile) (
  HANDLE        FileHandle,
  LPCVOID       Buffer,
  DWORD         NumberOfBytesToWrite,
  LPDWORD       NumberOfBytesWritten,
  LPOVERLAPPED  Overlapped
  );

 

经过修改之后的如下

typedef
EFI_STATUS
(EFIAPI *MyWinNtWriteFile) (
  IN EFI_HANDLE FileHandle,
  CHAR8*        Buffer,
  UINT32        NumberOfBytesToWrite,
  UINT32*       NumberOfBytesWritten,
  UINT32        Overlapped  
  );

 

就是这样,只要我们定义出正确的函数偏移,再喂给他正确的参数就能够完成调用。最后,完整的代码如下:

/** @file

A simple, basic, application showing how the Hello application could be

built using the "Standard C Libraries" from StdLib.

 

Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>

This program and the accompanying materials

are licensed and made available under the terms and conditions of the BSD License

which accompanies this distribution. The full text of the license may be found at

http://opensource.org/licenses/bsd-license.

 

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include <Library/BaseLib.h>

#include <Uefi.h>

#include <Library/UefiLib.h>

#include <Library/PrintLib.h>

#include <Library/ShellCEntryLib.h>

 

#define STD_OUTPUT_HANDLE -11

 

extern EFI_BOOT_SERVICES         *gBS;

 

EFI_GUID gEfiWinNtThunkProtocolGuid     =

{ 0x58C518B1, 0x76F3, 0x11D4,

{ 0xBC, 0xEA, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};

 

typedef

EFI_STATUS

(EFIAPI *MyWinNtWriteFile) (

IN EFI_HANDLE FileHandle,

CHAR8*        Buffer,

UINT32        NumberOfBytesToWrite,

UINT32*       NumberOfBytesWritten,

UINT32        Overlapped

);

 

typedef

EFI_HANDLE

(EFIAPI *MyWinNtGetStdHandle) (

EFI_HANDLE   StdHandle

);

typedef struct {

UINT64                              Signature;

//

// Win32 Process APIs

//

UINTN API1[17];

//

// Wint32 Mutex primitive

//

UINTN API2[11];

//

// Win32 Console APIs

//

UINTN API3[15];

//

// Win32 File APIs

//

UINTN API41[16];

MyWinNtGetStdHandle                 GetStdHandle;

UINTN API42[4];

MyWinNtWriteFile                    WriteFile;

UINTN API5[6];

//

// Win32 Time APIs

//

UINTN API6[10];

//

// Win32 Serial APIs

//

UINTN API7[44];

} MY_EFI_WIN_NT_THUNK_PROTOCOL;

 

/***

Demonstrates basic workings of the main() function by displaying a

welcoming message.

 

Note that the UEFI command line is composed of 16-bit UCS2 wide characters.

The easiest way to access the command line parameters is to cast Argv as:

wchar_t **wArgv = (wchar_t **)Argv;

 

@param[in]  Argc    Number of argument tokens pointed to by Argv.

@param[in]  Argv    Array of Argc pointers to command line tokens.

 

@retval  0         The application exited normally.

@retval  Other     An error occurred.

***/

int

main (

IN int Argc,

IN char **Argv

)

{

EFI_STATUS                      Status;

MY_EFI_WIN_NT_THUNK_PROTOCOL    *MyWinNTThunkProtocol;

//

// Cache of standard output handle .

//

EFI_HANDLE                      mStdOut;

 

CHAR8           Buffer[200];

UINT32          CharCount;

 

//

// Look for Ram Disk Protocol

//

Status = gBS->LocateProtocol (

&gEfiWinNtThunkProtocolGuid,

NULL,

(VOID **)&MyWinNTThunkProtocol

 

);

if (EFI_ERROR (Status)) {

Print(L"Couldn't find WinNtThunkProtocol\n");

return EFI_ALREADY_STARTED;

}

 

Print(L"Found WinNt Thunk\n");

//

// Cache standard output handle.

//

mStdOut = MyWinNTThunkProtocol-> GetStdHandle

((EFI_HANDLE)STD_OUTPUT_HANDLE);

Print(L"mStdOut=%X\n",mStdOut);

 

CharCount = (UINT32)AsciiSPrint (

Buffer,

sizeof (Buffer),

"www.lab-z.com %X\n\r",

2017

);

 

//

// Callout to standard output.

//

MyWinNTThunkProtocol->WriteFile (

mStdOut,

Buffer,

CharCount,

&CharCount,

0

);

 

return EFI_SUCCESS;

}

 

我们在 NT32 的Shell中调用编写好的 Application 2次:

nt1

对应在Log中可以看到有2次输出
nt2

参考:

  1. http://www.lab-z.com/stu82/ NT32Pkg的Debug Message

2018年1月4日 krishnaLee 给出了一个更简单高效的方法,亲测有效:

1,在Nt32Pkg.dsc的【component】区域写:
SampleAppDebug/SampleApp.inf {

gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0xffffffff
}
2,编译:build -p Nt32Pkg\Nt32Pkg.dsc -m SampleAppDebug\SampleApp.inf
3,运行。

附件是例子的 application:

SampleAppDebug

发表评论

电子邮件地址不会被公开。 必填项已用*标注