12

UEFI开发探索56-使用WSL编译Arm架构的UEFI镜像

 3 years ago
source link: http://yiiyee.cn/blog/2020/05/14/uefi%e5%bc%80%e5%8f%91%e6%8e%a2%e7%b4%a256-%e4%bd%bf%e7%94%a8wsl%e7%bc%96%e8%af%91arm%e6%9e%b6%e6%9e%84%e7%9a%84uefi%e9%95%9c%e5%83%8f/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

UEFI开发探索56-使用WSL编译Arm架构的UEFI镜像

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

这篇本想讨论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上,同样可以参考我之前写的博客:

或者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,加载执行:

工作正常!

想象中的大厦好像开始自动弥补裂缝,重新站好了。

还是同事眼神好,比较了新写的代码和原来的代码,发现某个参数多加了取值符,导致存入的位置全是错的。

在这个小插曲后,终于解决了飞腾遇到的所有设备访问问题,后续只要继续构建代码,调整细节就可以了。

感谢飞腾的张老师、合作厂商的兄弟以及这两周陪着我们调试的外协兄弟们,长沙见!

614 total views, 2 views today


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK