1.地址映射是搞得我最懵逼的地方,我也不知道我现在看懂没,先写上吧,有错误再改。
地址映射涉及到访问内存,访问外设(寄存器)啊。。。。不搞清楚,真的是程序看不懂。
2.首先物理地址吧。声明一下,龙芯3A3000启动就是使用虚拟地址。
2.1 上图《user1.pdf》
这个图片显示龙芯支持48位地址,但是实际只用了44位(单芯片的情况下)
44位能访问的空间也是足够大了,16TB。(这是内存空间,应该目前够用了吧。硬盘的空间不占用在这个地址范围哈。)
每一片龙芯3A3000的物理地址范围地址就是0-0xfff,ffff,ffff 共16T
44位的最高位,为0表示共享Cache模块
为1 表示4个方向的端口设备。(如下图,只有两个端口(6,7)有效,4,5已省略。)
其中[42:41] 还要进一步划分为4个部分(结合[44],总共划分8个部分)。如下图:
HT用于连接桥片(我的是7A1000),或者多片3A3000互联
根据实际的原理图,我的连接是在HT1上,所以访问桥片的物理地址是0xe00,0000,0000开始的地址。
2.2 一级XBAR和二级XBAR
这是龙芯的特色,机会都会涉及到这个话题。
这个图中,一级XBAR每个master(共有6个master)有8个地址窗口,每个窗口有3个64位寄存器,分别位BASE,MASK,MMAP
还有命中公式(重要):输入的地址 & MASK 要与BASE相等才行,否则就是没命中。
注意:
2.3 有XBAR之后,7A1000的桥片地址也一同映射。
这个是《7A1000user.pdf》中的截图。
这里5个区域使用了一级XBAR进行映射。主要都是桥片的地址。
在2.1节中,我们看到桥片的空间就是要0xe00开头的这样44位的地址(使用HT1桥接口)
以下我只是根据印象猜测,可能仍不正确请多多指教:
比如图中的1,当cpu准备访问0x1000,00xx的时候,XBAR会自动转为0xe00,1000,00xx这样的地址(转换是有规则的!!!后面讲),实际访问的也是后面的这个地址。其他依次类推。
注意,这里仍然是物理地址。
3.虚拟地址,这也必须要用啊。
龙芯3A3000使用64位虚拟地址。这里需要说的是cpu一开始就是使用的虚拟地址。(其中有一段是不需要MMU参与地址转换的)。
0xbfc0,0000 --> 对应的物理地址正好是0x1fc0,0000. 这是启动地址,无需MMU参与。
之前接触的arm,在没有使能mmu之前,使用的是物理地址,使能之后,使用的是虚拟地址。
而龙芯是没使能mmu,也能使用部分虚拟地址。
3.1首先分用户态和核心态,用户态访问受限,核心态无限制。
kuseg : 0x00000000 ------ 0x7fffffff (2G) user space kseg0 : 0x80000000 ------ 0x9fffffff (512M) unmapped, cached kseg1 : 0xa0000000 ------ 0xbfffffff (512M) unmapped, uncached kseg2 : 0xc0000000 ------ 0xffffffff (1G) mapped, cached
在32位CPU下(32位早于64位设计,后来64位出来之后,仍然要兼容32位cpu),程序地址空间划分为4个大区域。每个区域有一个传统的名字。对于在这些区域的地址,各自有不同的属性:
kuseg: 虚拟空间0x0000 0000 - 0x7FFF FFFF (低端2G):这些地址是用户态可用的地址。在有MMU的机器里,这些地址将一概被MMU作转换,除非MMU的设置被建立好,否则这2G地址是不可用的。对于没有MMU的机器,存取这2G地址的方法依具体机器相关,你的CPU具体厂商提供的手册将会告诉你关于这方面的信息。如果想要你的代码在有或没有 MMU的MIPS处理器之间有兼容性,尽量避免这块区域的存取。
kseg0: 虚拟空间0x8000 0000 - 0x9FFF FFFF(512M): 这些地址映射到物理地址简单的通过把最高位清零,然后把它们映射到物理地址低段512M(0x0000 0000 - 0x1FFF FFFF)。因为这种映射是很简单的,通常称之为“非转换的”地址区域。几乎全部的对这段地址的存取都会通过快速缓存(cache)。因此在cache设置好之前,不能随便使用这段地址。通常一个没有MMU的系统会使用这段地址作为其绝大多数程序和数据的存放位置。对于有MMU的系统,操作系统核心会存放在这个区域。
kseg1: 虚拟空间0xA000 0000 - 0xBFFF FFFF(512M): 这些地址通过把最高3位清零的方法来映射到相应的物理地址上,与kseg0映射的物理地址一样。但kseg1是非cache存取的。kseg1是唯一的在系统重启时能正常工作的地址空间。这也是为什么重新启动时的入口向量是0xBFC0 0000。这个向量相应的物理地址是0x1FC0 0000。你将使用这段地址空间去存取你的初始化ROM。大多数人在这段空间使用I/O寄存器。如果你的硬件工程师要把这段地址空间映射到非低段512M 空间,你得劝说他。
kseg2: 虚拟空间0xC000 0000 - 0xFFFF FFFF (1G): 这段地址空间只能在核心态下使用并且要经过MMU的转换。在MMU设置好之前,不能存取这段区域。除非你在写一个真正的操作系统,一般来说你不需要使用这段地址空间。
综上可以看到,MIPS32 CPU下面的不经过MMU转换的内存窗口只有kseg0和kseg1 的512M的大小,而且这两个内存窗口映射到同一512M的物理地址空间。其余的3G虚拟地址空间需要经过MMU转换成物理地址,这个转换规则是由CPU 厂商实现的。还句话说,在MIPS32 CPU下面访问高于512M的物理地址空间,必须通过MMU地址转换。
在核心态下(CPU启动时),CPU可以作任何事情。在用户态下,2G之上的地址空间是非法的,任何存取将会导致系统异常处理。注意的是,如果一个 CPU有MMU,这意味着所有的用户地址在真正访问到物理地址之前必须经过MMU的转换, 从而使得OS可以防止用户程序随便乱用。对于一个没有内存映射的OS,MIPS CPU的用户态其实是多余的。在核心态下,CPU可以存取低段地址空间,这个存取也是通过MMU的转换。
3.2下面来谈谈MIPS64 CPU的虚拟地址空间。
64位CPU的地址空间的最低2G和最高2G区域是和32位情况下一样的,64位扩展的地址部分在这两者之间。64位下那些大块的不需要MMU转换的窗口可以克服kseg0和kseg1 512M的局限,但是32位下我们可以通过对MMU编程来同样达到这一点。
在这个图中,右边出现的字母n表示结点号,我实际只有1个节点,所以n等于0;
0x90开头的虚拟地址(不使用cache的方式)和0x98开头的虚拟地址(使用cache的方式)可以映射整个物理地址空间,大小为2T(44位中还有3位要拿出来做设备选择,剩下41位)
除了这两段之外,0xffff,ffff,8000,0000开始的那段地址的映射,与32位映射一致,只是(32转64的时候)高位补充的是符号位。
3.3 用户空间0x0-0x7fff,ffff,ffff这段需要MMU映射才能使用。
PMON阶段不使用,此时处于内核态。但是仍然会初始化TLB,为操作系统的使用做准备
4.cpu访问地址空间的行为
CPU拿到地址(虚拟地址),其转换过程如下步骤:
(1) 判断当前是kernel mode还是user mode
(2) 如果是kernel mode
(A) 访问的地址是kuseg或者kseg2,进行 TLB 查找;如果查找不成功,exception。如果查找成功,得到物理地址
(B) 如果访问的地址是 kseg0/kseg1,不进行TLB 查找;通过减去一个偏移量得到物理地址
(3) 如果是user mode
(A) 访问地址kuseg,进行TLB 查找。如果查找不成功,exception。如果查找成功,得到物理地址
(B) 访问kseg0/1/2,exception