uefi bios代码中如何找到函数的实现?
2015-01-04 20:25
369 查看
写在最前,摘自 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 中去读(一段数据)
函数原型
这个函数提供了一个标准的方法去轮询 pci 内存位置,当然里面的Address指定之前,就会对他做一次内存读操作,
读多大,则取决于参数 width, 这个操作会重复进行直到timeout,(以100纳秒为单位) 或者 Resut & Mask = Value.
....
说了这么一大堆,可是我们应该怎么去实现这个函数呢?
首先,它是对pci 内存的操作,所以,BIOS 代码中,肯定会大量用到,我们以它为关键字,用source insight 搜一下。
返回两个结果:
第一个是它的定义,第二个是把它作为一个类型(指针类型)声明了一个变量。
既然是一个类型,那与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的精华所在
可以看到,绝大多数情况都是声明了一个指向这个结构体类型的指针(方便使用嘛)
但是!! 顺着找,可以有这么一段:
有没有很兴奋,里面,摆的都是实打实的函数名,用你的source insight 直接Jump To Definition 吧
-------------------------------------------------------------------------------------------分割线-------------------------------------------------------------------------------------------------------------
这里我们想要找的是 UsbReportDevices 的函数实现,这里pUsb指向了EFI_USB_PROTOCOL, UsbReportDevices 是他的一个member.
那么先找到EFI_USB_PROTOCOL定义的地方。
现在EFI_USB_PROTOCOL就是我们人为构造出的一个类型,然后它在uhcd.c里面有这样一句话 EFI_USB_PROTOCOL *gAmiUsbController;
声明了一个指针,指向这个类型。
在这里
它给gAmiUsbController 每个成员都给了一个明确的值。这里我们直接跳到ReportDevices处
注意有了最后面的intsallProtocolInterface 才有后续的一系列locate.
后续有新发现,会持续更新
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.
后续有新发现,会持续更新
相关文章推荐
- 如何找到public extern bool Equals(String value)的实现代码?[C#, C++, BCL, CLR]
- 如何找到public extern bool Equals(String value)的实现代码?[C#, C++, BCL, CLR]
- jquery的animate动画效果函数用JS代码是如何实现的
- 介绍如何通过代码实现模拟按键的函数
- 介绍如何通过代码实现模拟按键的函数
- 如何实现JS函数的重载
- 《Asp.Net Forums2.0深入分析》之 Asp.Net Forums是如何实现代码分离和换
- 如何实现自动生成在线播放代码?
- 《Asp.Net Forums2.0深入分析》之 Asp.Net Forums是如何实现代码分离和换皮肤的
- VB:如何实现在代码中弹出toolbar的ButtonMenu
- 如何实现参数个数可变的函数
- 如何在net中实现动态执行代码(js的eval)的功能?
- 如何实现利用类成员函数创建线程 选择自 iceezone 的 Blog
- 《Asp.Net Forums2.0深入分析》之 Asp.Net Forums是如何实现代码分离和换皮肤的
- 如何用Javascript代码实现浏览器菜单命令
- 自己写一个strcpy(char*dest,char*src),如何在函数内部实现防御性溢出?
- 请教:在java中如何实现线程的函数互斥调用,用synchronized好像实现不了
- 语法分析表产生器的代码之三:自定义类的实现函数文件implement_syntax.cpp
- 市面上所有号称"虚拟机","防火墙"的实时监控杀毒软件无一不是使用的IFSHOOK技术.但是同时也有一些朋友不断写MAIL给我打听如何实现读写的监控.下面给出用VTOOLSD写的代码.也就是所有实时杀毒软件的奥秘.同时,很多拦截文件操作的软件,例如对目录加
- 利用setTimeout()函数实现函数代码的延迟执行