经过这么一段时间的学习,再没有什么比搞清楚UEFI裸机程序,调用EFI系统表识别物理内存更重要的事情了。这是一个无论工程上遇到多少困难都寄希望解决的事情(比如笔记本电脑的UEFI隐身问题等等)。完成了裸机编程的相关开发,才可以说真正理解了什么是APB的物理地址映射关系,才对物理地址空间有一个全局的了解。
对于UEFI裸机编程,首先就是要从EFI文件编译入手,而EFI文件编译呢,又首先是由GRUB2入手。这里要解决的是两个主要问题:
1、解决UEFI固件传递过来的entry的PE头问题
2、解决vedio或者uart的其中一个的显示bash的问题
PE头问题
对于grub2来说,PE头问题的解决依赖于startup.S文件(/grub-core/kern/arm64/efi/startup.S)。
完整的一个EFI的编译流程为:
1、main文件编译
aarch64-linux-gnu-gcc -fPIC -ffreestanding -fno-stack-protector -c kqmain.c -o kqefi.omain文件本体可以参考另一篇文章专门讲解(值得注意的是,最最最要紧的就是要搞清楚EFI系统表怎么弄)。
2、准备链接脚本
由于grub2中实际上没有这个链接脚本。grub2使用了mkimage工具,然后在工具中实现了代码段的链接。
由于这里希望能拥有一个精简版的裸机编程工具,所以最好在此处提供一个手搓的最小lds文件来明确告诉链接器如何布局内存,lds文件本体比较简单,主要为一种段的映射关系,并最终会舍弃调不必要的debug等段。
链接前的o文件:

其objdump查看到的段为:

可以看到efi文件主要包含如下部分:

注意,对于UEFI来说,完成entry指向其实就结束了。剩下的重定位、数据等内容,并不一定是必须的。
链接命令为:
aarch64-linux-gnu-ld -shared -Bsymbolic -T kquefi.lds kqefi.o -o kqefi.so3、PE头格式转换
这里可以使用objcopy工具(来自于binutils工具箱)来实现。
aarch64-linux-gnu-objcopy -j .text -j .data -j .rodata -j .reloc --target=pei-aarch64-little kqefi.so kq.efi在这一步主要就是加一个PE头了,类似于kernel中的head.S文件添加汇编头的过程,不过objcopy工具本身就提供了这种功能会方便一些。
最终做出来的efi文件为:

4、U盘启动efi
首先准备一个U盘,挂载后准备GPT分区:
fdisk /dev/sda //启动fdisk程
g //创建GPT分区表
n //创建两个分区
t //改变第一个分区类型为‘EFI System’,一般为1
p //打印分区表,检查2个分区
w //写入分区表到磁盘
mkfs.vfat /dev/sda1 //格式化1盘为fat格式
mkfs.ext4 /dev/sda2 //格式化2盘为ext4格式
然后,把efi文件挂上去,在UEFI固件界面选中这个文件启动即可。