linux内核运行前先运行bootloader。龙芯启动时,是从地址0xbfc00000处开始执行,bootloader就是位于此处。
bootloader将内核文件(例如,zImage)拷贝到内存,然后跳转到这个内存中的内核处运行。
/**************************************************************************************/
1b-linux-3.0的内核第一个运行的文件是arch\mips\boot\compressed\head.S。
LEAF(start)
start:
/* 保存bootloader传递的四个函数参数a0,a1,a2,a3 */
move s0, a0
move s1, a1
move s2, a2
move s3, a3
/* 将地址从_edata到_end的BSS段清零 */
PTR_LA a0, _edata
PTR_LA a2, _end
1: sw zero, 0(a0)
bne a2, a0, 1b
addiu a0, a0, 4
PTR_LA a0, (.heap) /* 堆地址 */
PTR_LA sp, (.stack + 8192) /* 栈地址,供C函数用 */
PTR_LA ra, 2f /* 函数返回地址是下面的 2: 处 */
/*调用C函数
decompress_kernel解压kernel*/
PTR_LA k0, decompress_kernel
jr k0
nop
/*将保存的bootloader参数恢复到a0,a1,a2,a3寄存器*/
2:
move a0, s0
move a1, s1
move a2, s2
move a3, s3
/*跳转到解压后的kernel_entry入口(在arch\mips\kernel\head.S文件)*/
PTR_LI k0, KERNEL_ENTRY
jr k0
nop
/*循环*/
3:
b 3b
nop
END(start)
/**************************************************************************************/
arch\mips\kernel\head.S文件:
NESTED(kernel_entry, 16, sp) #
kernel_entry
kernel_entry_setup #cpu specific setup
setup_c0_status_pri #配置CP0状态寄存器
/* We might not get launched at the address the kernel is linked to,so we jump there.
? */
PTR_LA t0, 0f
jr t0
0:
/*
clear .bss*/
PTR_LA t0, __bss_start
LONG_S zero, (t0)
PTR_LA t1, __bss_stop - LONGSIZE
1:
PTR_ADDIU t0, LONGSIZE
LONG_S zero, (t0)
bne t0, t1, 1b
/*保存启动参数*/
LONG_S a0, fw_arg0
LONG_S a1, fw_arg1
LONG_S a2, fw_arg2
LONG_S a3, fw_arg3
MTC0 zero, CP0_CONTEXT # clear context register
/*配置和保存堆栈寄存器sp*/
PTR_LA $28, init_thread_union /*$28--gp寄存器*/
PTR_LI sp, _THREAD_SIZE - 32 - PT_SIZE
PTR_ADDU sp, $28
back_to_back_c0_hazard /*但是由于乱序执行的特点,很容易出现非预期行为,称为CP0 hazard。软件解决方法:(1)插入足够多的nop指令(2)ehb指令(3)SSNOP指令也值得注意,它可以自动知道需要停顿的周期数*/
set_saved_sp sp, t0, t1
PTR_SUBU sp, 4 * SZREG # init stack pointer
/*跳转到
start_kernel()*/
j start_kernel
END(kernel_entry)
/**************************************************************************************/
/*与
back_to_back_c0_hazard有关的定义*/
#define ASMMACRO(name, code...) \
__asm__(".macro " #name "; " #code "; .endm"); \
\
static inline void name(void) \
{ \
__asm__ __volatile__ (#name); \
}
ASMMACRO(_ssnop,
sll $0, $0, 1
)
ASMMACRO(back_to_back_c0_hazard,
_ssnop; _ssnop; _ssnop;
)
阅读(1427) | 评论(0) | 转发(0) |