uboot第一阶段start.s简单分析

时间:2022-07-20 04:04:31

下面是自己理解和查资料得出的一些解释。作为自己的笔记,里面还有些知识块不是理解非常透彻。希望指教。还有个这不是单纯的uboot ,而是一个移植的uboot,但是没看清楚,分析到后面发现有移植部分,想了下还是将错就错吧。


设置中断向量表

用globl来定义全局变量,因为这个中断变量在其他模块中也要用到。

把中断标号赋值给pc,其实真正的中断服务子程序地址在下面再次定义。

中断向量表中只有复位键不带返回的跳转,且该指令地址为0x00。中断向量表中的其他中断启动时是不会调用的,因为复位中断会跳过这些中断向量直接跳转到真正的运行代码,只有当程序运行出现中断时,才会回来查看这个中断向量表,然后查找中断服务子程序。

 

.globl _start

_start: b start_code

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

 

定义了真正的中断子程序的入口地址,word分配一个字长的地址空间。因为在启动时,全部切换到32为的ARM状态下操作,所以字长为4个字节。

_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

 

对于这条指令很多博友都有争议,下面是我个人的理解:balignl是个伪指令,由balign指令变来的,表示的意思是在当前位置及以后的代码中以16个字节的方式对齐,不够则以0xdeadbeef填充。至于这个0xdeadbeef值,则是个单词:坏死的牛肉。就是个标志性的单词,为了方便程序员阅读代码,没具体意思。

这是下面看到移植那部分添加的:可以算下下面这条指令的地址,是0x3C。

.balignl 16,0xdeadbeef

 

 

/*

 *************************************************************************

 *

 * Startup Code (called from the ARM reset exception vector)

 *

 * do important init only if we don't start from memory!

 * relocate armboot to ram

 * setup stack

 * jump to second stage

 *

 *************************************************************************

 */

 

定义代码基地址变量

在文件u-boot-2010.03\board\embedclub\smdk2440a中有定义:TEXT_BASE = 0x33F80000

_TEXT_BASE:

.word TEXT_BASE

 

定义代码起始地址,即是_start标号地址0x00

.globl _armboot_start

_armboot_start:

.word _start

 

/*

 * These are defined in the board-specific linker script.

 */

 

定义_bss的起始地址和结束地址,该地址在.../.../u-boot.lds文件中有定义

.globl _bss_start

_bss_start:

.word __bss_start

 

.globl _bss_end

_bss_end:

.word _end

 

IRQ/FIQ的堆栈地址设置

#ifdef 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

 

 

/*

 * the actual start code

 */

 

这是代码真正开始的地方,上电开始从复位中断0x00地址跳转到该标号地址执行。

start_code:

/*

* set the cpu to SVC32 mode

*/

uboot第一阶段的第二步:设置cpu工作模式为管理模式svc。具体指令不解释,步骤分析下:从cpsr状态寄存器中读取数据,然后更改工作模式位,再写入cpsr状态寄存器中,更改完毕。

mrs r0, cpsr

bic r0, r0, #0x1f

orr r0, r0, #0xd3

msr cpsr, r0

 

下面两个跳转指令被注释了,查了下资料:是说在移植的时候,解开注释跳转到函数中执行,然后测试LED灯来表示移植情况的。

/*

bl coloured_LED_init

bl red_LED_on

*/

这是个状态显示,当上电启动时,LED灯会一直闪烁不停。

#ifdef CONFIG_SMDK2440_LED

bl LED_on

#endif

 

 

至于这个段代码,我自己的解释是:把_start映射到0x00地址上。不知道理解正不正确,查了些资料,没找到解释,不知道是太简单了还是这个不太重要。我想这个是要关系到硬件板子的设计。

#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)

/*

* relocate exception table

*/

ldr r0, =_start

ldr r1, =0x0

mov r2, #16

copyex:

subs r2, r2, #1

ldr r3, [r0], #4

str r3, [r1], #4

bne copyex

#endif

 

首先是定义一些寄存器,用判断语句来兼容多个板子的寄存器地址不一样问题

#ifdef CONFIG_S3C24X0

/* turn off the watchdog */

 

# if defined(CONFIG_S3C2400)

#  define pWTCON 0x15300000

#  define INTMSK 0x14400008 /* Interupt-Controller base addresses */

#  define CLKDIVN 0x14800014 /* clock divisor register */

#else

#  define pWTCON 0x53000000

#  define INTMSK 0x4A000008 /* Interupt-Controller base addresses */

#  define INTSUBMSK 0x4A00001C

#  define CLKDIVN 0x4C000014 /* clock divisor register */

# endif

 

这是个为些特殊值得起的宏名,方便操作。我好奇的是后面的注释:Hanson ~_~ boy

#define CLK_CTL_BASE 0x4C000000 /* Hanson */

#define MDIV_405 0x7f << 12 /* Hanson */

#define PSDIV_405 0x21 /* Hanson */

#define MDIV_200 0xa1 << 12 /* Hanson */

#define PSDIV_200 0x31 /* Hanson */

 

uboot第一阶段第三步:关闭看门狗。

简单解释,看门狗是块定时调用复位中断的硬件模块,当程序运行一定时间后,要给看门狗设置个值,如果没有设置,则看门狗会自动调用复位中断来让系统进行复位。其作用是防止系统卡住,死循环之类的。这里关闭看门狗是为了省去喂狗操作,和启动方便。否则要不执行复杂的喂狗操作,要不就无限重启。

ldr r0, =pWTCON

mov r1, #0x0

str r1, [r0]

 

/*

* mask all IRQs by setting all bits in the INTMR - default

*/

uboot第一阶段第四步:禁止所有中断

设置主中断屏蔽寄存器和子中断屏蔽寄存器全为1.屏蔽所有中断。

mov r1, #0xffffffff

ldr r0, =INTMSK

str r1, [r0]

# if defined(CONFIG_S3C2410)

ldr r1, =0x3ff

ldr r0, =INTSUBMSK

str r1, [r0]

# endif

 

#if defined(CONFIG_S3C2440)

ldr r1, =0x7fff

ldr r0, =INTSUBMSK

str r1, [r0]

#endif

 

uboot第一阶段第五步:设置CPU时钟频率

按照硬件板子的规定FCLK:HCLK:PCLK的比例来分频。设置时钟频率的目的是让调整外围设备的时钟频率,使CPU能够操作外围硬件资源

#if defined(CONFIG_S3C2440)

/* FCLK:HCLK:PCLK = 1:4:8 */

ldr r0, =CLKDIVN

mov r1, #5

str r1, [r0]

 

uboot第一阶段第六步:设置cp15协处理器寄存器

mrc p15, 0, r1, c1, c0, 0

orr r1, r1, #0xc0000000

mcr p15, 0, r1, c1, c0, 0

mov r1, #CLK_CTL_BASE

mov r2, #MDIV_405

add r2, r2, #PSDIV_405

str r2, [r1, #0x04] /* MPLLCON tekkaman */

 

#else

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

mrc p15, 0, r1, c1, c0, 0

orr r1, r1, #0xc0000000

mcr p15, 0, r1, c1, c0, 0 /*write ctrl register tekkaman*/

mov r1, #CLK_CTL_BASE /* tekkaman*/

mov r2, #MDIV_200

add r2, r2, #PSDIV_200

str r2, [r1, #0x04]

#endif

#endif /* CONFIG_S3C24X0 */

 

/*

* we do sys-critical inits only at reboot,

* not when booting from ram!

*/

 

返回开发板设置些初始化值,bank的值之类的

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

 

uboot第一阶段第七步:拷贝代码到RAM中

 

检测代码所在的位置,如果是在flash(不相等)中则直接拷贝自身到RAM中,并且要判断是nor flash还是nand flash启动。如果在RAM中(相等)则直接跳转到栈设置中初始化。判断方法是代码的起始地址是否为0地址。

如果是在flash中运行则 _start的值就是0,

 如果是在RAM中运行,则 _start=0x33F80000

 

/***************** CHECK_CODE_POSITION ******************************************/

adr r0, _start /* r0 <- current position of code   */

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

cmp r0, r1 /* don't reloc during debug         */

beq stack_setup

/***************** CHECK_CODE_POSITION ******************************************/

 

/***************** CHECK_BOOT_FLASH ******************************************/

 

面代码是涉及到移植的问题,判断是nand falsh还是nor flash启动的。前面已经提示过了,记住0x3C位置的指令是什么?就是往该内存中添加一个0Xbeadbeef值。现在是把0x4000003C地址内容置0,然后读取0x0000003C地址内容,比较是否为0.如果是0,则说明是nand flash 启动,因为nand flash把4k以后的地址映射到了0x00地址上。记得要恢复开始的0Xbeadbeef值,因为搬运代码时要检测是否相等。

 

ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /* address of Internal SRAM  0x4000003C*/

mov r0, #0 /* r0 = 0 */

str r0, [r1]

 

mov r1, #0x3c /* address of men  0x0000003C*/

ldr r0, [r1]

cmp r0, #0

bne relocate

 

不相等则是nand flash启动,恢复被修改的值。

/* recovery  */

ldr r0, =(0xdeadbeef)

ldr r1, =( (4<<28)|(3<<4)|(3<<2) )

str r0, [r1]

/***************** CHECK_BOOT_FLASH ******************************************/

 

/***************** NAND_BOOT *************************************************/

从nand  flash启动把代码搬运到RAM中

 

#define LENGTH_UBOOT 0x60000

#define NAND_CTL_BASE 0x4E000000

 

#ifdef CONFIG_S3C2440

/* Offset */

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFCMD 0x08

#define oNFSTAT 0x20

 

@ reset NAND

mov r1, #NAND_CTL_BASE

ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

str r2, [r1, #oNFCONF]

ldr r2, [r1, #oNFCONF]

ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control

str r2, [r1, #oNFCONT]

ldr r2, [r1, #oNFCONT]

ldr r2, =(0x6) @ RnB Clear

str r2, [r1, #oNFSTAT]

ldr r2, [r1, #oNFSTAT]

mov r2, #0xff @ RESET command

strb r2, [r1, #oNFCMD]

mov r3, #0 @ wait

nand1:

add r3, r3, #0x1

cmp r3, #0xa

blt nand1

 

nand2:

ldr r2, [r1, #oNFSTAT] @ wait ready

tst r2, #0x4

beq nand2

ldr r2, [r1, #oNFCONT]

orr r2, r2, #0x2 @ Flash Memory Chip Disable

str r2, [r1, #oNFCONT]

@ get read to call C functions (for nand_read())

ldr sp, DW_STACK_START @ setup stack pointer

mov fp, #0 @ no previous frame, so fp=0

 

@ copy U-Boot to RAM

ldr r0, =TEXT_BASE

mov r1, #0x0

mov r2, #LENGTH_UBOOT

bl nand_read_ll

tst r0, #0x0

beq ok_nand_read

 

bad_nand_read:

loop2:

b loop2 @ infinite loop

ok_nand_read:

@ verify

mov r0, #0

ldr r1, =TEXT_BASE

mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes

go_next:

ldr r3, [r0], #4

ldr r4, [r1], #4

teq r3, r4

bne notmatch

subs r2, r2, #4

beq stack_setup

bne go_next

 

notmatch:

loop3:

b loop3 @ infinite loop

#endif

 

#ifdef CONFIG_S3C2410

 

/* Offset */

#define oNFCONF 0x00

#define oNFCMD 0x04

#define oNFSTAT 0x10

 

@ reset NAND

mov r1, #NAND_CTL_BASE

ldr r2, =0xf830 @ initial value

str r2, [r1, #oNFCONF]

ldr r2, [r1, #oNFCONF]

bic r2, r2, #0x800 @ enable chip

str r2, [r1, #oNFCONF]

mov r2, #0xff @ RESET command

strb r2, [r1, #oNFCMD]

mov r3, #0 @ wait

nand1:

add r3, r3, #0x1

cmp r3, #0xa

blt nand1

 

nand2:

ldr r2, [r1, #oNFSTAT] @ wait ready

tst r2, #0x1

beq nand2

ldr r2, [r1, #oNFCONF]

orr r2, r2, #0x800 @ disable chip

str r2, [r1, #oNFCONF]

@ get read to call C functions (for nand_read())

ldr sp, DW_STACK_START @ setup stack pointer

mov fp, #0 @ no previous frame, so fp=0

@ copy U-Boot to RAM

ldr r0, =TEXT_BASE

mov r1, #0x0

mov r2, #LENGTH_UBOOT

bl nand_read_ll

tst r0, #0x0

beq ok_nand_read

 

bad_nand_read:

loop2:

b loop2 @ infinite loop

 

 

ok_nand_read:

@ verify

mov r0, #0

ldr r1, =TEXT_BASE

mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes

go_next:

ldr r3, [r0], #4

ldr r4, [r1], #4

teq r3, r4

bne notmatch

subs r2, r2, #4

beq stack_setup

bne go_next

 

notmatch:

loop3:

b loop3 @ infinite loop

 

#endif

/***************** NAND_BOOT *************************************************/

 

表示是从nor flash启动,把代码搬运到RAM中

 

/***************** NOR_BOOT *************************************************/

relocate: /* relocate U-Boot to RAM     */

      /*********** CHECK_FOR_MAGIC_NUMBER***************/

ldr r1, =(0xdeadbeef)

cmp r0, r1

bne loop3

      /*********** CHECK_FOR_MAGIC_NUMBER***************/

adr r0, _start /* r0 <- current position of code   */

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot            */

add r2, r0, r2 /* r2 <- source end address         */

 

copy_loop:

ldmia r0!, {r3-r10} /* copy from source address [r0]    */

stmia r1!, {r3-r10} /* copy to   target address [r1]    */

cmp r0, r2 /* until source end addreee [r2]    */

ble copy_loop

/***************** NOR_BOOT *************************************************/

 

设置堆栈,为第二阶段的c程序设置运行做环境设置

/* Set up the stack

 

uboot第一阶段第八步:配置栈空间

    */

stack_setup:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot   */

sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area              */

sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                 */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp, r0, #12 /* leave 3 words for abort-stack    */

 

uboot第一阶段第九步:bss段清零

对bss段进行初始化:从起点循环置0到终点

clear_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, #4

cmp r0, r1

ble clbss_l

 

跳转到第二阶段

ldr pc, _start_armboot