BIOS/UEFI基础——EFI_HANDLE
来源:互联网 发布:qq邮箱smtp服务器端口 编辑:程序博客网 时间:2024/05/17 08:30
EFI_HANDLE
ImageHandle
一个普通的DXE模块的入口(以Snp.c举例):
EFI_STATUSEFIAPIInitializeSnpNiiDriver ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable );
这里的SystemTable不解释,但是ImageHandle又是什么呢?
这需要了解DXE Dispatcher里面的操作。
代码要从DxeMain.c中说起:
DxeMain()函数中有如下的代码:
// // Initialize the DXE Dispatcher // PERF_START (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ; CoreInitializeDispatcher (); PERF_END (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ; // // Invoke the DXE Dispatcher // PERF_START (NULL, "CoreDispatcher", "DxeMain", 0); CoreDispatcher (); PERF_END (NULL, "CoreDispatcher", "DxeMain", 0);
在CoreDispatcher()函数里面,就会运行各个DXE模块。
最终模块运行起来的代码是:
Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);这里的ImageHandle是下面的函数传进来的:
EFI_STATUSEFIAPICoreStartImage ( IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL )
而这个函数就在CoreDispatcher()中:
Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
所以我们实际要找的ImageHandle是DriverEntry的一部分。
原本它的值是NULL:
// // Load the DXE Driver image into memory. If the Driver was transitioned from // Untrused to Scheduled it would have already been loaded so we may need to // skip the LoadImage // if (DriverEntry->ImageHandle == NULL && !DriverEntry->IsFvImage) { DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName)); Status = CoreLoadImage ( FALSE, gDxeCoreImageHandle, DriverEntry->FvFileDevicePath, NULL, 0, &DriverEntry->ImageHandle );
在CoreLoadImage()中会有赋值的操作,再跟进去这个函数:
Status = CoreLoadImageCommon ( BootPolicy, ParentImageHandle, FilePath, SourceBuffer, SourceSize, (EFI_PHYSICAL_ADDRESS) (UINTN) NULL, NULL, ImageHandle, NULL, EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION );
还需要继续跟进CoreLoadImageCommon()函数:
// // Success. Return the image handle // *ImageHandle = Image->Handle;
这里的Image->Handle又是什么?
// // Allocate a new image structure // Image = AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));
Image其实就是各个被加载的模块的一个数据表现。
// // Install the protocol interfaces for this image // don't fire notifications yet // Status = CoreInstallProtocolInterfaceNotify ( &Image->Handle, &gEfiLoadedImageProtocolGuid, EFI_NATIVE_INTERFACE, &Image->Info, FALSE );
如果一个模块被顺利加载了,就会安装Protocol。上面就是安装一个LoadedImageProtocol的代码。
在这个函数中:
// // If caller didn't supply a handle, allocate a new one // Handle = (IHANDLE *)*UserHandle; if (Handle == NULL) {Handle = AllocateZeroPool (sizeof(IHANDLE)); …… if (!EFI_ERROR (Status)) { // // Return the new handle back to the caller //*UserHandle = Handle;
可以看到ImageHandle的最终赋值。
Handle的类型是IHANDLE:
////// IHANDLE - contains a list of protocol handles///typedef struct { UINTN Signature; /// All handles list of IHANDLE LIST_ENTRY AllHandles; /// List of PROTOCOL_INTERFACE's for this handle LIST_ENTRY Protocols; UINTN LocateRequest; /// The Handle Database Key value when this handle was last created or modified UINT64 Key;} IHANDLE;
而ImageHandle的类型其实是VOID*:
////// A collection of related interfaces.///typedef VOID *EFI_HANDLE;
由于空指针能够只想任何结构体,所以这里也没有问题。
从IHANDLE的结构体可以看出,一个ImageHandle连接着所有的Handle,以及它下挂的所有Protocol。
总结:
ImageHandle是DXE模块对应的数据结构中的一个参数,在该模块运行的过程中,会在这个ImageHandle上安装一系列的接口(就是Protocol)。而这个ImageHandle本身会在整个UEFI运行过程中被放在一个EFI_HANDLE数据库中。
因此在某个DXE模块中实现的接口(Protocol),可以通过一系列的函数,先找到ImageHandle,再通过它找到对应的Protocol,然后在其它的地方调用这些Protocol。
Controller
同样以Snp.c举例,其中包含着叫做UEFI Driver Model的东西,它的入口也有一个类型为EFI_HANDLE的参数:EFI_STATUSEFIAPISimpleNetworkDriverStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath );
这个函数是通过gBS->ConnectController()来调用的:
// //Perform Connect // HandleCount = 0; while (1) { OldHandleCount = HandleCount; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { break; } if (HandleCount == OldHandleCount) { break; } for (Index = 0; Index < HandleCount; Index++) { gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); } }
以上代码在BDS阶段执行,这里只是截取了一种形式,即获取DXE阶段安装的所有ImageHandle并作为参数传入。
实际上还有其它的方式,不过上面这种应该是最全面的了。
下面就需要看一下ConnectController()函数的实现,这个函数也是在DxeMain.c中初始化的:
(EFI_CONNECT_CONTROLLER) CoreConnectController, // ConnectController
// // Connect all drivers to ControllerHandle // If CoreConnectSingleController returns EFI_NOT_READY, then the number of // Driver Binding Protocols in the handle database has increased during the call // so the connect operation must be restarted // do { ReturnStatus = CoreConnectSingleController ( ControllerHandle, DriverImageHandle, AlignedRemainingDevicePath ); } while (ReturnStatus == EFI_NOT_READY);
而在CoreConnectSingleController()函数中:
Status = DriverBinding->Start ( DriverBinding, ControllerHandle, RemainingDevicePath );
这里的ControllerHandle就是gBS->ConnectController()函数中传入的第一个参数。
也就是说ControllerHandle可以是ImageHandle。
当然由于并不是所有的DXE模块都有安装UEFIDriver Model所有并不是所有ImageHandle都是ControllerHandle。
另外还需要说明,UEFI Driver Model对应一个EFI_DRIVER_BINDING_PROTOCOL:
//// Simple Network Protocol Driver Global Variables//EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = { SimpleNetworkDriverSupported, SimpleNetworkDriverStart, SimpleNetworkDriverStop, 0xa, NULL, NULL};
也就是SimpleNetworkDriverStart()函数的第一个参数。
这里还需要说一下SimpleNetworkDriverSupported()函数。它是一个条件判断函数,只有其中的函数满足了要求,才会运行对应的Start()函数,比如:
EFI_STATUSEFIAPISimpleNetworkDriverSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ){ EFI_STATUS Status; EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol; PXE_UNDI *Pxe; Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, NULL, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( Controller, &gEfiNetworkInterfaceIdentifierProtocolGuid_31, (VOID **) &NiiProtocol, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER );
这里的Controller需要安装了DevicePathProtocol和NetworkInterfaceIdentifierProtocol这两个Protocol。
因此就需要在之前的某个模块中,比如某个网卡模块,它需要安装了这两个协议,然后才能使网卡模块对应的EFI_HANDLE之上安装SNP这样的网络传输协议。
有个问题?
网卡运行起来后安装NetworkInterfaceIdentifierProtocol是没有问题的,但是DevicePathProtocol需要在什么时候安装呢?PCI扫描的时候?
可能也是在网卡驱动运行的时候吧……
需要有源代码才好。
据我所知,网卡驱动也是UEFI Driver Model。
说到DevicePathProtocol,就需要提供了另一种gBS->ConnectController()的调用方式了:
Status = gBS->LocateDevicePath ( &gEfiDevicePathProtocolGuid, &TempPciDevicePath, &PciDeviceHandle ); if (EFI_ERROR (Status)) { return Status; } gBS->ConnectController (PciDeviceHandle, NULL, MyDevicePath, FALSE);
这里就是根据安装有DevicePathProtocol的EFI_HANDLE来ConnectController。
追踪代码可以看到在PCI扫描的时候有:
RegisterPciDevice ( IN EFI_HANDLE Controller, IN PCI_IO_DEVICE *PciIoDevice, OUT EFI_HANDLE *Handle OPTIONAL ){ EFI_STATUS Status; VOID *PlatformOpRomBuffer; UINTN PlatformOpRomSize; UINT8 PciExpressCapRegOffset; EFI_PCI_IO_PROTOCOL *PciIo; UINT8 Data8; BOOLEAN HasEfiImage; // // Install the pciio protocol, device path protocol // Status = gBS->InstallMultipleProtocolInterfaces ( &PciIoDevice->Handle, &gEfiDevicePathProtocolGuid, PciIoDevice->DevicePath, &gEfiPciIoProtocolGuid, &PciIoDevice->PciIo, NULL ); if (EFI_ERROR (Status)) { return Status; }
所以在PCI扫描的时候,也会为设备创建EFI_HANDLE并安装对应的DevicePathProtocol。
总结:
ControllerHandle有两个主要来源,一个是ImageHandle,另外一个就是PCI扫描的时候创建的EFI_HANDLE。
其它还有没有不是很确定了。比如ChildHandle,不知道是不是也有一部分可以做ControllerHandle?
- BIOS/UEFI基础——EFI_HANDLE
- BIOS/UEFI基础——UEFI网络框架之概述
- BIOS/UEFI基础——UEFI网络框架之UNDI
- BIOS/UEFI基础——UEFI网络框架之SNP
- BIOS/UEFI基础——UEFI网络框架之MNP
- BIOS/UEFI基础——UEFI网络框架之ARP
- BIOS/UEFI基础——UEFI网络框架之TCP4
- BIOS/UEFI基础——UEFI网络框架之MNP2
- BIOS/UEFI基础——UEFI网络框架之IP4
- BIOS/UEFI基础——基础知识
- BIOS/UEFI基础——EDK
- BIOS/UEFI基础——变量
- BIOS/UEFI基础——定时器
- BIOS/UEFI基础——DEBUG
- BIOS/UEFI基础——Device Path
- BIOS/UEFI基础——x86架构中断基础介绍
- BIOS/UEFI基础——第一条指令
- BIOS/UEFI基础——System Table和Architecture Protocols
- MyEclipse下的Servlet环境搭建指南
- hadoop系列-linux及hadoop、hdfs、hive、hbase常用命令
- STL hash_map使用
- 第六章 访问权限控制
- Android ViewPager的使用方法
- BIOS/UEFI基础——EFI_HANDLE
- HDU 2955
- 明白了一些关于命名空间(using space)的小东西
- Java中的对称加密算法
- lcd——51程序
- 行人检测开题报告
- 80端口被NT kernel & System 占用pid 4
- 数字三角形_递归_递推(动态规划)
- 2015 ICPC长春赛区铜牌题