LK源码解析 1 crt0.s(转载)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/xichangbao/article/details/51484138

记录以下,方便自己学习

转载自

https://blog.csdn.net/xichangbao/article/details/51484138?locationNum=2&fps=1

k/arch/crt0.s中的_start函数为入口函数,crt0.s主要初始化CPU,然后长跳转(bl)到lk/kernel/main.c中kmain函数。

 

  1. lk的代码起始位置在crt0.S中。

#define DSB .byte 0x4f, 0xf0, 0x7f, 0xf5

#define ISB .byte 0x6f, 0xf0, 0x7f, 0xf5

 

.section ".text.boot"

.globl _start // 声明全局符号_start

_start: // _start中值即为当前地址

     // 设置异常向量表,从0地址开始,存放在8*4字节的连续内存中。需要将协处理CP15中的c1控制寄存器的中的V位配为0

    b    reset // 跳转到reset

    b    arm_undefined

    b    arm_syscall

    b    arm_prefetch_abort

    b    arm_data_abort

    b    arm_reserved

    b    arm_irq

    b    arm_fiq

 

reset:

 

#ifdef ENABLE_TRUSTZONE // makefile中ENABLE_TRUSTZONE := 0,因此不用关心

    /*Add reference to TZ symbol so linker includes it in final image */

    ldr r7, =_binary_tzbsp_tzbsp_bin_start

#endif

    /* do some cpu setup */

#if ARM_WITH_CP15

        /* Read SCTLR */

    mrc        p15, 0, r0, c1, c0, 0 // MCR/MRC{cond} P15,opcode_1,Rd,CRn,CRm,opcode_2 读取cp15协处理器的寄存器1(Control register)的值到通用寄存器r0中

        /* XXX this is currently for arm926, revist with armv6 cores */

        /* new thumb behavior, low exception vectors, i/d cache disable, mmu disabled */

    bic        r0, r0, #(1<<15| 1<<13 | 1<<12) // 位清除指令,Low addresses = 0x00000000, ICache disabled

    bic        r0, r0, #(1<<2 | 1<<0) // DCache disabled, MMU disabled

        /* disable alignment faults */

    bic        r0, r0, #(1<<1) // Data address alignment fault checking disabled

    /* Enable CP15 barriers by default */

#ifdef ARM_CORE_V8

    orr        r0, r0, #(1<<5)

#endif

        /* Write SCTLR */

    mcr        p15, 0, r0, c1, c0, 0 // 将设置好的r0的值写入到p15的寄存器1中,完成关闭MMU,禁用ICahce和DCache等。

#ifdef ENABLE_TRUSTZONE

  /*nkazi: not needed ? Setting VBAR to location of new vector table : 0x80000      */

 ldr             r0, =0x00080000

 mcr             p15, 0, r0, c12, c0, 0

#endif

#endif

 

#if WITH_CPU_EARLY_INIT // 目前使用的soc都没有打开此宏,因此不去关注

    /* call platform/arch/etc specific init code */

#ifndef ENABLE_TRUSTZONE

    /* Not needed when TrustZone is the first bootloader that runs.*/

    bl __cpu_early_init

#endif

    /* declare return address as global to avoid using stack */

.globl _cpu_early_init_complete

    _cpu_early_init_complete:

 

#endif

 

#if (!ENABLE_NANDWRITE)

#if WITH_CPU_WARM_BOOT  // 目前使用的soc都没有打开此宏,因此不去关注

    ldr     r0, warm_boot_tag

    cmp     r0, #1

 

    /* if set, warm boot */

    ldreq     pc, =BASE_ADDR

 

    mov     r0, #1

    str    r0, warm_boot_tag

#endif

#endif

 

    /* see if we need to relocate */ // 判断是否需要代码重定位

    mov        r0, pc // 由于PC(当前的PC值)=PC(正在执行的代码地址)+8,又由于ARM32一条指令4字节,所以r0的值为.Laddr的内存地址

    sub        r0, r0, #(.Laddr - _start) // 计算出_start的内存地址,保存在r0

.Laddr:

    ldr        r1, =_start // 加载_start的代码地址到r1

    cmp        r0, r1  

    beq        .Lstack_setup // 比较_start的代码地址是否等于内存地址。相等的话说明不需要进行代码重定位,可以进一步设置stack,否则需要继续进行代码重定位。

 

    /* we need to relocate ourselves to the proper spot */

    ldr        r2, =__data_end // __data_end的定义在system-onesegment.ld中

 

.Lrelocate_loop: // 进行循环拷贝,将代码段拷贝到代码地址处

    ldr        r3, [r0], #4

    str        r3, [r1], #4

    cmp        r1, r2 // 判断拷贝是否完成

    bne        .Lrelocate_loop

 

    /* we're relocated, jump to the right address */

    ldr        r0, =.Lstack_setup

    bx        r0  // 跳转到代码段的.Lstack_setup,继续执行

 

.ltorg

#if WITH_CPU_WARM_BOOT

warm_boot_tag:

    .word 0 // 分配一个32bit的内存,并初始化为0

#endif

 

.Lstack_setup:

    /* set up the stack for irq, fiq, abort, undefined, system/user, and lastly supervisor mode */

    mrs     r0, cpsr // Move to Status Register

    bic     r0, r0, #0x1f // 清除处理器模式位M[4:0]

 

    ldr        r2, =abort_stack_top // 将abort_stack_top的地址赋给r2

    orr     r1, r0, #0x12 // irq 0b10010

    msr     cpsr_c, r1 // 设置irq模式

    ldr        r13, =irq_save_spot        /* save a pointer to a temporary dumping spot used during irq delivery */ // 将全局符号irq_save_spot的地址赋给r13

 

    orr     r1, r0, #0x11 // fiq 0b10001

    msr     cpsr_c, r1 // 设置fiq模式

    mov        sp, r2 设置fiq模式的堆栈

 

    orr     r1, r0, #0x17 // abort 0b10111

    msr     cpsr_c, r1  // 设置abort模式

    mov        sp, r2 // 设置abort模式的堆栈

 

    orr     r1, r0, #0x1b // undefined 0b11011

    msr     cpsr_c, r1 // 设置undefined模式

    mov        sp, r2 // 设置undefined模式的堆栈

 

    orr     r1, r0, #0x1f // system 0b11111

    msr     cpsr_c, r1 // 设置system模式

    mov        sp, r2 // 设置system模式的堆栈

 

    orr        r1, r0, #0x13 // supervisor 0b10011

    msr        cpsr_c, r1 // 设置supervisor模式

    mov        sp, r2 // 设置supervisor模式的堆栈

 

    /* copy the initialized data segment out of rom if necessary */

    ldr        r0, =__data_start_rom //__data_start_rom,__data_start,__data_end的定义都在system-onesegment.ld中

    ldr        r1, =__data_start

    ldr        r2, =__data_end

 

    cmp        r0, r1

    beq        .L__do_bss // 比较__data_start_rom和__data_start的内存地址是否相等,如果相等则跳转到.L__do_bss处,否则继续执行

 

.L__copy_loop:

    cmp        r1, r2

    ldrlt    r3, [r0], #4

    strlt    r3, [r1], #4

    blt        .L__copy_loop // 完成数据段的拷贝

 

.L__do_bss:

    /* clear out the bss */

    ldr        r0, =__bss_start

    ldr        r1, =_end

    mov        r2, #0

.L__bss_loop:

    cmp        r0, r1

    strlt    r2, [r0], #4

    blt        .L__bss_loop // 完成bss段的清零

 

#ifdef ARM_CPU_CORTEX_A8

    DSB

    ISB

#endif

 

    bl        kmain // 跳转到kmain(lk代码kernel/main.c中)处继续执行,虽然使用了bl,但是正常情况是不会返回的

    b        .

 

.ltorg

 

.bss

.align 2

    /* the abort stack is for unrecoverable errors.

     * also note the initial working stack is set to here.

     * when the threading system starts up it'll switch to a new

     * dynamically allocated stack, so we don't need it for very long

     */

abort_stack:

    .skip 1024 // 异常堆栈的大小1024字节

abort_stack_top:

 

 

  1. MRC/MCR指令。

mrc p15, 0, r0, c1, c0{, 0}     ;将 CP15 的寄存器 C1 的值读到 r0 中

mcr p15, 0, r0, c1, c0{, 0}     ;将 r0 的值写到 CP15 的寄存器 C1 中

 

CP15 中的寄存器 C1 的编码格式及含义说明如下:

C1中的控制位含义

 

M(bit[0])

0 :禁止 MMU 或者 PU

1 :使能 MMU 或者 PU

 

A(bit[1])

0 :禁止地址对齐检查

1 :使能地址对齐检查

 

C(bit[2])

当数据cache和指令cache分开时,本控制位禁止/使能数据cache。当数据cache和指令cache统一时,该控制位禁止/使能整个cache。

0 :禁止数据 / 整个 cache

1 :使能数据 / 整个 cache

 

W(bit[3])

0 :禁止写缓冲

1 :使能写缓冲

 

P(bit[4])

0 :异常中断处理程序进入 32 位地址模式

1 :异常中断处理程序进入26 位地址模式

 

D(bit[5])

0 :禁止 26 位地址异常检查

1 :使能 26 位地址异常检查

 

L(bit[6])

0 :选择早期中止模型

1 :选择后期中止模型

 

B(bit[7])

0 : little endian 

1 : big endian

 

S(bit[8])

在基于 MMU 的存储系统中,本位用作系统保护

 

R(bit[9])

在基于 MMU 的存储系统中,本位用作 ROM 保护

 

F(bit[10])

由生产商定义

 

Z(bit[11])

0 :禁止跳转预测功能

1 :使能跳转预测功能

 

I(bit[12])

当数据cache和指令cache是分开的,本控制位禁止/使能指令cache

0 :禁止指令 cache 

1 :使能指令 cache

 

V(bit[13])

0 :选择低端异常中断向量 0x0~0x1c

1 :选择高端异常中断向量0xffff0000~ 0xffff001c

 

PR(bit[14])

0 :常规的 cache 淘汰算法,如随机淘汰

1 :预测性淘汰算法,如round-robin 淘汰算法

 

L4(bit[15])

0 :保持 ARMv5 以上版本的正常功能

1 :将 ARMv5 以上版本与以前版本处理器兼容,不根据跳转地址的 bit[0] 进行 ARM 指令和 Thumb 状态切换: bit[0] 等于 0 表示 ARM 指令,等于 1 表示 Thumb 指令

 

Bits[31:16])

保留将来使用

 

  1. MRS/MSR。

MRS: 程序状态寄存器到通用寄存器的数据传送指令

MSR: 通用寄存器到程序状态寄存器的数据传送指令

 

CPSR 当前程序状态寄存器

位[31:24]为条件标志位域,用f 表示;
位[23:16]为状态位域,用s 表示;
位[15:8]为扩展位域,用x 表示;

位[7:0]为控制位域,用c 表示;

 

运行模式位[4-0]

 0b10000 用户模式user

 0b10001 FIQ模式

 0b10010 IRQ模式

 0b10011 管理模式

 0b10111 终止模式Abort

 0b11011 未定义模式

 0b11111 系统模式

IFT[7-5],I=1禁止IRQ,F=1禁止FIQ,T=1执行thumb指令

[27-8]保留

 

NZCV[31-28]

N-(负)标志,N=1表示运算结果为负数,N=0表示运算结果为正数或零

Z-(零)标志,Z=1表示运算结果为零,Z=0表示运算结果为非零

C-(进位)标志

V-(溢出)标志

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值