little kernel分析

little kernel做为Android系统的bootloader,最早用google工程师实现,其后由高通,MTK等芯片厂商做了各自平台的适配。
lk的主要功能:

  • 初始化硬件模块,如时钟,中断,UART,USB,LCD,PMIC,eMMC/UFS等。
  • 更新cmdline。其中重要的是区分启动模式。
  • 选择和更新device tree。
  • 设置好系统状态,跳转到kernel。 MMU = off, D-cache = off, I-cache = on or off,x0 = physical address to the FDT blob。
  • fastboot功能。
  • 鉴权。

追踪代码可以看到c语言的入口函数为kmain,定义在lk/kernel/main.c中,然后用apps_init()函数调用lk中的另一个关键的c语言函数aboot_init()。由aboot_init()调用boot_linux_from_mmc()
再由boot_linux_from_mmc()调用boot_linux()
最后由boot_linux()调用entry()函数(32位kernel)或者scm_elexec_call()(64位kernel),完成lk到kernel的跳转。
lk初始化调用流程如下图:
这里写图片描述

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

#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
    /*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
        /* 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)
    bic     r0, r0, #(1<<2 | 1<<0)
        /* enable alignment faults */
    orr     r0, r0, #(1<<1)
        /* Write SCTLR */
    mcr     p15, 0, r0, c1, c0, 0
#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
    /* 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
    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
    sub     r0, r0, #(.Laddr - _start)      //计算出_start的内存地址,保存在r0
.Laddr:
    ldr     r1, =_start        //加载_start的代码地址到r1
    cmp     r0, r1
    beq     .Lstack_setup

    /* we need to relocate ourselves to the proper spot */
    ldr     r2, =__data_end 

.Lrelocate_loop:     //进行循环拷贝,将代码段拷贝到代码地址处
    ldr     r3, [r0], #4
    str     r3, [r1], #4
    cmp     r1, r2                    //判断拷贝是否完成
    bne     .Lrelocate_loop          //跳转到代码段的.Lstack_setup,继续执行

    /* we're relocated, jump to the right address */
    ldr     r0, =.Lstack_setup
    bx      r0

.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
    bic     r0, r0, #0x1f

    ldr     r2, =abort_stack_top
    orr     r1, r0, #0x12 // irq
    msr     cpsr_c, r1
    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
    msr     cpsr_c, r1
    mov     sp, r2

    orr     r1, r0, #0x1b // undefined
    msr     cpsr_c, r1
    mov     sp, r2

    orr     r1, r0, #0x1f // system
    msr     cpsr_c, r1
    mov     sp, r2

    orr     r1, r0, #0x13 // supervisor
    msr     cpsr_c, r1
    mov     sp, r2

    /* copy the initialized data segment out of rom if necessary */
    ldr     r0, =__data_start_rom
    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中)处继续执行
    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:  

以上汇编初始化代码最终跳转到kmain函数中,进入C代码,kmain函数定义在lk/kernel/main.c中:


/* called from crt0.S */
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void)
{
    // get us into some sort of thread context
    thread_init_early();          //初始化lk的线程系统

    // early arch stuff
    arch_early_init();            //架构相关早期初始化,如使能mmu,cache等

    // do any super early platform initialization
    platform_early_init();       //平台相关早期初始化,如获取板级信息,初始化时钟、中断、定时器等


    // do any super early target initialization
    target_early_init();        //初始化目标,其中只初始化了串口

    dprintf(INFO, "welcome to lk\n\n");
    bs_set_timestamp(BS_BL_START);      //设置bootloader初始的时间戳

    // deal with any static constructors
    dprintf(SPEW, "calling constructors\n");
    call_constructors();                 //构造函数相关初始化

    // bring up the kernel heap
    dprintf(SPEW, "initializing heap\n");
    heap_init();                    //堆初始化,用于malloc等函数的内存分配

    // initialize the threading system
    dprintf(SPEW, "initializing threads\n");
    thread_init();              //仅简单的初始化了定时器对象

    // initialize the dpc system
    dprintf(SPEW, "initializing dpc\n");
    dpc_init();             //delayed procedure call 延迟过程调用

    // initialize kernel timers
    dprintf(SPEW, "initializing timers\n");
    timer_init();            //初始化定时器

#if (!ENABLE_NANDWRITE)
    // create a thread to complete system initialization
    dprintf(SPEW, "creating bootstrap completion thread\n");
    thread_resume(thread_create("bootstrap2",
  • 7
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
littlefs 是一个用于嵌入式系统的轻量级文件系统,功能简单但高效。下面我将对其源码进行分析。 首先,littlefs 的源码结构清晰,主要包含了文件系统的核心逻辑、存储管理、文件操作等模块。在核心逻辑部分,源码实现了文件系统的初始化、格式化、挂载等功能,同时提供了基本的文件操作接口,如创建、打开、读取、写入和删除文件等。它还包含了一些实用的功能,比如目录操作、文件描述符的管理、簇(cluster)和扇区(sector)的管理等。 在存储管理方面,源码使用了位图(bitmap)来管理簇的分配情况,位图的每一位对应着簇的状态。这样,当需要分配或释放簇时,只需修改相应的位图即可。此外,源码还实现了一个缓存区(buffer)来加速读写操作,可以提高文件的访问速度。 在文件操作方面,源码使用了块(block)作为文件的基本单位,块的大小通过宏定义进行设置。它使用了文件控制块(file control block)来管理文件的元数据,包括文件名、长度、属性等。通过文件控制块,可以方便地对文件进行操作。 对于源码的性能方面,littlefs 采用了写前日志(write-ahead log)的方式来提高写入操作的性能和可靠性。在写入文件时,会先写入日志,然后再写入实际的数据块。这样即使发生意外断电等情况,也能保证数据的完整性。 总的来说,littlefs 的源码分析表明它是一个功能简单但高效的嵌入式文件系统。其清晰的结构和良好的性能使其成为嵌入式系统中的一个理想选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值