1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中的软件主要分为以下及部分:
(1)引导加载程序:其中包括内部ROM中的固化启动代码(汇编代码)和Boot Loader(C代码)两部分。而这个内部固化ROM是厂家在芯片生产时候固化的,作用基本上是引导Boot Loader。有的芯片比较复杂,比如Omap3,他在flash中没有代码的时候有许多启动方式:USB、UART或以太网等等。而S3C24x0则很简单,只有Norboot和Nandboot。比如三星的S3C24X0系列,它的bootROM直接跳到U-boot中执行,首先由bootROM将U-boot的前4KB拷贝到处理器ISRAM,接着在U-boot的前4KB中必须保证要完成的两项主要工作:初始化DDR,nand和nand控制器,接着将U-boot剩余的code拷贝到SDRAM中,然后跳到SDRAM的对应地址上去继续跑U-boot。总的来说,引导程序是初始化软硬件,为操作系统运行做准备。
(2)Linux kernel 和drivers。
(3)文件系统。包括根文件系统和建立于Flash内存设备之上的文件系统(EXT4、UBI、CRAMFS等等)。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好运行环境的载体。
(4)应用程序。用户自定义的应用程序,存放于文件系统之中。
在Flash 存储器中,他们的 一般分布如下:
但是以上只是大部分情况下的分布,也有一些可能根文件系统是initramfs,被一起压缩到了内核映像里,或者没有Bootloader参数区,等等。
由上可知,Loader大概可分为两部分:第一部分,汇编代码。第二部分,C代码。
以3288 U-Boot代码为例:
第一部分:
第一条指令从arch/arm/cpu/armv7/start.S开始(注意红色字体关键语句及注释):
.globl reset //硬件服务操作
reset:
/*
* check loader tag
*/
#ifdef CONFIG_ROCKCHIP
ldr r0, =__loader_tag //讲地址
ldr r1, [r0]
ldr r0, =LoaderTagCheck
ldr r0, [r0]
cmp r1, r0 //比较两个地址的内容是否一致。
movne pc, r14 //将r14(LR:链接寄存器,保存被调用子函数的返回地址)内容复制到pc寄存器(r15:程序计数器,保存将要 执行的指令地址)
#endif
bl save_boot_params //直接返回,没有做任何事情
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already,关中断,设置CPU到SVC(超级保护)模式
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTRL Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTRL Register
/* Set vector address in CP15 VBAR register */
#ifdef CONFIG_ROCKCHIP//设置寄存器
ldr r0, =_vector
#else
ldr r0, =_start
#endif
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
bl cpu_init_crit
#endif
bl _main
cpu_init_cp15主要是CP15协处理器初始化操作,disable cache和MMU
cpu_init_crit初始化ARM关键寄存器,刷新cache和TLB,关闭MMU,初始化时钟。Boot初始化的时候,程序看到的是物理地址,无需MMU
ENTRY(cpu_init_crit)
/*
* Jump to board specific initialization...
* The Mask ROM will have already initialized
* basic memory. Go here to bump up clock rate and handle
* wake up conditions.
*/
b lowlevel_init @ go setup pll,mux,memory//直接跳到板级文件实现
lowlevel_init的实现在arch/arm/cpu/armv7/rk32xx/lowlevel_init.S中
ENTRY(lowlevel_init)
/*
* Setup a temporary stack
*/
ldr sp, =CONFIG_SYS_INIT_SP_ADDR
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
#ifdef CONFIG_SPL_BUILD
ldr r8, =gdata
#else
sub sp, #GD_SIZE
bic sp, sp, #7
mov r8, sp
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
/*
* TTBCR default setting 0.
*/
mov r0, #0
mcr p15, 0, r0, c2, c0, 2 @ TTBCR (Translation Table Base Control Register)
#endif
/*
* Save the old lr(passed in ip) and the current lr to stack
*/
push {ip, lr}
bl rkclk_set_pll //初始化时钟
pop {ip, pc}
ENDPROC(lowlevel_init)
然后跳到_main()函数arch/arm/lib/crt0.S:_main()函数主要初始化C运行环境,然后跳到board_init_f,进行板级前端初始化操作