最近在编写一个小程序,需要读取PCI Configuration Space 上的寄存器。但是发现运行之后会死机,死机的位置在下面的调用中:
Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, Index*4, Sizeof(tmp), &tmp);
但是如果使用EfiPciIoWidthUint8, EfiPciIoWidthUint16都是能够正常工作的。
经过一番研究,找到了问题所在,首先看一下EFI PCI IO PROTOCOL 的定义【参考1】:
typedef struct _EFI_PCI_IO_PROTOCOL {
EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem;
EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo;
EFI_PCI_IO_PROTOCOL_ACCESS Mem;
EFI_PCI_IO_PROTOCOL_ACCESS Io;
EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci;
EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem;
EFI_PCI_IO_PROTOCOL_MAP Map;
EFI_PCI_IO_PROTOCOL_UNMAP Unmap;
EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
EFI_PCI_IO_PROTOCOL_FLUSH Flush;
EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation;
EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes;
EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes;
EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes;
UINT64 RomSize;
VOID *RomImage;
} EFI_PCI_IO_PROTOCOL;
我们需要关注的是EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci;
typedef
EFI_STATUS
(EFIAPI *EFI_PCI_IO_PROTOCOL_MEM) (
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
);
其中的参数定义如下:
仔细阅读会发现, Count的意思是有多少个 Width大小的元素,对于上面的代码来说,我只是想要1个32bits长度的INTU32。因此,Count 应该是1而不是4。
最终,完整的代码:
#include <Library/BaseLib.h>
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/ShellCEntryLib.h>
#include <Protocol/PciIo.h>
#include <IndustryStandard/Pci22.h>
#include <Library/MemoryAllocationLib.h>
extern EFI_BOOT_SERVICES *gBS;
extern EFI_HANDLE gImageHandle;
/***
Demonstrates basic workings of the main() function by displaying a
welcoming message.
Note that the UEFI command line is composed of 16-bit UCS2 wide characters.
The easiest way to access the command line parameters is to cast Argv as:
wchar_t **wArgv = (wchar_t **)Argv;
@param[in] Argc Number of argument tokens pointed to by Argv.
@param[in] Argv Array of Argc pointers to command line tokens.
@retval 0 The application exited normally.
@retval Other An error occurred.
***/
int
main (
IN int Argc,
IN char **Argv
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINTN Seg,Bus,Dev,Fun;
UINT32 Index;
UINT32 tmp;
Status = gBS->LocateProtocol(
&gEfiPciIoProtocolGuid,
NULL,
(VOID **) &PciIo);
if (EFI_ERROR(Status)) {
Print(L"Couldn't find PCIIO Protocol\n");
return EFI_SUCCESS;
}
PciIo->GetLocation(PciIo,&Seg,&Bus,&Dev,&Fun);
Print(L"Found PCI controller Bus[%d] Dev[%d] Fun[%d]\n",
Bus,Dev,Fun);
for (Index = 0; Index < 256/4; Index++) {
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint32,
Index*4,
1,
&tmp);
Print(L"%08X ",tmp);
if ((Index+1)%4==0) {Print(L"\n");}
}
return 0;
}
运行结果:
完整代码下载:
PCIIOTest
参考:
1. http://wiki.phoenix.com/wiki/index.php/EFI_PCI_IO_PROTOCOL
您好,根据您的代码,在电脑上运行了EKD2, 提示 Couldn't find PCIIO Protocol,我的inf文件是在 Nt32Pkg 中编译的,都能编译过去,就是运行的时候不行,请问这是什么问题呢?