uefi学习笔记414

Snp的Start和Stop函数最终由Mnp的Config函数调用

Arp的每一个ServiceData与MnpService中的一个instance对应,因为Service中的mnp结构体是创建Instance的时候安装的,而且安装的Efihandle都是新创建的

GE驱动在UEFI下的适配工作内容

1、edk2中网络协议栈的一些驱动还有这些驱动依赖的组件添加到编译和启动
uefi下的整个网络协议栈
在这里插入图片描述

要是使用完整的网络功能,就要把MNP及以上的模块都添加到编译和启动
我们现在使用的edk2版本,大部分网络协议栈相关的驱动模块都放在了edk2下的
ModeModulePkg/Universal/Network/
后边添加进来的网络驱动模块都放在edk2下的NetworkPkg下
比较新的版本的edk2已经把所有网络相关的移到NetworkPkg下了
在这里插入图片描述

2、edk2中shell的网络相关的内置命令添加到编译
edk2的shell本体以及Shell的所有内置命令位于根目录下ShellPkg
shell的内置命令以Lib的形式提供
每个lib可能包含多条命令
网络相关的内置命令在UefiShellNetwork1CommandsLib和UefiShellNetwork2CommandsLib
包括ping和ifconfig
Note:ifconfig没有up和down的功能
在这里插入图片描述

3、开发Snp驱动和它对应的PlatformDevice驱动
edk2也提供了SnpDxe这个模块,如果使用这个SnpDxe,网卡驱动就要实现一个undi驱动,适用于网卡模块作为pci外设的情况
参考edk2wPlatdorm下多个ArmSoc厂商的开源驱动,都是直接开发一个Snp驱动替代SnpDxe直接与上层的Mnp交互
主要参考BroadCom的开源驱动,实现一个Snp驱动(标准驱动)和一个PlatformDecice驱动(Dxe驱动)
PlatformDecice驱动主要作用是提供一个ControllerHandle,并在其上安装一个PlatformDeviceProtocol当然也可以将一些平台相关的操作封装成函数,作为PlatformDeviceProtocol的函数指针成员提供给Snp驱动调用

Snp驱动是标准驱动,采用DriverBindingProtocol,在Supported函数中判断ControllerHandle上是否安装了PlatformDeviceProtocol,并在Start函数中创建并初始化EFI_SIMPLE_NETWORK_PROTOCOL的PrivateData,将EFI_SIMPLE_NETWORK_PROTOCOL安装到ControllerHandle上

因此Snp的主要任务就是实现EFI_SIMPLE_NETWORK_PROTOCOL
在这里插入图片描述

与linux中网卡驱动提供的Ops有点类似
Initialze函数完成网卡驱动运行所需资源的申请
ShutDown函数是Initialize函数的反向操作

Start–>Initialize–>Shutdown–>Stop

Reset函数好像没有上层调用

Transmit函数被上层调用发送一帧的数据

Receice函数被上层调用查看是否收到一帧数据,如果有拷贝到上层申请好的存储区,没有返回ERROR
GetStatus函数被上层调用查看Phy的Link状态是否有变化,以及是否有数据发送完成,如果有直接返回发送数据的存储区指针
Mnp中创建了轮询事件,每500ms调用一次Snp->GetStatus

DriverBindingProtocol

uefi下的驱动分成两种
标准的和不标准的
不标准的就是常使用的.inf文件里边MODULE_TYPE:DXE_DRIVER的这种
标准的MODULE_TYPE:UEFI_DRIVER

不标准的驱动在戴正华那本书里称之为一种服务
也就是说这个模块的entryPoint中创建一个controller的ef_handle直接安装上一个功能性Protocol,供其他模块打开使用

而标准的驱动要在entryPoint中安装一个非功能性的Protocol,即DriverBindingProtocol
安装在这个模块的ImageHandle上边

这个就很像linux里驱动模块的入口函数中把一个驱动注册上去,驱动的功能暂时不会发挥作用,除非出现一个device,匹配上之后,prob函数执行,这个driver上的功能才会安装到device上

DriverBindingProtocl也是这个意思
它里边有三个重要的函数指针成员变量
在这里插入图片描述

其中Supported函数就是用来判断新产生的ControllerHandle是不是跟这个Driver匹配,如果匹配就返回EFI_SUCCESS,然后Start就得到执行,这个Start函数就类似Prob函数,Supported函数完成compatible的比对

执行Start的时候,会把这个驱动的功能性的一个Protocol安装到匹配的那个ControllerHandle上,这才是这个驱动真正要干的活儿

当然也可以在DxeDriver的erntryPoint中判断是否存在有匹配的ControllerHandle,不存在我就不安装,不安装就结束,这样后边如果有匹配的ControllerHandle被创建也不会运行这个驱动了,这样就需要保证这个DxeDriver必须在ControllerHandle产生之后创建,当然可以通过fdf文件去调整,但这样就很蹩脚

由此可见DriverBindingProtocl就是为了干这个而生的

ServiceBindingProtocol

ServiceBindingProtocol与DriverBindingProtocol配合使用

如果只使用DriverBindingProtocol,在ControllerHandle上安装一个功能性的Protocol,提供其他模块去使用
如果只有一个模块使用这个Protocol也还好
或者多个模块使用这个Protocol但是这个Protocol提供的功能比较简单,那也还好
但是,如果有多个模块使用这个Ptotocol,那在打开这个Protocol之后对应的PrivateData就会是同一个,这样多个模块使用Protocol的时候就要有一些同步互斥的行为,因为要访问同一个数据结构

这个时候使用ServiceBindingProtocol就比较合适,它的行为很像应用开发的时候,TCP的server端,它会在初始化的时候创建一个监听Socket,如果有Client端来连接,Sever端会建立一个Socket与Client的Socket去连接,通过这一对socket就可以提供服务了,监听Socket继续监听其他Client端的连接请求。

如果要使用它的话,也要先使用DriverBindingProtocol,在驱动模块的EntryPoint中安装DriverBindingProtocol到与之匹配的ControllerHandle上,在DriverBindingProtocol的Start函数中并不安装一个功能性的Protocol提供这个驱动真正要提供的功能,而是在ControllerHandle上安装一个ServiceBindingProtocol,然后结束

这个ServiceBindingProtocol只有两个函数指针成员变量
struct _EFI_SERVICE_BINDING_PROTOCOL {
EFI_SERVICE_BINDING_CREATE_CHILD CreateChild;
EFI_SERVICE_BINDING_DESTROY_CHILD DestroyChild;
};

如果只使用DriverBindingProtocol驱动提供的功能只要OpenProtocol打开ControllerHandle上安装的功能性的Protocol就可以了,如果使用ServiceBindingProtocol的话就要先打开安装在ControllerHandle上的ServiceBindingProtocol,然后调用CreateChild,这个函数中首先创建一个EfiHandle,然后把功能性的Protocol安装到新创建的EfiHandle上,当然也会创建一个这个功能性的Protocol对应的PrivateData

如果多个模块想使用这个驱动的功能,就会多次调用CreateChild,每次创建一份EfiHandle + 功能性的Protocol + 对应的PrivateData(Instance)

ServiceBindingProtocol也有对应的PrivateData(ServiceData)

通常一个ServiceBindingProtocol创建的多个Intance会通过双向链表连在一起,并在ServiceData有一个指向这个链表的指针

这样多个模块同时使用这个功能性的Protocol的时候,同步的工作就交给驱动内部完成,每个模块使用Protocol的时候不感知其他模块。

举例说明:snp+mnp+arp
这是UEFI网络驱动框架的一部分的调用关系
在这里插入图片描述

每个网卡对应一个SnpDxe

每个Snp对应一个MnpDxe

MnpDxe主要通过安装EFI_MANAGED_NETWORK_PROTOCOL向其他模块提供服务
在这里插入图片描述

Mnp并不属于网络协议栈,对于数据主要起一个透传的作用,也有Transit和Receive函数
但是可以通过Mnp管理Vlan,在网卡硬件不提供Vlan功能的时候

调用关系可以看出,Mnp向上层提供服务对象不只一个,因此MnpDxe中使用了ServiceBingingProtocol
在ControllerHandle上安装EFI_SERVICE_BINDING_PROTOCOL
在这里插入图片描述
在这里插入图片描述

EFI_STATUS
EFIAPI
MnpServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
)
{
EFI_STATUS Status;
MNP_SERVICE_DATA *MnpServiceData;
MNP_INSTANCE_DATA *Instance;
VOID *MnpSb;
EFI_TPL OldTpl;

MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);
//
// Allocate buffer for the new instance.
//
Instance = AllocateZeroPool (sizeof (MNP_INSTANCE_DATA));
//
// Init the instance data.
//
MnpInitializeInstanceData (MnpServiceData, Instance);

Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiManagedNetworkProtocolGuid,
&Instance->ManagedNetwork,NULL);
//
// Save the instance’s childhandle.
//
Instance->Handle = *ChildHandle;

Status = gBS->OpenProtocol (
MnpServiceData->ServiceHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
(VOID **)&MnpSb,
gMnpDriverBinding.DriverBindingHandle,
Instance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
//
// Add the child instance into ChildrenList.
//
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&MnpServiceData->ChildrenList, &Instance->InstEntry);
MnpServiceData->ChildrenNumber++;
gBS->RestoreTPL (OldTpl);
return Status;
}

DevicePathProtocol

DevicePathProtocol这也是一个要安装到ControllerHandle上的非功能性的Protocol,它没有函数指针成员,只有数据成员,这个成员表示这个ControllerHandle的路径

这个路径用来描述设备或者功能的从属关系

每个DevicePath由多个路径节点组成,存储上,这些节点都是一个挨一个的,uefi定义了很多种路径节点,每种节点的数据结构都不同,但是每种路径节点的第一个成员变量是相同的EFI_DEVICE_PATH_PROTOCOL,通过EFI_DEVICE_PATH_PROTOCOL的Type和SubType区分不同的类型,结合Length可以完成对一个DevicePath上所有节点的遍历

当然有专门的类型去标记一个DevicePath的结束

DevicePath每个节点根据类型不同,EFI_DEVICE_PATH_PROTOCOL之后的数据成员不同,有不同的意义

typedef struct {
UINT8 Type; ///< 0x01 Hardware Device Path.
///< 0x02 ACPI Device Path.
///< 0x03 Messaging Device Path.
///< 0x04 Media Device Path.
///< 0x05 BIOS Boot Specification Device Path.
///< 0x7F End of Hardware Device Path.

UINT8 SubType; ///< Varies by Type
///< 0xFF End Entire Device Path, or
///< 0x01 End This Instance of a Device Path and start a new
///< Device Path.

UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define
///< type of data. Size of data is included in Length.
} EFI_DEVICE_PATH_PROTOCOL;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

UEFI提供函数去解析DevicePath,遍历一个DevicePath,根据节点类型将后边的数据成员的意义解析并打印出来,就是我们在Shell中常见的DevicePath的样子

在这里插入图片描述

比如
一个pci的root上边挂了一个pci的usb控制器,pci口上又插了一个usb网卡
PciRoot节点/Usb节点/Mac节点

比如
一个网卡下管理了多个vlan
Mac节点/Vlan节点/Ip节点

比如
一个UsbController(Interface:0)连接到一个UsbHub(Interface:0)的第三个Port
UsbHub连接到一个PCI口的Usb根集线器(PCI Function Number:31;PCI_Device Number:2)的第一个Port上
USB根集线器连接到PCI Root上

在Shell中打印出来是这样的
PciRoot(0)/PCI(31,2)/USB(1,0)/USB(3,0).

在内存中是这样的

在这里插入图片描述在这里插入图片描述

除此之外DevicePath产生
1、可以直接定义一个Static的数据结构,可以包括多个节点
2、也可以只定义一个路径节点,调用UEFI提供的Append函数将ParentDevicePath拷贝一份并在之后添加自己定义的路径节点,形成自己的DevicePath

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
UEFI Shell是一种全新的操作系统环境,在现代计算机上广泛使用。相较于BIOS,UEFI Shell在启动时间和性能方面都有着很大的优势。UEFI Shell有其独特的运行环境,为用户提供了一种类似于操作系统的命令行界面来控制计算机的硬件和软件。 UEFI Shell可以很好的应用于系统调试和维护工作。因为UEFI Shell能够与UEFI BIOS直接进行交互,可以读取和修改UEFI BIOS中的各种变量。这些变量包括了计算机的系统时间、启动磁盘分区信息、设备启用状态等等。所以,当系统出现问题时,可以通过UEFI Shell来获取更多的系统信息、检测硬件故障以及查找系统错误等。 同时,UEFI Shell也支持各种文件系统格式。这使得我们可以在UEFI Shell中查看和管理硬盘分区,从而进行数据备份与还原、系统安装和修复等操作。此外,UEFI Shell还支持各种基本的命令,如文件与目录操作、网络连接管理、进程控制等。这让我们可以在更高效的状态下调试和管理系统。 对于初学者来说,UEFI Shell学习并不是一件容易的事情。因为UEFI Shell的命令和语法都有一定的学习曲线,需要一定的时间和经验去掌握。但是,如果您熟练掌握了UEFI Shell的使用,不仅可以解决常见的操作问题,还可以探究计算机系统的底层运作机理。这对于系统工程师来说尤为重要。 总之,UEFI Shell作为一种新兴的操作系统环境,拥有着广泛的应用场景和巨大的优势,不管是对于初学者还是经验丰富的系统工程师来说,掌握UEFI Shell的各种技术是一个不可或缺的技能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值