基于MIPS(LOOGSON)架构LINUX内核启动流程源代码分析(一)--kernel_entry

本文深入分析MIPS(LOONGSON)架构下Linux内核启动流程,从LOAD地址、Entry Point(EP)讲起,重点探讨kernel_entry函数。详细解读kernel_entry_setup、setup_c0_status_pri等关键步骤,包括对CP0寄存器的设置、BBS段清除、BIOS传参等,揭示内核启动背后的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系统加电启动后,MIPS处理器默认的程序入口是0xBFC00000(虚拟地址),此地址在KSEG1(无缓存)区域内,对应的物理地址是0x1FC00000高3位清零),所以CPU从物理地址0x1FC00000开始取第一条指令,这个地址在硬件上已经确定为FLASHBIOS)的位置,BIOS将Linux内核镜像文件拷贝到RAM中某个空闲地址(LOAD地址)处,然后一般有个内存移动的操作(Entry point(EP)的地址),最后BIOS跳转到EP指定的地址运行,此时开始运行Linux kernel。

关于LOAD地址的一些说明:

在我们编译完内核时,一般情况下会有俩个版本的内核vmlinuxvmlinuz。其中vmlinux为非压缩版内核,vmlinuz为压缩版内核(包含内核自解压程序)。
使用readelf -l vmlinux 命令可以读到LOAD地址,这个地址是由arch/mips/kernel/vmlinux.lds决定的:

OUTPUT_ARCH(mips) 
ENTRY(kernel_entry) 
jiffies = jiffies_64; 
SECTIONS 
{ 
. = 0xFFFFFFFF80200000; 
/* read-only */ 
_text = .; /* Text and read-only data */ 
.text : { 
*(.text) 
…

关于Entry point(EP)的一些说明:

EP(ELF可以读到)地址是BIOS移动完内核后,直接跳转的地址(控制权由BIOS转移到KERNEL)。这个地址由ld写入ELF的头中,会依次用下面的方法尝试设置入口地址,当遇见成功时则停止:
a.命令行选项 -e entry;
b.脚本(vmlinux.lds)中的ENTRY(xxx);
c.如果有定义start符号,则使用start符号(xxx);
d.如果存在.text节,则使用第一个字节的地址;
e.地址0。

由于上述ld 脚本(vmlinux.lds)中,用ENTRY宏设置了内核的EP是kernel_entry (KE)函数的地址,所以内核取得控制权(BIOS跳转之后)后执行的第一条指令就是 KE函数。

注意:这种情况只是vmlinux(非压缩版的内核),对于vmlinuz(压缩版的内核),EP会被设置成内核自解压缩的程序代码的地址,这样固件就会跳转到内核自解压代码(此时的EP为解压程序的代码地址),最后还是会到KE函数去执行。

由以上分析可知无论是压缩版还是非压缩版的Linux内核,内核第一个执行的函数是KE。接下来就是对KE函数的分析,看看它到底都做了些什么事?

kernel_entry(KE)分析:

内核版本:3.10.X
源代码文件:arch/mips/kernel/head.S
KE函数是体系相关的汇编语言实现的,源代码中汇编指令的含义(64位指令)为:

PTR_LA          dla
LONG_S          sd
PTR_ADDIU       daddiu
MTC0            dmtc0
PTR_LI          dli
PTR_ADDU        daddu
PTR_SUBU        dsubu

源代码:

NESTED(kernel_entry, 16, sp)            # KE函数定义,函数栈的大小为16字节

    kernel_entry_setup          # 对CPU的配置,详情见kernel_entry_setup函数分析NOTE1

    setup_c0_status_pri         #设置mips协处理器(cp0)中的寄存器,详情见NOTE2

    PTR_LA  t0, 0f
    jr  t0
0:

#ifdef CONFIG_MIPS_MT_SMTC     #硬件多线程
    mtc0    zero, CP0_TCCONTEXT
    mfc0    t0, CP0_STATUS
    ori t0, t0, 0xff1f
    xori    t0, t0, 0x001e
    mtc0    t0, CP0_STATUS
#endif /* CONFIG_MIPS_MT_SMTC */

    PTR_LA      t0, __bss_start     # 清除BSS段,详情见NOTE3
    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     # BIOS传参数,详情见NOTE4
    LONG_S      a1, fw_arg1
    LONG_S      a2, fw_arg2
    LONG_S      a3, fw_arg3

    MTC0        zero, CP0_CONTEXT   # NOTE5 
    PTR_LA      $28, init_thread_union    #为0号进程准备内核栈,详情见NOTE6
    PTR_LI      sp, _THREAD_SIZE - 32 - PT_SIZE
    PTR_ADDU    sp, $28
    back_to_back_c0_hazard #NOTE7
    set_saved_sp    sp, t0, t1 #NOTE6
    PTR_SUBU    sp, 4 * SZREG       #NOTE8

    j       start_kernel  #NOTE9
    END(kernel_entry)

    __CPUINIT

NOTE1(kernel_entry_setup函数分析):

Linux内核犹如一座巨大的迷宫,只有找到了正确的入口,才有可能找到出口。

之前的分析得出的结论是Linux内核第一个调用的函数是KE,而KE第一个调用函数则是kernel_entry_setup,这才是真正执行的第一个函数,那么我们就从它开始吧。

函数名称:kernel_entry_setup
源代码文件:arch/mips/include/asm/mach-loongson/kernel-entry-init.h
源代码:

#ifndef __ASM_MACH_LOONGSON_KERNEL_E
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值