一、常用命令
内存测试
mt -v
newmt
下载内核
通过网络下载 load tftp://10.2.5.22/vmlinux.32
通过硬盘下载 load /dev/fs/[email protected]/boot/vmlinux.32
通过SD卡下载load //fs/[email protected]/boot/vmlinux.32
升级 bios load -r -f 0xbfc00000 tftp://10.2..5.22/gzrom.bin
输出到串口从硬盘启动内核 g console=ttyS0,115200 init=/bin/sh root=/dev/hda1 rw
显示输出到显卡从硬盘启动内核 g console=tty root=/dev/hda1 fb =vfb:1
二、常见问题
1.串口不出字
可以按如下顺序检查
a.是否放入flash芯片烧入的bios是否跟主板匹配
b.是否有晶振是否放对位置是否能起振倍频关系是否合适
c.串口是否接对串口线是否是交叉线主机串口是否可用串口设置设备波特率是
否对)
d.CPU能否从LPC flash中取指
2.串口乱码怎么办
a.bios中串口的波特率是否和串口终端上的波特率设置是否一致
.串口线是否完好(可以换一跟串口线试一试
.bios中串口初始化的时候设置的倍频系数是否和外部的时钟频率一致:
LEAF(initserial_uart)
li a0, GS3_UART_BASE
li t1,128
# addiu a2,a0,3
sb t1,3(a0)
li t1,0x12 # divider, highest possible baud rate, 33M
# li t1,0x0e # divider, highest possible baud rate, 25M
sb t1,0(a0)
li t1,0x0 # divider, highest possible baud rate
sb t1,1(a0)
li t1,3
sb t1,3(a0)
........................................................
计算公式如下115200hz X 0x0e = 25M/16
115200hz X 0x12 = 33M/16
相应的kernel中串口频率也需要改过来主要修改的文件有
include/asm-mips/serial.h
include/asm/serial.h这个文件链接到 include/asm-mips/serial.h
arch/mips/kernel/8250-platform.c
如何在bios里面如何选用LPC串口
在 bios的配置文件里面conf.3aconf里,有 USE_LPC_UAR选项选中就会使用LPC串口
1.
#
#option USE_LPC_UART
#
如果要使用UART_0串口呢
在配置文件中禁用USE_LPC_UART而在UART0和UART1之间选用呢
修改相应B下的 /.中的 GS3——UART——
BASE的定义
#define GS3_UART0_BASE 0xbfe001e0
#define GS3_UART1_BASE 0xbfe001e8
#define GS3_UART_BASE GS3_UART0_BASE
如果串口始终不出字可用EJTAG看CPU到底有没有跑起来。
3.碰到内存跑飞怎么办
在时经常碰到内存跑飞的问题阅读.源代码可以看到出现这个问题
出现在把从中解压出来的代码和数据拷贝到内存的过称中。只要是内
存是正确的初始化并且当前设置的频率范围适当就不会出现这个问题。所以碰到这
个问题需要检查内存
.在内存插槽内是否放入内存条
.内存的晶振是否存在晶振频率、倍频系数是否合适
内存条和晶振是否好的
.放入内存条的插槽是否没有问题(比如有的MCP68板子上只能使用MC1
4。在内存不是自动检测和配置的板卡上手动设置的选项通道大小)是否和板卡上内
存的位置和大小匹配(有两个控制器可以引出四个插槽每个控制器对应两个插槽)
5。在内存自动检测和配置的板卡上通过I2C读出的DDR信息是否正确
.内存参数是否匹配
4.网卡不能用怎么办
1.pmon里面是否可以找到设备devls:rte0,fxp0,rtk0,rte0,em0
2。网卡是否没有损坏
3。网卡的支持是否在相应bonito的conf配置选项里面加入进去
4.网卡ping 的时候是否丢包3A3里面RTL8169网卡驱动里面是否要改个东西?)
PCI基址的设置是否正确
在对应Bonito下边检查pci/pci_machdep.c: 利用CPU 的PCI设备需要改这个)
169 /*set pci base0 address and window size*/
170 pci_local_mem_pci_base = 0x80000000;
171 #ifdef LS3_HT
172 #else
173 BONITO_PCIBASE0 = 0x80000000;
174 #endif
5.硬盘找不到怎么办
1.硬盘的数据线和电源线是否接好
2. BIOS里面的配置文件是否支持硬盘
3.如果是利用HT端口接桥片HT的接受端口窗口是否打开
#if 1//OPEN RX SPACE in HOST
TTYDBG("HT RX DMA address ENABLE\r\n")
dli t2, 0x90000efdfb000060
li t0, 0xc0000000
sw t0, 0x0(t2)
li t0, 0x0080fff0
sw t0, 0x4(t2)
TTYDBG("HT RX DMA address ENABLE done 1\r\n")
li t0, 0xc0000000
sw t0, 0x8(t2)
li t0, 0x00008000
sw t0, 0xc(t2)
TTYDBG("HT RX DMA address ENABLE done 2\r\n")
三、BIOS启动
bios是系统启动时最早的初始化和引导固件。主要完成初始化处理器状态、初始化cache
和DDR、划分并映射地址空间、设备自检、引导内核的功能。
1.处理器状态初始化
这个过程主要初始化CP0的一些寄存器设置CPU异常处理程序入口。系统reset或者上
电后首先会执行
/* 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
SR_BOOT_EXC_VEC = 0x04000000,告诉CPU使用ROMKSEG1空间的异常入口在
操作系统启动后BEV一般设置为0。另外设置gp,sp寄存器因为以后初始化DDR 从
flash中load 数据的时候需要用到。
Disassembly of section .text:
80010000 <_ftext>:
80010000: 00 60 80 40 00 68 80 40 40 00 08 3c 00 60 88 40 .`[email protected]@@..<.`[email protected]
80010010: 01 80 1d 3c 00 c0 bd 67 10 80 1c 3c e0 c0 9c 67 ...<...g...<...g
80010020: 00 00 00 00 e0 bf 02 3c 1c 01 42 34 04 00 43 8c .......<..B4..C.
80010030: 0f 00 63 34 0f 00 63 38 04 00 43 ac 0d 00 03 24 ..c4..c8..C....$
80010040: 00 00 43 ac 00 10 03 24 ff ff 63 24 fe ff 60 14 ..C....$..c$..`.
80010050: 00 00 00 00 f8 02 11 04 00 00 00 00 ............
实现的链接脚本如下
ENTRY(_start)
SECTIONS
{
. = 0xffffffff80010000;
.text :
{
_ftext = . ;
*(.text)
*(.rodata)
*(.rodata1)
*(.reginfo)
*(.init)
*(.stub)
*(.gnu.warning)
} =0
_etext = .;
。。。。。。。。
_gp = ALIGN(16) + 0x7ff0;
初始化gp是为了减少全局变量寻址的访存次数。而sp的值是
mips64el-linux-nm gzrom | grep stack
ffffffff80ffc000 T stack
刚好对应于start.S中的
_start:
start:
.globl stack
stack = start - 0x4000 /* Place PMON stack below PMON start in RAM */
而start.S中的_start来自编译链接脚本 zloader/ld.conf.S中的
KENTRY(_start)
8 SECTIONS
9 {
10
11 . = 0xffffffff81000000;
………………….
接下面放置的代码是一些约定的中断向量的地址具体见《MIPS处理器设计透视》85
页。它们并不会立即执行启动代码实际会接着执行
locate:
la s0,start
subu s0,ra,s0
and s0,0xffff0000
li t0,SR_BOOT_EXC_VEC
mtc0 t0,COP_0_STATUS_REG
mtc0 zero,COP_0_CAUSE_REG
.set noreorder
这段代码主要是得到s0的值。在这段代码中ra还是 基于访问bios flash的0xbfc0000地
址而s0的地址是基于编译器指定的start0x81000之上的地址反汇编代码如下
81000c38 <locate>:
locate():
81000c38: 3c108100 lui s0,0x8100
81000c3c: 66100000 daddiu s0,s0,0
81000c40: 03f08023 subu s0,ra,s0
81000c44: 3c01ffff lui at,0xffff
81000c48: 02018024 and s0,s0,at
81000c4c: 3c080040 lui t0,0x40
81000c50: 40886000 mtc0 t0,c0_sr
81000c54: 40806800 mtc0 zero,c0_cause
81000c58: 3c14bfe0 lui s4,0xbfe0
因此s0 = 0xbfc00000-0x81000000,它用来修正编译链接脚步中的指定的地址和访问flash芯
片的真实地址的偏移。此外s0如果为0怎表示系统是从RAM启动。这一点在阅读
start.S的代码中需要注意不能忘记。比如start.S串口打印的函数
LEAF(stringserial)
move a2, ra
#ifdef ROM_EXCEPTION
li a1,0x3ec00000
addu a1, a0, a1
#else
addu a1, a0, s0
#endif
lbu a0, 0(a1)
……………………………………….
接下来一个很重要的操作时在系统上打开64 bit 的地址空间。这是跟2F及之前的CPU
bios里面有差别的地方因为LS3A及以后的芯片是支持64位的而且后面的代码中也会
出现64bit地址比如内存自检前使能SMB总线。
//Open 64-bit address space
mfc0 t0, CP0_STATUS
li t1, 0x00e0 # {cu3,cu2,cu1,cu0}<={0110, status_fr<=1
or t0, t0, t1
mtc0 t0, CP0_STATUS
.set mips64
使能对User segment、supirvisor segment、kernel segment的64 bit 访问同时设置系统为
kernel model。为了便于 调试有的板卡上带有7段数码管下边这段代码就是往数码管
里面写入0x99的。这样调试人员就容易确定程序大概已经执行到的地方。
li a0,0x900000001ff00080
li t0,0x99
sb t0,0x0(a0)
完成上述操作之后主处理器核开始初始化一、二级cross bar和DDR而从处理器核进入
等待。多核之间的引导顺序可参考《龙芯3A启动概要》。
2.DDR/TLB/cache的初始化
龙芯3A及以后的多核芯片中每个处理器有不少于4个的处理器核每个核内部有自己
的指令cache、数据cache、指令TLB、数据TLB。这些由每个核自己初始化。核间通过一
级cross bar连接二级cache二级cache可以通过主处理器核初始化。同样连接在二级
cross bar 上的双通道内存控制器(MC0和MC1),一般也由主处理器核初始化。
主处理器核首先会跳到core0_start去执行
#ifdef LS3_HT
b core0_start
nop
#endif
首先通过下边的代码判断是否从RAM启动如果是就说明DDR已经初始化完成指令已
经是在内存中执行因此可以直接跳到initmips去执行。
bnez s0,1f
nop
li a0,128
la v0,initmips
jr v0
nop
1:
否则必须先初始化内存和cache。后面接着会看到
#include "loongson3_fixup.S"
这是为了禁止一些猜测执行的非法访问以防止死机。
接着调用 #include "loongson3_ddr2_config.S" 来执行内存初始化并且设置二级CROSS
BAR的窗口。二级cross bar里必不可少的是把系统内存的低256M路由到放入内存的
DDR控制器上。如果要用到网卡等PCI设备的话还必须把PCI DMA空间路由到一个放
入了内存条的DDR控制器上。
内存初始化完成之后理论上就可以用了。但只能通过uncache 的方式去访问因为这时
cache还没有初始化。不过uncach方式访存速度比较慢为此需要先初始化cache。至于
TLB虽然PMON里面中不会用到但为了避免猜测执行可能导致的TLB的意外命中
需要初始化TLB的每一项的entry_hi为unmapped的地址以确保在BIOS运行过程中不
可能出现TLB命中。
下面是初始化TLB的代码
LEAF(CPU_TLBClear)
li a3, 0 # First TLB index.
li a2, PG_SIZE_4K
MTC0 a2, COP_0_TLB_PG_MASK # Whatever...
1:
MTC0 zero, COP_0_TLB_HI # Clear entry high.
MTC0 zero, COP_0_TLB_LO0 # Clear entry low0.
MTC0 zero, COP_0_TLB_LO1 # Clear entry low1.
mtc0 a3, COP_0_TLB_INDEX # Set the index.
addiu a3, 1
li a2, 64
nop
nop
tlbwi # Write the TLB
bne a3, a2, 1b
nop
jr ra
nop
END(CPU_TLBClear)
清空TLB的每一项全部都清0,这样接可以避免命中CPU重启之后的一些不定状态。接
着初始化TLB从wired寄存器指定的到最后的TLB项
LEAF(tlb_init)
mtc0 $0, CP0_WIRED
mtc0 $0, CP0_PAGEMASK
tlb_flush_all:
lui a0, 0x8000
addiu a1, $0, 64
#a0=KSEG0,a1 = tlbsize, v0, v1, a3 used as local registers
mtc0 $0, CP0_ENTRYLO0
mtc0 $0, CP0_ENTRYLO1
mfc0 v0, CP0_WIRED
addu v1, $0, a0
1: sltu a3, v0, a1
beq a3, $0, 1f
nop
mtc0 v1, CP0_ENTRYHI
mtc0 v0, CP0_INDEX
tlbwi
addiu v1, v1, 0x2000
beq $0, $0, 1b
addiu v0, v0, 1
1:
###tlb_init finish####
tlbp
jr ra
nop
END(tlb_init)
###############################
注意这时候往 ENTRY_Hi中写入的是 0x80000000 + 0x2000 * n的值因为这段地址都是
unmap的所以这就可以保证每次都不会命中从而后面所有对mapped 空间的第一次方
访内存都会出现TLB Miss。接着跳到初始化一级cache的代码
LEAF(godson2_cache_init)
####part 2####
cache_detect_4way:
mfc0 t4, CP0_CONFIG
andi t5, t4, 0x0e00 // get size of L1 cache
srl t5, t5, 9 // t5 = L1 cache size IC
andi t6, t4, 0x01c0 // T6 DC size
srl t6, t6, 6
addiu t6, t6, 10 #4way
addiu t5, t5, 10 #4way
addiu t4, $0, 1
sllv t6, t4, t6 //
sllv t5, t4, t5
addiu t7, $0, 4 //计算出 icache /dache大小及每一组的大小 16k
####part 3####
lui a0, 0x8000 // start address of KSEG0 CACHED
#addu a1, $0, t5
#addu a2, $0, t6
li a1, (1<<14) #64k/4way
li a2, (1<<14)
cache_init_d4way:
#a0=0x80000000, a1=icache_size, a2=dcache_size
#a3, v0 and v1 used as local registers
mtc0 $0, CP0_TAGHI
li t0, 0x22
mtc0 t0, CP0_ECC
addu v0, $0, a0
addu v1, a0, a2
1: slt a3, v0, v1
beq a3, $0, 1f
nop
mtc0 $0, CP0_TAGLO //
//对当前cache line
cache Index_Store_Tag_D, 0x0(v0) // 初始化第一路对应cache line的TAG 域
cache Index_Store_Tag_D, 0x1(v0) // 初始化第二路对应cache line 的 TAG 域
cache Index_Store_Tag_D, 0x2(v0)
cache Index_Store_Tag_D, 0x3(v0)
beq $0, $0, 1b
addiu v0, v0, 0x20
1:
对 ICAHCE 也是一样初始化的过程如下
cache_flush_i4way:
addu v0, $0, a0
addu v1, a0, a1
mtc0 $0, CP0_TAGLO
mtc0 $0, CP0_TAGHI
mtc0 $0, CP0_ECC
1: slt a3, v0, v1
beq a3, $0, 1f
nop
cache 0x08, 0x0(v0)/*Index_Store_Tag_I*/
cache 0x08, 0x1(v0)/*Index_Store_Tag_I*/
cache 0x08, 0x2(v0)/*Index_Store_Tag_I*/
cache 0x08, 0x3(v0)/*Index_Store_Tag_I*/
beq $0, $0, 1b
addiu v0, v0, 0x20
1:
cache_init_finish:
//TTYDBG ("\r\ncache init ok\r\n")
jr ra
nop
// cache_init_panic:
// TTYDBG ("\r\ncache init panic\r\n")
// 1: b 1b
// nop
.end godson2_cache_init
同理之后对scache 的初始化类似也是把相应的tat_lo, tag_hi清0.因此所有第一次访
存都会出现cache mipss,这时会直接去访问mem ,完成之后又会用访存的物理地址的高
位来设置tag域 至于具体哪一项的tag被替换是根据随即替换算法实现。
这样此后就可以用cache 方式去访问0xbfc0000对应的指令和数据为此首先把当前
的ra (0xbfc00000)的地址与上0xdfff上实现,这样PC就变成了0x9fc开始的地址。
#if 1
PRINTSTR("Jump to 9fc\r\n")
lui t0, 0xdfff ####################### go to 9fc
ori t0, t0, 0xffff
bal 1f
nop
1:
and ra, ra, t0
addiu ra, ra, 16
jr ra
nop
#endif
此外还需要配置KSEG0段访问的缓存行为设置为缓存模式。否则即便PC地址是
cached的实际的访存行还是uncache的。
#if 1
mfc0 $4, $16
and $4,0xfffffff8
or $4,0x3 // config寄存器的K0域为 0x3
mtc0 $4,$16
TTYDBG("cache enable done\r\n")
nop
#endif
接着执行初始化 一级 CROSS BAR 的操作。(主要是为了兼容之前的32 bit pmon和PCI
设备,实现64位地址向32地址的映射以便CPU可以用32位地址访问HT 空间/PCI空
间)。最后把flash 里面的bios可执行代码和数据拷贝到编译脚本ld.script指定的相应地
方。完成上述所有操作后就可以完全跳转到initmips去执行。