UEFI开发学习 33 – 在 Visual Studio 使用纯 C 语言编写 EFI APP
正常情况下,我们写一个 efi app 需要在 edk2 的代码环境中去实现,需要处理 inf,dsc 文件中的各种依赖库,对于不熟悉 edk2 的人,开发一个 efi app 是一件麻烦事。有没可以像开发 Windows app 那样的方式,使用 Visual studio 开发 efi app 呢?
Github 上,有一个从事 uefi 领域开发的专家,移植了一个 c 库,可用于在 VS 中使用纯 C 语言开发 efi 应用,编写的程序,不涉及任何 edk2 代码。下面来演示如何使用该库。
打开此链接:https://github.com/KilianKegel/HowTo-configure-VS2022-to-build-.EFI-executables#howto-configure-vs2022-to-build-efi-executables
根据截图配置 Visual Studio,使其可以编译 EFI 应用,接着下载 toroC64.lib(https://github.com/KilianKegel/toro-C-Library),并添加到 Visual Studio 项目中,这样便可以使用 C 语言编写 EFI 应用了。

如果按照图中一步一步配置实在有点繁琐,我把它整理成了一个 Python 脚本,执行脚本即可生成 VS2022 的工程文件。
import os
import sys
import uuid
import argparse
# Configuration
TEMPLATE_MAIN_C = """#include
int main (int argc, char **argv)
{
printf("Hello, UEFI World!\n");
return 0;
}
"""
def generate_guid():
return str(uuid.uuid4()).upper()
def create_sln(project_name, project_guid, sln_path):
sln_content = f"""
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}}") = "{project_name}", "{project_name}.vcxproj", "{{{project_guid}}}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{{{project_guid}}}.Debug|x64.ActiveCfg = Debug|x64
{{{project_guid}}}.Debug|x64.Build.0 = Debug|x64
{{{project_guid}}}.Release|x64.ActiveCfg = Release|x64
{{{project_guid}}}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
"""
with open(sln_path, "w", encoding="utf-8") as f:
f.write(sln_content)
def create_vcxproj(project_name, project_guid, vcxproj_path):
# Standard EDK2 include paths (adjust if needed)
includes = []
include_str = ";".join(includes)
vcxproj_content = f"""
Debug
x64
Release
x64
16.0
Win32Proj
{{ {project_guid}}}
{project_name}
10.0
Application
false
v143
Unicode
Application
false
v143
true
Unicode
false
{include_str};$(IncludePath)
false
.efi
false
{include_str};$(IncludePath)
false
.efi
Level3
false
NDEBUG;UEFI_BUILD;_DEBUG;_CONSOLE;_NO_CRT_STDIO_INLINE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
true
false
false
Default
None
CompileAsC
true
MultiThreaded
EFI Application
true
_cdeCRT0UefiShell
false
false
0
/IGNORE:4281 /OPT:ICF /OPT:REF /FIXED:NO %(AdditionalOptions)
true
true
Level3
true
true
false
NDEBUG;UEFI_BUILD;NDEBUG;_CONSOLE;_NO_CRT_STDIO_INLINE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
true
false
false
CompileAsC
true
MultiThreaded
EFI Application
true
true
false
_cdeCRT0UefiShell
false
false
0
true
true
"""
with open(vcxproj_path, "w", encoding="utf-8") as f:
f.write(vcxproj_content)
def main():
parser = argparse.ArgumentParser(description="Generate a VS2022 UEFI Project.")
parser.add_argument("name", help="Name of the project")
args = parser.parse_args()
project_name = args.name
# Create project directory under current dir
project_dir = os.path.join(os.getcwd(), project_name)
if not os.path.exists(project_dir):
os.makedirs(project_dir)
print(f"Created directory: {project_dir}")
else:
print(f"Directory already exists: {project_dir}")
project_guid = generate_guid()
sln_path = os.path.join(project_dir, f"{project_name}.sln")
vcxproj_path = os.path.join(project_dir, f"{project_name}.vcxproj")
main_c_path = os.path.join(project_dir, "main.c")
create_sln(project_name, project_guid, sln_path)
print(f"Created solution: {sln_path}")
create_vcxproj(project_name, project_guid, vcxproj_path)
print(f"Created project file: {vcxproj_path}")
with open(main_c_path, "w", encoding="utf-8") as f:
f.write(TEMPLATE_MAIN_C)
print(f"Created main.c template: {main_c_path}")
print("nProject generated successfully!")
print(f"To build, open {sln_path} in VS2022 and build.")
if __name__ == "__main__":
main()
将代码保存为ConfigureVS2022Efi.py,执行
Python ConfigureVS2022Efi.py TotoCProject
即可生成一个 TotoCProject 的 VS2022 的工程,接着需要把下载的 toroC64.lib 文件放至 main.c 同目录便可编译。
如果需要读写端口,可直接使用 intrin.h 中的 __outbyte() ,__inbyte 等函数,该头文件中,还有 MSR 相关的函数,如 __writemsr()。如果还需要使用更加复杂的功能,还可以使用作者的另外一个项目:https://github.com/KilianKegel/Visual-ANSI-C-for-UEFI-Shell,该项目中有大量的实例,包括定时器,xlsx 表格,UI 界面等。
在测试生成 EFI APP 的时候,发现在 edk2 中的模拟器无法执行,刚开始以为是编译有问题,后来在实体机器测试,则是正常的,所以使用这方法生成的 EFI 注意要在实体机器测试!
版权声明:
作者:bin
链接:https://ay123.net/mystudy/clan/1913/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论