Last Updated on 04/11/18
This is the extraction of the UEFI development in form of an organized tips list. In this passage, we focus more on the implementation details than the general concepts involved in Tianocore.
(1) Pre-EFI Initialization
- Debug information output in PEI pahse
// MdeModulePkg/Core/Pei/Image/Image.c
if (Machine != EFI_IMAGE_MACHINE_IA64) {
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
} else {
// For IPF Image, the real entry point should be print.
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
}
- The dependency expression in PEI phase
- The PcdLIb instances will read the Module INF to ensure whether the PCD exists, and replace the PCD Token used in Module C source file with the value defined in platform DEC according to the [Pcd] part of Module INF
(2) Debugging
- Usage of QEMU serial port debugging:
# Ensure that the OVMF is built in DEBUG mode with DEBUG_ON_SERIAL_PORT enabled
# For common firmware on physical machine, ensure that the fundamental \
# debug library classes are included in the specific platform DSC
# and debug headers are included in the testing programmes.
../vtpm-support/qemu-tpm/x86_64-softmmu/qemu-system-x86_64 -display sdl \
-m 2048 -serial file:/home/hecmay/debug.log -global isa-debugcon.iobase=0x402 \
-net none -boot c -bios Build/Ovmf3264/DEBUG_GCC5/FV/OVMF.fd -boot menu=on \
-tpmdev cuse-tpm,id=tpm0,path=/dev/vtpm0 \
-device tpm-tis,tpmdev=tpm0 Build/test.img
- Tesing UEFI Apps with virtual hard-disk
# create the test image file
dd if=/dev/zero of=test.img bs=1M count=128
# format the file system of the image
mkfs -t vfat test.img
# Map the image to loop device && mount the formated image to /mnt/
sudo mount -o loop test.img /mnt/
# copy the compiled UEFI Apps to /mnt/ and run QEMU with it
qemu-system-x86_64 -bios Build/Ovmf3264/DEBUG_GCC5/FV/OVMF.fd test.img
- Testing UEFI Application on VMware WorkStation
Simply build up a naked virtual machine without OS installed in VMware, and enable the EFI Support in VMware configuration, we are able to enter the EFI Shell stage in virtual machine (without using OVMF).
By inserting a USB stick with FAT compatible File System and dump the EFI Applications into it, the testing job will be much easier.
https://blog.fpmurphy.com/2014/07/using-vmware-workstation-to-experiment-with-uefi.html
- Useful Hot-Keys of QEMU
Ctrl + Alt: release the mouse
Ctrl + Alt + 1: The main graphic console
Ctrl + Alt + 2: The QEMU Command condole
Ctrl + Alt + 3: Serial port debugging output
(3) Tricks for UEFI Aplication
- The console output of UEFI Application
# If using the Print function defined in UEFI, ensure UefiLib.h is included
# For string of CHAR8 type, conversion to CHAR16 is needed like
static VOID
AsciiToUnicodeSize( CHAR8 *String,
UINT8 length,
CHAR16 *UniString)
{
int len = length;
while (*String != '\0' && len > 0) {
*(UniString++) = (CHAR16) *(String++);
len--;
}
*UniString = '\0';
}
CHAR16 Buffer[100];
AsciiToUnicodeSize(Str, length, Buffer);
Print(L"text here: %x, %d, %s", Addr, Status, Buffer);
- The String type incompatibility error
// When running UEFI App in UEFI Shell
>FS: xxx.efi
>Error Command Status : Not Found
// edk2/ShellPkg/Application/Shell/Shell.c +2583
//
// Now print errors
//
if (EFI_ERROR(Status)) {
ConstScriptFile = ShellCommandGetCurrentScriptFile();
if (ConstScriptFile == NULL || ConstScriptFile->CurrentCommand == NULL) {
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status));
} else {
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR_SCRIPT), ShellInfoObject.HiiHandle, (VOID*)(Status), ConstScriptFile->CurrentCommand->Line);
}
}
//
// ......
//
// edk2/ShellPkg/Application/Shell/Shell.uni
#string STR_SHELL_ERROR #language en-US "%NCommand Error Status: %r\r\n"
Make sure the type selection and variable correspondent, otherwise the Shell.efi will not be able to read out the script from it.
- Creation of UUID for UEFI App
The uuidlib installation and usage in C programming please see:
linux下安装使用libuuid(uuid-generate)
A simpler way is to read the kernel interface for generating uuid with
>>> cat /proc/sys/kernel/random/uuid
... 968b810c-00ea-42a5-88dc-6f8fa952c9b9
- The definition of headers and compulsory inclusion for specific situation
> ShellPkg/Include/Library/ShellCEntryLib.h
>> This header includes the initial definition of function ShellAppMain(), which is compulsory for UEFI Shell App
> ShellPkg/Include/Library/ShellLib.h
>> Similar but includes function handles for Efi Shell.
>> And redefinition of ShellAppMain() Should return a INTN instead of EFI_STATUS
* A simple example of gRT
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/ShellLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/EfiShell.h>
#include <Protocol/LoadedImage.h>
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
EFI_STATUS Status = EFI_SUCCESS;
gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
return Status;
}
- The definition of fundamental types in UEFI
// MdePkg/Include/Ipf/ProcesserBind.h
// Other frequently-used base type in UEFI please refer to
// MdePkg/Include/Uefi/UefiBaseType.h
///
/// 1-byte Character.
///
typedef char CHAR8;
///
/// 1-byte signed value.
///
typedef signed char INT8;
#else
///
/// 8-byte unsigned value.
///
typedef unsigned long long UINT64;
///
/// 8-byte signed value.
///
typedef long long INT64;
///
/// 4-byte unsigned value.
///
typedef unsigned int UINT32;
///
/// 4-byte signed value.
///
typedef int INT32;
- Mechanism of Library/PCD/GUID Usage in Pkg Description File
The Platform includes the "Include" Path, the Protocol GUID, Platform Configuration Database items and the path of headers of the library in this specific Pkg
The DEC file includes the "Include" Path, with which the compiler will search for if encountering phrase like
#include <Library/xxx.h>
in the pragma code. In order to tell the compiler which Pkg "Include" Path the module is going to use, you should also declare the Pkg's DEC file path in the module's INF file.
About the Library you want to use: Please include the Library's INF files in the
[LibraryClass]
Part of the platform DSC File