UEFI实战Redfish的BIOS实现1

Posted jiangwei0512

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UEFI实战Redfish的BIOS实现1相关的知识,希望对你有一定的参考价值。

Redfish的Bios实现

EDK2提供了Redfish框架,用来实现带外的BIOS配置,其基本框架如下:

通过RedfishPkg中提供的Driver,可以实现BIOS与BMC或者其它的软件进行通信。它主要分为两个部分,分别是Client和Foundation。Client对应到UEFI应用,用于给Service交互,而Service就是前面说的BMC或者其它实现了Redfish的程序。

如何在BIOS下包含Redfish的内容

相关的模块都在RedfishPkg中,所以只需要在自己的项目中加入模块即可,主要是如下的模块:

!if $(REDFISH_ENABLE) == TRUE
  EmulatorPkg/Application/RedfishPlatformConfig/RedfishPlatformConfig.inf
  RedfishPkg/RestJsonStructureDxe/RestJsonStructureDxe.inf
  RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
  RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
  RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
  RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
  RedfishPkg/RedfishConfigHandler/RedfishConfigHandlerDriver.inf
!endif

当然还有一些额外的Lib和PCD等,这些在后续如果使用到再说明。此外,Redfish还依赖于其它基础模块,也需要增加,它们主要是SecurePkg和NetworkPkg中的内容,前者是安全方面的支持而后者是网络基础模块。

模块介绍

下面介绍前面包含的模块。

RedfishHostInterfaceDxe.inf

该模块用于创建SMBIOS Type42,在《Redfish Host Interface Specification》有说明该类型的SMBIOS:

The SMBIOS Type 42 structure is used to describe a Management Controller Host Interface. It consists of standard
SMBIOS entry information, followed by interface descriptors (which detail the physical interface to the Redfish
Service), and protocol descriptors (which describe the supported payload encoding between the Host and Redfish
Service).

具体的数据说明(表1):

OffsetNameLengthDescription
00hType1字节SMBIOS类型值,这里就是42
01hLength1字节最少9个字节
02hHandle2字节Handle值,根据实际代码确定
04hInterface Type1字节对于网络接口的枚举是MCHostInterfaceTypeNetworkHostInterface,值是40h
05hInterface Specific Data Length1字节见后续说明
06hInterface Specific DataN字节见后续说明
06h+NProtocol Count1字节通常只有一个,所以值是1
07h+NProtocol RecordsM字节见后续说明

在代码中的实现:

///
/// Management Controller Host Interface (Type 42).
///
/// The information in this structure defines the attributes of a Management
/// Controller Host Interface that is not discoverable by "Plug and Play" mechanisms.
///
/// Type 42 should be used for management controller host interfaces that use protocols
/// other than IPMI or that use multiple protocols on a single host interface type.
///
/// This structure should also be provided if IPMI is shared with other protocols
/// over the same interface hardware. If IPMI is not shared with other protocols,
/// either the Type 38 or Type 42 structures can be used. Providing Type 38 is
/// recommended for backward compatibility. The structures are not required to
/// be mutually exclusive. Type 38 and Type 42 structures may be implemented
/// simultaneously to provide backward compatibility with IPMI applications or drivers
/// that do not yet recognize the Type 42 structure.
///
typedef struct 
  SMBIOS_STRUCTURE                  Hdr;
  UINT8                             InterfaceType;                  ///< The enumeration value from MC_HOST_INTERFACE_TYPE
  UINT8                             InterfaceTypeSpecificDataLength;
  UINT8                             InterfaceTypeSpecificData[4];   ///< This field has a minimum of four bytes
 SMBIOS_TABLE_TYPE42;

InterfaceType的值是40h的时候,对应的InterfaceTypeSpecificData数据如下:

OffsetNameLengthDescription
00hDevice Type1字节网络接口的底层也有不同的硬件,下面是具体的类型:
02h:USB网络接口
03h:PCI/PCIe网络接口
04h:USB网络接口v2
05h:PCI/PCIe网络接口v2
80h-FFh:OEM
其它:保留
01hDevice Descriptor DataN字节由于类型不同,所以对应的数据也不同

对应的代码:

///
///  Interface Specific Data starts at offset 06h of the SMBIOS Type 42 struct.
///  This table defines the Interface Specific data for Interface Type 40h. There
///  are 3 types of Device Descriptor3 defined , however only 1 may be used in
///  specific Tape 42 table.
///
typedef struct 
  UINT8            DeviceType;        ///< The Device Type of the interface.
  DEVICE_DESCRITOR DeviceDescriptor;  ///< The Device descriptor.
 REDFISH_INTERFACE_DATA;

其中的DeviceType的值在代码中的定义:

#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB         0x02 // We don't support this type of interface.
                                                            // Use REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2 instead.
#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE    0x03 // We don't support this type of interface.
                                                            // Use REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2 instead.
#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2      0x04
#define REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2 0x05

对应的DeviceDescriptor

///
/// Define union for the Host Interface Device Descriptor
///
typedef union 
    USB_INTERFACE_DEVICE_DESCRIPTOR_V2          UsbDeviceV2;     ///< Device type USB V2 device discriptor.
    PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2  PciPcieDeviceV2; ///< Device type PCI/PCIe V2 device discriptor.
    OEM_DEVICE_DESCRIPTOR                       OemDevice;       ///< OEM type device discriptor.
 DEVICE_DESCRITOR; /// Device descriptor data formated based on Device Type.

这里以PCI网卡为例说明其内容:

//
// Structure definitions of Host Interface device type 05h (PCI/PCIE V2)
//
typedef struct 
  UINT8                   Length;               ///< Length of the structure, including Device Type and Length fields.
  UINT16                  VendorId;             ///< The Vendor ID of the PCI/PCIe device.
  UINT16                  DeviceId;             ///< The Device ID of the PCI/PCIe device.
  UINT16                  SubsystemVendorId;    ///< The Subsystem Vendor ID of the PCI/PCIe device.
  UINT16                  SubsystemId;          ///< The Subsystem ID of the PCI/PCIe device.
  UINT8                   MacAddress [6];       ///< The MAC address of the PCI/PCIe network device.
  UINT16                  SegmemtGroupNumber;   ///< The Segment Group Number of the PCI/PCIe.
  UINT8                   BusNumber;            ///< The Bus Number of the PCI/PCIe device.
  UINT8                   DeviceFunctionNumber; ///< The Device/Function Number of the PCI/PCIe.
 PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2;

可以看到它包含了PCI的Bus/Dev/Fun/VendorId/DeviceId/SubVendorId/SubDeviceId等PCI基础信息,还有MAC地址。

Protocol的个数目前就是1,而其类型一般是“Redfish over IP Protocol“,其具体内容如下:

OffsetNameLengthDescription
00hProtocol Type1字节Redfish over IP Protocol的值是04h
01hProtocol Type Specific Data Length1字节见后续说明
02hProtocol Specific Record DataP字节见后续说明

其具体的内容如下:

//
//  the protocol-specific data for the "Redfish Over IP" protocol
//
typedef struct 
  EFI_GUID            ServiceUuid;  //same as Redfish Service UUID in Redfish Service Root resource

  //
  //  Unknown=00h,
  //  Static=01h,
  //  DHCP=02h,
  //  AutoConfigure=03h,
  //  HostSelected=04h,
  //  other values reserved
  //
  UINT8               HostIpAssignmentType;

  //
  //  Unknown=00h,
  //  Ipv4=01h,
  //  Ipv6=02h,
  //  other values reserved
  //
  UINT8               HostIpAddressFormat;

  //
  //  Used for Static and AutoConfigure.
  //  For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
  //
  UINT8               HostIpAddress[16];

  //
  //  Used for Static and AutoConfigure.
  //  For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
  //
  UINT8               HostIpMask[16];

  //
  //  Unknown=00h,
  //  Static=01h,
  //  DHCP=02h,
  //  AutoConfigure=03h,
  //  HostSelected=04h,
  //  other values reserved
  //
  UINT8               RedfishServiceIpDiscoveryType;

  //
  //  Unknown=00h,
  //  Ipv4=01h,
  //  Ipv6=02h,
  //  other values reserved
  //
  UINT8               RedfishServiceIpAddressFormat;

  //
  //  Used for Static and AutoConfigure.
  //  For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
  //
  UINT8               RedfishServiceIpAddress[16];

  //
  //  Used for Static and AutoConfigure.
  //  For IPV4, use the first 4 Bytes and zero fill the remaining bytes.
  //
  UINT8               RedfishServiceIpMask[16];

  UINT16              RedfishServiceIpPort;  // Used for Static and AutoConfigure.
  UINT32              RedfishServiceVlanId;  // Used for Static and AutoConfigure.
  UINT8               RedfishServiceHostnameLength;   // length of the following hostname string
  UINT8               RedfishServiceHostname[1];  // hostname of Redfish Service
 REDFISH_OVER_IP_PROTOCOL_DATA;

以上就是Type42类型SMBIOS信息的内容。而本模块就是为了构建这个SMBIOS。其中的数据是根据实际的情况来确定的,比如使用PCIE还是USB网卡、MAC地址是什么、IP类型是什么等等,描述了详细的Redfish使用的接口的信息。

这些信息有一些在代码(包含通用的代码和平台相关的代码)中直接决定,而另外一些通过变量的方式写入,而这跟RedfishPlatformConfig.inf对应的模块相关。

RedfishPlatformConfig.inf

该模块已经在前面提过,它是一个UEFI应用,直接通过命令参数获取数据并存放到变量。下面是一个示例:

RedfishPlatformConfig.efi -s 192.168.10.101 255.255.255.0 192.168.10.123 255.255.255.0

它设置了一系列的IP供Redfish使用。

目前支持的变量包括:

  • HostIpAssignmentType
  • HostIpAddress
  • HostIpMask
  • RedfishServiceIpAddress
  • RedfishServiceIpMask
  • RedfishServiceIpPort

主要就是Client端和Service端的IP类型和地址,它们包含在REDFISH_OVER_IP_PROTOCOL_DATA这个结构体中,并被RedfishDiscoverDxe.inf使用到。

依赖 RedfishHostInterfaceDxe RedfishPlatformConfig

RedfishRestExDxe.inf

本模块实现了基于HTTP的传输协议,用于Redfish数据通信。它安装了如下的两个接口供后续数据传输使用:

EFI_SERVICE_BINDING_PROTOCOL mRedfishRestExServiceBinding = 
  RedfishRestExServiceBindingCreateChild,
  RedfishRestExServiceBindingDestroyChild
;

EFI_REST_EX_PROTOCOL  mRedfishRestExProtocol = 
  RedfishRestExSendReceive,
  RedfishRestExGetServiceTime,
  RedfishRestExGetService,
  RedfishRestExGetModeData,
  RedfishRestExConfigure,
  RedfishRestExAyncSendReceive,
  RedfishRestExEventService
;

RedfishDiscoverDxe.inf

本模块的作用是发现Redfish Service端,比如BMC或者实现了Redfish的程序,而它依赖于前面模块中提到的需要设置的各类变量。

RedfishDiscoverDxe模块是一个UEFI Driver,所以有Supported/Start等接口:

EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = 
  RedfishDiscoverDriverBindingSupported,
  RedfishDiscoverDriverBindingStart,
  RedfishDiscoverDriverBindingStop,
  REDFISH_DISCOVER_VERSION,
  NULL,
  NULL
;

这里简单说明:

RedfishDiscoverDriverBindingSupported()函数主要是判断依赖的模块是否存在,其依赖的部分如下:

static REDFISH_DISCOVER_REQUIRED_PROTOCOL gRequiredProtocol[] = 
  
    ProtocolTypeTcp4,
    L"TCP4 Service Binding Protocol",
    &gEfiTcp4ProtocolGuid,
    &gEfiTcp4ServiceBindingProtocolGuid,	// RequiredServiceBindingProtocolGuid
    &mRedfishDiscoverTcp4InstanceGuid,		// DiscoveredProtocolGuid
    Tcp4GetSubnetInfo
  ,
  
    ProtocolTypeTcp6,
    L"TCP6 Service Binding Protocol",
    &gEfiTcp6ProtocolGuid,
    &gEfiTcp6ServiceBindingProtocolGuid,	// RequiredServiceBindingProtocolGuid
    &mRedfishDiscoverTcp6InstanceGuid,		// DiscoveredProtocolGuid
    Tcp6GetSubnetInfo
  ,
  
    ProtocolTypeRestEx,
    L"REST EX Service Binding Protocol",
    &gEfiRestExProtocolGuid,
    &gEfiRestExServiceBindingProtocolGuid,	// RequiredServiceBindingProtocolGuid
    &mRedfishDiscoverRestExInstanceGuid,	// DiscoveredProtocolGuid
    NULL
  
;

它的判断依据是:

  1. 判断RequiredServiceBindingProtocolGuid是否存在;
  2. 如果存在,再判断对应的DiscoveredProtocolGuid是否存在;
  3. 如果已经存在,表示UEFI Driver已经执行过,所以不需要再执行了;
  4. 如果不存在,则这个UEFI Driver需要再次被执行。

实际上这里的三种传输方式只需要支持一种即可,前面两种是不同版本的TCP方式,而最后一种是基于HTTP的传输实现,它的实现在模块RedfishRestExDxe.inf中。

RedfishDiscoverDriverBindingStart()构建网络接口并最终安装如下的Protocol供后续使用:

EFI_REDFISH_DISCOVER_PROTOCOL mRedfishDiscover = 
  RedfishServiceGetNetworkInterface,
  RedfishServiceAcquireService,
  RedfishServiceAbortAcquire,
  RedfishServiceReleaseService
;

这些接口会被RedfishConfigHandlerDriver.inf使用。

到目前为止的依赖关系:

依赖 依赖 依赖 RedfishDiscoverDxe RedfishRestExDxe RedfishHostInterfaceDxe RedfishPlatformConfig

RedfishConfigHandlerDriver.inf

本模块是UEFI Redfish的处理中心。它也是一个UEFI Driver,因此包含如下的接口:

///
/// Driver Binding Protocol instance
///
EFI_DRIVER_BINDING_PROTOCOL gRedfishConfigDriverBinding = 
  RedfishConfigDriverBindingSupported,
  RedfishConfigDriverBindingStart,
  RedfishConfigDriverBindingStop,
  REDFISH_CONFIG_VERSION,
  NULL,
  NULL
;

RedfishConfigDriverBindingSupported()检测依赖关系,除了前面提到的RedfishDiscoverDxe模块,代码中主要依赖的是来自RedfishRestExDxe模块的接口,对应GUID是gEfiRestExProtocolGuidgEfiRestExServiceBindingProtocolGuid

RedfishConfigDriverBindingStart()里面是一个回调函数,这个回调函数会在gEdkIIRedfishConfigHandlerProtocolGuid安装的时候回调,而在回调函数中执行了该GUID对应的EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL中的函数Init(),关于这个Protocol的具体实现还没有在当前的EDK2代码中,具体见[EDK2 Redfish feature driver](#EDK2 Redfish feature driver)中的说明。

到目前为止的依赖关系:

依赖 依赖 依赖 依赖 RedfishConfigHandlerDriver RedfishDiscoverDxe RedfishRestExDxe RedfishHostInterfaceDxe RedfishPlatformConfig

RestJsonStructureDxe.inf

本模块是一个帮助模块,用来处理JSON数据,它安装了如下的Protocol:

EFI_REST_JSON_STRUCTURE_PROTOCOL mRestJsonStructureProtocol = 
  RestJsonStructureRegister,
  RestJsonStructureToStruct,
  RestJsonStructureToJson,
  RestJsonStructureDestroyStruct
;

RedfishCredentialDxe.inf

本模块涉及到认证相关的内容,它提供了如下的Protocol:

EDKII_REDFISH_CREDENTIAL_PROTOCOL  mRedfishCredentialProtocol = 
  RedfishCredentialGetAuthInfo,
  RedfishCredentialStopService
;

Redfish相关的认证信息在《Redfish Host Interface Specification》中有定义,不过看规范的说明是已经弃用了,所以这里也不再介绍。

EDK2 Redfish feature driver

前面的介绍Redfish在EDK中的框架内容,但是真正的Redfish操作一个也没有介绍,而且也没有对Redfish Client的实现。这部分内容UEFI还没有放到正式版本中,而是在GitHub - tianocore/edk2-staging at edk2-redfish-client这个库中。

后续的文章中会介绍这部分内容。

以上是关于UEFI实战Redfish的BIOS实现1的主要内容,如果未能解决你的问题,请参考以下文章

UEFI实战BIOS与IPMI

Redfish接口测试

UEFI实战Windows版本QEMU网络配置

UEFI实战Windows版本QEMU网络配置

win10 为什么可以秒开机?(附实战源码,真机操作)

win10 为什么可以秒开机?(附实战源码,真机操作)