文章目录
头文件包含
/*
* armboot - Startup Code for S5PC110/ARM-Cortex CPU-core
*
* Copyright (c) 2009 Samsung Electronics
*
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Base codes by scsuh (sc.suh)
*/
#include <config.h> @@在mkconfig里边编译生成的,位置include目录下
#include <version.h> @@包含一个头文件,头文件里存到版本号
#if defined(CONFIG_ENABLE_MMU)
#include <asm/proc/domain.h> @@跟mkconfig有关,符号链接
#endif
#include <regs.h> @@跟mkconfig有关,符号链接
#ifndef CONFIG_ENABLE_MMU
#ifndef CFG_PHY_UBOOT_BASE
#define CFG_PHY_UBOOT_BASE CFG_UBOOT_BASE
#endif
#endif
预留校验头与中断异常向量表
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
.word 0x2000 @@定义了一个变量(四个字节),这个变量的值是0x2000
.word 0x0
.word 0x0
.word 0x0
#endif
@@这十六字节是为了那十六字节的校验头预留的
@@什么要加这十六字节的数据呢;SD卡启动/Nand启动等整个镜像开头需要16字节的校验头,所以先在这占着,SD启动的时候mkv210image.c会给它加16字节的校验头(现在这个校验和是不对的,后边要去计算校验重新填充)
@@这十六字节是为了那十六字节的校验头预留的
.globl _start @@.globl指示告诉汇编器,_start是一个全局符号
_start: b reset @@复位异常
ldr pc, _undefined_instruction @@未定义指令
ldr pc, _software_interrupt @@软中断
ldr pc, _prefetch_abort @@预取指异常
ldr pc, _data_abort @@数据异常
ldr pc, _not_used
ldr pc, _irq @@普通中断
ldr pc, _fiq @@快速中断
中断异常处理与字节对齐(十六字节)
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq
_pad:
.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef @@di zhi dui qi,这些内存用0xdeadbeef 来填充
定义了一个类似指针的东西指向的位置是链接地址
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
_TEXT_BASE: @@链接地址;TEXT_BASE = 0xc3e00000
.word TEXT_BASE @@在makefile的2591行有给他一个地址(这个值来自于makefile)
物理地址
主要用来后边清理bss段
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE: @@物理地址
.word CFG_PHY_UBOOT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
中断处理
uboot中很少使用
#if defined(CONFIG_USE_IRQ)
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
设置状态寄存器cpsr
/*
* the actual reset code
*/
reset:
/*
* set the cpu to SVC32 mode and IRQ & FIQ disable
*/
@;mrs r0,cpsr
@;bic r0,r0,#0x1f
@;orr r0,r0,#0xd3
@;msr cpsr,r0
msr cpsr_c, #0xd3 @ I & F disable, Mode: 0x13 - SVC
@@cpsr 是cheng xu 状态寄存器;_c 为0~7位;
@@CPU设置为禁止FIQ和 IRQ,状态是ARM状态,SVC模式
cache
@@底层的初始化
bl disable_l2cache @@禁止L2 cache
bl set_l2cache_auxctrl_cycle @@L2 cache相关的初始化
bl enable_l2cache @@使能L2 cache
/*
* Invalidate L1 I/D @@刷新cache的icache和dcache
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
MMU
/*
* disable MMU stuff and caches @@关闭MMU
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
启动介质
判断是nand还是sd启动
/* Read booting information */ @@读取启动信息
ldr r0, =PRO_ID_BASE @@PRO_ID_BASE寄存器通过读取硬件OM引脚,判断启动介质是nand还是sd
ldr r1, [r0,#OMR_OFFSET]
bic r2, r1, #0xffffffc1 @@将启动的信息存在r2中,r2的值决定了是从SD启动还是nand启动
/* NAND BOOT */
cmp r2, #0x0 @ 512B 4-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x2 @ 2KB 5-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x4 @ 4KB 5-cycle 8-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x6 @ 4KB 5-cycle 16-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x8 @ OneNAND Mux
moveq r3, #BOOT_ONENAND
/* SD/MMC BOOT */
cmp r2, #0xc
moveq r3, #BOOT_MMCSD
@@通过比较r2里边的值,确定r3里的值
/* NOR BOOT */
cmp r2, #0x14
moveq r3, #BOOT_NOR
设置栈,调用lowlevel_init
到这要去分析lowlevel_init这个函数
/*
* Go setup Memory and board specific bits prior to relocation.
*/
@@设置栈,栈的位置在SRAM(DDR);
ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */
sub sp, sp, #12 /* set stack */
mov fp, #0
bl lowlevel_init /* go setup pll,mux,memory */ @@初始化一些底层的东西
供电锁存
没有什么意义,lowleve_init.S里有锁存过
/* To hold max8698 output before releasing power on switch,
* set PS_HOLD signal to high
*/
ldr r0, =0xE010E81C /* PS_HOLD_CONTROL register */ @@供电锁存
ldr r1, =0x00005301 /* PS_HOLD output high */
str r1, [r0]
第二次设置栈
/* get ready to call C functions */ @@设置栈(又),这次栈的位置在DDR里边。为什么要再次设置,因为原来SRAM中的内存少,容易溢出
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
判断是否要重定位
/* 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 */
判断是SD0还是 SD2启动
#if defined(CONFIG_EVT1)
/* If BL1 was copied from SD/MMC CH2 */
ldr r0, =0xD0037488 @@这个寄存器 硬件会自动往这里给值,通过这个值判断使用的是哪个口SD0是0xEB000000 SD2是0xEB200000
ldr r1, [r0]
ldr r2, =0xEB200000
cmp r1, r2 @@读出来的值跟0xEB200000比较
beq
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET] @@在把277行存入的值取出来
cmp r1, #BOOT_NAND /* 0x0 => boot device is nand */ @@在比较,确定启动方式,跳转到BOOT_MMCSD
beq nand_boot
cmp r1, #BOOT_ONENAND /* 0x1 => boot device is onenand */
beq onenand_boot
cmp r1, #BOOT_MMCSD
beq mmcsd_boot
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot
nand_boot:
mov r0, #0x1000
bl copy_from_nand
b after_copy
onenand_boot:
bl onenand_bl2_copy
b after_copy
mmcsd_boot:
#if DELETE @@设置栈(又又)删掉了
ldr sp, _TEXT_PHY_BASE
sub sp, sp, #12
mov fp, #0
#endif
真正的重定位操作
去movi.c文件分析
bl movi_bl2_copy @@真正的重定位在是这个函数里实现的
虚拟地址映射
b after_copy @@虚拟地址映射
after_copy:
#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
/* enable domain access */ @@使能预访问
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
@@协处理器里的c3是用来控制域访问的
@@
@@mcr指令是用来写协处理器的,mrc指令是用来读协处理器的
/* Set the TTB register */ @@TTB就是转换表的基址;找出重定位到DDR里边的转换表的地址
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0 @@将c1的值读到r0
orr r0, r0, #1 @@把1或到r0
mcr p15, 0, r0, c1, c0, 0 @@将r0的值写到c1,打开MMU
nop
nop
nop
nop
#endif
第三次设置栈
skip_hw_init:
/* Set up the stack */
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000) @@第三次设置栈是在合适的位置设置栈;安全、紧凑不浪费内存;设置在uboot起始地址上方的2M那,栈是满减栈
#else
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#if defined(CONFIG_USE_IRQ)
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
#endif
清BSS段
clear_bss: @@清BSS段
ldr r0, _bss_start /* find start of bss segment */@@_bss_start 来自链接脚本,但是他的值在本文件里定义
ldr r1, _bss_end /* stop here */ @@_end 来自链接脚本,但是他的值在本文件里定义
mov r2, #0x00000000 /* clear */
第一阶段最后一步
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot @@第一阶段的最后一步,也是第二阶段的开始;使用的是远跳转,可以从SRAM跳转到DDR中(当前还在SRAM中运行);_start_armboot 相当于一个指针,指向一个函数
@@在uboot/lib_arm/board.c