(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
这篇本想讨论USB的,学习过程中不小心迷上了WSL,又正好想在树莓派上折腾点UEFI的软件,顺理成章地就用WSL搭建了Arm架构的编译环境。
从结论来说,还不错,省得打开虚拟机了,编译速度也很快,有空把X86架构的编译环境也在WSL上搭建起来。
1 搭建WSL
个人比较喜欢用Ubuntu18.04,很多软件都在上面写的。搭建方法就不具体描述了,可以参考我的另外一篇博客:
https://blog.csdn.net/luobing4365/article/details/105752549
2 所需下载的代码
可以从github的仓库上下载以下开源代码,准备用来搭建开发环境。不过,github像乌龟一样的速度,如果不是为了修心养性,还是建议用gitee来下载。至于如何将github的库转到gitee上,同样可以参考我之前写的博客:
http://yiiyee.cn/blog/2020/04/21/%e4%bd%bf%e7%94%a8gitee%e4%b8%8b%e8%bd%bdgithub%e9%a1%b9%e7%9b%ae/
或者https://blog.csdn.net/luobing4365/article/details/105658274
1) edk2 仓库:tianocore\edk2 仓库地址:https://github.com/tianocore/edk2.git
这是包含固件开发环境的仓库,编译UEFI固件所需要的库都在其中。
2) edk2-platforms 仓库:tianocore\edk2-platforms
仓库地址:https://github.com/tianocore/edk2-platforms.git
各种平台的工作环境和相关的模块
3) ACPICA 仓库:acpica\acpica 仓库地址:https://github.com/acpica/acpica.git
ACPI组件框架(ACPI Component Architecture)工具,提供开源的iASL编译工具。
后面的这个是非必需的,不过建议下载,编程比较方便。
4) edk2-libc 仓库:tianocore\edk2-libc
仓库地址:https://github.com/tianocore/edk2-libc.git
UEFI下的StdLib库,可以使用C标准库进行UEFI的编程。
打开WSL(我的环境是Ubuntu18.04),建立工作目录,比如取名为MyWorkspce。并把上述需要的仓库代码git到本地,示例如下:
$ mkdir Myworkspace
$ git clone –recursive https://github.com/tianocore/edk2.git
$ git clone https://github.com/tianocore/edk2-platforms.git
$ git clone https://github.com/acpica/acpica.git
如需要编译使用StdLib库的程序,把edk2-libc库也git下来:
$ git clone https://github.com/tianocore/edk2-libc.git
下载后,我的目录夹如下所示:
图1 EDK2的工作目录
3 安装编译所需工具
编译所需的工具如下:
1) Python2.7/Python3 Python解释器,我使用的是Python3;
2) uuid-dev 需要头文件uuid/uuid.h;
3) build-essential 包含make、gcc、g++等工具;
4) bison 词法生成器,用于GNU编译工具包的语法生成,acpica工具需要它;
5) flex 词法分析器,acpica工具需要它;
安装命令如下:
$ sudo apt install bison build-essential flex uuid-dev
$ sudo apt install python3 python3-distutils
检查安装的工具,在我的环境中是这样的:
$ make -v
GNU Make 4.1
$ gcc –version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
$ g++ –version
g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
$ python3 -V
Python 3.6.9
4 Arm跨平台编译工具链
在x86_64-linux上,可编译aarch64-elf的跨平台工具链可以这里下载:https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads。
可选择最新的编译器下载,带有’AArch64 ELF bare-metal target (aarch64-elf)’字样的是我们所需要的,注意是x86_64 Linux为host。
比如可以下载这个:gcc-arm-8.2-2019.01-x86_64-aarch64-elf.tar.xz,下载地址为https://developer.arm.com/-/media/Files/downloads/gnu-a/8.2-2019.01/gcc-arm-8.2-2019.01-x86_64-aarch64-elf.tar.xz。
在工作目录下建立文件夹toolchain,如图1,把跨平台编译解压到此处。
$ cd toolchain
$ tar xf gcc-arm-8.2-2019.01-x86_64-aarch64-elf.tar.xz
5 准备acpica工具和BaseTools
进入工作目录,编译acpica工具
$ make -C acpica/
在工作目录下,新建myexport.sh的批处理文件,写入如下内容:
export WORKSPACE=$PWD
export GCC5_AARCH64_PREFIX=$PWD/toolchain/gcc-arm-8.2-2019.01-x86_64-aarch64-elf/bin/aarch64-elf-
export PACKAGES_PATH=$PWD/edk2:$PWD/edk2-platforms:$PWD/edk2-libc
export IASL_PREFIX=$PWD/acpica/generate/unix/bin/
export PYTHON_COMMAND=/usr/bin/python3
将此批处理文件设置为可执行(chmod +x),然后编译BaseTools工具集:
$ source ./myexport.sh
$ source edk2/edksetup.sh
$ make -C edk2/BaseTools
6 编译所需要的固件和UEFI程序
为FVP AEMv8A平台编译固件:
$ build -a AARCH64 -t GCC5 -p edk2-platforms/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc -b DEBUG
为Arm Juno平台编译固件:
$ build -a AARCH64 -t GCC5 -p edk2-platforms/Platform/ARM/JunoPkg/ArmJuno.dsc -b DEBUG
我自己建立的、常用的包RobinPkg,将其拷贝到edk2-libc目录下,也可以编译里面的代码了,比如:
$ build -a AARCH64 -t GCC5 -p edk2-libc/RobinPkg/RobinPkg.dsc -m edk2-libc/RobinPkg/Applications/Luo2/Luo2.inf
所有生成的文件都在工作目录下的Build文件夹中。
补充一个小故事。
昨天下午,和同事调试飞腾的问题,我们想把现有的UEFI代码移植到飞腾FT-2000的平台上。
调试到一半,接到报告说,在UEFI driver中,PCIIO的protocol调用,放在mian函数中能正常工作;另外写了个函数,把这个调用放在函数中,由main函数调用,就无法正常工作了。
???,还有这种事?!
我看了下调试现场,还确实是。再看代码,读了几分钟,也看不出什么错误。
一瞬间,冒出了各种想法:驱动的回调函数在不同阶段被调用,全局变量在栈上被清除了?调用过程中,被其他事件打断,用了核心变量?……
尝试着把核心变量的地址和值打印出来,也没有错。
那种心情到现在我还记得非常清楚,好像之前搭建的对计算机的理解、对语言的理解、对UEFI体系的理解,在逐渐解体,出现裂痕,开始崩塌…
我实在无法理解,同样的调用,加一层函数就无法工作了?
兴趣突然高涨,我一定要找到我理解的盲点。抛弃看到的代码,根据需要的功能,自己重新实现了一遍。
编译,没有出错;找U盘拷贝文件,开机运行;进入UEFI Shell,加载执行:
工作正常!
想象中的大厦好像开始自动弥补裂缝,重新站好了。
还是同事眼神好,比较了新写的代码和原来的代码,发现某个参数多加了取值符,导致存入的位置全是错的。
在这个小插曲后,终于解决了飞腾遇到的所有设备访问问题,后续只要继续构建代码,调整细节就可以了。
感谢飞腾的张老师、合作厂商的兄弟以及这两周陪着我们调试的外协兄弟们,长沙见!