BIOS/UEFI基础——UEFI网络框架之SNP

来源:互联网 发布:免费英语口语软件 编辑:程序博客网 时间:2024/05/17 22:27

SNP

SNP全称是Simple Network Protocol。

该模块的作用有以下的几个部分:

1. 网卡操作,比如初始化网卡,打开/关闭网口等;

2. 提供数据的传输接口,供上层协议使用;

SNP驱动依赖于UNDI/NII驱动,即网卡驱动。该驱动执行后会安装gEfiNetworkInterfaceIdentifierProtocolGuid_31对应的协议。

SNP驱动执行时就会去查看该协议是否存在,如果存在,就会据此构造SNP_DRIVER结构体来表示这张网卡。

后续对该网卡的操作都是通过SNP_DRIVER结构体,及其中的SNP来完成。

SNP驱动的初始化主要做了以下的是事情:

1. 初始化SNP_DRIVER结构体;

2. 创建ExitBootServicesEvent事件,是为了在退出UEFI之前关闭网络,避免网络的DMA写坏了OS启动需要的内存空间;

3. 安装gEfiSimpleNetworkProtocolGuid对应的Protocol,供上层接口使用;

所以对于SNP来说,最重要的其实是两点,一个是SNP_DRIVER这个结构体,另一个是SNP提供的接口。


SNP_DRIVER structure

SNP_DRIVER定义在Snp.h文件中,如下所示:

typedef struct {  UINT32                      Signature;  EFI_LOCK                    Lock;  EFI_SIMPLE_NETWORK_PROTOCOL Snp;  EFI_SIMPLE_NETWORK_MODE     Mode;  EFI_HANDLE                  DeviceHandle;  EFI_DEVICE_PATH_PROTOCOL    *DevicePath;  //  //  Local instance data needed by SNP driver  //  //  Pointer to S/W UNDI API entry point  //  This will be NULL for H/W UNDI  //  ISSUE_UNDI32_COMMAND  IssueUndi32Command;  BOOLEAN               IsSwUndi;  //  // undi interface number, if one undi manages more nics  //  PXE_IFNUM             IfNum;  //  //  Allocated tx/rx buffer that was passed to UNDI Initialize.  //  UINT32                TxRxBufferSize;  VOID                  *TxRxBuffer;  //  // mappable buffers for receive and fill header for undi3.0  // these will be used if the user buffers are above 4GB limit (instead of  // mapping the user buffers)  //  UINT8                 *ReceiveBufffer;  VOID                  *ReceiveBufferUnmap;  UINT8                 *FillHeaderBuffer;  VOID                  *FillHeaderBufferUnmap;  EFI_PCI_IO_PROTOCOL   *PciIo;  UINT8                 IoBarIndex;  UINT8                 MemoryBarIndex;  //  // Buffers for command descriptor block, command parameter block  // and data block.  //  PXE_CDB               Cdb;  VOID                  *Cpb;  VOID                  *CpbUnmap;  VOID                  *Db;  //  // UNDI structure, we need to remember the init info for a long time!  //  PXE_DB_GET_INIT_INFO  InitInfo;  VOID                  *SnpDriverUnmap;  //  // when ever we map an address, we must remember it's address and the un-map  // cookie so that we can unmap later  //  struct MAP_LIST {    EFI_PHYSICAL_ADDRESS  VirtualAddress;    VOID                  *MapCookie;  } MapList[MAX_MAP_LENGTH];  EFI_EVENT              ExitBootServicesEvent;  //  // Whether UNDI support reporting media status from GET_STATUS command,  // i.e. PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED or  //      PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED  //  BOOLEAN                MediaStatusSupported;  //  // Whether UNDI support cable detect for INITIALIZE command,  // i.e. PXE_STATFLAGS_CABLE_DETECT_SUPPORTED or  //      PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED  //  BOOLEAN                CableDetectSupported;  //  // Array of the recycled transmit buffer address from UNDI.  //  UINT64                 *RecycledTxBuf;  //  // The maximum number of recycled buffer pointers in RecycledTxBuf.  //  UINT32                 MaxRecycledTxBuf;  //  // Current number of recycled buffer pointers in RecycledTxBuf.  //  UINT32                 RecycledTxBufCount;} SNP_DRIVER;
这些值的介绍如下:

1. Signature:就是一个标识,对应的值是"sdns";

2. Lock:是UEFI下的锁。UEFI下没有多线程,所以这个锁应该是用于中断的,目前并不清楚它具体想要锁什么;

3. Snp:这个就Simple Network Protocol,下面会介绍它的所以成员;

4. Mode:在Snp中也有一个成员Mode,两者的值是一致的,后面会介绍;

5. DeviceHandle:每个SNP_DRIVER结构体对应一个设备,所以也就对应到一个Handle上;

6. DevicePath:同上,每个SNP_DRIVER结构体也对应到一个DevicePath上;

7. IssueUndi32Command:这个是UEFI下的执行函数,通过它可以调用UNDI中的接口,可以有软件和硬件两种形式,不过SNP目前只实现了软件形式的;

8. IsSwUndi:如果是软件形式的UNDI,就设置为TRUE;

9. IfNum:表示一个!PXE结构体控制的网卡数目;

10. TxRxBufferSizeTxRxBuffer:这两个值确定一段内存空间,是UNDI需要使用的。UEFI通过UNDI的PXE_OPCODE_GET_INIT_INFO操作符获取UNDI的初始化信息(即TxRxBufferSize),再通过这个初始化信息来分配一段内容空间(由TxRxBuffer指定),在SNP中调用PxeInit()函数时,会将TxRxBuffer放到Cpb中传递给UNDI。至于这段内存空间到底是干什么的,从名字上看应该是UNDI收发数据的缓存区;

11. ReceiveBuffferReceiveBufferUnmapFillHeaderBufferFillHeaderBufferUnmap:这4个参数并没有用到;

12. PciIoIoBarIndexMemoryBarIndex:前面已经说过一个SNP_DRIVER对应一个网卡,所以这里的PciIo就是用来访问该设备的接口,通过它也可以确定IoBarIndex和MemoryBarIndex,这两个参数指定了网卡在系统中映射的资源空间;

13. CdbCpbCpbUnmapDb:CpbUnmap并没有使用,剩下的三个参数是UNDI调用需要的参数,Cdb中放置的数据表示需要进行什么操作,Cpb表示操作需要的参数,Db存放的是具体需要传递的参数;

14. InitInfo:SNP调用PXE_OPCODE_GET_INIT_INFO之后会保留到这个参数中,具体的调用函数如下:

  Snp->Cdb.OpCode     = PXE_OPCODE_GET_INIT_INFO;  Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;  Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;  Snp->Cdb.CPBaddr    = PXE_DBADDR_NOT_USED;  Snp->Cdb.DBsize     = (UINT16) sizeof (Snp->InitInfo);  Snp->Cdb.DBaddr     = (UINT64)(UINTN) (&Snp->InitInfo);//作为参数传入,UNDI会去填充  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;  Snp->Cdb.IFnum      = Snp->IfNum;  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;  DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info()  "));  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
15. SnpDriverUnmap:又是一个并没有使用的参数;

16. MapList:一个映射数组,似乎是给DMA用的,但是看不出来怎么样的;

17. ExitBootServicesEvent:一个事件,在UEFI调用gBS->ExitBootServices()是调用;

18. MediaStatusSupported:如果UNDI支持上报网卡的连接信息,则为TRUE;

19. CableDetectSupported:如果UNDI支持测试网线是否连接,则为TRUE;

20. RecycledTxBufMaxRecycledTxBufRecycledTxBufCount:这三个值共同管理一段内存空间,内存空间的大小是32个64位数,这段内存空间由UEFI分配,在SNP调用PxeGetStatus时会使用,现在还不知道这个函数有什么用。

以上就是所有的参数。


SNP Interface

SNP提供的接口如下:

////// The EFI_SIMPLE_NETWORK_PROTOCOL protocol is used to initialize access /// to a network adapter. Once the network adapter initializes, /// the EFI_SIMPLE_NETWORK_PROTOCOL protocol provides services that /// allow packets to be transmitted and received.///struct _EFI_SIMPLE_NETWORK_PROTOCOL {  ///  /// Revision of the EFI_SIMPLE_NETWORK_PROTOCOL. All future revisions must   /// be backwards compatible. If a future version is not backwards compatible   /// it is not the same GUID.  ///  UINT64                              Revision;  EFI_SIMPLE_NETWORK_START            Start;  EFI_SIMPLE_NETWORK_STOP             Stop;  EFI_SIMPLE_NETWORK_INITIALIZE       Initialize;  EFI_SIMPLE_NETWORK_RESET            Reset;  EFI_SIMPLE_NETWORK_SHUTDOWN         Shutdown;  EFI_SIMPLE_NETWORK_RECEIVE_FILTERS  ReceiveFilters;  EFI_SIMPLE_NETWORK_STATION_ADDRESS  StationAddress;  EFI_SIMPLE_NETWORK_STATISTICS       Statistics;  EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC  MCastIpToMac;  EFI_SIMPLE_NETWORK_NVDATA           NvData;  EFI_SIMPLE_NETWORK_GET_STATUS       GetStatus;  EFI_SIMPLE_NETWORK_TRANSMIT         Transmit;  EFI_SIMPLE_NETWORK_RECEIVE          Receive;  ///  /// Event used with WaitForEvent() to wait for a packet to be received.  ///  EFI_EVENT                           WaitForPacket;  ///  /// Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device.  ///  EFI_SIMPLE_NETWORK_MODE             *Mode;};extern EFI_GUID gEfiSimpleNetworkProtocolGuid;

如UNDI章节所述,上面的接口都是通过UNDI来实现的。

SNP提供的数据接口是纯数据包的传输,并不涉及到具体的网络协议。

理论上我们可以自己构造网络协议并传输。

当然也可以使用SNP之上的各个模块提供的接口来传输数据。


在SNP的初始化过程中会安装gEfiSimpleNetworkProtocolGuid:

  //  //  add SNP to the undi handle  //  Status = gBS->InstallProtocolInterface (                  &Controller,                  &gEfiSimpleNetworkProtocolGuid,                  EFI_NATIVE_INTERFACE,                  &(Snp->Snp)                  );
另外,在完成SNP的初始化之后,网络设备并没有一直打开:

  //  // We should not leave UNDI started and initialized here. this DriverStart()  // routine must only find and attach the SNP interface to UNDI layer that it  // finds on the given handle!  // The UNDI layer will be started when upper layers call Snp->start.  // How ever, this DriverStart() must fill up the snp mode structure which  // contains the MAC address of the NIC. For this reason we started and  // initialized UNDI here, now we are done, do a shutdown and stop of the  // UNDI interface!  //  PxeShutdown (Snp);  PxeStop (Snp);

所以在SNP被初始化完成之后,UEFI的网络收发并没有被打开。


0 0