本文涉及的异常和地址空间的相关知识,需要结合《龙芯1c的芯片手册》、《see mips run》和《北京龙芯的龙芯1c开发板手册》。这几个文档都已经放到龙芯1c库的git上了,最新最完整的代码也请移步到git查看。龙芯1c库的git地址是https://gitee.com/caogos/OpenLoongsonLib1c
背景知识
使用mipsel-linux-objdump反汇编
为什么需要使用反汇编
为什么这里首先讨论使用objdump反汇编呢?可能大家习惯了仿真,单步调试。很少单独使用反汇编。可是目前龙芯1c是不能仿真和单步调试的(至少目前我不知道),所以手动反汇编就有必要了,通过查看反汇编,可以很清楚的查看程序的运行流程,可以看到上电后CPU运行的第一条汇编指令是什么。
举个例子吧,在调试上电初始化这部分汇编程序的过程中,发现汇编源码和pmon中的差不多,可是串口没有打印helloworld。经过一番排除,最后用objdump反汇编发现,链接后执行的第一条语句不是汇编,而是c程序。原因是ld链接时,c文件放在了依赖文件列表的前面,改为汇编文件在前面,就可以了。
怎样反汇编
为了能在反汇编的结果中同步显示源码,在编译时,需要增加选项” -g ”,
例如“make cfg all tgt=rom DEBUG=-g”,
使用mipsel-linux-objdump反汇编,
例如
root@ubuntu:/home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c# mipsel-linux-objdump -S pmon.gdb > /mnt/hgfs/VmShare/pmon-gdb-objdump.S
比如,pmon反汇编后,得到如下内容
pmon.gdb: file format elf32-tradlittlemips
Disassembly of section .text:
80010000 <_ftext>:
80010000: 40806000 mtc0 zero,$12
80010004: 40806800 mtc0 zero,$13
80010008: 3c080040 lui t0,0x40
8001000c: 40886000 mtc0 t0,$12
80010010: 3c1d8001 lui sp,0x8001
80010014: 27bdc000 addiu sp,sp,-16384
80010018: 3c1c800c lui gp,0x800c
8001001c: 279c6cf0 addiu gp,gp,27888
80010020: 3c08bfe8 lui t0,0xbfe8
80010024: 24090017 li t1,23
80010028: a1090004 sb t1,4(t0)
8001002c: 24090005 li t1,5
80010030: a1090006 sb t1,6(t0)
80010034: 3c04bfd0 lui a0,0xbfd0
80010038: 348411c0 ori a0,a0,0x11c0
8001003c: 8c850040 lw a1,64(a0)
80010040: 34a50001 ori a1,a1,0x1
80010044: ac850040 sw a1,64(a0)
80010048: 041101b9 bal 80010730 <locate>
8001004c: 00000000 nop
...
反汇编结果是如何与源码一一对应的
这里主要讨论一下,反汇编得到的汇编代码,与start.S中的汇编代码的对应关系
左边为start.S中的汇编源码,右边为反汇编的结果。图中用线将其一一对应了。
异常入口点(CP0的SR寄存器的BEV)
上电运行的第一条指令在什么地方,地址是多少
mips系列cpu的异常和中断是两个不同的概念,中断一般指外设中断,所有外设中断共用一个异常入口,即外设中断是一种特定类型的异常。《龙芯1c的芯片手册》中目前几乎没怎么讲这部分内容,而《see mips run》中却讲得很详细,专门用一章来讲异常。
本文不是要讨论上电初始化那部分汇编代码吗?怎么这里研究异常呢?在mips系列cpu上,上电(冷复位)也属于一种异常,异常入口固定为ROM入口点0xBFC00000,如下图
《龙芯1c的芯片手册》中也有对应描述,如下
图中,明确说了,根据系统启动方式将内存地址0xBFC00 0000 -- )XBFCF FFFF映射到SPI或NAND,即从地址0xBFC0 0000处取出的指令,就是SPI或NAND的地址0处的指令。也是上电后运行的第一条指令。
刚上电时,把BEV置1
截图中,讲清楚了,在cpu刚上电时,cache还未初始化之前,只能使用不经过cache的kseg1。
初始化完成后,把BEV清零
(内存,cache等)初始化完成后,就可以使用cache了,通过把协处理器0的SR寄存器中的BEV清零,使所有异常入口从ROM入口点(0xBFC0 0000)改为RAM入口点(BASE + 0x180),其中BASE为寄存器EBase的值。《see mips run》中的描述为
Pmon中对应的代码为
地址空间的划分
see mips run中关于程序地址空间的划分情况
see mips run中kseg0和kseg1的详细描述
因为kseg0(0x8000 0000 - 0x9fff ffff)和kseg1(0xa000 0000 - 0xBfff ffff)实际上是映射到低端同一块512M的物理地址上,只是kseg1不需要cache,而kseg0必须等cache初始化后才能使用。
所以,把固件拷贝到kseg1上,等等于拷贝到了kseg0上。
龙芯1c芯片手册中关于地址空间分配的描述
链接时的起始地址(代码段的首地址)
标号start的值为0x80010000
代码段是从0x8001 0000处开始的,初始化完成后,异常入口改为RAM入口,即BASE+0x180=0x8000 0000+0x180
栈空间在什么地方
在代码段之前有0x4000大小的栈空间,代码如下<