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

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

luobing4365

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

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

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

打赏作者

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

抵扣说明:

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

余额充值