EFI介绍 EFI全名Extended Firmware Interface,一种应用于固态硬盘的启动引导,作为Bios后新发展的PC扩展接口升级。在Windows系统安装中,会在硬盘分出一片区域,名字就是efi,用于引导系统的启动(之前我卸载过这个分区,印象很深)
对于更多EFI启动的流程可以看下面的图片,里面包含了一套完整的EFI周期
更多的EFI介绍可以参考百度,现在不关心历史只关系用处🤣
安装解释EDK EDK也就是EFI Development Kit,类似JDK一样,EDK将会是开发efi文件的库,我们在ubuntu下操作,安装EDK2
1 git clone https://github.com/tianocore/edk2.git
一些依赖库文件的下载指令放在下面,当然是ubuntu的apt,如果你是debian就改成yum
1 apt install build-essential uuid-dev iasl git gcc-5 nasm python3-distutils
文件指针切入edk2目录下,导入一些子项目
1 git submodule update --init
安装完成会出现一大堆文件,这些文件夹的共性就是都以Pkg
结尾,其中关注两个文件夹MdePkg
和BaseTools
,前者是库而后者就是工具,因为我们要自己写Efi,所以我们新建一个文件夹,就叫MinPkg
1 2 3 4 5 6 7 8 9 root@minloha:~/LearnEFI/code/edk2# ls ArmPkg CryptoPkg FatPkg Maintainers.txt pip-requirements.txt SourceLevelDebugPkg ArmPlatformPkg DynamicTablesPkg FmpDevicePkg MdeModulePkg ReadMe.rst StandaloneMmPkg ArmVirtPkg edksetup.bat IntelFsp2Pkg MdePkg RedfishPkg UefiCpuPkg BaseTools edksetup.sh IntelFsp2WrapperPkg NetworkPkg SecurityPkg UefiPayloadPkg Conf EmbeddedPkg License-History.txt OvmfPkg ShellPkg UnitTestFrameworkPkg CONTRIBUTING.md EmulatorPkg License.txt PcAtChipsetPkg SignedCapsulePkg root@minloha:~/LearnEFI/code/edk2# mkdir MinPkg root@minloha:~/LearnEFI/code/edk2#
强调两个文件类型.dsc
和.dec
,前者是对当前Pkg的描述后者是用于声明公开接口的描述。找到最经典的Hello world
代码存放位置,里面保存了.inf
和源码.c
文件,这里注意,因为是底层所以没有标准库,也就意味着所有的输出函数和变量定义都必须重新写,也就是无法再像以往写代码一样去定义变量了
1 2 3 4 root@minloha:~/LearnEFI/code# cd edk2/MdeModulePkg/Application/HelloWorld root@minloha:~/LearnEFI/code/edk2/MdeModulePkg/Application/HelloWorld# ls HelloWorld.c HelloWorldExtra.uni HelloWorld.inf HelloWorldStr.uni HelloWorld.uni root@minloha:~/LearnEFI/code/edk2/MdeModulePkg/Application/HelloWorld#
打开.inf
进行解释,内容如下,[Defines]
定义了程序的版本、程序名、引导UID、版本以及程序入口,[Sources]
写出了程序所需要的资源文件,即源码和配置。[Packages]
定义了所需要EDK的包,[LibraryClasses]
列举了使用的接口,[Pcd]
规定了一些常量字符串,引用了.dec
文件中所写的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 [Defines] INF_VERSION = 0 x00010005 BASE_NAME = HelloWorld MODULE_UNI_FILE = HelloWorld.uni FILE_GUID = 6987936 E-ED34-44 db-AE97-1 FA5E4ED2116 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 1.0 ENTRY_POINT = UefiMain UEFI_HII_RESOURCE_SECTION = TRUE [Sources] HelloWorld.c HelloWorldStr.uni[Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec[LibraryClasses] UefiApplicationEntryPoint UefiLib PcdLib[FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes [UserExtensions.TianoCore."ExtraFiles"] HelloWorldExtra.uni
EDK的编译是通过make进行的,我们需要切换到EDK2的目录下的Conf
文件夹修改target.txt来改变编译输出。
C的指针很强大 指针是C语言的核心,在深入EFI底层前,必须要先复习一下C指针的含义,随便写两句代码
1 2 3 4 5 6 7 8 9 #include "stdio.h" int main () { int age = 20 ; int *p_age = &age; printf ("age=%d,address=%p\n" ,age,&age); printf ("p_age=%d,address=%p,paddress=%p\n" ,*p_age,p_age,&p_age); return 0 ; }
利用gcc编译并运行,可以看到age与p_age的内存地址address是一个,但是paddress却和address不同
p_age作为指向age内存的指针,内部必然存储了age变量的内存地址,对p_age变量而言,输出的address就是保存age的内存地址,而paddress输出的是指针在内存的位置,通俗的说就是一个是复制别人的,一个是自己保存的。
1 2 3 4 5 root@minloha:~/LearnEFI/C/pointer# gcc main.c root@minloha:~/LearnEFI/C/pointer# ./a.out age=20,address=0x7ffee75e2bac p_age=20,address=0x7ffee75e2bac,paddress=0x7ffee75e2bb0 root@minloha:~/LearnEFI/C/pointer#
指针就是保存地址的变量,地址就是一个可以被指的指针。在底层操作中,直接操作变量是无意义的,因为无法从根本上修改变量内容,所以利用指针进行操作内存,直接修改数据是非常高效的。
编译出EFI 在EDK2目录中使用指令,可以编译出.efi
文件
第一次编译会出现问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 make[2]: Leaving directory '/root/LearnEFI/code/edk2/BaseTools/Source/C/DevicePath' Finished building BaseTools C Tools with HOST_ARCH=X64 make[1]: Leaving directory '/root/LearnEFI/code/edk2/BaseTools/Source/C' make -C Source/Python make[1]: Entering directory '/root/LearnEFI/code/edk2/BaseTools/Source/Python' make[1]: Nothing to be done for 'all'. make[1]: Leaving directory '/root/LearnEFI/code/edk2/BaseTools/Source/Python' make -C Tests make[1]: Entering directory '/root/LearnEFI/code/edk2/BaseTools/Tests' /bin/sh: 1: python: not found make[1]: *** [GNUmakefile:11: test] Error 127 make[1]: Leaving directory '/root/LearnEFI/code/edk2/BaseTools/Tests' make: *** [GNUmakefile:19: Tests] Error 2 make: Leaving directory '/root/LearnEFI/code/edk2/BaseTools' root@minloha:~/LearnEFI/code/edk2#
没错,python: not found
,原因是python版本问题,解决方法就是先找到python位置,然后就要把python3.8与python连接在一起。
1 2 3 4 5 6 root@minloha:~/LearnEFI/code/edk2# whereis python python: /usr/bin/python3.8-config /usr/bin/python3.8 /usr/bin/python2.7 /usr/lib/python3.8 /usr/lib/python2.7 /usr/lib/python3.9 /etc/python3.8 /etc/python2.7 /usr/local/lib/python3.8 /usr/local/lib/python2.7 /usr/include/python3.8 root@minloha:~/LearnEFI/code/edk2# sudo ln -s /usr/bin/python3.8 /usr/bin/python root@minloha:~/LearnEFI/code/edk2# python --version Python 3.8.10 root@minloha:~/LearnEFI/code/edk2#
然后重新make一下就可以了。为了运行.efi
我们要一个软件qemu
,安装一下吧。
结语 在了解这么多关于EFI的知识和C语言的操作后,相信你一定可以写出一个自己的EFI系统了,年三十晚的一篇文字
新年快乐哟!