UEFI开发探索61-VFR文件和其他资源文件2(NVRAM上存储数据)

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

NVRAM全称为Non-Volatile Ram(非易失性内存) ,Legacy BIOS下这块是使用CMOS来实现的,UEFI下则可以直接在ROM中分出一部分来实现。(问题来了,在UEFI下CMOS到底怎么用的呢? 有机会再研究一下)

UEFI下,对NVRAM的使用如图1所示。

图 1 配置参数存储于NVRAM

在上一篇博客代码的基础上,进行部分修改,将用户的选择存储于NVRAM,修改步骤如下。

继续阅读“UEFI开发探索61-VFR文件和其他资源文件2(NVRAM上存储数据)”

40 total views, 5 views today

UEFI开发探索60-VFR文件和其他资源文件1(在BIOS setup上增加项)

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

如何使用VFR文件,是我这一段时间比较感兴趣的课题。包括VFR文件在内,UNI文件、IDF文件,都属于资源文件。UNI文件的使用,在之前Hii的例子中,已经讨论过了。而如何使用VFR文件,一直没有涉及到。

接下来的几篇博客,将以修改BIOS Setup(当然,还是以OvmfPkg编译的镜像来做BIOS文件)为例,演示如何使用VFR文件和相关的资源文件。

图1 OVMF镜像的BIOS界面

本篇的例子以Intel提供的示例驱动MyWizardDriver为基础,添加了字符串和窗体,修改步骤如下。

继续阅读“UEFI开发探索60-VFR文件和其他资源文件1(在BIOS setup上增加项)”

76 total views, 6 views today

UEFI开发探索59-UDK Debugger Tool调试Firmware

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

这篇博客使用的是Windbg+UDK Debugger Tool调试代码,在Windows10下操作,具体搭建方法可以查看以前的博客。

在最近的开发中,因为碰到不少问题,对UEFI的调试方法更为深入了。在第39篇博客中留下的问题(7 小尾巴),也有了解答,后续看什么时候再把解答补上。

虽然在日常开发中,很少直接用到固件,但在学习中,需要跟踪UEFI每个阶段的工作,直接使用OvmfPkg编译后的Firmware,对其进行调试是个不错的方法。

图1为UEFI运行的7个阶段:

图1 UEFI运行过程
继续阅读“UEFI开发探索59-UDK Debugger Tool调试Firmware”

66 total views, 3 views today

UEFI开发探索58-UTF-8编码问题

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

这篇要记录的知识,实际上不限于UEFI编程,在其他编程上也一样会遇到。只是因为最近这段时间,沉迷于国产机器开发的项目,频繁地调试UEFI代码,遇到了这些问题,我觉得应该有普遍性,姑且记录下来。

在日常的编程中,特别是处理字符串以及显示汉字的时候,会被各种编码搞得糊里糊涂。毕竟编码是给计算机程序看的,记忆起来还是比较费事,即使当时搞清楚了,过一段时间不用,好像又会混淆。

1 历史

计算机从美国发展起来,最早是使用1个字节来表示各种字符和控制符。0x020以下的用来做控制,称为为“控制码”;0x20以上直至0x7F,用来表示各种英文字母、标点和各种符号的编码。

这种编码方式,就是我们现在熟知的ANSI的ASCII编码。其后计算机广泛发展,曾经也使用过0x7F~0xFF用来表示新的符号和字模,比如交叉等形状,这些字符集被称为“扩展字符集”。

在中国,我们有上万汉字,几个个常用字,使用1个字节明显无法表示完。我们制定了一个汉字的解决方案:小于0x7F的字符的意义与原来相同,但两个大于0x7F的字符连在一起时,就表示一个汉字,前面的一个字节(高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样就可以组合出大约7000多个简体汉字了。

在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的“全角”字符,而原来在0x7F号以下的那些就叫“半角”字符了。

这种方案称为GB2312,是对ASCII的扩展。后来发现还是不够用,于是干脆取消了低字节必须大于0x7F的规定了,只要高字节大于0x7F,就是汉字了。这个方案就是GBK,它比GB2312多了2万多个新汉字和符号。再后来增加几千少数民族的字,GBK扩展成了GB18030。

好了,我们汉字这么搞,其他国家也制定自己的文字编码方案。互相之间谁都不懂,也不支持。于是ISO(国际标准化组织)出来搞定这件事,他们准备废了所有地区性编码方案,建立一套新的编码方案,包括地球上所有文化、所有字母和符号的编码,取名为“Universal Multiple-Octet Coded Character Set”,简称 UCS, 就是我们常说的 UNICODE方案。

图1 我的Unicode启蒙书
继续阅读“UEFI开发探索58-UTF-8编码问题”

209 total views, 4 views today

UEFI开发探索57-如使用最新的EDK2搭建编译环境

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

最近浏览github上edk2的发布代码,注意到一个问题,现在发布的方式有点不一样了。之前过一段时间,就会发布一个完整的打包源代码,比如2018年3月发布的UDK2018,我一直都用这个开发的。不过,我没有找到UDK2019,更别说UDK2020了。

为什么我关注这个呢?主要是因为这种打好包的源码,整理得比较好,也比较稳定,并且还提供完整的API文档。另外,如果直接git EDK2的主线,编程时会发现它其实缺一些包是,有的包些还需要在Google的项目中下载。(观察下https://github.com/tianocore/edk2下的.gitmodules就知道了)

既然没有更新的打包源码,就只能用git下载最新的EDK2来编译了。不过,github那感人的下载网速,没有一定的定力,还真扛不住。

之前的博客中,其实已经给了解决的方法了。但是没有详细讲如何搭建最新的EDK2编译环境,正好用这篇博客完整地说一遍。

1 将github上项目导入到gitee仓库上

具体的方法可以参考我之前的博客:

或者

https://blog.csdn.net/luobing4365/article/details/105658274

继续阅读“UEFI开发探索57-如使用最新的EDK2搭建编译环境”

310 total views, 4 views today

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的工作目录
继续阅读“UEFI开发探索56-使用WSL编译Arm架构的UEFI镜像”

164 total views, 2 views today

使用gitee下载github项目

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

这段时间在写UEFI的代码,总需要从github上下载东西。众所周知的原因,github下载非常的慢,有时甚至只有8Kb/s。在这个外网速度动辄百兆的时代,这种下载速度也是比较感人了。也试过修改hosts,修改DNS,没什么作用。

最近实在忍受不了了,我用gitee把需要下载的项目,从github上同步过来,终于解决了这个问题。

这里把步骤记录一下。

1 为gitee设置ssh key

申请一个gitee账号,如同github一样,现在提供两种下载方法:

https://gitee.com/luobing4365/edk2.git
git@gitee.com:luobing4365/edk2.git

使用git clone,跟上两者任何一个地址,都可以把项目git到本地。不过,如果需要提交项目时,前者必须要输入用户名和密码;后者可以通过ssh key通过rsa把私钥存在本地,公钥存在远程库的网站上,省去认证的过程。

也就是说,设不设置ssh key都可以。不过,作为一个可以躺着绝对不站着的极懒程序员,我建议还是设置下比较好。

以下的操作,我是在windows 10的WSL(ubuntu 18)中进行的。

1) 设置git的用户名和邮件地址

命令如下,当然,git应该已经安装了才行:

git config –global user.name “luobing”  #注意是双中横线
git config –global user.mail “luobingxxxx@yyy.com”

提醒:git config -? 可以获取支持的命令参数。

使用 git config –list获取当前设置的用户名和邮箱。

继续阅读“使用gitee下载github项目”

2,462 total views, 28 views today

UEFI开发探索55 – UEFI与网络5(IPv6)

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

本篇开始编写IPV6的代码。因为一直使用的网络调试助手不支持IPV6的通信,只好花了点时间,自己把相关的IPV6的代码(windows和linux下)实现了一遍。

1 搭建IPV6的通信环境

由于现在基本上还在使用IPV4的网络,特别是家庭中,很少使用支持IPV6的路由器。所以,如果需要在双机间调试IPV6的代码,最好买个支持IPV6的路由器,按照路由器手册设置一下就可以了。

当然,我们也可以虚拟机来搭建通信环境。我所使用的虚拟机,都是使用NAT模式的。在打开IPV6支持选项前,虚拟机操作系统上的网卡,没有分配对外的IPV6的地址,导致无法与宿主机通信。

做个类比,开启虚拟机的IPV6支持选项,相当于为虚拟机添加了IPV6的路由器。虚拟机操作系统上的网卡设备会分配IPV6地址,虚拟机之间、虚拟机和宿主机之间可以通过IPV6通信。

记录下Vmware和VirtualBox打开IPV6的方法。

继续阅读“UEFI开发探索55 – UEFI与网络5(IPv6)”

226 total views, no views today

UEFI开发探索54 – UEFI与网络4(IPv4)

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

本篇主要讨论怎么使用StdLib的库函数编写TCP4的代码。

上一篇中直接使用UEFI提供的TCP4 Protocol编写代码,比较复杂,需要自己重新构建所有代码。我们还是希望能够直接使用标准的Socket库来编程,这样可以直接复用以前编写的Socket代码,减少编程的工作量。

1 BSD Socket接口

StdLib中提供的是标准BSD Socket接口,允许不同主机或同一计算机的不同进程之间的通信,是事实上的连接互联网的标准接口。

BSD Socket中要求的API接口,在UEFI的实现中基本都提供了。主要的头文件如下(StdLib\Include下):

<sys/socket.h>  socket 的核心函数和数据结构;
<netinet/in.h>  互联网地址族,AF_INET 和AF_INET6 地址家族和他们对应的协议家族 PF_INET 和 PF_INET6,包括IP地址以及TCP和UDP端口号;
<arpa/inet.h> 和IP地址相关的一些函数,比如地址转换的inet_pton()等;

由于UEFI并非完整的操作系统,也有很多BSD Socket中的API没有实现,比如针对计算机上程序间的本地通信的un.h。这些没有实现的函数,大部分是与网络通信无关,对我们的UEFI网络编程影响不大。

继续阅读“UEFI开发探索54 – UEFI与网络4(IPv4)”

321 total views, 1 views today

UEFI开发探索53 – VS2015调试UEFI代码(续第27篇)

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

在开发网络代码的时候,光用Print打印信息不足以满足开发要求,必须源代码级别的跟踪。我所测试的环境,大部分是在TianCore的模拟环境下。因此,如何在这个环境中,实现源码级跟踪,成为了很迫切的需求。

当然,我可以在Linux下开发,使用Qemu+gdb的方式来调试。不过,每次都要编译好,然后拷贝到镜像文件中,再启动调试,略嫌麻烦。我还是希望能在Windows下,使用VS来调试。

之前的博客第27篇中,我已经介绍了如何使用Vs2015搭建UEFI调试环境。经过这几天的学习,发现之前的有些结论有点偏差,所以再写一篇作为补充。

以我的经验,使用Nt32Pkg编译出来的模拟环境,配合VS2015自带的调试器,能满足我至少90%以上的开发需求。除去那些必须要在硬件上调试,只能使用windbg/gdb进行双机调试之外,这是目前为止最好的调试方法了。

上一篇讨论Vs2015调试环境中,谈到使用AppPkg编译的代码,无法进行源代码级调试,这个结论有点问题。实际上,只要做一些调整,是可以解决这个问题的。

继续阅读“UEFI开发探索53 – VS2015调试UEFI代码(续第27篇)”

197 total views, 1 views today

UEFI开发探索52 – UEFI与网络3(UEFI TCP4)

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

搭建好网络测试环境之后,可以着手进行网络编程了。

UEFI下提供了相应的Protocol,可以进行TCP和UDP的编程,而且针对IPv4和IPv6都提供了相应的支持。另外,也可以通过StdLib中封装好的Socket接口进行编程。

如果所有的编程方式都实现一遍,博客的篇幅就太长了。我原计划是用5篇左右的博客,把网络编程探索完的,因此,我准备用UEFI Protocol编写TCP(IPv4)示例和UDP(IPv4) 示例,以及StdLib接口把上述例子重新实现。

1 EFI_TCP4_PROTOCOL的使用

大部分的UEFI Protocol,可通过设备的GUID找到,直接访问即可。与其他UEFI Protocol不同,网络需要频繁地生成新的Socket。在规范中,针TCP4,提供了两种Protocol。

一是EFI_TCP4_PROTOCOL,可以进行TCP的网络配置和通讯;二是EFI_TCP4_SERVICE_BINDING_PROTOCOL,用来生成EFI_TCP4_PROTOCOL实例。

不过,在EDK2的实现中,并没有提供EFI_TCP4_SERVICE_BINDING_PROTOCOL,而是为所有的网络协议提供了EFI_SERVICE_BINDING_PROTOCOL。也就是说,虽然在Spec中提供了各种名为EFI_XXXX_SERVICE_BINDING_PROTOCOL的协议,其实都是使用EFI_SERVICE_BINDING_PROTOCOL。

继续阅读“UEFI开发探索52 – UEFI与网络3(UEFI TCP4)”

224 total views, 1 views today

UEFI开发探索51 – UEFI下的打印函数

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

原计划的50篇博客,终于完成了。可惜的是,现有的篇幅无法把最初设想的内容全部覆盖。因此,开发探索系列还会继续写下去,既然原定目标50篇已经达成,新的目标篇数就不设定了。只针对我感兴趣的各方面的内容,继续探索。

在日常的开发中,总会用到各种打印(print)函数。UEFI下的打印函数,其格式有点奇怪,和Windows及Linux下的print函数不大相同。而且又涉及到Ascii字符和Unicode字符的支持,在使用中总是犯一些小错,让人很是恼火。

因此,为了方便后面的开发,我准备将相关的打印函数整理出来,以备参考。

1OutputString()

最基本的打印输出函数,其他Print函数都是基于此函数构建的。其函数原型为:

typedef
EFI_STATUS
(EFIAPI *EFI_TEXT_STRING) (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This,//指向    
                                 //EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
实例的指针
IN CHAR16 *String //Null结尾的字符串
);

此函数向输出设备写入字符串,显示在当前光标处,是最基本的输出机制。

示例如下:

gST->ConOut->OutputString(gST->ConOut,L”Hello, UEFI World!\n\r”);

这是Simple Text Output Protocol最核心的函数,配合此Protocol的其他函数,比如SetAttribute等,可以实现彩色背景和彩色字体。在之前的博客中曾经展示过,可以做出与众不同的命令行式Sell程序。

2 格式化输出

PrintLib提供了格式化输出的支持函数,它支持所有Unicode和ASCII字符串。在Package的dsc文件中,一般都会提供这个库的编译。如下:

PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf

UEFI的格式化方式,与ANSI C的标准不尽相同,在使用的时候,很容易造成概念混淆。

格式化语法如下:

%[flags][width][.precision]type

继续阅读“UEFI开发探索51 – UEFI下的打印函数”

279 total views, 3 views today

UEFI开发探索50 – UEFI与网络2

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

3 在VirtualBox中使用网络

在UEFI开发探索系列博客的第48篇中,我介绍了如何在VirtualBox中搭建UEFI Shell。本节就在这篇博客的基础上,让VirtualBox下的UEFI Shell有访问网络的功能。

1) 安装网络驱动和网络协议驱动

我使用的是VirtualBox6.1.4,其虚拟网卡为Intel Pro/1000MT Desktop。网卡驱动下载地址为:

https://downloadcenter.intel.com/download/27539/Ethernet-Intel-Ethernet-Connections-Boot-Utility-Preboot-Images-and-EFI-Drivers

下载版本为22.10的PREBOOT.exe,双击安装。将目录/APPS/EIF/EFIx64下的驱动E3522X2.EFI拷贝到虚拟机的硬盘中。同时,将之前编译好x64的Ipv4网络协议驱动(MdeModulePkg)也拷贝到虚拟机的硬盘中。

启动虚拟机,进入UEFI Shell,执行如下命令,加载网卡驱动和网络协议驱动:

Shell>fs0:
fs0:>load E3522X2.EFI
fs0:> load SnpDxe.efi MnpDxe.efi ArpDxe.efi Ip4Dxe.efi VlanConfigDxe.efi Udp4Dxe.efi Dhcp4Dxe.efi Mtftp4Dxe.efi Tcp4Dxe.efi

2) 配置网卡。

使用ifconfig命令设置:

fs0:\>ifconfig -s eth0 dhcp

检查网络配置情况:

图1 VirtualBox的UEFI Shell中查看IP
继续阅读“UEFI开发探索50 – UEFI与网络2”

248 total views, 2 views today

UEFI开发探索49 – UEFI与网络1

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

UEFI提供了非常完整的TCP/IP网络协议栈,开发人员甚至可以在UEFI上开发自己的Web服务器。其网络协议栈如图1所示:

图1 UEFI的网络协议栈
继续阅读“UEFI开发探索49 – UEFI与网络1”

399 total views, 3 views today

UEFI开发探索48 – 搭建UEFI Shell环境

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

做UEFI的实验,32位的程序可以使用TianoCore的模拟环境进行测试。64位的程序,可以使用启动盘在实际的机器上测试,也可以使用虚拟机来测试。

制作启动盘很简单,不过,我之前保存的启动文件丢失了,正好重新做一遍,把过程记录下来。

1 制作UEFI BIOS下的启动盘

启动文件可以通过编译ShellPkg来得到。打开VS命令行,进入EDK的目录,执行edksetup.bat后,输入以下命令:

build -a IA32 -a X64 -p ShellPkg\ShellPkg.dsc -b RELEASE

在EDK的Build\Shell\RELEASE_VS2015x86目录下,会生成32位和64位的完整shell执行文件。

然后执行以下步骤:

1) 将U盘格式化为FAT32(FAT、FAT16也可以,现在很少使用了)格式;

2) 在U盘的根目录下建立efi\boot文件夹;

3) 将刚才生成的两个32位和64位shell执行文件(名称都是Shell.efi),分别改名为bootx32.efi和bootx64.efi,拷贝到U盘的efi\boot目录下。

做好的U盘插到计算机上,开机的时候选择从U盘启动(每款BIOS不大一样,常见的可以按F11选择启动项,或者进入Bios Setup设置从U盘启动),即可进入UEFI shell了。

继续阅读“UEFI开发探索48 – 搭建UEFI Shell环境”

472 total views, 3 views today

UEFI开发探索47 – UEFI上移植GUILite

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

上一篇的博客中,已经搭建了C++的编程框架,虽然不是所有C++特性都支持了,比如new和delete,以及虚析构函数等,但是用来移植GuiLite已经足够了。下面就开始着手这一工作。

1 代码选择

GuiLite的例子比较丰富,从控件到动画、甚至3D的实现,都可以找到。浏览了一圈后,我选择从HelloTimer开始动手。

这是在STM32F103上运行的代码:

图1 STM32F103例程: HelloTimer
继续阅读“UEFI开发探索47 – UEFI上移植GUILite”

354 total views, 2 views today