首页 > 其他分享 >计算机启动过程分析 -- 7.3 设备的探测及驱动加载

计算机启动过程分析 -- 7.3 设备的探测及驱动加载

时间:2024-10-07 14:33:43浏览次数:1  
标签:BAR -- 总线 7.3 IO Memory 空间 加载 设备

PCI总线于20世纪90年代初提出,发展到现在已经逐渐被PCIE等高速接口所替代,但其软件配置结构却基本没有发生变化,包括HyperTransport、PCIE等新一代高速总线都兼容PCI协议的软件框架。

在PCI软件框架下,系统可以灵活地支持设备的自动识别和驱动的自动加载。下面对PCI的软件框架进行简要说明。

在PCI协议下,IO的系统空间分为三个部分:配置空间、IO空间和Memory空间。配置空间存储设备的基本信息,主要用于设备的探测和发现;IO空间比较小,用于少量的设备寄存器访问;Memory空间可映射的区域较大,可以方便地映射设备所需要的大块物理地址空间。

对于X86架构来说,IO空间的访问需要使用IO指令操作,Memory空间的访问则需要使用通常的load/store指令操作。而对于MIPS或者LoongArch这种把设备和存储空间统一编址的体系结构来说,IO空间和Memory空间没有太大区别,都使用load/store指令操作。IO空间与Memory空间的区别仅在于所在的地址段不同,对于某些设备的Memory访问,可能可以采用更长的单次访问请求。例如对于IO空间,可以限制为仅能使用字访问,而对于Memory空间,则可以任意地使用字、双字甚至更长的Cache行访问。

配置空间的地址偏移由总线号、设备号、功能号和寄存器号的组合得到,通过对这个组合的全部枚举,可以很方便地检测到系统中存在的所有设备。

以HyperTransport总线为例,配置访问分为两种类型,即Type0和Type1,其区别在于基地址和对总线号的支持。如图7.3所示,只需要在图中总线号、设备号、功能号的位置上进行枚举,就可以遍历整个总线,检测到哪个地址上存在设备。

图 7.3: HyperTransport总线配置访问的两种类型

通过这种方式,即使在某次上电前总线上的设备发生了变化,也可以在这个枚举的过程中被探测到。而每个设备都拥有唯一的识别号,即图7.4中的设备号和厂商号,通过加载这些识别号对应的驱动,就完成了设备的自动识别和驱动的自动加载。

图7.4为标准的设备配置空间寄存器分布。对于所有设备,这个空间的分布都是一致的,以保证PCI协议对其进行统一的检索。

图 7.4: 标准的设备配置空间寄存器分布

图7.4中的厂商识别号(Vendor ID)与设备识别号(Device ID)的组合是唯一的,由专门的组织进行管理。每一个提供PCI设备的厂商都应该拥有唯一的厂商识别号,以在设备枚举时正确地找到其对应的驱动程序。例如英特尔的厂商识别号为0x8086,龙芯的厂商识别号为0x0014。设备识别号对于每一个设备提供商的设备来说应该是唯一的。这两个识别号的组合就可以在系统中唯一地指明正确的驱动程序。

除了通过厂商识别号与设备识别号对设备进行识别并加载驱动程序之外,还可以通过设备配置空间寄存器中的类别代码(Class Code)对一些通用的设备进行识别,并加载通用驱动。例如USB接口所使用的OHCI(Open Host Controller Interface,用于USB2.0 Full Speed或其他接口)、EHCI(Enhanced Host Controller Interface,用于USB2.0 High Speed)、XHCI(eXtensible Host Controller Interface,用于USB3.0),SATA接口所使用的AHCI(Advance Host Controller Interface,用于SATA接口)等。这一类通用接口控制器符合OHCI、EHCI、XHCI或AHCI规范所规定的标准接口定义和操作方法,类似于处理器的指令集定义,只要符合相应的规范,即使真实的设备不同,也能够运行标准的驱动程序。

所谓驱动程序就是一组函数,包含用于初始化设备、关闭设备或是使用设备的各种相关操作。还是以最简单的串口设备为例,如果在设备枚举时找到了一个PCI串口设备,它的驱动程序里面可能包含哪些函数呢?首先是初始化函数,在找到设备后,首先执行一次初始化函数,以使设备到达可用状态。然后是发送数据函数和接收数据函数。在Linux内核中,系统通过调用读写函数接口实现真正的设备操作。在发送数据函数和接收数据函数中,需要将设备发送数据和接收数据的方法与读写函数的接口相配合,这样在系统调用串口写函数时,能够通过串口发送数据,调用串口读函数时,能够得到串口接收到的数据。此外还有中断处理函数,当串口中断发生时,让中断能够进入正确的处理函数,通过读取正确的中断状态寄存器,找到中断发生的原因,再进行对应的处理。

当然,为了实现所有设备的共同工作,还需要其他PCI协议特性的支持。

首先就是对于设备所需IO空间和Memory空间的灵活设置。从图7.4可以看到,在配置空间中,并没有设备本身功能上所使用的寄存器。这些寄存器实际上是由可配置的IO空间或Memory空间来索引的。

图7.4的配置空间中存在6组独立的基址寄存器(Base Address Registers,简称BAR)。这些BAR一方面用于告诉软件该设备所需要的地址空间类型及其大小,另一方面用于接收软件给其配置的基地址。

BAR的寄存器定义如图7.5所示,其最低位表示该BAR是IO空间还是Memory空间。BAR中间有一部分只读位为0,正是这些0的个数表示该BAR所映射空间的大小,也就是说BAR所映射的空间为2的幂次方大小。BAR的高位是可写位,用来存储软件设置的基地址。

图 7.5: BAR的寄存器定义

在这种情况下,对一个BAR的基地址配置方式首先是确定BAR所映射空间的大小,再分配一个合适的空间,给其高位基地址赋值。确定BAR空间大小的方法也很巧妙,只要给这个寄存器先写入全1的值,再读出来观察0的个数即可得到。

对PCI设备的探测和驱动加载是一个递归调用过程,大致算法如下:

1)将初始总线号、初始设备号、初始功能号设为0。

2)使用当前的总线号、设备号、功能号组成一个配置空间地址,这个地址的构成如图7.3所示,使用该地址,访问其0号寄存器,检查其设备号。

3)如果读出全1或全0,表示无设备。

4)如果该设备为有效设备,检查每个BAR所需的空间大小,并收集相关信息。

5)检测其是否为一个多功能设备,如果是则将功能号加1再重复扫描,执行第2步。

6)如果该设备为桥设备,则给该桥配置一个新的总线号,再使用该总线号,从设备号0、功能号0开始递归调用,执行第2步。

7)如果设备号非31,则设备号加1,继续执行第2步;如果设备号为31,且总线号为0,表示扫描结束,如果总线号非0,则退回上一层递归调用。

通过这个递归调用,就可以得到整个PCI总线上的所有设备及其所需要的所有空间信息。有了这些信息,就可以使用排序的方法对所有的空间从大到小进行分配。最后,利用分配的基地址和设备的ID信息,加载相应的驱动就能够正常使用该设备。

下面是从龙芯3A处理器PCI初始化代码中抽取出的程序片段。通过这个片段,可以比较清楚地看到整个软件处理过程。

void _pci_businit(int init)
{
    ……

    /* 这里的pci_roots用于表示系统中有多少个根节点,通常的计算机系统中都为1 */
    for (i=0,pb=pci_head;i<pci_roots;i++,pb=pb->next) {
        _pci_scan_dev(pb, i, 0, init);
    }
    ……

    /* 对地址窗口等进行配置 */
    _setup_pcibuses(init);
}

static void _pci_scan_dev(struct pci_pdevice *dev, int bus, int device, int initialise)
{
    /* 对本级总线,扫描所有32个设备位置,判断是否存在设备 */
    for (;device<32; device++) {
        _pci_query_dev(dev,bus,device,initialize);
    }
}

static void _pci_query_dev(struct pci_device *dev, int bus, int device, int initialise)
{
    ……
    misc = _pci_conf_read(tag, PCI_BHLC_REG);
    /* 检测是否为多功能设备 */
    if(PCI_HDRTYPE_MULTIFN(misc)){
        for(function=0;function<8;function++){
            tag = _pci_make_tag(bus,device,function);
            id  = _pci_conf_read(tag, PCI_ID_REG);
            if(id==0 || id==0xFFFFFFFF){
                continue;
            }
            _pci_query_dev_func(dev,tag,initialise);
        }
    } else {
        _pci_query_dev_func(dev,tag,initialise);
    }
}

void _pci_query_dev_func(struct pci_device *dev, pcitag tag, int initialise)
{
    ……
    /* 读取配置头上的设备类别 */
    class = _pci_conf_read(tag, PCI_CLASS_REG);
    /* 读取配置头上的厂商ID和设备ID */
    id    = _pci_conf_read(tag, PCI_ID_REG);
    ……
    /* 如果是桥设备,需要递归处理下级总线 */
    if(PCI_ISCLASS(class,PCI_CLASS_BRIDGE,PCI_SUBCLASS_BRIDGE_PCI)){
        /* 开始递归调用 */
        ……
        pd->bridge.pribus_num = bus;
        pd->bridge.secbus_num = ++_pci_nbus;
        ……
        /* 收集整个下级总线所需要的资源信息 */
        _pci_scan_dev(pd, pd->bridge.secbus_num, 0, initialise);
        ……
        /*收集下级总线mem/IO空间信息*/
    } else {
        ……
        /*收集本设备mem/IO空间信息*/
    }
}

假设Memory空间的起始地址为0x40000000,在设备扫描过程中发现了USB控制器、显示控制器和网络控制器,三个设备对于Memory空间的需求如表7.3所示。

表 7.3: 三个设备的空间需求

在得到以上信息后,软件对各个设备的空间需求进行排序,并依次从Memory空间的起始地址开始分配,最终得到的设备地址空间分布如表7.4所示。

表 7.4: 三个设备的地址空间分布

经过这样的设备探测和驱动加载过程,可以将键盘、显卡、硬盘或者网卡等设备驱动起来,在这些设备上加载预存的操作系统,就完成了整个系统的正常启动。

如果把CPU比作一个大房间,至此,房间内灯火通明,门窗均已打开,门窗外四通八达。CPU及相关硬件处于就绪状态。

标签:BAR,--,总线,7.3,IO,Memory,空间,加载,设备
From: https://www.cnblogs.com/sys-123456/p/18449922

相关文章

  • 图像分割(Image segementation)
    图像分割(ImageSegmentation)是指在计算机视觉和图像处理领域中,将一幅图像分割成多个具有不同语义或特征的区域,这些区域通常是连续的像素集合,并且每个区域内包含的像素在某些属性上是相似的。这一过程旨在识别图像中的各个对象或者背景,为后续的图像分析、物体识别与跟踪、三维重建......
  • 公司网站出现乱码怎么解决
    解决公司网站出现乱码的问题,通常可以按照以下步骤进行:检查文件编码设置确保所有网页文件(如HTML,CSS,JavaScript等)保存时使用的编码一致,推荐使用UTF-8编码。设置正确的HTTP头部信息在服务器端设置正确的Content-Type HTTP头部,确保它指定了正确的字符集,例如:Content-Ty......
  • 公司网站出现乱码怎么处理
    处理公司网站出现乱码的问题,可以按照以下步骤进行:检查字符编码设置:确认网页和数据库的字符编码是否一致,通常推荐使用 UTF-8 编码。审查HTTP响应头:确保服务器正确设置了 Content-Type 响应头,指明了正确的字符集。查看HTML元信息:在HTML文档中 <head> 部分检查......
  • Gamma调整
    色彩空间色彩空间定义了一种特定方式来表示颜色,包括红、绿、蓝(RGB)等基本颜色分量的组合方式,以及这些颜色如何映射到人类可见光谱的数学模型。常见的色彩空间有sRGB、AdobeRGB、DCI-P3、BT.2020等。每种色彩空间覆盖的色域范围不同,影响着所能表示的颜色种类和饱和度。sRGB是最......
  • 川土微在直流充电桩上的应用,CA-IS3641HVW隔离芯片、CA-IS3417WT隔离开关、CA-IS3980P
    川土微隔离器芯片涵盖:标准数字隔离器、电表专用数字隔离器、集成隔离电源的标准数字隔离器、隔离I2C、隔离CAN、带隔离电源的隔离CAN、隔离RS-485/422、带隔离电源的隔离RS-485/422、低成本隔离RS-485/422、0.5W全集成隔离电源、全差分隔离运放、隔离误差运放等。充电桩控制器整......
  • 网站连接数据库配置文件
    网站连接数据库的配置文件通常包含数据库连接所需的各项参数。这些参数包括数据库类型、主机地址、端口号、数据库名称、用户名和密码等。下面是一些常见的数据库配置文件示例:MySQL配置文件示例假设你使用的是PHP语言,以下是一个典型的MySQL数据库配置文件(db_config.php)......
  • 教你如何快速找到网站管理后台_网站后台
    要快速找到一个网站的管理后台登录入口,可以尝试以下几种方法:常见的URL路径猜测:很多网站的后台登录页面通常会放在一些固定的路径下,例如:/admin/administrator/wp-admin(WordPress站点)/login/manage/backend在网站域名后面加上这些路径尝试访问。搜索引擎......
  • 怎么查找登陆网站后台?(如何查询网站后台地址)
    查找或确定一个网站的后台登录地址通常不是一件直接的事情,因为不同的网站可能会有不同的后台管理入口。不过,这里有一些通用的方法可以帮助你找到或猜测一个网站的后台登录地址:常见的后台路径许多网站使用一些常见的路径作为后台登录页面,例如:/admin/administrator/wp-ad......
  • 图像增强(Image enhancement)
    图像增强(ImageEnhancement)是一种图像处理技术,其主要目的是通过特定算法和方法改善图像的视觉效果或提升图像中目标特征的识别能力。它主要包括以下几个方面:提高图像质量:针对原始图像可能存在的噪声、模糊、低对比度等问题进行处理,以提升整体图像的质量。突出重要信息:通过强调......
  • 忘记管理员密码了怎么办
    忘记管理员密码可以根据不同的场景采取相应的措施来解决:尝试使用已知的安全问题或备份邮箱重置密码:如果你在创建账户时设置了安全问题或者关联了一个备份邮箱,可以通过这些方式来找回或重置密码。联系系统管理员或技术支持:如果你是企业或组织的一员,并且不是最高权限的管......