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

(请保留-> 作者: 罗冰   https://blog.csdn.net/luobing4365)

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

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。

相对的,EFI_SERVICE_BINDING_PROTOCOL本身并没有GUID。其他网络协议的Protocol都有自己的GUID,比如TCP4、UDP4、TCP6等,它们共享同一EFI_SERVICE_BINDING_PROTOCOL接口,用来生成本身的实例。

1) EFI_SERVICE_BINDING_PROTOCOL接口说明

typedef struct _EFI_SERVICE_BINDING_PROTOCOL {
EFI_SERVICE_BINDING_CREATE_CHILD CreateChild; //生成子设备,并安装对应的Protocol
EFI_SERVICE_BINDING_DESTROY_CHILD DestroyChild;//销毁生成的子设备
EFI_SERVICE_BINDING_PROTOCOL;

typedef EFI_STATUS (EFIAPI *EFI_SERVICE_BINDING_CREATE_CHILD) (
IN EFI_SERVICE_BINDING_PROTOCOL 
*This, //EFI_SERVICE_BINDING_PROTOCOL实例
IN OUT EFI_HANDLE *ChildHandle //创建的子设备句柄
);

typedef EFI_STATUS (EFIAPI *EFI_SERVICE_BINDING_DESTROY_CHILD) (
IN EFI_SERVICE_BINDING_PROTOCOL 
*This,//EFI_SERVICE_BINDING_PROTOCOL实例
IN EFI_HANDLE ChildHandle //创建的子设备句柄
);

基本的操作流程如下:

1-A) 通过gEfiArpServiceBindingProtocolGuid打开EFI_SERVICE_BINDING_PROTOCOL实例;
1-B) 使用此实例的CreateChild创建子设备;
1-C) 使用各网络协议的GUID,在子设备上安装对应的Protocol。具体的例子可以参考UEFI sepc 2.8 P390。


2) EFI_TCP4_PROTOCOL接口说明

typedef struct _EFI_TCP4_PROTOCOL {
EFI_TCP4_GET_MODE_DATA 
GetModeData;//获取当前协议栈状态
EFI_TCP4_CONFIGURE Configure;//配置TCP地址、端口等属性
EFI_TCP4_ROUTES Routes;//添加或删除此TCP实例的路由
EFI_TCP4_CONNECT Connect;//初始化TCP三次握手,建立TCP连接
EFI_TCP4_ACCEPT Accept;//侦听TCP连接请求
EFI_TCP4_TRANSMIT Transmit;//发送数据
EFI_TCP4_RECEIVE Receive;//接收数据
EFI_TCP4_CLOSE Close;//关闭连接
EFI_TCP4_CANCEL Cancel;//取消当前连接上的异步操作
EFI_TCP4_POLL Poll//完成当前连接上的发送或接收操作
} EFI_TCP4_PROTOCOL;

typedef EFI_STATUS (EFIAPI *EFI_TCP4_TRANSMIT) (
IN EFI_TCP4_PROTOCOL 
*This, //实例
IN EFI_TCP4_IO_TOKEN *Token //指向完成令牌的队列
);

typedef EFI_STATUS (EFIAPI *EFI_TCP4_RECEIVE) (
IN EFI_TCP4_PROTOCOL 
*This, //实例
IN EFI_TCP4_IO_TOKEN *Token //指向完成令牌的队列
);

Config、Connect以及Accept,可以在Spec中查到说明,这里只对发送和传输重点解释。发送和传输都使用了EFI_TCP_IO_TOKEN型指针,其原型如下:

typedef struct {
EFI_TCP4_COMPLETION_TOKEN 
CompletionToken;//完成操作的令牌
union {
EFI_TCP4_RECEIVE_DATA 
*RxData; //接收数据缓冲
EFI_TCP4_TRANSMIT_DATA *TxData//发送数据缓冲
Packet;
} EFI_TCP4_IO_TOKEN;

typedef struct {
EFI_EVENT 
Event;//此事件在请求完成之后触发
EFI_STATUS Status;//完成操作之后的状态标志
} EFI_TCP4_COMPLETION_TOKEN;

typedef struct {
BOOLEAN 
UrgentFlag;  //TCP头的紧急标志位
UINT32 DataLength; //数据总长度
UINT32 FragmentCount; //数据分段个数
EFI_TCP4_FRAGMENT_DATA FragmentTable[1];//数据分段的数组
} EFI_TCP4_RECEIVE_DATA;

typedef struct {
BOOLEAN 
Push//TCP头的PSH标志位
BOOLEAN Urgent; //TCP头的URG标志位
UINT32 DataLength; //数据总长度
UINT32 FragmentCount; //数据分段个数
EFI_TCP4_FRAGMENT_DATA FragmentTable[1]; //数据分段的数组
} EFI_TCP4_TRANSMIT_DATA;

数据结构有点多,不过条理还是比较清楚的。网络协议中大量的使用了事件,具体不一一解释了,参照数据结构还是比较容易理解的。

2 TCP4的编程

在实验中,我把UEFI作为客户端进行测试。设想中,服务端接收到客户端的数据后,将数据原样返回。

服务器的代码还没有编写,暂时使用“网络助手”来替代,模拟操作。

客户端代码编写过程大致可以分为以下几步:

1) 使用EFI_SERVICE_BINDING_PROTOCOL生成EFI_TCP4_PROTOCOL对象;
2) 对生成的对象进行配置,同时创建所需要的各种Event对象;
3) 向服务端发起连接;
4) 数据传输;
5) 关闭连接,并销毁EFI_TCP4_PROTOCOL对象。

下面对提供的示例代码作简单的解释。

为了保存网络通信的相关配置项和缓冲区地址,构造了名为MYTCP4SOCKET的数据结构,包括所用到的各种句柄、缓冲区、令牌等,都在此结构内。同时,定义了此类型的全局数组TCP4SocketFd[32],方便各个函数使用。

创建EFI_TCP4_PROTOCOL对象的函数为UINTN CreateTCP4Socket(VOID),大致是按照Spec中提供的例子编写的。

需要着重了解的是函数EFI_STATUS InitTcp4SocketFd(INTN index)。此函数在CreateTCP4Socket()中调用了,截图如下:

图1 代码截图

图中红框处的代码,与Spec中要求的略有不同。在测试中,如果使用EVT_NOYIFY_SIGNAL类型的话,数据是发送不了的(在TianCore模拟器中做的实验),所以做了一点改变。

其他的函数,理解相对简单,对照Spec中的Protocol说明,比较容易看懂,就不解释了。

测试

对照前几篇中的说明,搭建好网络测试环境。按如下命令进行代码编译:

C:\MyWorkspace>build -p RobinPkg\RobinPkg.dsc -a IA32 -m RobinPkg\Applications\EchoTCP4\ EchoTCP4.inf

在搭好的环境中,测试情况如下:

图2 测试TCP通信

Gitee地址:https://gitee.com/luobing4365/uefi-explorer
项目代码位于:/
FF RobinPkg/ RobinPkg /Applications/EchoTCP4

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
从BIOS到UEFI,是计算机引导程序的演进过程。 BIOS是基本输入输出系统(Basic Input/Output System)的简称,它是一组固化在计算机主板上的固件程序。BIOS的主要功能是在计算机开机时对硬件进行初始化,并将控制权转移给操作系统。然而,随着计算机硬件的不断进化和操作系统的更新,BIOS逐渐暴露出了一些局限性,比如启动速度较慢、内存限制等。 为了克服这些问题,UEFI(统一可扩展固件接口)应运而生。UEFI是一种现代的计算机固件接口规范,它取代了传统的BIOS。与BIOS相比,UEFI具有更多的优势。首先,UEFI支持更大的硬盘驱动器,允许操作系统和应用程序访问更多的存储空间。其次,UEFI还支持更加丰富和灵活的图形界面,使用户能够更方便地进行设置和操作。此外,UEFI还引入了许多新的功能,如网络启动、安全启动等,增强了计算机的性能和安全性。 从开发角度来看,BIOS和UEFI开发也有所不同。对于BIOS而言,开发人员主要需要熟悉硬件架构和编程语言,如汇编语言,以实现硬件初始化和操作系统加载。而对于UEFI开发人员则需要掌握C语言和面向对象编程,因为UEFI基于C语言进行开发,并且引入了面向对象的编程理念。此外,UEFI还需要开发和维护固件升级机制以及兼容性测试,以确保固件的稳定性和功能完整性。 总之,从BIOS到UEFI的发展是计算机引导程序的演进过程。UEFI作为一种现代的固件接口规范,解决了传统BIOS存在的一些问题,并且具备更多的扩展性和功能。从开发角度来看,UEFI需要掌握不同的编程语言和技术,以实现固件的开发和维护。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luobing4365

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值