1.编写读取设备PCI信息的Application

代码参考罗斌大佬,博客地址:UEFI开发探索13 – 访问PCI/PCI-E设备1
       感谢罗斌大佬的贡献,让我在学习UEFI的道路上站在了巨人的肩膀上。

代码:

#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/DebugLib.h>#include <Protocol/PciIo.h>
#include <Protocol/PciRootBridgeIo.h>
#include <IndustryStandard/Pci.h>#include <stdio.h>
#include <stdlib.h>EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *gPciRootBridgeIo;EFI_STATUS LocatePciRootBridgeIo(void);EFI_STATUS PciDevicePresent(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo,OUT PCI_TYPE00 * Pci,IN UINT8 Bus,IN UINT8 Device,IN UINT8 Func);EFI_STATUS ListPciInformation(void);int main(IN int Argc, IN char **Argv)
{EFI_STATUS Status;PCI_TYPE00 Pci;Status = LocatePciRootBridgeIo();if(EFI_ERROR(Status)){printf("Call LocatePciRootBridgeIo failed,Can't find protocol!\n");}else{printf("Call LocatePciRootBridgeIo successed,Find protocol!\n");}ListPciInformation();return 0;
}EFI_STATUS LocatePciRootBridgeIo()
{EFI_STATUS Status;EFI_HANDLE *PciHandleBuffer = NULL;UINTN      HandleIndex = 0;UINTN      HandleCount = 0;Status = gBS->LocateHandleBuffer(ByProtocol,&gEfiPciRootBridgeIoProtocolGuid,NULL,&HandleCount,&PciHandleBuffer  //二级指针);if(EFI_ERROR(Status))  return Status;for(HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++){Status = gBS->HandleProtocol(PciHandleBuffer[HandleIndex],&gEfiPciRootBridgeIoProtocolGuid,(VOID **)&gPciRootBridgeIo);if(EFI_ERROR(Status))  continue;else                   return EFI_SUCCESS;}return Status;}EFI_STATUS ListPciInformation()
{EFI_STATUS Status = EFI_SUCCESS;PCI_TYPE00 Pci;UINT16 Dev,Func,Bus,PciDevicecount = 0;printf("PciDeviceNo\tBus\tDev\tFunc | Vendor.Device.ClassCode\n");for(Bus=0; Bus<64; Bus++)for(Dev=0; Dev<= PCI_MAX_DEVICE; Dev++)for(Func=0; Func<=PCI_MAX_FUNC; Func++){Status = PciDevicePresent(gPciRootBridgeIo,&Pci,(UINT8)Bus,(UINT8)Dev,(UINT8)Func);if(Status == EFI_SUCCESS){PciDevicecount++;printf("%d\t%x\t%x\t%x\t",PciDevicecount,(UINT8)Bus,(UINT8)Dev,(UINT8)Func);printf("%x\t%x\t%x\n",Pci.Hdr.VendorId,Pci.Hdr.DeviceId,Pci.Hdr.ClassCode[0]);}}return EFI_SUCCESS;
}EFI_STATUS
PciDevicePresent (IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo,OUT PCI_TYPE00                          *Pci,IN  UINT8                               Bus,IN  UINT8                               Device,IN  UINT8                               Func)
{UINT64      Address;EFI_STATUS  Status;//// Create PCI address map in terms of Bus, Device and Func//Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);//// Read the Vendor ID register//Status = PciRootBridgeIo->Pci.Read (PciRootBridgeIo,EfiPciWidthUint32,Address,1,Pci);if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {//// Read the entire config header for the device//Status = PciRootBridgeIo->Pci.Read (PciRootBridgeIo,EfiPciWidthUint32,Address,sizeof (PCI_TYPE00) / sizeof (UINT32),Pci);return EFI_SUCCESS;}return EFI_NOT_FOUND;
}

注意:

这是我这篇博客之前的描述,这个描述不对!下面是修改过的:

在LocatePciRootBridgeIo函数中根据guid利用LocateHandleBuffer找到支持gEfiPciRootBridgeIoProtocolGuid的所有handle,再调用HandleProtocol从handle数组里寻找安装了protocol的handle,找到了就会通过参数传递给定义的全局变量EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *gPciRootBridgeIo中。接下来就可以利用全局变量EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *gPciRootBridgeIo查询Pci设备的信息了。

查询并显示PCI信息的函数是ListPciInformation,函数中主要用PciDevicePresent函数查询PCI的信息。
       在PciDevicePresent中,先创造PCI的地址映射,再根据映射的地址和gPciRootBridgeIo,读取PCI的信息到参数Pci中,然后在验证返回值是否正确,验证VendorId是否有效(当VendorID寄存器为0xFFFF时,为无效VendorID)。验证成功后读取PCI设备的整个配置头的信息,配置头信息结构体为:

typedef struct {PCI_DEVICE_INDEPENDENT_REGION Hdr;PCI_DEVICE_HEADER_TYPE_REGION Device;
} PCI_TYPE00;

而我们在打印时只打印Hdr中的信息,Hdr中的信息都有:

typedef struct {UINT16  VendorId;UINT16  DeviceId;UINT16  Command;UINT16  Status;UINT8   RevisionID;UINT8   ClassCode[3];UINT8   CacheLineSize;UINT8   LatencyTimer;UINT8   HeaderType;UINT8   BIST;
} PCI_DEVICE_INDEPENDENT_REGION;

我们只打印VendorId,DeviceId和ClassCode[0]。
       代码写好后将其编译为.efi文件,我编译的是64位的.efi文件,因为PCI信息的查看在windows的模拟环境下查看不了,我第一次查看PCI信息时是用DUET做了个启动盘,将.efi文件放在启动盘的根目录下,在我的笔记本上用U启动,查看PCI信息。后面我会放一张在实体机(即我的笔记本)上查看PCI信息的截图。
       下面就是在qemu虚拟机上查看PCI信息的步骤了。

2.制作OVMF固件

参照戴正华《UEFI编程与原理》,制作OVMF固件的命令:
       ①制作64位OVMF固件:

       ②制作32位OVMF固件:

3.将生成的.efi文件用UltraISO制作成镜像文件

打开UltraISO,New->Disk Image,然后

       点击OK,将.efi文件拖入UltraISO,Ctrl+s,保存为PCI.img,保存到和OVMF.fd相同的目录下。

4.用qemu运行OVMF固件并将PCI.img挂载到UEFIShell下



       FS0就是我们挂载的PCI.img。

       先用pci命令查看PCI信息:

       然后运行我们生成的.efi文件:

到这里就成功在qemu上读取PCI信息了,撒花花。
       最后,再附上再我笔记本上用U盘启动进入UEFIShell查看PCI信息的图片:
       ①运行.efi文件

②PCI命令

如有错误,欢迎指出。

UEFI学习——在qemu上读取设备PCI信息相关推荐

  1. android获取已连上热点设备名称,2、android获取连接到手机热点上的设备的信息

    转自:http://blog.csdn.net/beijingshi1/article/details/9119297 最近开发一个项目,遇到一个问题,在手机开启热点的情况下,想要获取是哪个设备已经连 ...

  2. UEFI 学习3.6 - ARM QEMU上的ACPI表

    文章目录 ACPI 表结构 RSDP XSDT FADT DSDT MADT SPCR 如果对ACPI概念不熟悉,可以先参考这篇[UEFI基础]ACPI基础 解析代码github地址: TestPkg ...

  3. 数据结构与算法学习笔记之 提高读取性能的链表(上)

    数据结构与算法学习笔记之 提高读取性能的链表(上) 前言 链表(Linked list)比数组稍微复杂一点,在我们生活中用到最常见的应该是缓存,它是一种提高数据读取性能的技术,常见的如cpu缓存,浏览 ...

  4. 我的内核学习笔记14:内核设备树学习

    李迟按: 上一篇内核的文章是2年半前,期间因工作转行而停止研究,最近又重新捡起.这个系列从2013年起间断地更新,本来想从系统角度逐步写的,但工作量十分庞大,现在也想通了,在适合的时间写,不带目的,不 ...

  5. linux lddbus设备,Linux设备驱动程序学习(14)-Linux设备模型(各环节的整合)

    Linux设备驱动程序学习(14) -Linux设备模型(各环节的整合) 通过一个设备在内核中生命周期的各个阶段,可以更好地理解Linux设备模型.我将通过分析lddbus和sculld的源码来了解L ...

  6. 【降维打击,带你深度学习CPU(上)】

    系列文章目录 1.<带你深挖计算机底层逻辑,打通你计算机基础知识的任督二脉> 2.<深度学习计算机底层原理,深度剖析存储器> 3.<基于内存全面理解高速缓冲存储器> ...

  7. 如何在QEMU上执行iOS并启动一个交互式bash shell,内含整个安装流程并且提供了相关工具(二)

    我们在上一篇文章中介绍如何在QEMU上执行iOS并启动一个交互式bash shell,在第这篇文章中,我们将详细介绍为实现这些目标所进行的一些具体的项目研究. 本文的研究项目是以该项目为基础进行的,我 ...

  8. 基于UEFI的BIOS怎么识别不同设备(SataHdd、SataCdrom、USB、BMC)

    基于UEFI的BIOS怎么识别不同设备(SataHdd.SataCdrom.USB.BMC) 参考:UEFI_SPEC    第一种方法:   SATA设备根据EFI_ATA_DEVICE_TYPE类 ...

  9. c语言获取PCI信息,C语言-遍历pci设备

    目录 前言 pci简介 后记 前言 最近楼主比较苦逼啊,主管布置了一道访问pci的作业,这个作业使用io方式还可以非常浪地将所有的东西都给读取出来,虽然不能读取出pci-e设备的所有信息,但是还是可以 ...

  10. 1.搭建深度学习项目树莓派的硬件设备选择

    搭建深度学习项目树莓派的硬件设备选择 文章目录 搭建深度学习项目树莓派的硬件设备选择 1.型号选择 1.1 官网产品 1.2 型号介绍 1.2.1 树莓派 400 1.2.2 树莓派 数字系列 1.2 ...

最新文章

  1. 人工智能的鱼与熊掌:精度与可解释性
  2. Fliptile POJ - 3279 (翻转)(二进制+对第一行暴力遍历翻转的位置)
  3. 面试题36:数组中的逆序对
  4. 7-8 菲波那契数列 (15 分)
  5. webpack4学习之问题一
  6. android实例教程_Android共享首选项示例教程
  7. Android AIDL
  8. 移动端调试工具-Debuggap
  9. QQ连连看单机版辅助制作全流程
  10. php写浏览记录,php 浏览历史记录的实现方法
  11. 如何运行计算机学报的LaTeX模板?
  12. 【TensorFlow】DNNRegressor 的简单使用
  13. 小米9se开发版系统回刷MIUI稳定版系统
  14. Mybatis官方文档及使用简记
  15. 重载和重写的区别。。。。
  16. CSMA/CD的基本工作过程
  17. 基于 Mesh 的统一路由在海外业务的实践
  18. 小米3刷android 6.0,小米3/4/Note适配Android6.0刷机包链接 注意事项及提取密匙
  19. python打造记账本,记账本-简单的python脚本
  20. C#与基恩士PLC的KV-Nano系列通讯

热门文章

  1. 苹果背后的拼多多双11“农产品狂想曲”
  2. 生成QQ/MSN/旺旺/SKYPE等在线状态图标
  3. M3U8视频流下载神器CocoCut
  4. Visual Studio 2022把C#代码打印出来的技巧 有屋设计拆单管理一体化软件 全屋定制拆单 橱柜衣柜整装 木门归方程序
  5. 摄像模组中光学相关知识(一)
  6. 谷歌Chrome繁体字乱码问题
  7. 可道云kodexplorer隐藏免费版按钮及简单修改使用方法
  8. Android:JNI调用C++自定义类的详细方法
  9. 单片机C语言编程实例分析详解,单片机C语言编程的八个基本规则解析
  10. [ZT]范伟导老师Sniffer课程资料