查看文章
 
pmon启动流程(一)
2008-05-24 18:38
下面介绍的pmon流程,基于龙芯2c,计算所的北桥。

1 pmon的编译
1.1 pmon的配置
1)配置文件
总的配置文件在 :/usr/src/pmon-all/conf/files
开发板的配置文件: /usr/src/pmon-all/Target/bonito/conf/Bonito
其他配置文件还有 /usr/src/pmon-all/sys/dev/pci/files.pci
/usr/src/pmon-all/sys/dev/ata/files.ata
2)配置设置
我们这里最重要的是 /usr/src/pmon-all/Target/bonito/conf/Bonito文件
文件格式,#表示注释
include "conf/GENERIC_ALL1"
#包含/usr/src/pmon-all/conf/GENERIC_ALL1文件,其内容如下

#
# Module selection. Selects pmon features
#
select mod_flash_amd # AMD flash device programming
select mod_flash_intel # intel flash device programming
select mod_flash_sst # intel flash device programming
#目前pmon支持amd,inter和sst公司的flash的烧写,有两个作用,一是储存环境变量,二是在线更新bios
#
# Command selection. Selects pmon commands
#
#select cmd_about # Display info about PMON
select cmd_boot # Boot wrapper
select cmd_cache # Cache enabling
select cmd_call # Call a function command
select cmd_mycfg
select cmd_date # Time of day command
select cmd_env # Full blown environment command set
select cmd_flash # Flash programming cmds
select cmd_hist # Command history
select cmd_ifaddr # Interface address command
select cmd_l # Disassemble
select cmd_mem # Memory manipulation commands
select cmd_more # More paginator
select cmd_mt # Simple memory test command
select cmd_misc # Reboot & Flush etc.
select cmd_set # As cmd_env but not req. cmd_hist
select cmd_stty # TTY setings command
select cmd_tr # Host port-through command
select cmd_devls # Device list
#
select cmd_shell # Shell commands, vers, help, eval
select cmd_vers
select cmd_help
select cmd_eval
select    cmd_mycmd
select cmd_newmt #test86内层检测程序
select cmd_setup     #条棒式配置程序
上面这些选项选择编译那些命令到pmon中
option    CONFIG_CACHE_64K_4WAY
#龙芯2c的cache设置4路,64k.
再返回到原配置文件中
# Platform options
#
option BONITOEL #平台北桥的类型,计算所binito结构北桥
option MIPS
option INET

select mod_uart_ns16550 # Standard UART driver
option CONS_BAUD=B115200
#串口的波特率设置
select ext2
select iso9660
#pmon支持ext2,iso9660文件系统,可以从网络硬盘软驱光驱引导内核
select mod_x86emu_int10
#显卡rom模拟程序
select mod_vgacon
#显示器和键盘虚拟终端
option AUTOLOAD
#pmon起动后,自动引导内核
# Functional options.
#
option HAVE_TOD # Time-Of-Day clock
#实时钟
option HAVE_NVENV #   Platform has non-volatile env mem
#环境变量支持
option          NVRAM_IN_FLASH
#打开这个选项环境变量存储在flash中,关闭环境变量存在cmos中
option    HAVE_NB_SERIAL
#北桥有串口,在正式的电路板中北桥无串口
#下面是pmon的设备树的设置
#
#   Now the Machine specification
#
mainbus0        at root
localbus0 at mainbus0
fd0       at mainbus0
#软驱驱动
pcibr0 at mainbus0
pci* at pcibr?
# fxp normally only used for debugging (enable/disable both)
fxp0          at pci? dev ? function ?        # Intel 82559 Device
inphy*       at mii? phy ?                # Intel 82555 PHYs
#82559网卡驱动
##########82546
#82546 use a lot of memory so setup NKMEMCLUSTERS as bellow
#       #define NKMEMCLUSTERS (16 * 1024 * 1024 / CLBYTES) /* 0.5Mb */
em*          at pci? dev ? function ?        # Intel 82559 Device
#82546网卡驱动
#### IDE controllers
pciide* at pci ? dev ? function ? flags 0x0000

#### IDE hard drives
wd* at pciide? channel ? drive ? flags 0x0000
#硬盘驱动
ide_cd* at pciide? channel ? drive ? flags 0x0001
#光驱驱动
1.2 pmon的编译

Cd /usr/src/pmon-all/zloader
Make cfg #根据配置文件重新产生makefile
Make tgt=rom #生成rom bin文件gzrom.bin
Make tgt=ram #生成网络加载文件gzram,通过网络tftp重新加载pmon在调pmon程序的时候很有用
也可以用老的编译方法
cd /usr/src/pmon-all/Targets/Bonito/conf
pmoncfg Bonito
cd /usr/src/pmon-all/Targets/Bonito/compile/Bonito
make
2.利用gdb来分析pmon
2.1.得到编译信息
要使生成的pmon带编译信息,改 Targets/Bonito/compile/Bonito/Makefile
直接将gcc 改成了gcc -ggdb -g3
将Makefile中的
STRIPFLAGS=     -g -S --strip-debug
LFLAGS+=        -S
注释掉。其中ld的参数 -S和--strip-debug的作用是去掉调试的信息。
STRIPFLAGS=     #-g -S --strip-debug
LFLAGS+=        #-S
make DEBUG=-g
2.使用gdb
mips-elf-gdb pmon
(gdb) target sim
load
(gdb) disassemble   0xffffffff80010000

0xffffffff80010030 <uncached>:   lui     $at,0xa000
0xffffffff80010034 <uncached+4>:        or    $ra,$ra,$at
0xffffffff80010038 <uncached+8>:        jr    $ra
反汇编出来的和原来的不一样
其他gdb使用方面的知识就不介绍了。
3.pmon的起动流程
Targets/Bonito是计算所北桥相关的代码位置,起动代码为Targets/Bonito/Bonito/start.S.
看代码的时候要注意pmon中的一些宏是定义在头文件中的,另一些则定义在Makefile中,通过gcc参数-D来定义。
3.1mips cpu和北桥的基本知识

kseg0: 0x8000 0000 - 0x9FFF FFFF(512M): 只需要把最高位清零,这些地址就被转换(translate)为物理地址,
然后把它们连续地映射到物理内存中512M大小的低字段 (0x0000 0000 - 0x1FFF FFFF)内。这种转换是很简单的,
因此常常把这些地址称为“无需转换的“。一般情况下,都是通过快速缓存(cache),对这段区域内的地址进行访问。
因此在cache被正确地初始化之前,不要使用这些地址。通常,在没有MMU的系统中,这段区域用于存放大多数程序和数据。
至于有MMU的系统,操作系统的内核会存放在这个区域。
kseg1: 0xA000 0000 - 0xBFFF FFFF(512M): 通过将最高3位清零的方法,把这些地址映射为相应的物理地址,然后象kseg0一样,
再映射到物理内存中512M大小的低字段。但要注意,kseg1是不通过cache存取的(uncached)。kseg1是唯一的在系统重启时能正常工作
的地址空间,这也是为什么重新启动时的入口向量0xBFC0 0000会在这个区域内。入口向量对应的物理地址是0x1FC0 0000――这个应该
告诉你的硬件工程师。
因此,你可以使用这段地址空间来访问你的初始化程序的ROM。还有大多数人把它用来访问I/O寄存器。如果你的硬件工程师要把这些东西
映射到非低段512M物理空间,那你应该试图说服他们修改。
kseg2: 0xC000 0000 - 0xFFFF FFFF (1GB): 这段地址空间只能在核心态下使用并且要经过MMU的转换。在MMU设置好之前,
不要对其进行访问。通常,除非你在写一个真正的操作系统,否则都不必使用这段地址空间。

maped指的是要经过TLB进行虚拟内存的翻译。cached指先从cache取,未命中才从内存中取。
从北桥的映射图上看其大部分区域映射在低512M物理内存上。省下三个段512M-2G maps 1-1 on pci access用处不大,2G-4G pci窗口,4G以上sdram。

3.2 代码分析
总的来说:
1)启动位置位于cpu的启动地址是0xbfc00000,这个地址对应的物理地址是0x1fc00000,北桥将这一地址影射到flash的0地址上.
因此准确的说pmon是从flash的0地址开设运行。编译的时候start.o正好是第一个被链接的obj文件,因此start.S的第一条指令是cpu运行的第一个指令,位于_start。
2)c代码的第一个入口是initmips,位于tgt_machdep.c中。最后程序到main函数中运行命令循环。
3)pmon开始应该是freebsd移植过来的,系统调用,设备驱动是unix风格的。
4)pmon中cpu运行于32位模式下,是关中断运行。pmon完全靠查询来完成整个系统,技巧是idle函数中调用scandevs来扫描设备驱动程序。驱动程序 中的中断也是通过被系统查询的时候不断调用来实现的。
5)在cpu的状态寄存器中有一个bev,设置异常向量从rom中取,还是重ram中取.
         bcopy(MipsException, (char *)TLB_MISS_EXC_VEC, MipsExceptionEnd - MipsException);
         bcopy(MipsException, (char *)GEN_EXC_VEC, MipsExceptionEnd - MipsException);

下面具体介绍启动流程:

start.S中
_start:
start:
.globl stack
stack = start - 0x4000 /* Place PMON stack below PMON start in RAM */

/* NOTE!! Not more that 16 instructions here!!! Right now it's FULL! */
mtc0 zero, COP_0_STATUS_REG
mtc0 zero, COP_0_CAUSE_REG
li t0, SR_BOOT_EXC_VEC /* Exception to Boostrap Location */
mtc0 t0, COP_0_STATUS_REG
la sp, stack
la gp, _gp

bal uncached /* Switch to uncached address space */
nop

bal locate /* Get current execute address */
nop
从pmon中反汇编得到
(gdb) disassemble 0xffffffff80010000
Dump of assembler code for function start:
0xffffffff80010000 <start>:     mtc0 $zero,$12
0xffffffff80010004 <start+4>: mtc0 $zero,$13
0xffffffff80010008 <start+8>: lui     $t0,0x40
0xffffffff8001000c <start+12>:   mtc0 $t0,$12
0xffffffff80010010 <start+16>:   lui     $sp,0x8001
0xffffffff80010014 <start+20>:   daddiu   $sp,$sp,-16384 #0xffffc000
0xffffffff80010018 <start+24>:   lui     $gp,0x8009
0xffffffff8001001c <start+28>:   daddiu   $gp,$gp,30800
0xffffffff80010020 <start+32>:   bal     0x80010030
0xffffffff80010024 <start+36>:   nop
0xffffffff80010028 <start+40>:   bal     0x80010638
0xffffffff8001002c <start+44>:   nop
可以看出sp的指向的位置,并不是指向flash,因此开始的堆栈用的就是sdram
bal uncached
nop
bal locate
nop
uncached:
or ra, UNCACHED_MEMORY_ADDR
j ra
nop
#machine/cpu.h
#define UNCACHED_MEMORY_ADDR 0xa0000000

此处是可以从cache空间转换到uncache的空间,ra中保留的是bal_locate这条指令的地址,然后或上UNCACHED_MEMORY_ADDR,该地址就变成uncache的地址了.
为什么pmon的启动地址为0xbfc00000,而ld生成代码的text段的起始地址为0x80010000
应该有从flash到ram的搬移过程
la    s0, start         
   subu s0, ra, s0
   and     s0, 0xffff0000

    这段代码是为了访问数据,因为这段汇编在Rom执行,而编译出来的数据段在0x8002xxxx,为了能够访问数据段的数据,需要进行一个
    地址的修正,s0这是起到这种修正的目的。

bal     1f
nop
BONITO_BIC(BONITO_BONPONCFG,BONITO_BONPONCFG_CPUBIGEND)
展开后变成
.word 0x00000018 | 0x00000002   ,((   0x1fe00000   +( ( 0x100   + 0x00 ) )   ) | 0xa0000000 ) ;   .word ( ~( 0x00004000   ) ),( 0 )
后面的程序解析这些数据完成对应的初始化操作
...
EXIT_INIT(0)
展开后变成
.word 0x00000000 ,( 0 );    .word 0,0
这样初始化数据定义完成
下面的程序
1: move a0,ra
因为前面bal     1f,因此此时ra的值恰好就是定义的初始化数据的地址,下面的reginit开始的
一段程序解析前面的数据来对寄存器进行配置

reginit: /* local name */
lw t3, Init_Op(a0)
lw t0, Init_A0(a0)
and t4,t3,OP_MASK
/*
    * EXIT(STATUS)
    */
bne t4, OP_EXIT, 8f
nop
move v0,t0
b .done
nop
剩下的初始化寄存器的过程省略

.done:
/* Initialise other low-level I/O devices */

bal initserial
nop


PRINTSTR("\r\nPMON2000 MIPS Initializing. Standby...\r\n")

PRINTSTR("ERRORPC=")
mfc0 a0, COP_0_ERROR_PC
bal hexserial
nop

PRINTSTR(" CONFIG=")
mfc0 a0, COP_0_CONFIG
bal hexserial
nop
PRINTSTR("\r\n")

PRINTSTR(" PRID=")
mfc0 a0, COP_0_PRID
bal hexserial
nop
PRINTSTR("\r\n")
简单的打印一些寄存器的值
....
一些sdram的配置
1: sw sdCfg,BONITO_SDCFG(bonito)

2: b 3f
nop
3:
...
配置pci内存影射
li t1,0 # accumulate pcimembasecfg settings

/* set bar0 mask and translation to point to SDRAM */
sub t0,msize,1
not t0
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE0_MASK_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE0_MASK
or t1,t0

li t0,0x00000000
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE0_TRANS_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE0_TRANS
or t1,t0
or t1,BONITO_PCIMEMBASECFG_MEMBASE0_CACHED

/* set bar1 to minimum size to conserve PCI space */
li t0, ~0
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE1_MASK_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE1_MASK
or t1,t0

li t0,0x00000000
srl t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE1_TRANS_SHIFT
and t0,BONITO_PCIMEMBASECFG_MEMBASE1_TRANS
or t1,t0
or t1,BONITO_PCIMEMBASECFG_MEMBASE1_CACHED

sw t1,BONITO_PCIMEMBASECFG(bonito)

/* enable configuration cycles now */
lw t0,BONITO_BONPONCFG(bonito)
and t0,~BONITO_BONPONCFG_CONFIG_DIS
sw t0,BONITO_BONPONCFG(bonito)

PRINTSTR("Init SDRAM Done!\r\n");

地址译码的结果和bonito64 的相兼容,为了实现对大容量(2GB)
存储器的支持,将原来的0x8000_0000~0x1_0000_0000 之间的2GB 空间分配给了SDRAM,
为了保持软件的兼容性,把2GB 空间的低256MB 和起始的256MB 存储空间重叠,对应同
一块存储区。
<img src=北桥设计文档.pdf:北桥内部地址空间分配>
初始化cache,将cache寄存器中填入内容,并cache有效?
...

下面完成程序和数据从flash到内存的拷贝

la a0, start
li a1, 0xbfc00000
la a2, _edata
       or    a0, 0xa0000000
       or    a2, 0xa0000000
subu t1, a2, a0
srl t1, t1, 2

move t0, a0
move t1, a1
move t2, a2

/* copy text section */

1: and t3,t0,0x0000ffff
bnez t3,2f
nop
move a0,t0
bal hexserial
nop
li a0,'\r'
bal tgt_putchar
nop
2: lw t3, 0(t1)
nop
sw t3, 0(t0)
addu t0, 4
addu t1, 4
bne t2, t0, 1b
nop

PRINTSTR("\ncopy text section done.\r\n")

/* Clear BSS */
la a0, _edata
la a2, _end
2: sw zero, 0(a0)
bne a2, a0, 2b
addu a0, 4


TTYDBG("Copy PMON to execute location done.\r\n")
/* zhb */
#if 0
zhb:
TTYDBG("Testing...\r\n")
la a0, start
li a1, 0xbfc00000
la a2, _edata
       or    a0, 0xa0000000
       or    a2, 0xa0000000
/* subu s6, a2, a0*/
/* srl s6, s6, 2*/

move t0, a0
move t1, a1
move t2, a2
/* copy text section */

1: lw t4, 0(t1)
nop
lw t5, 0(t0)
addu t0, 4
addu t1, 4
beq t4, t5, 2f
nop
move a0, t0
subu a0, 4
bal hexserial
nop
TTYDBG (" ")
move a0, t4
bal hexserial
nop
TTYDBG (" ")
move a0, t5
bal hexserial
nop
TTYDBG ("\r\n")
2: bne t2, t0, 1b
nop
TTYDBG ("test ok!\r\n")
3: beqz zero, 3b
nop
#endif


#if 1
       mfc0 a0,COP_0_CONFIG
       and a0,a0,0xfffffff8
       or     a0,a0,0x2
       mtc0 a0,COP_0_CONFIG
#endif

li a0, 4096*1024
sw a0, CpuTertiaryCacheSize /* Set L3 cache size */
move a0,msize
srl a0,20
la v0, initmips
jalr v0
nop

其中initmips是c代码的入口,初始化过程结束
initmips传入了memorysize,其中memorysize是start.S中的msize,是根据sdram内存条的信息计算出来的。

/home/dsm/pmon2003/src/Targets/Bonito/Bonito/tgt_machdep.c:
140     void
141     initmips(unsigned int memsz)
142     {
143          /*
144              *    Set up memory address decoders to map entire memory.
145              *    But first move away bootrom map to high memory.
146              */
147     #if 0
148          GT_WRITE(BOOTCS_LOW_DECODE_ADDRESS, BOOT_BASE >> 20);
149          GT_WRITE(BOOTCS_HIGH_DECODE_ADDRESS, (BOOT_BASE - 1 + BOOT_SIZE) >> 20);
150     #endif
151          memorysize=(memsz&0x0000ffff) << 20;//recover to original size:256M
152          memorysize_high=((memsz&0xffff0000)>>16) << 20;//0
153
154          /*
155              *   Probe clock frequencys so delays will work properly.
156              */
157          tgt_cpufreq();
158          SBD_DISPLAY("DONE",0);
159          /*
160              *   Init PMON and debug
161              */
162          cpuinfotab[0] = &DBGREG;
163          dbginit(NULL);
164
165          /*
166              *   Set up exception vectors.
167              */
168          SBD_DISPLAY("BEV1",0);
169          bcopy(MipsException, (char *)TLB_MISS_EXC_VEC, MipsExceptionEnd - MipsException);
170          bcopy(MipsException, (char *)GEN_EXC_VEC, MipsExceptionEnd - MipsException);
171
172          CPU_FlushCache();
173
174          CPU_SetSR(0, SR_BOOT_EXC_VEC);
175          SBD_DISPLAY("BEV0",0);
176
177          printf("BEV in SR set to zero.\n");
178
179     #if 0
180          /* memtest */
181          addr_tst1();
182          addr_tst2();
183          movinv1(2,0,~0);
184          movinv1(2,0xaa5555aa,~0xaa5555aa);
185          printf("memtest done\n");
186     #endif
187
188          /*
189              * Launch!
190              */
191          main();
192     }


类别:loongson-2e| |分享到i贴吧|浏览(431)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu