首页 | 新闻 | 交流 | 问吧 | 文档 | 手册 | 下载 | 博客

MIPS地址空间(转)

作者:  时间: 2010-10-12
2 位下,程序地址空间(虚拟地址)划分为4 个大区域。每个区域有一个传统的名字。对于在这些区域的地址,各自有不同的属性:
[转载]MIPS基本地址空间

       kuseg: 0x000 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 设置好之前,不能存取这段区域。除非你在写一个真正的操作系统,一般来说你不需要使用这段地址空间。

 

> 一个 物理地址的两个虚拟地址映射关系,不冲突.
>

实际上使用时并不会真的用2个不同的虚地址去映射同一个物理地址,因为这两个区域的属性不同。
kseg0是unmapping,cached;而kseg1是unmapping,uncached的,所以真正使用时kseg0一般 给
内核使用,kseg1作为设备地址空间使用
,划分的话,可以各占一半,譬如在mips32里,kseg0使用
0x8000_0000到0x9000_0000;kseg1使用0xB000_0000到0xC000_0000,各256M即可



二: MIPS 存储空间分配
MIPS将存储空间分为4块分别是:
kuseg, kseg0,kseg1 and kseg2
1. 0xFFFF FFFF mapped kseg2
2. 0xC000 0000 unmapped uncached kseg1
3. 0xA000 0000 unmapped cached kseg0
4. 0x8000 0000 2G kuseg

呵呵可以直观的看到只有kseg1是不需要映射(物理虚拟转换),没有被缓存的,也就是说只有kseg1的内存区域可以做引导的存储区(在这里放置引导用
flash存储器).被cached区域必须等到MMU 的TLB被初始化后才可以使用的。


我现在也知道, mips向量入口的虚拟地址是 0xbfc00000 , 对应的物理地址就是 0x1fc00000 (高三位清0 , 或者 减去 0xa0000000 ,都可以) ,这些我都知道, 可是我还是不太理解为什么 mips 要 这样弄呢? 基于什么目的呢?

2, 到底什么时候用0xbfc00000 , 什么时候用0x1fc00000 呢? 也就是什么用物理地址,什么时候用虚拟地址呢?

我的理解是 0x0 到 0xffffffff 这4G 空间, 都是CPU 角度看到的可寻址的空间。 如果可以直接访问 0x1fc00000 ,干吗还要 访问 0xbfc00000 呢? ARM就没这么麻烦。


3, 还有 我觉得see mips run 有一点我没搞明白。
上面说 kseg1 是 kernel unmapped ,uncacheable 。
这里kernel unmapped 到底是什么意思呢? 我的理解是 别的地址不能指向这个地址(也就是 别的地址不能映射到这段区间, 只能这段区间的地址指向到其他区段) 。

不知道是不是这个意思?

4, 对于mips上所说的虚拟地址和物理地址
我的理解是 这段地址空间如果没有接任何的设备,比如nor flash , SDRAM 什么的, 就是虚拟地址
比如我们不可能在kseg1 段内接如何外设。 只能接在 0x0 ~0x80000000 范围内。
比如nor flash 接在 0x1fc00000 地址上, 而cpu的设计者 设定冷启动后, cpu只能从0xbfc00000 处取第一条指令 , 而0xbfc00000 -> 0x1fc00000 是cpu内定的, 不需要我们关心。

我的疑问是 mips 干脆设计的时候 从 0x1fc00000 上取指不就得了, 这么麻烦干吗呢?

5, 最关键的一个问题 , 就是 kseg1 和kseg0 都是kernel unmapped的, 他们对应的物理地址都是 0x0~0x20000000 , 这个区间, 会不会冲突呢? 这样又为了什么呢?
当然 多个va 对应一个pa 是没什么问题, 可是我还是不太清楚 kseg1和kseg0 同时出现是为了什么?


6,对于一块板子, 我们上面最重要的就是 接nor flash 和 DRAM 了, 能否给个例子, 我们怎么接呢?怎么给他们分配地址呢?(应该是在 0x80000000以下吧?)

最好能给个实际例子, 感激不尽, 能否介绍一款mips的板子, 就象 s3c2410 那么有教育目的的板子? 有吗?


谢谢大家了。





--------------------
http://KernelChina.cublog.cn

编辑者: bob2004 (09-01-07 13:18)

文章选项: 打印

yjfpb04
(member)
09-01-07 13:11
Re: 【mips新手疑问】 关于 kseg1 新 [re: bob2004] 

呵呵.友情顶一记.
楼主很好学.看过你的好些个贴子


--------------------
像小强一样活着..

文章选项: 打印

bob2004
(old hand)
09-01-07 14:25
Re: 【mips新手疑问】 关于 kseg1 新 [re: yjfpb04] 

找到一篇好文:

http://blog.chinaunix.net/u1/40363/showart_434188.html

讲的不错, 不过也都是一些结论性的东西, 也没有讲为什么要那样。
不过里面掺杂了一些英文, 反而好懂一些。 看来,英文是比较适合描述技术问题啊。


转过来一些关于地址的。

我们在这里不谈64位CPU,只谈32位的。

MIPS将存储空间划分为4大块--kuseg, kseg0,kseg1 and kseg2.
------------------------------------------------------------------
0xFFFF FFFF
mapped kseg2
0xC000 0000
unmapped uncached kseg1
0xA000 0000
unmapped cached kseg0
0x8000 0000
2G kuseg
0x0000 0000
------------------------------------------------------------------

对于上述图表,弟兄们要记住以下几点:

* 当开电(Power On)的时候,只有kseg0 and kseg1 是可以存取的。

*kseg0 512M(From 0x8000 0000 to 0xA000 0000) are DIRECTLY mapped to phyiscal
memory ranging from 0x0000 0000 to 0x2000 0000, with cache-able(either write
back or write through, which is decided by SR(Status Register of MIPS CPU)

*kseg1 512M(From 0xA000 0000 to 0xC000 0000) are (also) DIRECTLy mapped
to physical memory ranging from 0x0000 0000 t0 0x2000 0000, with non-cachable.


以上两点对于理解MIPS OS的启动是至关重要的。细心的读者会发现:kseg1有点象

其他CPU的real-mode方式。

*(虚拟)地址from 0x0000 0000 to 0x8000 0000 是不可以存取的,在加电时(POWER
ON)!必须等到MMU TLB初始化之后才可以。

*同理对地址from 0xC000 0000 to 0xFFFF 0000


*MIPS的CPU运行有3个态--User Mode; Supervisor Mode and Kernel Mode.
For simplicity, let's just talk about User Mode and Kernel Mode. Please
always keep this in mind:

CPU can ONLY access kuseg memory area when running in User Mode
CPU MUST be in kernel mode or supervisor mode when visiting kseg0, kseg1
and kseg2 memory area.



--------------------
http://KernelChina.cublog.cn

文章选项: 打印

1help1
(old hand)
09-01-07 14:30
Re: 【mips新手疑问】 关于 kseg1 新 [re: bob2004] 

>2, 到底什么时候用0xbfc00000 , 什么时候用0x1fc00000 呢? 也就是什么用物理地址,什么时候用虚拟地址呢?

>我的理解是 0x0 到 0xffffffff 这4G 空间, 都是CPU 角度看到的可寻址的空间。 如果可以直接访问 0x1fc00000 ,干吗还要 访问 0xbfc00000 呢? ARM就没这么麻烦。

如果直接访问0x1fc00000,CPU怎么知道你这个是 虚拟地址0X1fc00000(KUSEG)还是物理地址0x1fc00000呢?

>这里kernel unmapped 到底是什么意思呢? 我的理解是 别的地址不能指向这个地址(也就是 别的地址不能映射到这段区间, 只能这段区间的地址指向到其他区段) 。

unmapped 就是 说VA->PA不需要TLB转换

>我的疑问是 mips 干脆设计的时候 从 0x1fc00000 上取指不就得了, 这么麻烦干吗呢? >

实际上就是从0x1fc00000.只不过,CPU接受的地址必须是虚拟地址。 原因见 第一条。(如果直接访问0x1fc00000,CPU怎么知道你这个是 虚拟地址0X1fc00000(KUSEG)还是物理地址0x1fc00000呢?)

>当然 多个va 对应一个pa 是没什么问题, 可是我还是不太清楚 kseg1和kseg0 同时出现是为了什么?
KSEG1是uncached,因此通常用来接 外设。 比如 DRAM 控制器,DMA控制器等等。

>6,对于一块板子, 我们上面最重要的就是 接nor flash 和 DRAM 了, 能否给个例子, 我们怎么接呢?怎么给他们分配地址呢?(应该是在 0x80000000以下吧?)

DRAM的物理地址从0x0开始,到 size-1 结束。 这样,访问kseg0 就对应到DRAM.

NOR Flash 一般是接到虚拟地址0xbfc00000 开始。不过也有的 soc nor flash 从 0xbe000000开始。原因是0xbfc00000 到0xc0000000的空间太小了。放不下nor flash。

7. 最好能给个实际例子, 感激不尽, 能否介绍一款mips的板子, 就象 s3c2410 那么有教育目的的板子? 有吗?

买一个 MIPS SOC 路由器能玩 DD-WRT的,就是一个很好的MIPS开发板。开发资料还蛮丰富的。

或者关注一下这个
http://www.linuxforum.net/forum/showflat.php?Cat=&Board=life&Number=707757&page=0&view=collapsed&sb=5&o=0&fpart=







--------------------
http://vm-kernel.org/blog/

文章选项: 打印

bob2004
(old hand)
09-01-07 15:04
Re: 【mips新手疑问】 关于 kseg1 新 [re: 1help1] 

太感谢您的回答了, 我好像理解你的意思了。

>>NOR Flash 一般是接到虚拟地址0xbfc00000 开始。不过也有的 soc nor flash 从 0xbe000000开始。
>>原因是0xbfc00000 到0xc0000000的空间太小了。放不下nor flash。

我觉得应该是 接到 0x1fc00000 或者 0x1e000000 地址上吧 ?



你的核心的意思还是CPU 访问的都是虚拟地址,而kseg1和kseg0 的地址到物理地址的转换是cpu自动完成的根本不需要TLB 。

那这样的理解的话, 就是 系统内 有两套地址 , 0~4G是虚拟地址空间(对与CPU而言) ,
可能还有DRAM ,和nor flash , 他们本身有地址,这是物理的, 但是都是相对的 , 都是从0开始的, 所以必须把他们接到系统的memory bank上面, 这样CPU 就可以访问到他们了(但是CPU访问他们却是通过0xbfc00000 这样的虚拟地址来访问的, 不能直接用 0x1fc00000 来访问, 这是mips决定的) 这点和 ARM不同, 比如s3c2410 有7个bank , 每个bank 有不同的范围, 比如我们的板子, DRAM的起始地址是 0x30000000, nor flash的起始地址是 0x0,
对于ARM来讲, 一个片上外设接到某个bank 上, 就已经有地址, 就可以通过 这个地址 来控制这个寄存器了。

所以我的理解是 在kernel mode , 只能访问 kseg0/1/2 ,但是 kseg0和kseg1 对应的仍然是 0x~ 0x20000000 范围, 也就是 访问的也就是那个 512M内存 (当然真的接了 512M内存,也可以是 64M)

如果是 user mode , 只能访问 kuseg , 那么这个空间是 0x0~0x80000000 , 2G 的空间,
可是这个时候, 这个kuseg的地址也是 虚拟的, 而实际上 DRAM 还是接在了 0~0x20000000 (512M) . 这个时候 的 虚拟地址 已经和 kseg1的虚拟地址有点不一样的味道了吧?




--------------------
http://KernelChina.cublog.cn

文章选项: 打印

bob2004
(old hand)
09-01-07 15:11
Re: 【mips新手疑问】 关于 kseg1 新 [re: bob2004] 

最后一个问题, 还没有搞清楚。

就是我们接外设的时候, 分配的物理地址 ,是不是就是从0x0 到 0x8000_0000 这个区间呢?

kseg1和kseg0 ,kseg3 肯定不能接外设是吧?




--------------------
http://KernelChina.cublog.cn

文章选项: 打印

1help1
(old hand)
09-01-07 15:30
Re: 【mips新手疑问】 关于 kseg1 新 [re: bob2004] 

>我觉得应该是 接到 0x1fc00000 或者 0x1e000000 地址上吧 ?
对。物理地址是 0x1fc00000 或者 0x1e000000

>所以我的理解是 在kernel mode , 只能访问 kseg0/1/2 ,但是 kseg0和kseg1 对应的仍然是 0x~ 0x20000000 范围, 也就是 访问的也就是那个 512M内存 (当然真的接了 512M内存,也可以是 64M)

kernel mode 是 kuseg/kseg0/kseg1/Kseg2 都可以访问。
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


所有,硬件工程师必须要保证, DRAM/NOR FLASH/外设物理地址不能重叠。
下面是一个典型的 MIPS SOC的物理地址分布:
DRAM的物理地址是从0开始,到 size-1
NOR Flash物理地址是0x1fc00000
外设物理地址:从0x10000000 开始

要从虚拟地址的角度来看 CPU,而不是物理地址哦。






--------------------
http://vm-kernel.org/blog/

文章选项: 打印

bob2004
(old hand)
09-01-07 15:40
Re: 【mips新手疑问】 关于 kseg1 新 [re: 1help1] 

再次感谢, 我再研究研究, 有什么问题, 再请教您。



--------------------
http://KernelChina.cublog.cn

文章选项: 打印

1help1
(old hand)
09-01-07 15:41
Re: 【mips新手疑问】 关于 kseg1 新 [re: bob2004] 

>最后一个问题, 还没有搞清楚。
>就是我们接外设的时候, 分配的物理地址 ,是不是就是从0x0 到 0x8000_0000 这个区间呢?
>kseg1和kseg0 ,kseg3 肯定不能接外设是吧?

实际上,应该是 0x0- 0x20000000
超过了 0x200000000,你让kernel 怎么通过 kseg0/Kseg1 怎么找到这个外设的物理地址呢?
也许可以通过 kseg2 然后通过 TLB .不过我没有见过这样用的。

前言
很久没和硬件打交道了,花了些时间来学习mips,确也收获了不少,拿出来和大家共享,其中会有理解有误或 不完整的地方,还请大家积极指出,共同进步。

1、概述
au1500是amd公司生产的一款遵循MIPS32体系结构的SOC类的 微处理器,属于RISC结构,我们采用的是主频为396(400)MHz的产品。pb1500是alchemy公司针对au1500cpu生产的一款开发 板。

2、特点
au1500:32个通用寄存器($0-$31),三个专用寄存器(hi,lo,pc),没有浮点运算的寄存器,浮 点运算单元是用软件来模拟的。处理器内还集成了ac'97声卡,2个以太网控制器,usb控制器,2个uart控制器,静态存储控制器,动态存储控制 器,EJTAG(用于调试)。

pb1500:板上安装了两组flash,共64M;SDRAM64M;2个ide接口,声卡I/O接 口,USB接口,RJ45,LED显示,串口,显示器接口,一个PCI插槽,一个PCMCIA接口,LCD接口。

3、编程模型

3.1 指令
AU1500的指令兼容MIPS32指令集,每条指令占4字节,指令的边界对齐要求很严格。另外我在MIPS32的指令集中未找到 LI,LA,MOVE,但是,在YAMON的原码中用的很多,不知道为什么?有篇资料讲了。
1)LI用于将一个立即数存入一个通用寄存器
2)LA 用于将一个地址(通常是一个标签)存入一个通用寄存器
3)MOVE用于将一个寄存器的值存入另一个寄存器
知道为什么mips32中没有 了,li,la,move指令是as汇编编译器增加的,分别对应在addiu,addiu,addu命令上,在反汇编的时候可以看到相应的改变。其余的指 令均可以在MIPS32指令集的说明文档中找到详细说明。

CODE

3.2 寄存器
1)通用寄存器$0-$31
-----------------------------------------------------------------------------------------
| 寄存器  | 别名  |               主要用途                                              |
-----------------------------------------------------------------------------------------
|$0       |       |  值总是为0,可能主要用途是清空内存地址空间,以及做一些与或非        |
|         |       |       的操作,访问速度快。                                          |
-----------------------------------------------------------------------------------------
|$1       | $AT   |  是为编译器保留的寄存器                                             |
-----------------------------------------------------------------------------------------
|$2..$3   | V0..V1|  保存函数返回值用                                                   |
-----------------------------------------------------------------------------------------
|$4..$11  | A0..A7|  函数调用时传递参数,可以传递8个整型参数                            |
-----------------------------------------------------------------------------------------
|$12..$15 | T0..T3|  临时寄存器,用于保存临时变量的值,也是用的最多的寄存器             |
-----------------------------------------------------------------------------------------
|$16..$23 | S0-S7 |  他们的值在过程调用的时候保持不变,可以用于传递参数或者返回值       |
-----------------------------------------------------------------------------------------
|$24..$25 | T8..T9|  临时寄存器,用于保存临时变量的值,也是用的最多的寄存器             |
-----------------------------------------------------------------------------------------
|$26..$27 | K0..K1|  保留给操作系统内核使用                                             |
-----------------------------------------------------------------------------------------
|$28      | GP    |  保存全局指针                                                       |
-----------------------------------------------------------------------------------------
|$29      | SP    |  保存堆栈指针                                                       |
-----------------------------------------------------------------------------------------
|$30      | FP或S8|  保存帧指针,也可以和S0..S7一样使用                                 |
-----------------------------------------------------------------------------------------
|$31      | RA    |  保存返回地址                                                       |
-----------------------------------------------------------------------------------------

2) 专用寄存器
HI和LO主要用于地址转换使选择页面,PC是指令计数器。

3)控制寄存器
在au1500中有很多的控制寄存 器,象串口、网卡、时钟、中断、PCI,内存、DMA等等的设置都是通过这些寄存器来完成的,这些寄存器的操作是通过内存中特定的地址空间来进行的,读或 写这些地址空间就是读取或设置相应寄存器的值。
-----------------------------------------------
|      控制器           |        基地址       |
-----------------------------------------------
| 内存控制器(FLASH,SDRAM)|       0xB4000000    |
-----------------------------------------------
|PCI 控制器              |       0x014005000   |
-----------------------------------------------
|DMA 控制器              |       0xB4002000    |
-----------------------------------------------
| 中断控制器1            |       0xB0400000    |
-----------------------------------------------
| 中断控制器2            |       0xB1800000    |
-----------------------------------------------
|AC97 的                 |       0XB0000000    |
-----------------------------------------------
|USB HOST               |       0XB0100000    |
-----------------------------------------------
|USB DEVICE             |       0XB0200000    |
-----------------------------------------------
|Ethernet MAC0          |       0XB1500000    |
-----------------------------------------------
|Ethernet MAC1          |       0XB1510000    |
-----------------------------------------------
|UART0                  |       0XB1100000    |
-----------------------------------------------
|UART3                  |       0XB1400000    |
-----------------------------------------------
|GPIO2                  |       0XB1700000    |
-----------------------------------------------
| 系统控制(CLOCK,POWER)  |       0XB1900000    |
-----------------------------------------------

3.3 内存
内存分为静态存储(FLASH/ROM),动态存储(SDRAM,SYNCFLASH)。
AU1500的虚地址空间有4G,物理地 址空间有512M。
内存的CSBA和CSMASK是在系统初始化的时候设定的。

 虚拟地址空间                                             物理地址空间
|-------------|0xffffffff              /\------------|-------------|0x1fffffff
|             |                        |      /|\    |    bootzone |
|             |                        |       |     |  ---->0x1fc00000启动地址
|             |                        |       |     | 32M flash1  |
|             |                        |       |     |             |
|  kseg3      |通过MMU映射为物理地址使用|      |     |  -----------0x1e000000
|             |                        |       |     |    bootzone |
|             |                        |       |     |  ---->0x1dc00000启动地址
|             |                        |       |     | 32M flash0  |
|             |                        |       |     |             |
|-------------|0xe0000000              |       |     |-------------|0x1c000000
|             |                        |       |     |             |
|  kseg2      |通过MMU映射为物理地址使用|      |     |             |
|             |                        |       |     |             |
|             |0xc0000000              |       |     |             |
|-------------|0xbfffffff------------->|       |     |-------------|0x04000000
|  |         |     |             |
|  kseg1      |直接对应为物理地址使用        |     |  64M SDRAM  |
|             |                                |     |             |
|-------------|0xa0000000--------------------------->|-------------|0x00000000
|             |0x9fffffff--------------------->|    /|\
|             |                                      |
|  kseg0      |直接对应为物理地址使用                |
|             |                                      |
|-------------|0x80000000--------------------------->|
|             |
|  kuseg      |映射为物理地址使用
|             |
|-------------|0x00000000

3.4 启动
PB1500启动所选择的FLASH可以通过开关S13来选择两组中的一组,分别对应物理基地址0x1fc00000和 0x1dc00000.
系统加电的时候cpu就从此地址处开始读入代码执行。此地址也就是系统异常处理向量表的第一项(reset)。

3、 bootloader
PB1500自带一个引导程序YAMON,同时YAMON还完成一些系统配置和程序调试的功能。再启动过程中主要涉及的 yamon的几个主要文件依次 为:reset.S-->reset_pb1500.S-->init.S-->main.c-->shell_init.c
下 面对yamon的启动流程做一个简要的说明:(详细的注释可以查看相关文件的注释)
0xbfc00000   系统的第一条指令,无他,和许多系统的一样,跳!b reset_au1xxx,跳到了标号reset_au1xxx促 执行,此标号处是个include指令,系统随即进入了reser_pb1500中,那reset.S作了什么?原来reset设置了系统的一些参数和一 些入口地址,象异常处理,中断,shell函数入口等。以便下面的程序执行时出现异常有地方可去,不至于莫名其妙的死掉。reset_pb1500.S完 成了系统的大部分初始化工作,设置寄存器,初始化cpu,初始化SDRAM,初始化FLASH等,然后回到reset.S,reset.S剩下的代码没几 行,主要是根据cpu的endian mode来决定接下来跳转的函数,_reset_handler_be/_reset_handler_le,这两个标号再连接脚本中定义,分别指向两种 mode下的入口函数的地址,0xbfc90000/0xbfc10000,此地址也就是函数__reset_handler_end函数的地址,这个函 数位于init.s文件中,此文件所作的工作是初始化和pb1500以及yamon运行环境相关的一些环境,包括 cpu,cache,mem,stack,uart等,然后调用了系统的第一个c函数,终于熬出苦海了:-),main.c函数还是在设置系统环境,不知 道哪里有这么多的东西要设置,最后调用shell_setup函数,进入shell_init.c文件,此文件准备了shell的环境,终于我们期待已久 的提示符  YAMON>出现了。

下面按指令的顺序开始介绍:
0xbfc00000   jump to reset_au1x00
            3个nop
            板子id
            nop
            1个测试数据
0xbfc00400   异常处理的入口,进入中断或死循环
0xbfc00480   EJTAG的处理
0xbfc00500   shell函数的入口,22个表项
0xbfc00558   reset_pb1x00
            设置cpu的endian mode
            设置cp0的状态
            失效watchpoint
            失效性能计数器
            设置EJTAG寄存器
            设置CAUSE寄存器
            初始化cache,并转到cachable的内存中执行指令从kseg1-->kseg0
            初始化TLB
            设置cpu pll频率
            设置系统总线
            设置AUX PLL频率
            开始32KHz的震荡?
            初始化静态存储器
            设置外设
            探测reset的原因(硬件,睡眠,运行期)
            初始化动态存储器
            初始化外设
            到init.S中

init.S
            初始化cp0-cause寄存器
            探测板子
            初始化串口
            显示cpu信息
            初始化cpu
            初始化cache
            内存测试
            拷贝代码到ram中,并转到ram中继续执行
            拷贝数据
            设置堆栈
            设置系统信息和cache
            调用c_entry,进入main.c
main.c
            初始化平台相关的参数
            初始化模块
            参数优化
            设置loader的参数
            shell_setup

shell_init.c
             加载shell的函数
             加载shell命令
             进入shell循环:shell():YAMON>

yamon对于内核加载的完成步骤:
            使用load命令
            load命令调用loader函数
            loader函数从网络上通过tftp获取内核映象
            将映象存储在shell_load_addr全局变量中
            设置shell_load_addr_valid全局变量为true
            使用go命令
            go命令将shell_load_addr存储在cp0-epc寄存器中
            用break命令产生一个exception
            系统转到shell_load_addr去执行异常处理函数,也就是我们的内核的入口

AU1200 SoC 及 NorFlash 物理地址与虚拟地址的映射机制 收藏

基准文档: au1200_datasheet.pdf, ml2010-0129.pdf(美菱项目电路图), S29GL064N90TFI04 Flash datasheet


 

 

      以上为AU1200 SoC的结构/接口示意图,其中左上角为MIPS32 Core(Au1 Core),其他模块均为各种SoC片上的外设控制器,所有的这些片内模块都是通过SoC内部的System Bus 和 Peripheral Bus 进行连接和通信的。

      Au1 Core作为一个典型的MIPS32架构的CPU,其特性符合《See MIPS Run, 2nd》文档中的描述,此处参考该文 2.8 节中的描述的MIPS架构地址空间基本概念和图示。在程序中(即使是已经过编译、汇编和链接得到的可执行二进制程序,也不论是应用程序还是系统程序)使用 的任何地址都是虚拟地址,当MIPS-Core读取这些程序的机器指令时,这些虚拟地址都要通过特定的地址映射机制进行地址转换(不一定非得是通过 MMU),从而由Au1 Core的数据总线送出物理地址到 SoC 的  System Bus 上。虽然MIPS的地址映射机制与x86不一样,VM中某些区域的虚拟地址到物理地址的转换非常简单,但是虚拟地址和物理地址的值肯定时不一样的。

      MIPS CPU运行的状态同样也分为用户态和内核态,不过和其他处理器的内核态/用户态机制不同,MIPS架构下当从内核态切换到用户态时,除了应用程序不能访问 虚拟地址空间高2GB区域(虚拟地址最高位为1),否则会引发错误导致trap之外,其他并没有任何区别。程序所见的虚拟地址空间布局如下:

  • kuseg(0x0000 0000~0x8000 0000) —— 这是应用程序可以使用的VM,该区域的所有VP需要通过MMU进行映射,因此对于这个区域地址的引用必须首先确保MMU(或其他特定的地址映射机构)已经 正确设定(而这个工作通常是由OS kernel完成的),故而在OS kernel没有完全启动之前,这个区域在程序中是不可访问的;


  • kseg0(0x8000 0000~0xA000 0000) —— 这个区域的虚拟地址到物理地址的映射很简单,直接将虚拟地址高3位置零即可。但是MIPS设计方案中规定,这个区域的地址都是通过Cache来访问的,所 以在Cache没有初始化设定好之前,这个区域也是不可用的。对于有MMU的系统,OS Kernel代码中常使用该区域地址。
  • kseg1(0xA000 0000~0xC000 0000) —— 与kseg0区域一样, 这个区域的虚拟地址到物理地址的映射仍然是直接将虚拟地址高3位置零即可,并且对这 个区域地址的访问不再需要通过Cache,因此kseg1 区域是MIPS Core 处理器启动的同时就可以由程序直接访问的唯一VM区域 。MIPS Core CPU上电后执行的第一条指令的虚拟地址为 0xBFC0 0000,该地址就是,且必然是位于kseg1区域中的,该地址经过MIPS架构的地址映射后,对应的物理地址为 0x1FC0 0000
          同时,硬件连接上也必须保证系统启动存储设备(NorFlash,或者ROM 等)中,系统启动代码(YAMON、UBoot等)所处位置与 0x1FC0 0000 对应 ——注意是“对应”,而不是“就是” ,即系统上电启动后,传输到NorFlash设备地址总线上的物理地址并不是0x1FC0 0000,在本项目使用的AU1200 SoC硬件环境下,系统上电启动后,传输到NorFlash地址总线上的地址信号是由NorFlash自身的地址总线宽度、SRAM Controller共同决定的。详见下述
  • kseg2(0xC000 0000~0xFFFF FFFF) ——MIPS CPU内核态下程序才可访问的VM区域,一般只有OS kernel代码才会使用这个区域的地址,这个区域的地址同样需要经过MMU映射,因此也必须要在MMU初始化完成之后才可用。

      AU1200 SoC 中,Au1-Core 会将32位的虚拟地址转换为36-bit的物理地址送上 System Bus(datasheet, 2.5),System Bus 的36-bit物理总线由 36-bits 地址总线sysbus_addr[35:0] 和 32-bits数据总线sysbus_data[31:0] 复用。

      AU1200 SoC中,Flash、ROM等外设是通过片内的SRAM Controller控制和连接的。SRAM Controller描述位于datasheet中的3.2节,它包括4个片选(chip select),在美菱项目原理图中,这个四个片选信号对应于AU_CS0~AU_CS3引脚,我们使用的是AU_CS0来作为NorFlash的片使能 (见原理图P7)。

      对于sysbus_addr[36], sysbus_addr[35:32]的值见AU1200 datasheet, Table 20 所述,我们使用SRAM Controller连接的是NorFlash,因此对于NorFlash,System Bus传递过来的36-bits物理地址中高四位为0。

      在AU1200 datasheet 3.2.5 节中描述了SRAM Controller 连接NorFlash时,发送给NorFlash的各种信号,其中的RAD[14:0]就是AU1200 SoC真正发送给NorFlash物理设备的地址信号 ,RAD[14:0]在美菱项目电路图中对应于 AU_ADDR[0:14] 这一组15根引脚。由于SRAM Controller内部实现的地址锁存机制(Datasheet 3.2.2节),最终AU1200 SoC传出给NorFlash、ROM设备的地址数据可以达到 30 bits,即可以寻址最大1 GB的 NorFLash设备,而这30 bits的地址值正是SoC内的System Bus传递给SRAM Controller的36-bits 物理地址中的低30 bits,分两次发送到NorFlash物理外设的地址引脚上。

      在美菱项目中, 我们使用的 8MB NorFlash(型号:S29GL064N90TFI04, 其中的64表示64Mbit)是按word(16 bits)进行寻址的,并且由于我们在电路设计中, NorFlash 的 BYTE# 引脚被拉高,所以每次NorFlash读写都是2 Bytes的数据(详见 Flash datasheet)。因此,我们使 用的8MB NorFlash实际有效的地址引脚共22根(A0~A21) ,222 × 2 Bytes = 8MB,即NorFlash的地址总线为23 bits。在电路原理图中所标识出来的A23实际是无效的,仅仅只是为了一个系列NorFlash封装一致,才往往将该系列NorFlash封装的地址引 脚数统一为该系列中大容量NorFlash的地址引脚数。

     我们只使用了SRAM Controller通过 RAD[14:0]+锁存 送出来的30-bits地址中的22位, 即对应于原理图Page 7中所示的 AU_ADDR1 ~ AU_ADDR14LATCH_ADDR15 ~ LATCH_ADDR22 在美菱项目电路原 理图Page 7中可见,我们外加了一个地址锁存器SN74LVC16374ADGGR,锁存 AU_ADDR[0:15]中的AU_ADDR[0:7],这正是SRAM Controller通过内部的锁存机制送出来的15-bits物理地址的低8位。 AU_ADDR[1:14] 和 LATCH_ADDR[15:22] 这22根引脚,依次对应于SoC片内System Bus传递的 sysbus_addr[0:35] 中的 sysbus_addr[1:22] ,对应连接至NorFlash外设的 A0~A21这22根引脚。

     为什么将 AU_ADDR1 和 A0 连接而不是将 AU_ADDR0 和 A0 连接呢?这还是因为我们使用的NorFlash是以word(16 bits)寻址的,而程序所面对的虚拟地址空间则是按8-bits字节寻址的,假设在程序中需要操作0xBFD0 0000 和 0xBFD0 0001 这两个地址中的字节数据,但是这两个8-bits数据在NorFlash中其实是同一个16-bits单元中的数据,因此我们在程序中使用的 0xBFD0 0000 和 0xBFD0 0001 这两个地址需要在NorFlash中对应于同一个基本数据单元——将 AU_ADDR1 和 A0 引脚连接就可以达到这个目的。

      最后来说明程序中(这里的“程序”包括在机器上跑的典型应用程序,flash_eraseall、flashcp等flash软件,也包 括BDI内置软件,BDI控制台下使用erase、prog、go等命令时都是直接使用虚拟地址 )所使用的系统上电启动地址 0xBFC0 0000 是如何一步一步映射到NorFlash A0~A21这22根引脚上的:

  1. VM中的虚拟地址0xBFC0 0000 经过Au1 Core 输出36-bits 的 0x0 1FC0 0000 到Soc内的System Bus的 sysbus_addr[35:0]上,送至SRAM Controller
  2. SRAM Controller将0x0 1FC0 0000中的低30-bits,即 0x1FC00000(01 1111 1100 0000 0000 0000 0000 0000=011111110000000 000000000000000)通过 RAD[14:0](即AU1200 SOC的 AU_ADDR[0:14] 这一组15根引脚)经过锁存机制分两次送出
                                                              ————在此之上的事情是由AU1200 SoC 片内完成的————
  3. 美菱PCB板上的外加地址锁存器 SN74LVC16374ADGGR 将 SoC AU_ADDR[0:14] 这组引脚上第二次输出的地址信号的 AU_ADDR[0:7],对应于 (0x1FC00000 = 011111110000000 000000000000000 )中的 ( 10000000 进行锁存,并由 LATCH_ADDR[15:22] 这8根引脚送出;
  4. SoC AU_ADDR[0:14] 这组引脚上第一次输出的地址信号中的AU_ADDR[1:14], 对应于(0x1FC00000 = 011111110000000 000000000000000 )中的( 00000000000000 )直接连接到NorFlash的 A0~A13 引脚
  5. 综合3、4步骤,NorFlash地址总线引脚 A21~A0 上对应的电位值应该是( 10000000 00000000000000 = 10 0000 0000 0000 0000 0000
    ——这就是0xBFC0 0000 这个AU1200上电启动虚拟地址最后对应于NorFlash物理设备上的地址引脚信号

      综上,上电启动地址对应到NorFlash的地址引脚的值 ( 10 0000 0000 0000 0000 0000 = 0x20000 0) 所标识的物理地址位于NorFlash中的最后 4MB 起始处,注意:此处的NorFlash的基本存储单元是16 bits=2 Bytes,因此上电启动地址之后的NorFlash容量为 (0x3FFFFF - 0x200000 + 1)*2 = 4MB,也就意为着作为上电执行的Yamon程序,应该保存在NorFlash的最后4MB起始处。

      如果NorFlash仍然保持word寻址,当NorFlash容量变为至4 MB,即NorFlash设备有效地址引脚变为 A0~A20,相应地,地址锁存器锁存的 AU1200 SoC 第二次输出的地址信号的 AU_ADDR[0:6], 最终NorFlash 地址总线引脚 A20~A0 上对应的值应该是 ( 0 0000 0000 0000 0000 0000 =0x000000 ), 即NorFlash的起始处。此时, Yamon程序仍然应该保存在NorFlash的最后4MB起始处,只是此时最后 4MB也就是最开始的4MB而已

      当NorFlash容量小于 4 MB的时候,则无论容量是多少, 0xBFC0 0000 上电启动地址对应的NorFlash 地址总线引脚 A0~An (n<20)上信号全为0,则此时YAMON程序应该放在NorFlash的起始位置。


      同理,当NorFlash容量扩大至16 MB的时候, NorFlash 设备有效地址引脚变为 A0~A22,  相应地,地址锁存 器锁存的 AU1200 SoC 第二次输出的地址信号的 AU_ADDR[0:8], 最终 NorFlash 地址总线引脚 A20~A0 上对应的值应该是 ( 110 0000 0000 0000 0000 0000 =0x600000 ), 上电启动地址之后 的NorFlash容量为 (0x7FFFFF - 0x600000 + 1)*2 = 4MB ,即Yamon程序仍然应该保存在NorFlash的最后4MB起始处。

      同理,如果 NorFlash容量扩大至512 MB的时候, 假设引脚数也是足够的, NorFlash 设备有效地址引脚变为 A0~A27, 相应地,地址锁存器锁存 AU1200 SoC 第二次输出的地址信号中的AU_ADDR[0:13], 最终 NorFlash 地址总线引脚 A27~A0 上对应的值应该是 ( 1111 1110 0000 0000 0000 0000 0000 =0xFE00000 ), 上电启动地址之后 的NorFlash容量为 (0xFFFFFFF - 0xFE00000 + 1)*2 = 4MB, 即Yamon程序 仍然应该保存在NorFlash的最后4MB起始处。

      但是,当NorFlash容量扩大至1024 MB时, NorFlash 设备有效地址引脚变为 A0~A28, 地址锁存器锁存 SoC 第二次输出的地址信号中的全部AU_ADDR[0:14], 最终 NorFlash 地址总线引脚 A28~A0 上对应的值应该是 ( 0 1111 1110 0000 0000 0000 0000 0000 =0x0FE00000 ), 此时 上电启动地址之后 的NorFlash容量变为了 (0x1FFFFFFF - 0x0FE00000 + 1)*2 = 516 MB 了,即此时 Yamon程序仍 然应该保存在NorFlash的最后516MB起始处。而此时的情况也就是AU1200能够通过SRAM Controller寻址的最大容量NorFlash 了。