uefi bios代码中如何找到函数的实现?

写在最前,摘自 K&R

The only legal operations on a structure are copying it or assigning to it as a unit, taking its address with & (读作

ampersand),  and accessing its members,

翻译成中文是这样的,对于一个结构体而言,唯一合法的操作是把它当成一个整体去给它赋值,或者拷贝到另一个地方。

取它的地址,访问它的成员。


UEFI 定义了很多个I (interface). Interface 很像面向对象里面Class的概念,里面有成员函数(用函数指针模拟),有成员变量。它定义了这个interface

需要有哪些功能,需要有哪些参数。至于这个函数的具体实现,各IBV就怎么搞都可以了。比如

EFI_PCI_IO_PROTOCOL.Pollmem()     摘自  UEFI SPEC Chapter 13.


Reads from the memory space of a PCI Root Bridge.

从pci root bridge 中去读(一段数据)


函数原型

typedef
EFI_STATUS
(EFI *API_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM) (
 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL	    *This,
 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
 IN UINT64				     Address,
 IN UINT64 				     Mask,
 IN UINT64                                   Value,
 IN UINT64				     Delay,
 OUT UINT64                                  *Result
);

参数
This    一个指向EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL的指针


Width    标识出对内存操作的宽度


Address  内存操作的基地址,调用这个函数的函数有义务去给它赋一个明确的值

Mask     用来去检测polling(轮询)的标准,即是否达到了结束轮询的标准

Value    用来和退出标准去比较的一个值

Dealy    以100纳秒为单位去延时。

Result    一个指针,指向操作后最后读的那个值。pointer to the last value read from the 
          memory location.


这个函数提供了一个标准的方法去轮询 pci 内存位置,当然里面的Address指定之前,就会对他做一次内存读操作,

读多大,则取决于参数 width, 这个操作会重复进行直到timeout,(以100纳秒为单位) 或者  Resut & Mask = Value.

....

说了这么一大堆,可是我们应该怎么去实现这个函数呢?

首先,它是对pci 内存的操作,所以,BIOS 代码中,肯定会大量用到,我们以它为关键字,用source insight 搜一下。

返回两个结果:

typedef
EFI_STATUS
(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM)(
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
  IN  UINT64                                   Address,
  IN  UINT64                                   Mask,
  IN  UINT64                                   Value,
  IN  UINT64                                   Delay,
  OUT UINT64                                   *Result
  );

struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
  ///
  /// The EFI_HANDLE of the PCI Host Bridge of which this PCI Root Bridge is a member.
  ///
  EFI_HANDLE                                      ParentHandle;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM     PollMem;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM     PollIo;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS          Mem;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS          Io;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS          Pci;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM        CopyMem;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP             Map;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP           Unmap;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER     FreeBuffer;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH           Flush;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES  GetAttributes;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES  SetAttributes;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION   Configuration;
  
  ///
  /// The segment number that this PCI root bridge resides.
  ///
  UINT32                                          SegmentNumber;
}


第一个是它的定义,第二个是把它作为一个类型(指针类型)声明了一个变量。

既然是一个类型,那与int , float , double ,本质上,也就是一样的,标识出不同的长度而已。

这时候,回到文章最开始,对于结构体的操作,只可能把它作为一个整体去赋值。

那么我们以这个结构体的名字为关键字去搜一把

typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;

它把这种类型,重命名为了 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL。 以后_EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL 就是 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL

那就以EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL 再搜一把,这时候,出来一大片,因为到处都要用下,这也正是UEFI的精华所在

可以看到,绝大多数情况都是声明了一个指向这个结构体类型的指针(方便使用嘛)

但是!!  顺着找,可以有这么一段:

static EFI_PCI_IO_PROTOCOL gPciIoInstance = {
    PciIoPollMem,
    PciIoPollIo, 
    {
        PciIoMemRead,  
        PciIoMemWrite
    },
    {
        PciIoIoRead,   
        PciIoIoWrite
    },
    {
        PciIoConfigRead, 
        PciIoConfigWrite
    },
    PciIoCopyMem,
    PciIoMap,
    PciIoUnmap,
    PciIoAllocateBuffer,
    PciIoFreeBuffer,
    PciIoFlush,
    PciIoGetLocation,
    PciIoAttributes,
    PciIoGetBarAttributes,
    PciIoSetBarAttributes,
    0,                      //RomSize;
    NULL                    //RomImage
};

有没有很兴奋,里面,摆的都是实打实的函数名,用你的source insight 直接Jump To Definition 吧

// Procedure:	PciIoMemRead()
//
// Description: Protocol Function Performs a PCI Memory Read Cycle
//
// Notes: See EFI Specification for detail description
//
//----------------------------------------------------------------------------
//<AMI_PHDR_END>
EFI_STATUS PciIoMemRead(IN EFI_PCI_IO_PROTOCOL        *This,
						IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
						IN UINT8                      BarIndex,
						IN UINT64                     Offset,
						IN UINTN                      Count,
						IN OUT VOID                   *Buffer)
{
	EFI_STATUS     Status;
	PCI_DEV_INFO	*dev=(PCI_DEV_INFO*)This;
//---------------------------------------------

	if (Width < 0 || Width >= EfiPciIoWidthMaximum) return EFI_INVALID_PARAMETER;

	Status=PciIoCheckBar(dev, BarIndex, tBarMem, Width, Count, &Offset);
	if(EFI_ERROR(Status)) return EFI_UNSUPPORTED;

	Status=dev->RbIo->Mem.Read(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
							   Offset, Count, Buffer);
	
	return Status;

-------------------------------------------------------------------------------------------分割线-------------------------------------------------------------------------------------------------------------

VOID DisplayUSBInfo(VOID)
{
    EFI_USB_PROTOCOL	*pUsb;
    CONNECTED_USB_DEVICES_NUM   Devs;    
    EFI_STATUS Status;
    CHAR8   UsbName[80];
    UINT8   NextDev;
    CHAR16  text[100];
    UINT8   i;
    CHAR16 *item1=NULL;
    
    Status = pBS->LocateProtocol(&gEfiUsbProtocolGuid, NULL, &pUsb);
    if(EFI_ERROR(Status)) return;

        
//Show devices total

    pUsb->UsbReportDevices(&Devs);

这里我们想要找的是 UsbReportDevices 的函数实现,这里pUsb指向了EFI_USB_PROTOCOL, UsbReportDevices 是他的一个member.

那么先找到EFI_USB_PROTOCOL定义的地方。

typedef struct _EFI_USB_PROTOCOL {
	UINT32							Signature;				//(EIP55275+)
	VOID        					*USBDataPtr;
//    VOID                            *UsbBadDeviceTable;		//(EIP60706-)
	EFI_USB_REPORT_DEVICES			UsbReportDevices;
	EFI_USB_GET_NEXT_MASS_DEVICE_NAME	UsbGetNextMassDeviceName;
    EFI_USB_CHANGE_EFI_TO_LEGACY    UsbChangeEfiToLegacy;
//    EFI_USB_BBS_REMOVE_MASSSTORAGE  UsbBbsRemoveMassStorage;
    EFI_USB_GET_RUNTIME_REGION      UsbGetRuntimeRegion;
    EFI_USB_INSTALL_LEGACY_DEVICE   UsbInstallLegacyDevice;
    EFI_USB_UNINSTALL_LEGACY_DEVICE UsbUninstallLegacyDevice;
    EFI_GET_ASSIGN_USB_BOOT_PORT    UsbGetAssignBootPort;
    EFI_KBC_ACCESS_CONTROL          UsbRtKbcAccessControl;
    EFI_USB_RT_LEGACY_CONTROL       UsbLegacyControl;
	EFI_USB_STOP_UNSUPPORTED_HC		UsbStopUnsupportedHc;
    EFI_USB_SHUTDOWN_LEGACY       UsbRtShutDownLegacy;      //EIP52339+
    EFI_USB_COPY_SKIP_TABLE       	UsbCopySkipTable;			//(EIP51653+)	
    EFI_USB_RT_STOP_CONTROLLER      UsbRtStopController;	        //(EIP74876+)
    EFI_USB_INVOKE_API				UsbInvokeApi;
} EFI_USB_PROTOCOL;

现在EFI_USB_PROTOCOL就是我们人为构造出的一个类型,然后它在uhcd.c里面有这样一句话 EFI_USB_PROTOCOL            *gAmiUsbController;

声明了一个指针,指向这个类型。

在这里

  gAmiUsbController->UsbReportDevices = ReportDevices;
    gAmiUsbController->UsbGetNextMassDeviceName = GetNextMassDeviceName;
    gAmiUsbController->UsbChangeEfiToLegacy = UsbChangeEfiToLegacy;
    gAmiUsbController->UsbGetRuntimeRegion = GetRuntimeRegion;
    gAmiUsbController->UsbInstallLegacyDevice = Dummy1;
    gAmiUsbController->UsbUninstallLegacyDevice = Dummy1;
    gAmiUsbController->UsbGetAssignBootPort = OemGetAssignUsbBootPort;
    gAmiUsbController->UsbRtShutDownLegacy = UsbRtShutDownLegacy;		//<(EIP52339+)
	gAmiUsbController->UsbCopySkipTable = UsbGetSkipList;			//(EIP51653+)
	gAmiUsbController->UsbRtStopController= UsbRtStopController;	//(EIP74876+)
    Status = gBS->InstallProtocolInterface (
        &UsbHandle,
        &gEfiUsbProtocolGuid,
        EFI_NATIVE_INTERFACE,
        gAmiUsbController
    );

它给gAmiUsbController 每个成员都给了一个明确的值。这里我们直接跳到ReportDevices处
 
 
VOID
ReportDevices(
    IN OUT CONNECTED_USB_DEVICES_NUM    *Devs
)
{
											//(EIP38434)> 
	UINT8	i,Kbd = 0, Hub = 0, Mouse = 0, Mass = 0, Point = 0, Ccid = 0;
	
	for (i = 1; i<MAX_DEVICES; i++) {

		if ((gUsbData->aDevInfoTable[i].bFlag & DEV_INFO_VALIDPRESENT) 
			!= DEV_INFO_VALIDPRESENT) {
			continue;
		}
		switch(gUsbData->aDevInfoTable[i].bDeviceType)
		{
			case BIOS_DEV_TYPE_HID:
                                        //(EIP84455+)>
                    if(gUsbData->aDevInfoTable[i].bSubDeviceType& SUB_DEV_TYPE_KEYBOARD)
                        Kbd++;
                    if(gUsbData->aDevInfoTable[i].bSubDeviceType & SUB_DEV_TYPE_MOUSE)
                        Mouse++;
                    if(gUsbData->aDevInfoTable[i].bSubDeviceType & SUB_DEV_TYPE_POINT)
                        Point++;
                                        //<(EIP84455+)
				break;

			case BIOS_DEV_TYPE_HUB:
				Hub++;
				break;

			case BIOS_DEV_TYPE_STORAGE:
				Mass++;
				break;

			case BIOS_DEV_TYPE_CCID:
				Ccid++;
				break;				
		}
	}


注意有了最后面的intsallProtocolInterface 才有后续的一系列locate.


后续有新发现,会持续更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值