(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
EDK2模拟器搭建网络环境
最近一段时间,很多网友问的问题都是和网络相关的。讨论的问题大部分是关于网络环境的搭建,有些现象我也没有遇到过。
在UEFI开发探索49中,介绍过在Nt32模拟器和真实环境中搭建UEFI网络环境。当时我使用的EDK2是UDK2018的版本。
随着EDK2版本的升级,原有的NT32模拟器(使用Nt32Pkg编译)已经取消了,随之替代的是EmulatorPkg。后者提供的功能更为全面,提供了32位和64位的模拟器,之前的博客中也曾经介绍过。
因此,本篇准备用EmulatorPkg编译的模拟器重新搭建网络测试环境。之前的模拟器使用Nt32Pkg编译,所以我取名为Nt32模拟器;现在的EmulatorPkg名字太长了,为方便行文,称之为EDK2模拟器了。
1 搭建EDK2开发环境
详细的搭建过程,可以参考UEFI开发探索22和57,这里简单描述本次的搭建过程。步骤如下:
1)工具安装
安装必要的开发工具,包括Visual Studio、Python、ASL和Nasm;
2)下载代码库
使用Git将EDK2的代码和StdLib的代码下载到本地。
在C盘新建目录edk202011,使用如下命令下载:
robin@robin-PC MINGW64 /c/edk202011
$ git clone --branch stable/202011 https://gitee.com/luobing4365/edk2.git
$ git clone https://gitee.com/luobing4365/edk2-libc.git
请注意,这里下载的地址是我的私有仓库,我把github上的edk2和edk2-libc的仓库同步到我在gitee上的仓库中了,方便自己下载。
不要按照我给的命令去下载,原始的仓库为https://github.com/tianocore/edk2.git 和https://github.com/tianocore/edk2-libc.git,可以使用如下命令去下载:
$ git clone --branch stable/202011 https://github.com/tianocore/edk2.git
$ git clone https://github.com/tianocore/edk2-libc.git
当然,取决于你所在地方的网速,下载速度会很慢。建议使用同样的方法,将github上的仓库同步到gitee上,或者直接在gitee上找到同样的仓库再下载。
本篇使用的分支为stable/202011,后续的实验结果均是基于此版本得出的。
3)更新子模块
修改edk2中的.gitmodules,更子模块。
如果能使用github直接下载,可以不用修改.gitmodules,直接运行后续的更新命令就可以了。我修改的内容如下:
[submodule "CryptoPkg/Library/OpensslLib/openssl"]
path = CryptoPkg/Library/OpensslLib/openssl
url = https://gitee.com/luobing4365/openssl.git
[submodule "SoftFloat"]
path = ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
url = https://gitee.com/luobing4365/berkeley-softfloat-3.git
[submodule "UnitTestFrameworkPkg/Library/CmockaLib/cmocka"]
path = UnitTestFrameworkPkg/Library/CmockaLib/cmocka
url = https://gitee.com/luobing4365/cmocka.git
[submodule "MdeModulePkg/Universal/RegularExpressionDxe/oniguruma"]
path = MdeModulePkg/Universal/RegularExpressionDxe/oniguruma
url = https://gitee.com/luobing4365/oniguruma.git
[submodule "MdeModulePkg/Library/BrotliCustomDecompressLib/brotli"]
path = MdeModulePkg/Library/BrotliCustomDecompressLib/brotli
url = https://gitee.com/luobing4365/brotli.git
[submodule "BaseTools/Source/C/BrotliCompress/brotli"]
path = BaseTools/Source/C/BrotliCompress/brotli
url = https://gitee.com/luobing4365/brotli.git
ignore = untracked
再次提醒,上述的子模块给出的地址,均是我将子模块在github上的仓库,导到gitee上的地址。可以参考我的方法,但是不要直接使用,这些都是我的私有地址,没法直接用。
具体的导入方法,可以参考UEFI开发探索57的内容。
接着使用如下命令,更新子模块:
$ git submodule update --init
4)编译工具
将ekd2-libc中的三个文件夹:AppPkg、StdLib和StdLibPrivateInternalFiles,全部复制到edk2目录下,方便后续的编译。(当然也可以不这么做,之前的博客中介绍过方法,请自行查阅)
打开Visual Studio的Native命令行(比如“VS2015 x86 Native Tools Command Prompt”),使用如下命令编译BaseTools以及其他的工具:
C:\edk202011\edk2> edksetup.bat Rebuild
编译完成后,BaseTools及其他工具会自动生成。
可以使用如下命令,测试开发环境是否搭建成功:
C:\edk202011\edk2> build -p AppPkg\AppPkg.dsc -a IA32
会发现提示错误。主要是因为AppPkg的第31行,有这么一句话(我使用的是最新的StdLib库-20210821):
!include MdePkg/MdeLibs.dsc.inc
edk2的源代码中,并没有找到这个文件。在语句前加符号“#”,将此句注释掉,再次编译AppPkg。可以看到编译成功,表示开发环境搭建好了。
2 搭建网络测试环境
本次搭建的网络测试环境,只针对EDK2的32位模拟环境。主要是因为Intel所提供的NetNt32Io文件,只支持32位的。虽然EDK2模拟环境(EmulatorPkg编译)支持32位和64位,测试64位的网络程序,还是在实际机器上进行吧。
搭建步骤如下:
1)安装Winpcap
Winpcap是一款用于网络抓包的专业软件,是一个免费、公共的网络访问系统。它能为win32应用程序提供访问网络底层的能力,在模拟器中,相当于网卡的驱动。下载地址为:
https://www.winpcap.org/default.htm。
此工具必须安装,通过模拟器发出的网络包,会被Winpcap抓到并转发。
2)编译SnpNt32Io
从github上将源码下载到本地:https://github.com/tianocore/edk2-NetNt32Io。
在C盘下建立文件夹NetNt32Io,将源代码复制进去。
然后下载Winpcap的开发包WpdPack,下载地址为:https://www.winpcap.org/devel.htm。解压WpdPack,复制到刚才建立的文件夹NetNt32Io中。建立好的目录如下:
图1 SnpNt32Io编译目录结构
打开Visual Studio的命令行(与编译UEFI代码的命令行相同),进入到源码目录,输入如下命令:
C:\NetNt32Io> nmake TARGET=RELEASE
NetNt32Io文件夹中会自动生成目录Release_IA32,目录中包含我们需要的SnpNt32Io.dll。
3)编译EDK2模拟器
按如下命令编译32位模拟器:
C:\edk202011\edk2> edksetup.bat
C:\edk202011\edk2> build -p EmulatorPkg\ EmulatorPkg.dsc -a IA32
所编译的出的模拟器,位于文件夹C:\edk202011\edk2\Build\EmulatorIA32\DEBUG_VS2015x86\IA32下。
4)配置模拟器网络环境
将之前编译好的SnpNt32Io.dll复制到模拟器所在目录,并在此目录下建立批处理文件loadnetwork.nsh,内容为:
load MnpDxe.efi ArpDxe.efi Ip4Dxe.efi VlanConfigDxe.efi Udp4Dxe.efi Dhcp4Dxe.efi Mtftp4Dxe.efi TcpDxe.efi
批处理文件中的UEFI驱动,都可以在模拟器目录下找到,编译模拟器的时候一起编译生成的。
双击模拟器目录下的执行文件WinHost.exe,启动模拟器,进入UEFI Shell环境。运行批处理文件,加载网络相关驱动:
Shell> fs0:
FS0:\> loadnetwork.nsh
我机器的IP地址为192.168.181.132,网关为192.168.181.2。将模拟器中的网络地址设置为192.168.181.135,命令如下:
FS0:\> ifconfig -s eth0 static 192.168.181.135 255.255.255.0 192.168.181.2
配置完成后,可以使用“ifconfig -l eth0”和ping命令查看是否配置成功。
FS0:\> ifconfig -l eth0
name : eth0
Media State : Media state unknown
policy : static
mac addr : 00:0C:29:D5:97:D7
ipv4 address : 192.168.181.135
subnet mask : 255.255.255.0
default gateway: 192.168.181.2
Routes(2 entries):
Entry[0]
Subnet : 192.168.181.0
Netmask : 255.255.255.0
Gateway: 0.0.0.0
Entry[1]
Subnet : 0.0.0.0
Netmask : 0.0.0.0
Gateway: 192.168.181.2
DNS server :
FS0:\> ping 192.168.1.42
ping 192.168.1.42 16data bytes.
16 bytes from 192.168.1.42 : icmp_seq=1 ttl=0 time0~26ms
…
我的UEFI开发用机器,是Vmware虚拟机,操作系统为Win10,UEFI的开发环境是在其上构建的。宿主机的操作系统也为Win10,宿主机上跑了一堆的虚拟机,用来进行各种不同需求的开发。
宿主机相当于局域网内的另外一台机器,其IP地址为192.168.1.42。
总之,到此为止,网络环境搭建完成了,下面进行网络程序测试。
3 网络程序测试
之前为了测试UEFI的网络,开发了Windows端的服务器程序和UEFI端的客户端程序,分别为EchoServerTCP4.exe和EchoTcp4.efi。
EchoServerTcp4.exe的程序之前就编译好了,只需要编译客户端的代码。
将UEFI开发探索博客的仓库中的RobinPkg,复制到现在搭建的UEFI开发环境中,编译EchoTcp4.efi:
C:\edk202011\edk2>build -p RobinPkg\RobinPkg.dsc -m RobinPkg\Applications\EchoTcp4\EchoTcp4.inf -a IA32
(近期我重新修改了EchoTcp4了,代码更新过。实际上,使用stdEchoTcp4项目也是一样的。)
把编译好的EchoTcp4.efi,复制到模拟器所在的目录。
在宿主机上运行服务器程序,EDK2模拟器上运行客户端程序,测试结果如下:
图2 测试网络通信
当然,也可以使用常用的网络调试助手来进行测试。测试结果如下:
图3 使用网络调试助手测试
平常我很少需要调试UEFI的网络程序,因此一直都用本篇的方法搭建好的环境进行测试。
实验过程中,也发现几个问题:
1)防火墙会影响包的发送,最好把防火墙全部关掉。也许是Winpcap的抓包能力被影响了,我没有使用过Winpcap写过程序,了解原理的网友可以帮忙看下;
2)设置EDK2模拟器网址的时候,设置为dhcp的时候,有的时候成功,有的不成功,怀疑与路由器有关。具体原因未知,也许在深入模拟器原理后能解释这问题。
3)在运行EDK2模拟器的操作系统上,使用服务端软件和模拟器上的客户端软件通信,是不成功的。也就是说,服务端软件需要运行在同局域网内的其他机器上才行。比如我使用的宿主机跑服务端软件,虚拟机Win10跑EDK2模拟器,模拟器上跑客户端软件。宿主机和虚拟机相当于是在一个局域网内,所以运行正常。
这些问题供大家参考,具体原因我也不清楚,欢迎大家留言讨论。
为方便实验,我把本篇实验需要的Winpcap、WdpPack(Winpcap开发包)和NetNt32Io的源码放到了仓库里:
Gitee地址:https://gitee.com/luobing4365/uefi-explorer
项目文件位于:/ 97 Network-Emulator下