【UEF基础之PCI 枚举过程】

【UEFI基础之PCI的枚举】

【UEFI基础之PCI的枚举】

1.如何判断PCI设备是否在位?

BIOS代码在枚举设备的时候,会去读每个设备的VID,当系统软件读到某个设备的 Vendor ID 是 0xFFFF 时,就会知道该设备不存在。
DID&VID是出厂时就固定在PCIE设备配置空间中的数据,表示每个不同的设备,同理,我们在BIOS中也可通过判断这个ID值来寻找指定的PCIE设备。

2. 设备中的配置空间的数据一开始就有嘛?谁写的?

每个设备在出厂时,其配置空间中的值都有一些default值,枚举该设备时为每个设备分配BUS号和内存资源时,会再写入部分值。

3. Bus号,Dev号,和Fun号与硬件有关系嘛?硬件链接与BUS号的分配是否有关?

Dev和Fun号应该是和硬件设计有关系,也就是硬件就已经固定,软件的枚举过程是更多的是在分配Bus号。

4.以PCI的枚举过程

PCI Bus 是一个树状结构,所以 PCI Devices 的枚举算法采用了深度优先遍历算法,即:对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。
系统软件在遍历PCI总线时,需要对这些PCI总线进行编号,即初始化primary、secondary、Subordinate Bus Number寄存器。
在这里插入图片描述
1.主机起电后,操作系统首先扫描 Bus0(一般把与Host Bridge 相连的 PCIe Bus 定为 Bus0)。随后发现 Bridge1,将 Bridge1 下游的 PCIe Bus 定为 Bus1。初始化 Bridge 1 的配置空间,并 Bridge1 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 0 和 1,表明 Bridge1 的上游总线是 Bus0,下游总线是 Bus1。由于还无法确定 Bridge1 下挂载设备的具体情况,系统先暂时将 Subordinate Bus Number 设为 0xFF。

2.扫描PCI Bus1 发现Bridge2,初始化 Bridge 2 的配置空间,并 Bridge2 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 1 和 2,表明 Bridge2 的上游总线是 Bus1,下游总线是 Bus2。由于还无法确定 Bridge2 下挂载设备的具体情况,系统先暂时将 Subordinate Bus Number 设为 0xFF。

3.扫描PCI Bus2 发现Bridge3,初始化 Bridge 3 的配置空间,并 Bridge3 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 2 和 3,表明 Bridge3 的上游总线是 Bus2,下游总线是 Bus3。

4.扫描PCI Bus3 没有发现任何Bridge ,说明Bus3下不会有任何总线,将 Subordinate Bus Number 设为 3。**系统扫描PCI Bus3后回退到上一级总线,即PCI Bus2继续扫描。
**
5.扫描PCI Bus2,发现除了Bridge 3后没有其余的Bridge ,将 Subordinate Bus Number 设为 3,系统扫描PCI Bus2后回退到上一级总线,即PCI Bus1继续扫描。

6.扫描PCI Bus1,发现除了Bridge 2后没有其余的Bridge ,将 Subordinate Bus Number 设为 3,系统扫描PCI Bus1后回退到上一级总线,即PCI Bus0继续扫描。

7.扫描PCI Bus0,发现除了Bridge 4, 将Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 0 和 4,表明 Bridge4 的上游总线是 Bus0,下游总线是 Bus4。
继续扫描PCI Bus4,现除了PCI Bus4后没有其余的Bridge,将 Subordinate Bus Number 设为 4

8。系统软件发现PCI 总线0下的,总线1和总线4已经扫描完,将结束对PCI总线的DFS遍历。(PCIE枚举类似)

5.PCI总线Device号的分配

一条PCI总线会挂接各种各样的PCI设备,而每一个PCI设备在PCI总线下有唯一的设备号。系统通过总线号和设备号定位一个PCI设备后,才能访问改设备的配置空间。
而设备号与PCI的IDSEL信号息息相关(IDSEL信号相当于PCI配置空间的片选信号),该信号将与PCI总线的AD[31:0]信号连接。

可以看出,Config_Address寄存器的Device Number有5bit可以访问32个设备,但是与AD Bus信号线无法一 一对应,AD Bus信号线是从11 ~ 31,一共接21个设备,所以我们连接的信号线只能是从0 ~ 20,或者11 ~32开始接。
在这里插入图片描述
PCI总线推荐了一种Device Number字段与AD[31:16]之间的映射关系。其中PCI设备0与Device Number字段的0b00000对应。PCI设备1与Device Number字段的0b00001对应,以此类推,PCI设备15与Device Number字段的0b01111对应。
所以与AD16信号线相连的设备的设备和为0,以此类推与AD31设备相连的设备号为15

在这里插入图片描述

总结

基本描述完PCIE设备的枚举过程,过程还是比较简单的,
我是农夫三拳,喜欢的话请大家点个赞,有错误的地方也请大家多多指出,感谢大家!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
private final CharSequence getSmallTime() { Context context = getContext(); boolean is24 = DateFormat.is24HourFormat(context); LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); final char MAGIC1 = '\uEF00'; final char MAGIC2 = '\uEF01'; SimpleDateFormat sdf; String format = is24 ? d.timeFormat24 : d.timeFormat12; if (!format.equals(mClockFormatString)) { /* * Search for an unquoted "a" in the format string, so we can * add dummy characters around it to let us find it again after * formatting and change its size. */ if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { int a = -1; boolean quoted = false; for (int i = 0; i < format.length(); i++) { char c = format.charAt(i); if (c == ''') { quoted = !quoted; } if (!quoted && c == 'a') { a = i; break; } } if (a >= 0) { // Move a back so any whitespace before AM/PM is also in the alternate size. final int b = a; while (a > 0 && Character.isWhitespace(format.charAt(a-1))) { a--; } format = format.substring(0, a) + MAGIC1 + format.substring(a, b) + "a" + MAGIC2 + format.substring(b + 1); } } mClockFormat = sdf = new SimpleDateFormat(format); mClockFormatString = format; } else { sdf = mClockFormat; } String result = sdf.format(mCalendar.getTime()); if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { int magic1 = result.indexOf(MAGIC1); int magic2 = result.indexOf(MAGIC2); if (magic1 >= 0 && magic2 > magic1) { SpannableStringBuilder formatted = new SpannableStringBuilder(result); if (AM_PM_STYLE == AM_PM_STYLE_GONE) { formatted.delete(magic1, magic2+1); } else { if (AM_PM_STYLE == AM_PM_STYLE_SMALL) { CharacterStyle style = new RelativeSizeSpan(0.7f); formatted.setSpan(style, magic1, magic2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); } formatted.delete(magic2, magic2 + 1); formatted.delete(magic1, magic1 + 1); } return formatted; } } return result; }添加秒
06-08
你的问题是如何在这段代码中添加秒? 这段代码的作用是获取当前时间并以指定格式显示出来,但没有显示秒数。要添加秒数,可以修改格式字符串。在这里,我们可以在格式字符串的末尾添加一个”:ss“,表示显示秒数。修改后的代码如下: ``` private final CharSequence getSmallTime() { Context context = getContext(); boolean is24 = DateFormat.is24HourFormat(context); LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); final char MAGIC1 = '\uEF00'; final char MAGIC2 = '\uEF01'; SimpleDateFormat sdf; String format = is24 ? d.timeFormat24 : d.timeFormat12; // Add seconds to the format string format += ":ss"; if (!format.equals(mClockFormatString)) { /* * Search for an unquoted "a" in the format string, so we can * add dummy characters around it to let us find it again after * formatting and change its size. */ if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { int a = -1; boolean quoted = false; for (int i = 0; i < format.length(); i++) { char c = format.charAt(i); if (c == '\'') { quoted = !quoted; } if (!quoted && c == 'a') { a = i; break; } } if (a >= 0) { // Move a back so any whitespace before AM/PM is also in the alternate size. final int b = a; while (a > 0 && Character.isWhitespace(format.charAt(a-1))) { a--; } format = format.substring(0, a) + MAGIC1 + format.substring(a, b) + "a" + MAGIC2 + format.substring(b + 1); } } mClockFormat = sdf = new SimpleDateFormat(format); mClockFormatString = format; } else { sdf = mClockFormat; } String result = sdf.format(mCalendar.getTime()); if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { int magic1 = result.indexOf(MAGIC1); int magic2 = result.indexOf(MAGIC2); if (magic1 >= 0 && magic2 > magic1) { SpannableStringBuilder formatted = new SpannableStringBuilder(result); if (AM_PM_STYLE == AM_PM_STYLE_GONE) { formatted.delete(magic1, magic2+1); } else { if (AM_PM_STYLE == AM_PM_STYLE_SMALL) { CharacterStyle style = new RelativeSizeSpan(0.7f); formatted.setSpan(style, magic1, magic2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); } formatted.delete(magic2, magic2 + 1); formatted.delete(magic1, magic1 + 1); } return formatted; } } return result; } ``` 在修改后的代码中,我们在格式字符串的末尾添加了一个冒号和“ss”,表示显示秒数。然后,我们将修改后的格式字符串传递给SimpleDateFormat对象,以便格式化当前时间。最后,我们返回格式化后的时间字符串,它包含了秒数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值