uboot1.1.6中启动流程
U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:
(1)第一阶段的功能
Ø 硬件设备初始化
Ø 加载U-Boot第二阶段代码到RAM空间
Ø 设置好栈
Ø 跳转到第二阶段代码入口
(2)第二阶段的功能
Ø 初始化本阶段使用的硬件设备
Ø 检测系统内存映射
Ø 将内核从Flash读取到RAM中
Ø 为内核设置启动参数
Ø 调用内核

图 2.1 U-Boot启动第一阶段流程
Linux环境下的源码一般的编译起始文件是根目录下的Makefile文件,我们先充这个地方说起,看看能不能通过这个文件一直找到ARM的启动流程。
这里是整个Makefile的开始地方。既然系统是需要通过Makefile编译并链接成镜像文件的,那么
这个文件中一定在这一行的存在一个链接脚本。
这里有删除u-boot.lds的操作,什么这是链接镜像的脚本。再去单独查找整个文件,发现有很多
因为这里我们是要查看ok6410的处理器,所以,我们选中了
U-boot.lds (board\samsung\smdk6410)16192012/1/17
OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{.=0x00000000;.= ALIGN(4);.text :{cpu/s3c64xx/start.o (.text)cpu/s3c64xx/s3c6410/cpu_init.o (.text)cpu/s3c64xx/onenand_cp.o (.text)cpu/s3c64xx/nand_cp.o (.text)cpu/s3c64xx/movi.o (.text)*(.text)lib_arm/div0.o}.= ALIGN(4);.rodata :{*(.rodata)}.= ALIGN(4);.data :{*(.data)}.= ALIGN(4);.got :{*(.got)}__u_boot_cmd_start =.;.u_boot_cmd :{*(.u_boot_cmd)}__u_boot_cmd_end =.;.= ALIGN(4);.mmudata :{*(.mmudata)}.= ALIGN(4);__bss_start =.;.bss :{*(.bss)}_end =.;}
这里的代码很简单,就是主入口函数_start,并且执行下述几个文件
cpu/s3c64xx/start.o (.text)cpu/s3c64xx/s3c6410/cpu_init.o (.text)cpu/s3c64xx/onenand_cp.o (.text)cpu/s3c64xx/nand_cp.o (.text)cpu/s3c64xx/movi.o (.text)
经查找,入口函数_start在start.S (cpu\s3c64xx)中,
这个时候,我们就可以看到ok6410是怎么启动的了,也就是它的启动流程正式开始执行了。先执行reset函数:
reset:/** set the cpu to SVC32 mode*/mrs r0,cpsrbic r0,r0,#0x1f /* 1f=1 1111 = ~ = 0 0000 */orr r0,r0,#0xd3 /* d3=1101 0011 => 1 0011*/msr cpsr,r0
| 31 | 30 | 29 | 28 | 27 | ~ | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||
| N | Z | C | V | 保留 | I | F | T | M4 | M3 | M2 | M1 | M0 | |||||
| N | Negative/Less Than | I | IRQ disable | ||||||||||||||
| Z | Zero | F | FIQ disable | ||||||||||||||
| C | Carry/Borrow/Extend | T | State bit | ||||||||||||||
| V | Overflow | M0~4 | Mode bits | ||||||||||||||
1、条件码标志
N、Z、C、V均为条件码标志位。它们的内容可被算术或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。条件码标志各位的具体含义如下表所示:
| 标志位 | 含 义 |
| N | 当用两个补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果为正数或零 |
| Z | Z=1表示运算的结果为零,Z=0表示运算的结果非零。 |
| C | 可以有4种方法设置C的值: |
| -加法运算(包括CMP):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。 | |
| -减法运算(包括CMP):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。 | |
| -对于包含移位操作的非加/减运算指令,C为移出值的最后一位。 | |
| -对于其它的非加/减运算指令,C的值通常不会改变。 | |
| V | 可以有2种方法设置V的值: |
| -对于加减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出 | |
| -对于其它的非加/减运算指令,V的值通常不会改变。 | |
| Q | 在ARM V5及以上版本的E系列处理器中,用Q标志位指示增强的DSP运算指令是否发生了溢出。在其它版本的处理器中,Q标志位无定义 |
在ARM状态下,绝大多数的指令都是有条件执行的;在THUMB状态下,仅有分支指令是条件执行的。
2 控制位
CPSR的低8位(包括I、F、T和M[4:0])称为控制位,当发生异常时这些位可以被改变。如果处理器运行于特权模式时,这些位也可以由程序修改。
·中断禁止位I、F:置1时,禁止IRQ中断和FIQ中断。
·T标志位:该位反映处理器的运行状态。当该位为1时,程序运行于THUMB状态,否则运行于ARM状态。该信号反映在外部引脚TBIT上。在程序中不得修改CPSR中的TBIT位,否则处理器工作状态不能确定。
·运行模式位M[4:0]:这几位是模式位,这些位决定了处理器的运行模式。具体含义如下表所示:
·保留位:CPSR中的其余位为保留位,当改变CPSR中的条件码标志位或者控制位时,保留位不要改变,在程序中也不要用保留位存储数据。保留位将用于ARM版本的扩展。
| M[4:0] | 处理器模式 | ARM模式可访问的寄存器 | THUMB模式可访问的寄存器 |
| 0b10000 | 用户模式 usr | PC,CPSR,R0~R14 | PC,CPSR,R0~R7,LR,SP |
| 0b10001 | FIQ模式 fiq | PC,CPSR,SPSR_fiq,R14_fiq~R8_fiq,R0~R7 | PC,CPSR,SPSR_fiq,LR_fiq,SP_fiq,R0~R7 |
| 0b10010 | IRQ模式 irq | PC,CPSR,SPSR_irq,R14_irq~R13_irq,R0~R12 | PC,CPSR,SPSR_irq,LR_irq,SP_irq,R0~R7 |
| 0b10011 | 管理模式 svc | PC,CPSR,SPSR_svc,R14_svc~R13_svc,R0~R12 | PC,CPSR,SPSR_svc,LR_svc,SP_svc,R0~R7 |
| 0b10111 | 中止模式 abt | PC,CPSR,SPSR_abt,R14_abt~R13_abt,R0~R12 | PC,CPSR,SPSR_abt,LR_abt,SP_abt,R0~R7 |
| 0b11011 | 未定义模式 und | PC,CPSR,SPSR_und,R14_und~R13_und,R0~R12 | PC,CPSR,SPSR_und,LR_und,SP_und,R0~R7 |
| 0b11111 | 系统模式 sys | PC,CPSR,R0~R14 | PC,CPSR,LR,SP,R0~R74 |
执行完reset后,顺序接着执行cpu_init_crit
/**************************************************************************** CPU_init_critical registers** setup important registers* setup memory timing***************************************************************************//** we do sys-critical inits only at reboot,* not when booting from ram!*/cpu_init_crit:/** flush v4 I/D caches*/mov r0,#0mcr p15,0, r0, c7, c7,0/* flush v3/v4 cache */mcr p15,0, r0, c8, c7,0/* flush v4 TLB *//** disable MMU stuff and caches*/mrc p15,0, r0, c1, c0,0bic r0, r0,#0x00002300 @ clear bits 13, 9:8 (--V- --RS)bic r0, r0,#0x00000087 @ clear bits 7, 2:0 (B--- -CAM)orr r0, r0,#0x00000002 @ set bit 2 (A) Alignorr r0, r0,#0x00001000 @ set bit 12 (I) I-Cachemcr p15,0, r0, c1, c0,0/* Peri port setup */ldr r0,=0x70000000orr r0, r0,#0x13mcr p15,0,r0,c15,c2,4@256M(0x70000000-0x7fffffff)
接着顺序执行lowlevel_init函数
lowlevel_init.S (board\samsung\smdk6410)86152012/3/31
#include<config.h>#include<version.h>#include<s3c6410.h>#include"smdk6410_val.h"_TEXT_BASE:.word TEXT_BASE.globl lowlevel_initlowlevel_init:- ...
- /* LED on only #8 */
- ...
- /* Disable Watchdog */
- ...
/* init system clock */- bl system_clock_init
- ...
点led灯
执行关闭看门狗
初始化系统时钟
lowlevel_init.S (board\samsung\smdk6410) 8615 2012/3/31
/** system_clock_init: Initialize core clock and bus clock.* void system_clock_init(void)*/system_clock_init:ldr r0,=ELFIN_CLOCK_POWER_BASE @0x7e00f000ldr r1,[r0,#OTHERS_OFFSET]mov r2,#0x40orr r1, r1, r2str r1,[r0,#OTHERS_OFFSET]nopnopnopnopnopldr r2,=0x80orr r1, r1, r2str r1,[r0,#OTHERS_OFFSET]check_syncack:ldr r1,[r0,#OTHERS_OFFSET]ldr r2,=0xf00and r1, r1, r2cmp r1,#0xf00bne check_syncackmov r1,#0xff00orr r1, r1,#0xffstr r1,[r0,#APLL_LOCK_OFFSET]str r1,[r0,#MPLL_LOCK_OFFSET]str r1,[r0,#EPLL_LOCK_OFFSET]/* CLKUART(=66.5Mhz) = CLKUART_input(532/2=266Mhz) / (UART_RATIO(3)+1) *//* CLKUART(=50Mhz) = CLKUART_input(400/2=200Mhz) / (UART_RATIO(3)+1) *//* Now, When you use UART CLK SRC by EXT_UCLK1, We support 532MHz & 400MHz value */#if defined(CONFIG_CLKSRC_CLKUART)ldr r1,[r0,#CLK_DIV2_OFFSET]bic r1, r1,#0x70000orr r1, r1,#0x30000str r1,[r0,#CLK_DIV2_OFFSET]#endif- ldr r1,[r0,#CLK_DIV0_OFFSET] /*Set Clock Divider*/
bic r1, r1,#0x30000bic r1, r1,#0xff00bic r1, r1,#0xffldr r2,=CLK_DIV_VALorr r1, r1, r2str r1,[r0,#CLK_DIV0_OFFSET]ldr r1,=APLL_VALstr r1,[r0,#APLL_CON_OFFSET]ldr r1,=MPLL_VALstr r1,[r0,#MPLL_CON_OFFSET]ldr r1,=0x80200203/* FOUT of EPLL is 96MHz */str r1,[r0,#EPLL_CON0_OFFSET]ldr r1,=0x0str r1,[r0,#EPLL_CON1_OFFSET]ldr r1,[r0,#CLK_SRC_OFFSET] /* APLL, MPLL, EPLL select to Fout */ldr r2,=0x2007orr r1, r1, r2str r1,[r0,#CLK_SRC_OFFSET]/* wait at least 200us to stablize all clock */mov r1,#0x100001: subs r1, r1,#1bne 1bldr r1,[r0,#OTHERS_OFFSET]orr r1, r1,#0x20str r1,[r0,#OTHERS_OFFSET]mov pc, lr /* 子函数执行完毕返回 */
执行完后顺序执行
/* for UART */bl uart_asm_init
具体函数如下:
/** uart_asm_init: Initialize UART in asm mode, 115200bps fixed.* void uart_asm_init(void)*/uart_asm_init:/* set GPIO to enable UART */@ GPIO setting for UARTldr r0,=ELFIN_GPIO_BASEldr r1,=0x220022str r1,[r0,#GPACON_OFFSET]ldr r1,=0x2222str r1,[r0,#GPBCON_OFFSET]ldr r0,=ELFIN_UART_CONSOLE_BASE @0x7F005000mov r1,#0x0str r1,[r0,#UFCON_OFFSET]str r1,[r0,#UMCON_OFFSET]mov r1,#0x3 @was 0.str r1,[r0,#ULCON_OFFSET]#if defined(CONFIG_CLKSRC_CLKUART)ldr r1,=0xe45/* UARTCLK SRC = 11 => EXT_UCLK1*/#elseldr r1,=0x245/* UARTCLK SRC = x0 => PCLK */#endifstr r1,[r0,#UCON_OFFSET]#if defined(CONFIG_UART_50)ldr r1,=0x1A#elif defined(CONFIG_UART_66)ldr r1,=0x22#elseldr r1,=0x1A#endifstr r1,[r0,#UBRDIV_OFFSET]#if defined(CONFIG_UART_50)ldr r1,=0x3#elif defined(CONFIG_UART_66)ldr r1,=0x1FFF#elseldr r1,=0x3#endifstr r1,[r0,#UDIVSLOT_OFFSET]ldr r1,=0x4f4f4f4fstr r1,[r0,#UTXH_OFFSET] @'O'mov pc, lr
在接着顺序执行
ldr r0,=ELFIN_UART_BASEldr r1,=0x4b4b4b4bstr r1,[r0,#UTXH_OFFSET]#if defined(CONFIG_NAND)/* simple init for NAND */bl nand_asm_init#endifbl mem_ctrl_asm_init#if 1ldr r0,=(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)ldr r1,[r0]bic r1, r1,#0xfffffff7cmp r1,#0x8beq wakeup_reset#endif
初始化NAND
/** Nand Interface Init for SMDK6400 */nand_asm_init:ldr r0,=ELFIN_NAND_BASEldr r1,[r0,#NFCONF_OFFSET]orr r1, r1,#0x70orr r1, r1,#0x7700str r1,[r0,#NFCONF_OFFSET]ldr r1,[r0,#NFCONT_OFFSET]orr r1, r1,#0x03str r1,[r0,#NFCONT_OFFSET]mov pc, lr
内存控制器初始化
cpu_init.S (cpu\s3c64xx\s3c6410)32702012/1/17
#include<config.h>#include<s3c6410.h>.globl mem_ctrl_asm_initmem_ctrl_asm_init:ldr r0,=ELFIN_MEM_SYS_CFG @Memory sussystem address 0x7e00f120mov r1,#0xd @ Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1str r1,[r0]...mov pc, lr
最后执行
wakeup_reset:/*Clear wakeup status register*/ldr r0,=(ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET)ldr r1,[r0]str r1,[r0]/*LED test*/ldr r0,=ELFIN_GPIO_BASEldr r1,=0x3000str r1,[r0,#GPNDAT_OFFSET]/*Load return address and jump to kernel*/ldr r0,=(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET)ldr r1,[r0]/* r1 = physical address of s3c6400_cpu_resume function*/mov pc, r1 /*Jump to kernel (sleep-s3c6400.S)*/
最后回到start.S (cpu\s3c64xx)162102016/9/4
/* when we already run in ram, we don't need to relocate U-Boot.* and actually, memory controller must be configured before U-Boot* is running in ram.*/ldr r0,=0xff000fff- bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */bic r2, r2, r0 /* r0 <- current base addr of code */cmp r1, r2 /* compare r0, r1 */beq after_copy /* r0 == r1 then skip flash copy */
接着执行
after_copy:#ifdef CONFIG_ENABLE_MMUenable_mmu:/* enable domain access */ldr r5,=0x0000ffffmcr p15,0, r5, c3, c0,0@ load domain access register/* Set the TTB register */ldr r0,ldr r1,=CFG_PHY_UBOOT_BASEldr r2,=0xfff00000bic r0, r0, r2orr r1, r0, r1mcr p15,0, r1, c2, c0,0/* Enable the MMU */mmu_on:mrc p15,0, r0, c1, c0,0orr r0, r0,#1 /* Set CR_M to enable MMU */mcr p15,0, r0, c1, c0,0nopnopnopnop#endifskip_hw_init:/* Set up the stack */stack_setup:#ifdef CONFIG_MEMORY_UPPER_CODEldr sp,=(CFG_UBOOT_BASE + CFG_UBOOT_SIZE -0xc)#elseldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */sub r0, r0,#CFG_MALLOC_LEN /* malloc area */sub r0, r0,#CFG_GBL_DATA_SIZE /* bdinfo */#ifdef CONFIG_USE_IRQsub r0, r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)#endifsub sp, r0,#12 /* leave 3 words for abort-stack */#endifclear_bss:ldr r0, _bss_start /* find start of bss segment */ldr r1, _bss_end /* stop here */mov r2,#0x00000000 /* clear */clbss_l:str r2,[r0]/* clear loop... */add r0, r0,#4cmp r0, r1ble clbss_lldr pc, _start_armboot- _start_armboot:
.word start_armboot
到执行start_armboot函数这一步,就开始跳出硬件依赖了,跳转到第二阶段代码入口
Board.c (lib_arm)142052012/7/11

图 2.3 U-Boot第二阶段执行流程
通过bootm引导linux内核启动
使用do_bootm_linux引导kernel
直至
至此,Linux系统开始运行。

浙公网安备 33010602011771号