EDK2开发(3)-Hello World

简介

本文分两部分

  1. 编译MdeModulePkg下的HelloWorld 并运行
  2. 自己新建一个 Package 并且写一个 HelloWorld,然后编译运行

编译现有程序并在 OVMF 运行

你可以在MdeModulePkg/Application/HelloWorld/HelloWorld.c找到这个程序的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT32 Index;

Index = 0;

//
// Three PCD type (FeatureFlag, UINT32 and String) are used as the sample.
//
if (FeaturePcdGet (PcdHelloWorldPrintEnable)) {
for (Index = 0; Index < PcdGet32 (PcdHelloWorldPrintTimes); Index++) {
//
// Use UefiLib Print API to print string to UEFI console
//
Print ((CHAR16 *)PcdGetPtr (PcdHelloWorldPrintString));
}
}

return EFI_SUCCESS;
}

你可以修改Index来指定循环次数,以多次打印字符串

构建并复制到文件系统

直接构建,然后复制到之前搞好的文件系统里

1
2
build -a X64 -t GCC5 -p MdeModulePkg/MdeModulePkg.dsc -b DEBUG
cp ../edk2/Build/MdeModule/DEBUG_GCC5/X64/HelloWorld.efi hda-contents/

启动 QEMU

加载 OVMF

1
qemu-system-x86_64 -L . -pflash bios.bin -nographic  -net none --hda fat:rw:hda-contents

可以看到 UEFI Shell 已经识别到了本地的文件系统

1
2
3
4
5
6
7
8
9
10
11
UEFI Interactive Shell v2.2
EDK II
UEFI v2.70 (EDK II, 0x00010000)
Mapping table
FS0: Alias(s):HD0a1:;BLK1:
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
BLK0: Alias(s):
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
BLK2: Alias(s):
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Press ESC in 5 seconds to skip startup.nsh or any other key to continue.

使用fs0:进入文件系统,并输入文件名HelloWorld.efi回车即可运行

1
2
3
4
5
6
7
8
Shell> fs0:
FS0:\> ls
Directory of: FS0:\
05/22/2022 08:33 8,704 HelloWorld.efi
1 File(s) 8,704 bytes
0 Dir(s)
FS0:\> HelloWorld.efi
UEFI Hello World!

这个字符串哪来的

你可能会问,下面这行代码怎么打出来UEFI Hello World!的?

1
Print ((CHAR16 *)PcdGetPtr (PcdHelloWorldPrintString));

唉,这你就不知道了吧,我刚学的我也不知道

不知道咋办呢,拿 VSCode 嗯搜,肯定可以搜到

首先可以查一下PcdGetPtr()这个函数,可以看到他是做到了一个TokenName到指针的映射,有点像 GTA 三部曲的GXT文件原理

1
2
3
4
5
6
7
8
9
10
11
12
/**
Retrieves a pointer to a PCD token buffer based on a token name.

Returns a pointer to the buffer for the token specified by TokenName.
If TokenName is not a valid token in the token space, then the module will not build.

@param TokenName The name of the PCD token to retrieve a current value for.

@return A pointer to the buffer.

**/
#define PcdGetPtr(TokenName) _PCD_GET_MODE_PTR_##TokenName

那么再搜一下UEFI Hello World!这个东西,经过查找,锁定到MdeModulePkg/MdeModulePkg.dec的 1704 行

1
2
3
4
## This PCD defines the HelloWorld print string.
# This PCD is a sample to explain String typed PCD usage.
# @Prompt HelloWorld print string.
gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString|L"UEFI Hello World!\n"|VOID*|0x40000004

呃。。虽然但是,我自己试了一下确实是这个部分决定了字符串内容,有兴趣你可以改一下重新编译看一下效果

通过注释可以看到这是一个PCD,并且是一个字符串类型的PCD,这个是什么东西呢,我搜了一下,感觉一时半会说不清,简单说就是变量,具有如下形式

1
变量名|默认值|类型|Token值

此处丢出一个我看的参考文:UEFI 原理与编程实践–PCD 的使用_潇洒 Anthony 的博客-CSDN 博客

自己写一个

Author

BakaFT

Posted on

2022-05-22

Updated on

2023-12-28

Licensed under

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×