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/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
UEFI开发学习 33 – 在 Visual Studio 使用纯 C 语言编写 EFI APP
  正常情况下,我们写一个 efi app 需要在 edk2 的代码环境中去实现,需要处理 inf,dsc 文件中的各种依赖库,对于不熟悉 edk2 的人,开发一个 efi app 是一……
<<上一篇
下一篇>>
文章目录
关闭
目 录