免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: albcamus
打印 上一主题 下一主题

PCI规范里BAR寄存器的一段话看不懂 [复制链接]

论坛徽章:
0
31 [报告]
发表于 2008-09-04 09:23 |只看该作者

回复 #1 albcamus 的帖子

Linux Device Driver 中说, PCI的地址空间的BAR寄存器是如下设计的:
          这个寄存器有较高位是可编程的, 较低位是厂商设定的,不可编程的, 在读取这个寄存器时, 不可编程位被返回0.
      (我的理解) 然后这个不可编程位的大小就代表了Memory 或 IO 空间的大小
          同时,映射后的区域必须以这个SIZE进行对齐, 即写入其中可编程位的值 * SIZE 就是映射后的基地址

如果Memory或IO空间大小是 1M, 那么低20位不可编程, 读取时返回为0, 代表1M空间大小。高12位被用来设定映射基地址,厂商设定的任何高12位值(base)代表在第base个1M的地址,即起始基地址为base * 1M处

              BASE(可编程的高位) + SIZE(不可编程的低位)  = 32 位
          这两个部分必须 同时存在, 因此, SIZE最大为2G(BASE只占一位)
               1M地址空间, 则SIZE占20位, 1M大小, 编程BASE,则指定起始基地址
     
IO空间的最小范围是8字节, 即低3位必须不可编程,
Memory空间在最小范围是16字节, 即低4位必须不可编程,    于是这低3位(或低4位)被用来作其他的配置信息,表示
楼主所说的:
         bit 0 : 为1代表是IO区间,为0代表MMIO区间
         bit [1:2] :  00表示是32位的, 10表示是64位的, 11和01这两种编码被reserve
             bit 3: 代表该区间是否是prefetable

论坛徽章:
0
32 [报告]
发表于 2008-09-06 15:05 |只看该作者
标准中描述的确有些含糊,尤其是英文的大家可能更容易忽略它里面一些描述,还是看一下紧跟在后面的Implementation Note中的例子会更清楚一些。

最大空间只有2G是因为,如果BAR全零表示这个寄存器是可以忽略的,不用来申请地址空间。这样的话至少要有一个bit为1,而由于BAR即表示设备要申请多少总线空间,反过来CPU分配的总线空间的起始位置又要通过这一寄存器告诉设备,所以它的实现有些特别,实际上是后面连续的不能写0的bit数表示了它的长度(这也是为什么标准中是取反加1,而有些资料上描述说是第一个1到后面的值代表了长度)。
实际上可以把写全1之后读出来的值看做一个有符号的,如果长度是size,则读到的值总是-size。有符号的而且总是负的,那么它的范围当然是2G了。要把从上面一段话一直到最后的例子都看了并且连贯起来才能理解BAR,当然最好的还是对照一些系统中的实现来看。

[ 本帖最后由 Cyberman.Wu 于 2008-9-6 15:07 编辑 ]

论坛徽章:
0
33 [报告]
发表于 2008-09-07 22:18 |只看该作者

回复 #23 bluesky_jxc 的帖子

为什么这样子比较好呢?

另外,理论上讲,PCI Bar可以在对齐的32位地址的任意位置。但是,北桥只会将超过Memlowtop寄存器以上到4G(出去APIC的固定地址空间和其它)范围+超过Memhightop以上范围的访问送到PCI总线上面,这个意义上说,不是X86的硬件限制,而是芯片组的限制。
而且,MMIO空间不见得一定是3G到4G,只是习惯上把Memlowtop配置在3G左右罢了。

论坛徽章:
0
34 [报告]
发表于 2008-09-08 09:38 |只看该作者

回复 #33 minifish 的帖子

芯片组也不能限制,这个TOM可以改变的

这样比较好的原因,可以尽量保证物理内存连续吧,比如3GMemroy,如果MMIO放在2G,那么中间就不连续了。个人看法而已

论坛徽章:
0
35 [报告]
发表于 2008-09-08 09:49 |只看该作者
原帖由 bluesky_jxc 于 2008-9-8 09:38 发表
芯片组也不能限制,这个TOM可以改变的

这样比较好的原因,可以尽量保证物理内存连续吧,比如3GMemroy,如果MMIO放在2G,那么中间就不连续了。个人看法而已

你这个说法感觉很有道理,把hole都往地址空间的末端移,保证RAM能尽量连续的映射,是个很正义的想法

论坛徽章:
0
36 [报告]
发表于 2008-09-10 11:57 |只看该作者
原帖由 zx_wing 于 2008-9-8 09:49 发表

你这个说法感觉很有道理,把hole都往地址空间的末端移,保证RAM能尽量连续的映射,是个很正义的想法


RAM在物理空间上不存在连接或不连接的映射了吧?如果被PCI空间占掉了那一段就无法再访问了。

论坛徽章:
0
37 [报告]
发表于 2009-03-17 00:06 |只看该作者
原帖由 bluesky_jxc 于 2008-9-2 16:09 发表
帮你回答算了

PCI spec里面有一句话,叫“don't care bit”, 就是说,不管写什么进去,这些bit读出来的值都是0.
换句话说,写1进去读回来是0,那么就表示这个位是“don't care”的,也就决定了PCI Mem bar的 ...


OpenSolaris的add_reg_props的代码就是这么做的。

OpenSolaris的add_reg_props函数里,首先是将BAR读出备份,然后写全1,然后读,结果存在value里,再将备份BAR写回,

                /* determine the size of the address space */
                base = pci_getl(bus, dev, func, offset);                              <<< 备份原来的BAR
                pci_putl(bus, dev, func, offset, 0xffffffff);                    <<< 写全1,探测长度
                value = pci_getl(bus, dev, func, offset);                            <<< 读出探测结果,待后面的代码去处理取得长度
                pci_putl(bus, dev, func, offset, base);                                <<<写回备份的BAR

...........................................................................

对于PCI内存空间的BAR,

                        /* skip base regs with size of 0 */
                        value &= PCI_BASE_M_ADDR_M;             <<< MMIO方式,value的低4位根据规范被clear掉。

                        if (value == 0)                                          <<<value全部为0意味着这个BAR没有被硬件实现。
                                continue;

                        len = ((value ^ (value-1)) + 1) >> 1;        <<< value ^ (value -1) 就找到了所有的don't care bit, 这些don't carebit这时都是1。
                                                                                           <<< 全1的don't care bit +1 再右移1位即可找到第一个不是0的bit, 就是BAR影射区域的长度。


挖出这个帖子不是为了考古,我的新问题来了。

Xen 3.3应该早就支持Direct hardware access了,那么当DomU是Linux操作系统,并且是Para Virtulaization (泛虚拟化)的时候,

当一个PCI设备被分给这个DomU的时候,Linux的DomU会用上述方式去读写这个PCI设备BAR吗?

如果答案是肯定的,那么BAR里的地址是"物理地址"还是"机器地址"?

请熟悉Xen的朋友回答。

[ 本帖最后由 Solaris12 于 2009-3-17 00:17 编辑 ]

论坛徽章:
0
38 [报告]
发表于 2009-03-18 09:25 |只看该作者
这个帖子是不是应该放在驱动板块啊,呵呵。看了前面一部分,好像都是在猜,没有确定的。它所谓的12bit是指高12bit而不是低12bit,1M是2^20,所以是低20bit为0,而高12bit全部为1。之所以最大是2G,是因为全零表示未实现,所以至少要有最高bit为1;而最小16bit是因为MM映射时低4bit有其它意义。
Spec实际上是写得清楚的,但描述有些晦涩,我当时是看了它的Implementation Notes才明白的。软件/BIOS确定空间大小时是先写全1到寄存器,然后读出来把低4bit清零之后取反加1即可,这样也可以看出来做为有符号数的话,读出来的总是空间大小的负值。

论坛徽章:
0
39 [报告]
发表于 2009-03-20 11:37 |只看该作者
原帖由 Cyberman.Wu 于 2009-3-18 09:25 发表
软件/BIOS确定空间大小时是先写全1到寄存器,然后读出来把低4bit清零之后取反加1即可,这样也可以看出来做为有符号数的话,读出来的总是空间大小的负值。


Solaris没有按照”取反加1“的建议去做,而是直接去判断第一个地位不为0的位置。

我看Linux的做法和Solaris类似。

这种实现的好处就在于你根本不要求 第一个为1的bit以上所有位还是1,更通用一些。

论坛徽章:
0
40 [报告]
发表于 2009-03-20 12:47 |只看该作者
原帖由 Solaris12 于 2009-3-20 11:37 发表


Solaris没有按照”取反加1“的建议去做,而是直接去判断第一个地位不为0的位置。

我看Linux的做法和Solaris类似。

这种实现的好处就在于你根本不要求 第一个为1的bit以上所有位还是1,更通用一些。


在最前面全部是连续1的时候的两种算法得到的结果是相同的,我也见过有资料按你说的办法去判断空间大小的,Linux的具体实现没看过,在PC上BIOS本身也会做这件事吧。
如你所说是可以灵活一些,但实际上PCI规范已经要求了BAR要占用的系统地址空间大小必须是power of 2,所以第一个为1的bit前面的bit必然全部为1。你仔细看一下PCI 3.0的6.2.5.1,后面给出的implementation note里面就是取反再加1的算法。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP