免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 23897 | 回复: 74

kernel 中如何访问管理pci memory [复制链接]

论坛徽章:
0
发表于 2009-04-12 22:50 |显示全部楼层
10可用积分
PCI memory 已经在bios boot阶段正确映射了到了一段Memory地址 也就是说boot linux时 bios提供给os 一个全局的physical memory map (其中包括了pci MMIO memory address segment) 但是请问linux kernel下面如何访问透过虚拟内存映射访问并管理这些pci memory呢?我看了system init根据E820 function call得到memory 并建立kernel C0000000以上虚拟地址到system memory address的映射的代码,这种system memory映射和管理机制与MMIO 的 有区别吗?
  实际上我看到EFI中对PCI extension memory 如果不是prefrech mode,都会在GCD(global coherent domain)中也会报称TypeMem32,所以很困惑linux中如何管理 区分 映射这种MMIO的memory。 谢谢

最佳答案

查看完整内容

linux 内核启动的时候,将system ram中的896M内存一一映射到3G~4G的空间去了,这也是为什么在内核中常出现物理地址到虚拟地址的转变只需加上一个常数0xC0000000的原因。至于内核想访问其他的设备,比如说物理内存的高端地址抑或是外围设备的local ram或者是MMIO,都需要经过ioremap的函数,其实这个函数没有什么特别的地方,它只是将你指定的那段物理地址空间和3G~4G空间的专门用来映射用的虚拟地址空间建立一个页表,到此为止,io ...

论坛徽章:
0
发表于 2009-04-12 22:50 |显示全部楼层

回复 #1 javacool 的帖子

linux 内核启动的时候,将system ram中的896M内存一一映射到3G~4G的空间去了,这也是为什么在内核中常出现物理地址到虚拟地址的转变只需加上一个常数0xC0000000的原因。至于内核想访问其他的设备,比如说物理内存的高端地址抑或是外围设备的local ram或者是MMIO,都需要经过ioremap的函数,其实这个函数没有什么特别的地方,它只是将你指定的那段物理地址空间和3G~4G空间的专门用来映射用的虚拟地址空间建立一个页表,到此为止,ioremap的所有工作算是完成了。接下来,如果某条指令要访问刚刚映射过的虚拟地址空间,那么它会经过CPU的MMU运算,即该地址线离开CPU之后就是指向了刚刚ioremap的时候你传进去的物理地址空间了。至于这条地址线如何通过北桥的内存控制单元到达你设备的MMIO,各家chip都有自己的实现方式。
另外:
1.像大家讨论的那样,物理内存被内核指令访问和被用户进程访问用的页表是各自独立的,这个比较重要。也即用户空间进程访问物理内存时,不会用到内核刚启动时候建立起来的一一映射的页表,而是自己建立了另外一个页表。
2.之所以叫MMIO(memory map的io),意思是CPU将外围设备的寄存器看成跟内存一样的访问,因此对于CPU来说,基本分辨不出到底访问的是MMIO还是正常的物理内存,它所做的就是将拿到的指令的地址经过MMU运算到某个物理地址上去。
3.显卡之所以不占用3G~4G的vmalloc的虚拟地址空间,这跟X的实现有很大的关系,X本身就是一个用户进程,一个用户进程是不会在用户态用到内核页表去访问相应的物理地址的,因此它要建立自己的页表来访问显卡的显存(即外围设备的local ram)。但是拿显卡的frame buffer driver来说,情况就不一样了,由于frame buffer driver是内核驱动,因此它最终还是需要调用ioremap来映射显卡的显存到3G~4G的虚拟地址空间来进行访问(可以参考nv的fb driver函数nvidiafb_probe或者intel的fb driver函数intelfb_pci_register)。如楼上说的那样,如果此时剩余的vmalloc的空间不够映射显卡的显存大小,那么frame buffer driver就会abort退出。

[ 本帖最后由 fantry_t 于 2009-4-14 22:36 编辑 ]

论坛徽章:
0
发表于 2009-04-13 13:37 |显示全部楼层
原帖由 javacool 于 2009-4-12 22:50 发表
PCI memory 已经在bios boot阶段正确映射了到了一段Memory地址 也就是说boot linux时 bios提供给os 一个全局的physical memory map (其中包括了pci MMIO memory address segment) 但是请问linux kernel下面如 ...



1. MMIO的区域应该是firmware初始化好的,北桥通过TOM TOLM寄存器就可以区分了。

2. 驱动访问MMIO是通过把BAR开始的内存空间影射到虚拟地址空间来访问的,一个mov指令发出,虚拟地址会被操作系统转换成物理地址,然后物理地址送到北桥,北桥根据TOM和TOLM就知道是MMIO的访问了。

论坛徽章:
0
发表于 2009-04-13 13:59 |显示全部楼层
呵呵 我想问的是 如何在kernel中构建virtual address到类似MMIO mapping physical address 的映射
打个粗略的比方吧 我有1Gsystem memory 另外还有1G pci memory,这是c0000000以上的地址是不是完全映射给system memory? 这时如果驱动想访问1G pcimemory该如何处理virtual address到pci memoryaddr映射呢,另外对于MMIO mapping physical memory 和真正的system memory kernel中会有区别的管理吗?

楼上讲的很对,但涉及的应该是physical address 如何再次区分是指向system memory还是转化成总线指令到pci bus。这些都是bios在北桥设置好的。谢谢了

论坛徽章:
0
发表于 2009-04-13 14:05 |显示全部楼层
驱动访问MMIO是通过把BAR开始的内存空间影射到虚拟地址空间来访问的


他是如何来映射virtual addr到MMIO memory的?如果在kernel virtual addr 都被映射到system memory 之后呢(现在超过1G的system memory很正常)。还有个问题就是kernel对于这种MMIO 映射的非system memory 是否有不同于system memory的管理分配策略?毕竟他们虽然在physical space中 但是性质不一样

[ 本帖最后由 javacool 于 2009-4-13 14:07 编辑 ]

论坛徽章:
0
发表于 2009-04-13 14:32 |显示全部楼层
原帖由 javacool 于 2009-4-13 14:05 发表


他是如何来映射virtual addr到MMIO memory的?如果在kernel virtual addr 都被映射到system memory 之后呢(现在超过1G的system memory很正常)。还有个问题就是kernel对于这种MMIO 映射的非system memory 是 ...


偶不懂Linux kernel, 我想你需要看一下Linux driver影射BAR的API是什么。

Solaris下是ddi_regs_map_setup,会把指定BAR的寄存器的虚拟地址影射成虚拟地址,对应的函数在Linux的应该是什么呢? 好像是ioremap。

BAR的物理地址和物理地址空间的长度你在枚举时都拿到了,所以ioremap只需要调用内核API就可以影射了。

这段函数的实现应该很简单。至于MMIO内存和普通内存在内存管理的差异,你需要看ioremap使用的内核函数和普通的内存是否一样,在Solaris上是有差异的,不知道Linux是怎么样的,请高人回答。

论坛徽章:
0
发表于 2009-04-13 14:42 |显示全部楼层
谢谢了,实际上 我对如何在linux kernel下面 如何利用1G的kernel虚拟地址空间管理4G phyical address还是很模糊,看了一些代码 但是不是很清楚 呵呵

论坛徽章:
0
发表于 2009-04-13 14:55 |显示全部楼层
原帖由 javacool 于 2009-4-13 14:42 发表
谢谢了,实际上 我对如何在linux kernel下面 如何利用1G的kernel虚拟地址空间管理4G phyical address还是很模糊,看了一些代码 但是不是很清楚 呵呵


32位下MMIO的内存不大可能到1G,真到了1G那内核地址空间岂不是很紧张?

另外,不清楚MMIO是否在ZONE_HIMEM里管理,个人感觉不应该是。但目前显卡都256M内存了,如果是ZONE_NORMAL里管理,那MMIO的空间占用的够大的,
希望谁看完ioremap的代码给个答案。

论坛徽章:
0
发表于 2009-04-13 17:51 |显示全部楼层
原帖由 Solaris12 于 2009-4-13 14:55 发表


另外,不清楚MMIO是否在ZONE_HIMEM里管理,个人感觉不应该是。但目前显卡都256M内存了,如果是ZONE_NORMAL里管理,那MMIO的空间占用的够大的,


MMIO是 *设备内存* 和 虚拟地址之间建立的影射, 和系统RAM一点关系都没有 — 而Linux的那些ZONE_XXX, 只是用来划分系统RAM的。

32 x86上显卡driver, 传统方式是在xorg里头, 读取/dev/mem,找到显卡的 设备内存, 然后mmap到 *用户空间*, 来访问的。 这样不占用内核虚拟地址空间。  但是32位x86上使用in-kernel显卡driver的情况我就不清楚了。

论坛徽章:
0
发表于 2009-04-13 18:21 |显示全部楼层
是的  MMIO是physical层的映射 实际上如果pci设备不需要通过cpu访问全部的pci  memory(cpu访问往往时间耗费太大),因此只每次需要部分virtual address的映射空间就行

  albcamus版主 请问你说的in-kernel显卡driver 和前面所说将local memory map到用户空间来做 这两种做法有什么不同? 哪种更普遍
各有什么优点呢? 还有一个问题,对于zone_highmemory type的system memory kernel如何来管理呢?

[ 本帖最后由 javacool 于 2009-4-13 21:17 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP