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
  1. OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
  2. /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
  3. OUTPUT_ARCH(arm)
  4. ENTRY(_start)
  5. SECTIONS
  6. {
  7. .=0x00000000;
  8. .= ALIGN(4);
  9. .text :
  10. {
  11. cpu/s3c64xx/start.o (.text)
  12. cpu/s3c64xx/s3c6410/cpu_init.o (.text)
  13. cpu/s3c64xx/onenand_cp.o (.text)
  14. cpu/s3c64xx/nand_cp.o (.text)
  15. cpu/s3c64xx/movi.o (.text)
  16. *(.text)
  17. lib_arm/div0.o
  18. }
  19. .= ALIGN(4);
  20. .rodata :{*(.rodata)}
  21. .= ALIGN(4);
  22. .data :{*(.data)}
  23. .= ALIGN(4);
  24. .got :{*(.got)}
  25. __u_boot_cmd_start =.;
  26. .u_boot_cmd :{*(.u_boot_cmd)}
  27. __u_boot_cmd_end =.;
  28. .= ALIGN(4);
  29. .mmudata :{*(.mmudata)}
  30. .= ALIGN(4);
  31. __bss_start =.;
  32. .bss :{*(.bss)}
  33. _end =.;
  34. }
这里的代码很简单,就是主入口函数_start,并且执行下述几个文件
  1. cpu/s3c64xx/start.o (.text)
  2. cpu/s3c64xx/s3c6410/cpu_init.o (.text)
  3. cpu/s3c64xx/onenand_cp.o (.text)
  4. cpu/s3c64xx/nand_cp.o (.text)
  5. cpu/s3c64xx/movi.o (.text)
经查找,入口函数_start在start.S (cpu\s3c64xx)中,
 这个时候,我们就可以看到ok6410是怎么启动的了,也就是它的启动流程正式开始执行了。先执行reset函数:
  1. reset:
  2. /*
  3. * set the cpu to SVC32 mode
  4. */
  5. mrs r0,cpsr
  6. bic r0,r0,#0x1f /* 1f=1 1111 = ~ = 0 0000 */
  7. orr r0,r0,#0xd3 /* d3=1101 0011 => 1 0011*/
  8. 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
  1. /*
  2. *************************************************************************
  3. *
  4. * CPU_init_critical registers
  5. *
  6. * setup important registers
  7. * setup memory timing
  8. *
  9. *************************************************************************
  10. */
  11. /*
  12. * we do sys-critical inits only at reboot,
  13. * not when booting from ram!
  14. */
  15. cpu_init_crit:
  16. /*
  17. * flush v4 I/D caches
  18. */
  19. mov r0,#0
  20. mcr p15,0, r0, c7, c7,0/* flush v3/v4 cache */
  21. mcr p15,0, r0, c8, c7,0/* flush v4 TLB */
  22. /*
  23. * disable MMU stuff and caches
  24. */
  25. mrc p15,0, r0, c1, c0,0
  26. bic r0, r0,#0x00002300 @ clear bits 13, 9:8 (--V- --RS)
  27. bic r0, r0,#0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
  28. orr r0, r0,#0x00000002 @ set bit 2 (A) Align
  29. orr r0, r0,#0x00001000 @ set bit 12 (I) I-Cache
  30. mcr p15,0, r0, c1, c0,0
  31. /* Peri port setup */
  32. ldr r0,=0x70000000
  33. orr r0, r0,#0x13
  34. mcr p15,0,r0,c15,c2,4@256M(0x70000000-0x7fffffff)
接着顺序执行lowlevel_init函数
 lowlevel_init.S (board\samsung\smdk6410)86152012/3/31
  1. #include<config.h>
  2. #include<version.h>
  3. #include<s3c6410.h>
  4. #include"smdk6410_val.h"
  5. _TEXT_BASE:
  6. .word TEXT_BASE
  7. .globl lowlevel_init
  8. lowlevel_init:
  9.  
  10. ...
  11.  
  12. /* LED on only #8 */
  13.  
  14. ...
  15. /* Disable Watchdog */
  16.  
  17. ...
  18. /* init system clock */
  19. bl system_clock_init
  20.  
  21. ...
 
点led灯
执行关闭看门狗
初始化系统时钟
lowlevel_init.S (board\samsung\smdk6410)    8615    2012/3/31
  1. /*
  2. * system_clock_init: Initialize core clock and bus clock.
  3. * void system_clock_init(void)
  4. */
  5. system_clock_init:
  6. ldr r0,=ELFIN_CLOCK_POWER_BASE @0x7e00f000
  7.  
  8. ldr r1,[r0,#OTHERS_OFFSET]
  9. mov r2,#0x40
  10. orr r1, r1, r2
  11. str r1,[r0,#OTHERS_OFFSET]
  12. nop
  13. nop
  14. nop
  15. nop
  16. nop
  17. ldr r2,=0x80
  18. orr r1, r1, r2
  19. str r1,[r0,#OTHERS_OFFSET]
  20. check_syncack:
  21. ldr r1,[r0,#OTHERS_OFFSET]
  22. ldr r2,=0xf00
  23. and r1, r1, r2
  24. cmp r1,#0xf00
  25. bne check_syncack
  26. mov r1,#0xff00
  27. orr r1, r1,#0xff
  28. str r1,[r0,#APLL_LOCK_OFFSET]
  29. str r1,[r0,#MPLL_LOCK_OFFSET]
  30. str r1,[r0,#EPLL_LOCK_OFFSET]
  31. /* CLKUART(=66.5Mhz) = CLKUART_input(532/2=266Mhz) / (UART_RATIO(3)+1) */
  32. /* CLKUART(=50Mhz) = CLKUART_input(400/2=200Mhz) / (UART_RATIO(3)+1) */
  33. /* Now, When you use UART CLK SRC by EXT_UCLK1, We support 532MHz & 400MHz value */
  34. #if defined(CONFIG_CLKSRC_CLKUART)
  35. ldr r1,[r0,#CLK_DIV2_OFFSET]
  36. bic r1, r1,#0x70000
  37. orr r1, r1,#0x30000
  38. str r1,[r0,#CLK_DIV2_OFFSET]
  39. #endif
  40.  
  41. ldr r1,[r0,#CLK_DIV0_OFFSET] /*Set Clock Divider*/
  42. bic r1, r1,#0x30000
  43. bic r1, r1,#0xff00
  44. bic r1, r1,#0xff
  45. ldr r2,=CLK_DIV_VAL
  46. orr r1, r1, r2
  47. str r1,[r0,#CLK_DIV0_OFFSET]
  48. ldr r1,=APLL_VAL
  49. str r1,[r0,#APLL_CON_OFFSET]
  50. ldr r1,=MPLL_VAL
  51. str r1,[r0,#MPLL_CON_OFFSET]
  52. ldr r1,=0x80200203/* FOUT of EPLL is 96MHz */
  53. str r1,[r0,#EPLL_CON0_OFFSET]
  54. ldr r1,=0x0
  55. str r1,[r0,#EPLL_CON1_OFFSET]
  56. ldr r1,[r0,#CLK_SRC_OFFSET] /* APLL, MPLL, EPLL select to Fout */
  57.  
  58. ldr r2,=0x2007
  59. orr r1, r1, r2
  60. str r1,[r0,#CLK_SRC_OFFSET]
  61. /* wait at least 200us to stablize all clock */
  62. mov r1,#0x10000
  63. 1: subs r1, r1,#1
  64. bne 1b
  65.  
  66. ldr r1,[r0,#OTHERS_OFFSET]
  67. orr r1, r1,#0x20
  68. str r1,[r0,#OTHERS_OFFSET]
  69. mov pc, lr /* 子函数执行完毕返回 */
 
执行完后顺序执行
  1. /* for UART */
  2. bl uart_asm_init
具体函数如下:
  1. /*
  2. * uart_asm_init: Initialize UART in asm mode, 115200bps fixed.
  3. * void uart_asm_init(void)
  4. */
  5. uart_asm_init:
  6. /* set GPIO to enable UART */
  7. @ GPIO setting for UART
  8. ldr r0,=ELFIN_GPIO_BASE
  9. ldr r1,=0x220022
  10. str r1,[r0,#GPACON_OFFSET]
  11. ldr r1,=0x2222
  12. str r1,[r0,#GPBCON_OFFSET]
  13. ldr r0,=ELFIN_UART_CONSOLE_BASE @0x7F005000
  14. mov r1,#0x0
  15. str r1,[r0,#UFCON_OFFSET]
  16. str r1,[r0,#UMCON_OFFSET]
  17. mov r1,#0x3 @was 0.
  18. str r1,[r0,#ULCON_OFFSET]
  19. #if defined(CONFIG_CLKSRC_CLKUART)
  20. ldr r1,=0xe45/* UARTCLK SRC = 11 => EXT_UCLK1*/
  21. #else
  22. ldr r1,=0x245/* UARTCLK SRC = x0 => PCLK */
  23. #endif
  24. str r1,[r0,#UCON_OFFSET]
  25. #if defined(CONFIG_UART_50)
  26. ldr r1,=0x1A
  27. #elif defined(CONFIG_UART_66)
  28. ldr r1,=0x22
  29. #else
  30. ldr r1,=0x1A
  31. #endif
  32. str r1,[r0,#UBRDIV_OFFSET]
  33. #if defined(CONFIG_UART_50)
  34. ldr r1,=0x3
  35. #elif defined(CONFIG_UART_66)
  36. ldr r1,=0x1FFF
  37. #else
  38. ldr r1,=0x3
  39. #endif
  40. str r1,[r0,#UDIVSLOT_OFFSET]
  41. ldr r1,=0x4f4f4f4f
  42. str r1,[r0,#UTXH_OFFSET] @'O'
  43. mov pc, lr
在接着顺序执行
  1. ldr r0,=ELFIN_UART_BASE
  2. ldr r1,=0x4b4b4b4b
  3. str r1,[r0,#UTXH_OFFSET]
  4. #if defined(CONFIG_NAND)
  5. /* simple init for NAND */
  6. bl nand_asm_init
  7. #endif
  8. bl mem_ctrl_asm_init
  9. #if 1
  10. ldr r0,=(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
  11. ldr r1,[r0]
  12. bic r1, r1,#0xfffffff7
  13. cmp r1,#0x8
  14. beq wakeup_reset
  15. #endif
初始化NAND
  1. /*
  2. * Nand Interface Init for SMDK6400 */
  3. nand_asm_init:
  4. ldr r0,=ELFIN_NAND_BASE
  5. ldr r1,[r0,#NFCONF_OFFSET]
  6. orr r1, r1,#0x70
  7. orr r1, r1,#0x7700
  8. str r1,[r0,#NFCONF_OFFSET]
  9. ldr r1,[r0,#NFCONT_OFFSET]
  10. orr r1, r1,#0x03
  11. str r1,[r0,#NFCONT_OFFSET]
  12. mov pc, lr
内存控制器初始化
cpu_init.S (cpu\s3c64xx\s3c6410)32702012/1/17
  1. #include<config.h>
  2. #include<s3c6410.h>
  3. .globl mem_ctrl_asm_init
  4. mem_ctrl_asm_init:
  5. ldr r0,=ELFIN_MEM_SYS_CFG @Memory sussystem address 0x7e00f120
  6. mov r1,#0xd @ Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1
  7. str r1,[r0]
  8. ...
  9. mov pc, lr
最后执行
  1. wakeup_reset:
  2. /*Clear wakeup status register*/
  3. ldr r0,=(ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET)
  4. ldr r1,[r0]
  5. str r1,[r0]
  6. /*LED test*/
  7. ldr r0,=ELFIN_GPIO_BASE
  8. ldr r1,=0x3000
  9. str r1,[r0,#GPNDAT_OFFSET]
  10. /*Load return address and jump to kernel*/
  11. ldr r0,=(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET)
  12. ldr r1,[r0]/* r1 = physical address of s3c6400_cpu_resume function*/
  13. mov pc, r1 /*Jump to kernel (sleep-s3c6400.S)*/
最后回到start.S (cpu\s3c64xx)162102016/9/4
  1. /* when we already run in ram, we don't need to relocate U-Boot.
  2. * and actually, memory controller must be configured before U-Boot
  3. * is running in ram.
  4. */
  5. ldr r0,=0xff000fff
  6. bic r1, pc, r0 /* r0 <- current base addr of code */
  7. ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
  8. bic r2, r2, r0 /* r0 <- current base addr of code */
  9. cmp r1, r2 /* compare r0, r1 */
  10. beq after_copy /* r0 == r1 then skip flash copy */
接着执行
  1. after_copy:
  2. #ifdef CONFIG_ENABLE_MMU
  3. enable_mmu:
  4. /* enable domain access */
  5. ldr r5,=0x0000ffff
  6. mcr p15,0, r5, c3, c0,0@ load domain access register
  7. /* Set the TTB register */
  8. ldr r0,
  9. ldr r1,=CFG_PHY_UBOOT_BASE
  10. ldr r2,=0xfff00000
  11. bic r0, r0, r2
  12. orr r1, r0, r1
  13. mcr p15,0, r1, c2, c0,0
  14. /* Enable the MMU */
  15. mmu_on:
  16. mrc p15,0, r0, c1, c0,0
  17. orr r0, r0,#1 /* Set CR_M to enable MMU */
  18. mcr p15,0, r0, c1, c0,0
  19. nop
  20. nop
  21. nop
  22. nop
  23. #endif
  24. skip_hw_init:
  25. /* Set up the stack */
  26. stack_setup:
  27. #ifdef CONFIG_MEMORY_UPPER_CODE
  28. ldr sp,=(CFG_UBOOT_BASE + CFG_UBOOT_SIZE -0xc)
  29. #else
  30. ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
  31. sub r0, r0,#CFG_MALLOC_LEN /* malloc area */
  32. sub r0, r0,#CFG_GBL_DATA_SIZE /* bdinfo */
  33. #ifdef CONFIG_USE_IRQ
  34. sub r0, r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
  35. #endif
  36. sub sp, r0,#12 /* leave 3 words for abort-stack */
  37. #endif
  38. clear_bss:
  39. ldr r0, _bss_start /* find start of bss segment */
  40. ldr r1, _bss_end /* stop here */
  41. mov r2,#0x00000000 /* clear */
  42. clbss_l:
  43. str r2,[r0]/* clear loop... */
  44. add r0, r0,#4
  45. cmp r0, r1
  46. ble clbss_l
  47. ldr pc, _start_armboot
  48. _start_armboot:
  49. .word start_armboot
到执行start_armboot函数这一步,就开始跳出硬件依赖了,跳转到第二阶段代码入口
Board.c (lib_arm)142052012/7/11
图 2.3 U-Boot第二阶段执行流程
 

通过bootm引导linux内核启动

使用do_bootm_linux引导kernel
 直至
 至此,Linux系统开始运行。

 

 




posted @ 2016-09-16 20:35  naedzq  阅读(527)  评论(0编辑  收藏  举报