cpu/arm920t/start.S

/*

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

*

* Jump vector table as in table 3.1 in [1]

*

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

*/

;定义变量_start,然后跳转到处理器复位代码

.globl _start

_start: b       reset

;产生中断则利用pc来跳转到对应的中断处理程序中

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来在当前位置放置一个值,这个值实际上就用对应的中断处理函数的地址

;.word的意义为在当前地址处放入一个16bits值

_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 16,0xdeadbeef

/*

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

*

* Startup Code (reset vector)

*

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

* relocate armboot to ram

* setup stack

* jump to second stage

*

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

*/

;定义变量

_TEXT_BASE:

.word TEXT_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

#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 reset code

*/

;实际处理代码

reset:

/*

* set the cpu to SVC32 mode

*/

mrs r0,cpsr

;bic清除指定为1的位

bic r0,r0,#0x1f

;orr逻辑或操作

orr r0,r0,#0xd3

;经过以上两步r0值控制位位11010011,第0~4位标识处理器当前所处模式为10011(32位管理模式),第6、7位

;为1标识禁止IRQ和FIQ中断,第5位为0标识程序运行为arm状态,若其为1则运行在thumb状态

;设置处理器为32位管理模式,并运行与arm状态

msr cpsr,r0

/* turn off the watchdog */

#if defined(CONFIG_S3C2400)

# define pWTCON  0x15300000

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

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

#elif defined(CONFIG_S3C2410)

;看门狗寄存器地址

# define pWTCON  0x53000000

;中断掩码寄存器,决定那个中断源被屏蔽,某位为1则屏蔽中断源,初始值为0xFFFFFFFF,屏蔽所有中断

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

;中断子掩码寄存器,该寄存器只能屏蔽11个中断源,因此其仅低11位有效,初始值为0x7FF

# define INTSUBMSK 0x4A00001C

;时钟分频控制寄存器

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

#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

;将看门狗寄存器清空,其各位含义为,第0位为1则当看门狗定时器溢出时重启,为0则不重启,初值为1

;第2位为中断使能位,初值为0

;第3、4位为时钟分频因子,初值为00,

;第5位为看门狗的使能位初值为1

;第8~15位为比例因子,初值为0x80

ldr     r0, =pWTCON

mov     r1, #0x0

;将看门狗寄存器所有位置零,关闭看门狗,其实只要将第5位置0即可

str     r1, [r0]

;屏蔽所有中断,实际上中断屏蔽掩码寄存器初值即为0xFFFFFFF

mov r1, #0xffffffff

ldr r0, =INTMSK

str r1, [r0]

# if defined(CONFIG_S3C2410)

;设置子中断掩码寄存器

ldr r1, =0x3ff

ldr r0, =INTSUBMSK

str r1, [r0]

# endif

;设置时钟寄存器,CLKDIVN第0位为PDIVN,为0则PCLK=HCLK,为1则PCLK=HCLK/2

;第1位为HDIVN,为0则HCLK=FCLK,为1则HCLK=FCLK/2

;这里两位均为1,则FCLK:HCLK:PCLK = 4:2:1

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */

/*

* we do sys-critical inits only at reboot,

* not when booting from ram!

*/

;对临界寄存器的初始化,如果从ram中启动则不执行,如果重启则执行

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

;重定向代码,也就是从flash中复制到ram中

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

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

;当前代码地址,adr获取当前代码的地址信息,若从ram运行则_start=TEXT_BASE,否则_start=0x00000000

adr r0, _start  /* r0  ;获取_TEXT_BASE

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

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

;两者相等,表示从ram运行则跳转到堆栈设置

beq     stack_setup

;不相等则表示从flash中运行,重定向代码

ldr r2, _armboot_start

;获取未初始化数据段地址

ldr r3, _bss_start

;计算代码段大小

sub r2, r3, r2  /* r2  ;计算代码段终止地址

add r2, r0, r2  /* r2  ;复制代码,r0为代码的起始地址,r1为ram中地址,r2为代码的终止地址

;每次copy后将r0值递增同r2比较来判断是否复制完成

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

#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

/* Set up the stack          */

stack_setup:

;获取_TEXT_BASE

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

;获取分配区域起始指针,CFG_MALLOC_LEN=128*1024+CFG_ENV_SIZE=128*1024+0x10000=192K

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

;另外分配128bytes来存储开发板信息

sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

;再减去12bytes用于栈起点

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

;清空未初始化数据段

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

#if 0

;关闭看门狗

/* try doing this stuff after the relocation */

ldr     r0, =pWTCON

mov     r1, #0x0

str     r1, [r0]

/*

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

*/

;禁止中断

mov r1, #0xffffffff

ldr r0, =INTMR

str r1, [r0]

;设置时钟

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

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

/* END stuff after relocation */

#endif

;完成复制后跳转到start_armboot,到这里就进入函数lib_arm/board.c的start_armboot函数中

ldr pc, _start_armboot

_start_armboot: .word start_armboot

;这里指的从flash中运行是指的从flash rom中运行,也就是常说的从nor flash中运行程序,现在有很多开发板;都是利用SDRAM和NAND-FLASH共同工作,所以需要添加从nand flash启动的代码。在ldr pc,_start_armboot前;;添加如下代码:

#ifdef CONFIG_S3C2410_NAND_BOOT

bl    copy_myself

@ jump to ram

ldr   r1, =on_the_ram

add  pc, r1, #0

nop

nop

1:  b     1b          @ infinite loop

on_the_ram:

#endif

;开始就跳转到函数copy_myself中,

#ifdef CONFIG_S3C2410_NAND_BOOT

copy_myself:

;保存断点地址

mov r10, lr

@ reset NAND

;NAND_CTRL_BASE为nand flash的寄存器基址为0x4E000000

;根据flash手册来复位flash

mov r1, #NAND_CTL_BASE

;通过nand flash配置寄存器配置nand flash,该寄存器仅低16位有效

;第15位为nand flash控制器使能位,第12位为初始化ECC使能位,第11位为nand falsh memory nFCE使能

ldr   r2, =0xf830           @ initial value

str   r2, [r1, #oNFCONF]

ldr   r2, [r1, #oNFCONF]

;将第11位清零,使能芯片

bic  r2, r2, #0x800         @ enable chip

str   r2, [r1, #oNFCONF]

;写入命令

mov r2, #0xff               @ RESET command

strb r2, [r1, #oNFCMD]

;循环延时

mov r3, #0                  @ wait

1: add  r3, r3, #0x1

cmp r3, #0xa

blt   1b

;利用状态寄存器测试flash内部操作是否完成,如果完成则其状态寄存器将返回1

;等待flash操作完成

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

tst    r2, #0x1

beq  2b

;禁止芯片

ldr   r2, [r1, #oNFCONF]

orr  r2, r2, #0x800         @ disable chip

str   r2, [r1, #oNFCONF]

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

;建立堆栈,栈起点为0x33f00000,大小为0x8000

ldr   sp, DW_STACK_START    @ setup stack pointer

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

@ copy U-BOOT to RAM

;UBOOT_RAM_BASE应该同TEXT_BASE相同

ldr   r0, =UBOOT_RAM_BASE

mov   r1, #0x0  @address

mov   r2, #0x30000  @size

;这里设置大小为192K,为什么取这个值?为什么这三个寄存器的值就作为参数传递进去了?

;跳转到board/smdk2410/nand_read.c中的nand_read_ll函数,代码见后面

;该函数需要三个参数,r0为其在ram中的起始地址,r1为在源地址也就是flash中的起始地址,r2为需要

;复制的中大小

bl    nand_read_ll

tst   r0, #0x0 ;r0为返回值

;如果成功完成复制则跳转到ok_nand_read

beq   ok_nand_read

#ifdef CONFIG_DEBUG_LL

bad_nand_read:

ldr   r0, STR_FAIL

ldr   r1, SerBase

bl    PrintWord

1: b     1b          @ infinite loop

#endif

;打印信息

ok_nand_read:

#ifdef CONFIG_DEBUG_LL

ldr   r0, STR_OK

ldr   r1, SerBase

bl    PrintWord

#endif

;校验,因为从nand flash启动只需要将bootloader的前4K代码复制到stepping stone处即可

@ verify

mov r0, #0

ldr   r1, =UBOOT_RAM_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  done_nand_read

bne  go_next

notmatch:

#ifdef CONFIG_DEBUG_LL

sub  r0, r0, #4

ldr   r1, SerBase

bl    PrintHexWord

ldr   r0, STR_FAIL

ldr   r1, SerBase

bl    PrintWord

#endif

1: b     1b

done_nand_read:

#ifdef CONFIG_DEBUG_LL

ldr   r0, STR_OK

ldr   r1, SerBase

bl    PrintWord

#endif

;恢复断点,程序继续运行

mov pc, r10

;内存清零???

@ clear memory

@ r0: start address

@ r1: length

mem_clear:

mov r2, #0

mov r3, r2

mov r4, r2

mov r5, r2

mov r6, r2

mov r7, r2

mov r8, r2

mov r9, r2

clear_loop:

stmia      r0!, {r2-r9}

subs r1, r1, #(8 * 4)

bne  clear_loop

mov pc, lr

#endif  @ CONFIG_S3C2410_NAND_BOOT

/*

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

*

* CPU_init_critical registers

*

* setup important registers

* setup memory timing

*

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

*/

;对临界寄存器的初始化

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

/*

* flush v4 I/D caches

*/

;清空指令和数据caches

mov r0, #0

mcr 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, 0

bic 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) Align

orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache

mcr p15, 0, r0, c1, c0, 0

/*

* before relocating, we have to setup RAM timing

* because memory timing is board-dependend, you will

* find a lowlevel_init.S in your board directory.

*/

;在重定向代码之前,必须初始化内存时序,因为重定向时需要将flash中的代码复制到内存中

;内存初始化的代码在开发板目录下

mov ip, lr

bl lowlevel_init

mov lr, ip

mov pc, lr

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*

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

*

* Interrupt handling

*

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

*/

;中断处理

@

@ IRQ stack frame.

@

#define S_FRAME_SIZE 72

#define S_OLD_R0 68

#define S_PSR  64

#define S_PC  60

#define S_LR  56

#define S_SP  52

#define S_IP  48

#define S_FP  44

#define S_R10  40

#define S_R9  36

#define S_R8  32

#define S_R7  28

#define S_R6  24

#define S_R5  20

#define S_R4  16

#define S_R3  12

#define S_R2  8

#define S_R1  4

#define S_R0  0

#define MODE_SVC 0x13

#define I_BIT  0x80

/*

* use bad_save_user_regs for abort/prefetch/undef/swi ...

* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling

*/

.macro bad_save_user_regs

sub sp, sp, #S_FRAME_SIZE

stmia sp, {r0 - r12}   @ Calling r0-r12

ldr r2, _armboot_start

sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack

ldmia r2, {r2 - r3}   @ get pc, cpsr

add r0, sp, #S_FRAME_SIZE  @ restore sp_SVC

add r5, sp, #S_SP

mov r1, lr

stmia r5, {r0 - r3}   @ save sp_SVC, lr_SVC, pc, cpsr

mov r0, sp

.endm

.macro irq_save_user_regs

sub sp, sp, #S_FRAME_SIZE

stmia sp, {r0 - r12}   @ Calling r0-r12

add     r8, sp, #S_PC

stmdb   r8, {sp, lr}^                   @ Calling SP, LR

str     lr, [r8, #0]                    @ Save calling PC

mrs     r6, spsr

str     r6, [r8, #4]                    @ Save CPSR

str     r0, [r8, #8]                    @ Save OLD_R0

mov r0, sp

.endm

.macro irq_restore_user_regs

ldmia sp, {r0 - lr}^   @ Calling r0 - lr

mov r0, r0

ldr lr, [sp, #S_PC]   @ Get PC

add sp, sp, #S_FRAME_SIZE

subs pc, lr, #4   @ return & move spsr_svc into cpsr

.endm

.macro get_bad_stack

ldr r13, _armboot_start  @ setup our mode stack

sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

str lr, [r13]   @ save caller lr / spsr

mrs lr, spsr

str     lr, [r13, #4]

mov r13, #MODE_SVC   @ prepare SVC-Mode

@ msr spsr_c, r13

msr spsr, r13

mov lr, pc

movs pc, lr

.endm

.macro get_irq_stack   @ setup IRQ stack

ldr sp, IRQ_STACK_START

.endm

.macro get_fiq_stack   @ setup FIQ stack

ldr sp, FIQ_STACK_START

.endm

/*

* exception handlers

*/

.align  5

undefined_instruction:

get_bad_stack

bad_save_user_regs

bl  do_undefined_instruction

.align 5

software_interrupt:

get_bad_stack

bad_save_user_regs

bl  do_software_interrupt

.align 5

prefetch_abort:

get_bad_stack

bad_save_user_regs

bl  do_prefetch_abort

.align 5

data_abort:

get_bad_stack

bad_save_user_regs

bl  do_data_abort

.align 5

not_used:

get_bad_stack

bad_save_user_regs

bl  do_not_used

#ifdef CONFIG_USE_IRQ

.align 5

irq:

get_irq_stack

irq_save_user_regs

bl  do_irq

irq_restore_user_regs

.align 5

fiq:

get_fiq_stack

/* someone ought to write a more effiction fiq_save_user_regs */

irq_save_user_regs

bl  do_fiq

irq_restore_user_regs

#else

.align 5

irq:

get_bad_stack

bad_save_user_regs

bl  do_irq

.align 5

fiq:

get_bad_stack

bad_save_user_regs

bl  do_fiq

#endif

#ifdef CONFIG_S3C2410_NAND_BOOT

.align     2

DW_STACK_START:

.word      STACK_BASE+STACK_SIZE-4

#endif

//该函数来自于board/smdk2410/nand_read.c

//通过r0,r1,r2三个寄存器传递参数过来,返回值为r0

int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

{

int i, j;

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

return -1; /* invalid alignment */

}

//按照芯片的时序来进行读写操作

/* chip Enable */

NFCONF &= ~0x800;

for(i=0; i<10; i++);

for(i=start_addr; i < (start_addr + size);) {

/* READ0 */

NFCMD = 0;

/* Write Address */

NFADDR = i & 0xff;

NFADDR = (i >> 9) & 0xff;

NFADDR = (i >> 17) & 0xff;

NFADDR = (i >> 25) & 0xff;

wait_idle();

for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {

*buf = (NFDATA & 0xff);

buf++;

}

}

/* chip Disable */

NFCONF |= 0x800; /* chip disable */

return 0;

}

board/qt2410/lowlevel_init.S

;总线宽度和等待寄存器

#define BWSCON 0x48000000

;宽度8bits、16bits、32bits

/* BWSCON */

#define DW8    (0x0)

#define DW16    (0x1)

#define DW32    (0x2)

;等待

#define WAIT    (0x1<<2)

;UBLB标识引脚信号的类型,为0则为nWBE,为1则为nBE

#define UBLB    (0x1<<3)

;定义总线类型

#define B1_BWSCON    (DW32)

#define B2_BWSCON    (DW16)

#define B3_BWSCON    (DW16 + WAIT + UBLB)

#define B4_BWSCON    (DW16)1

#define B5_BWSCON    (DW16)

#define B6_BWSCON    (DW32)

#define B7_BWSCON    (DW32)

;bank0寄存器

/* BANK0CON */

#define B0_Tacs    0x0 /*  0clk */

#define B0_Tcos    0x0 /*  0clk */

#define B0_Tacc    0x7 /* 14clk */

#define B0_Tcoh    0x0 /*  0clk */

#define B0_Tah    0x0 /*  0clk */

#define B0_Tacp    0x0

#define B0_PMC    0x0 /* normal */

;bank1寄存器

/* BANK1CON */

#define B1_Tacs    0x0 /*  0clk */

#define B1_Tcos    0x0 /*  0clk */

#define B1_Tacc    0x7 /* 14clk */

#define B1_Tcoh    0x0 /*  0clk */

#define B1_Tah    0x0 /*  0clk */

#define B1_Tacp    0x0

#define B1_PMC    0x0

;bank2寄存器

#define B2_Tacs    0x0

#define B2_Tcos    0x0

#define B2_Tacc    0x7

#define B2_Tcoh    0x0

#define B2_Tah    0x0

#define B2_Tacp    0x0

#define B2_PMC    0x0

;bank3寄存器

#define B3_Tacs    0x0 /*  0clk */

#define B3_Tcos    0x3 /*  4clk */

#define B3_Tacc    0x7 /* 14clk */

#define B3_Tcoh    0x1 /*  1clk */

#define B3_Tah    0x0 /*  0clk */

#define B3_Tacp    0x3     /*  6clk */

#define B3_PMC    0x0 /* normal */

;bank4寄存器

#define B4_Tacs    0x0 /*  0clk */

#define B4_Tcos    0x0 /*  0clk */

#define B4_Tacc    0x7 /* 14clk */

#define B4_Tcoh    0x0 /*  0clk */

#define B4_Tah    0x0 /*  0clk */

#define B4_Tacp    0x0

#define B4_PMC    0x0 /* normal */

;bank5寄存器

#define B5_Tacs    0x0 /*  0clk */

#define B5_Tcos    0x0 /*  0clk */

#define B5_Tacc    0x7 /* 14clk */

#define B5_Tcoh    0x0 /*  0clk */

#define B5_Tah    0x0 /*  0clk */

#define B5_Tacp    0x0

#define B5_PMC    0x0 /* normal */

;bank6寄存器

#define B6_MT    0x3 /* SDRAM */

#define B6_Trcd     0x1

#define B6_SCAN    0x1 /* 9bit */

;bank7寄存器

#define B7_MT    0x3 /* SDRAM */

#define B7_Trcd    0x1 /* 3clk */

#define B7_SCAN    0x1 /* 9bit */

/* REFRESH parameter */

#define REFEN    0x1 /* Refresh enable */

#define TREFMD    0x0 /* CBR(CAS before RAS)/Auto refresh */

#define Trp    0x0 /* 2clk */

#define Trc    0x3 /* 7clk */

#define Tchr    0x2 /* 3clk */

#define REFCNT    1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */

/**************************************/

_TEXT_BASE:

.word TEXT_BASE

.globl lowlevel_init

lowlevel_init:

/* memory control configuration */

/* make r0 relative the current location so that it */

/* reads SMRDATA out of FLASH rather than memory ! */

ldr     r0, =SMRDATA

ldr r1, _TEXT_BASE

sub r0, r0, r1

ldr r1, =BWSCON /* Bus Width Status Controller */

add     r2, r0, #13*4

/*added by kyle*/

lmov  r3,pc

lldr  r4,=0x3FFF0000

land  r3,r3,r4

laad  r0,r0,r3

ladd  r2,r2,r3

0:

ldr     r3, [r0], #4

str     r3, [r1], #4

cmp     r2, r0

bne     0b

/* everything is fine now */

mov pc, lr

.ltorg

/* the literal pools origin */

SMRDATA:

.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))

.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))

.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))

.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))

.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))

.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))

.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))

.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))

.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))

.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)

.word 0x32

.word 0x30

.word 0x30

;定义函数指针

typedef int (init_fnc_t) (void);

;定义函数指针数组,对硬件初始化按照该数组进行

init_fnc_t *init_sequence[] = {

cpu_init,  //cpu/arm920t/cpu.c中定义,该函数为空,因为没有采用IRQ或FIQ模式

board_init,  //board/smdk2410/smdk2410.c

interrupt_init,  //cpu/arm920t/s3c24x0/interrupt.c

env_init,  //tools/env/FW_env.c

init_baudrate,  //lib_arm/board.c

serial_init,  //cpu/arm920t/s3c24x0/serial.c

console_init_f,  //common/console.c

display_banner,  //lib_arm/board.c

#if defined(CONFIG_DISPLAY_CPUINFO)

print_cpuinfo,  //

#endif

#if defined(CONFIG_DISPLAY_BOARDINFO)

checkboard,  //

#endif

dram_init,  //board/smdk2410/smdk2410.c

display_dram_config,//lib_arm/board.c

NULL,

};

int board_init (void)

{

;将时间相关的寄存器定义为结构体S3C24X0_CLOCK_POWER,S3C24X0_GPIO也是一样

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

;设置cpu时钟

/* to reduce PLL lock time, adjust the LOCKTIME register */

clk_power->LOCKTIME = 0xFFFFFF;

/* configure MPLL */

//M_MDIV=0xA1,M_PDIV=0x3,M_SDIV=0x1

//这样系统时钟为202.80M

clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);

/* some delay between MPLL and UPLL */

delay (4000);

;USB时钟为48M

/* configure UPLL */

clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);

/* some delay between MPLL and UPLL */

delay (8000);

;设置GPIO

/* set up the I/O ports */

gpio->GPACON = 0x007FFFFF;

gpio->GPBCON = 0x00044555;

gpio->GPBUP = 0x000007FF;

gpio->GPCCON = 0xAAAAAAAA;

gpio->GPCUP = 0x0000FFFF;

gpio->GPDCON = 0xAAAAAAAA;

gpio->GPDUP = 0x0000FFFF;

gpio->GPECON = 0xAAAAAAAA;

gpio->GPEUP = 0x0000FFFF;

gpio->GPFCON = 0x000055AA;

gpio->GPFUP = 0x000000FF;

gpio->GPGCON = 0xFF95FFBA;

gpio->GPGUP = 0x0000FFFF;

gpio->GPHCON = 0x002AFAAA;

gpio->GPHUP = 0x000007FF;

;初始化bd结构体中的bi_arch_number和bi_boot_params

/* arch number of SMDK2410-Board */

gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

/* adress of boot parameters */

gd->bd->bi_boot_params = 0x30000100;

;启用指令和数据cache

;通过对协处理器的操作了实现cache的使能

icache_enable();

dcache_enable();

return 0;

}

int interrupt_init (void)

{

;获取计时控制寄存器

S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();

;使用PWM定时器4

/* use PWM Timer 4 because it has no output */

/* prescaler for Timer 4 is 16 */

timers->TCFG0 = 0x0f00;

if (timer_load_val == 0)

{

/*

* for 10 ms clock period @ PCLK with 4 bit divider = 1/2

* (default) and prescaler = 16. Should be 10390

* @33.25MHz and 15625 @ 50 MHz

*/

timer_load_val = get_PCLK()/(2 * 16 * 100);

}

/* load value for 10 ms timeout */

lastdec = timers->TCNTB4 = timer_load_val;

/* auto load, manual update of Timer 4 */

timers->TCON = (timers->TCON & ~0x0700000) | 0x600000;

/* auto load, start Timer 4 */

timers->TCON = (timers->TCON & ~0x0700000) | 0x500000;

timestamp = 0;

return (0);

}

static int env_init (void)

{

int crc1, crc1_ok;

uchar *addr1;

int crc2, crc2_ok;

uchar flag1, flag2, *addr2;

//解析参数,定义了两个envdev_t型变量

//typedef struct envdev_s {

//uchar devname[16];  /* Device name */

//ulong devoff;   /* Device offset */

//ulong env_size;   /* environment size */

//ulong erase_size;  /* device erase size */

//} envdev_t;

//程序中定义了/dev/mtd1和/dev/mtd2两个,parse_config函数用来初始化这两个结构体,并利用stat函数

//初始化一个struct stat结构体

if (parse_config ())  /* should fill envdevices */

return 1;

//为参数分配空间,ENV_SIZE=CFG_ENV_SIZE - ENV_HEADER_SIZE=0x10000-sizeof(unsigned long)

if ((addr1 = calloc (1, ENV_SIZE)) == NULL) {

fprintf (stderr,

"Not enough memory for environment (%ld bytes)n",

ENV_SIZE);

return (errno);

}

//从flash中读取参数

//typedef struct environment_s {

//ulong crc;   /* CRC32 over data bytes    */

//uchar flags;   /* active or obsolete */

//uchar *data;

//} env_t;

/* read environment from FLASH to local buffer */

//确定其指针

environment.data = addr1;

curdev = 0;

;该函数用来将旧的参数从flash中擦除,然后将新的参数写入flash

if (flash_io (O_RDONLY)) {

return (errno);

}

;进行crc校验

crc1_ok = ((crc1 = crc32 (0, environment.data, ENV_SIZE))

== environment.crc);

if (!HaveRedundEnv) {

if (!crc1_ok) {

fprintf (stderr,

"Warning: Bad CRC, using default environmentn");

memcpy(environment.data, default_environment, sizeof default_environment);

}

} else {

flag1 = environment.flags;

curdev = 1;

if ((addr2 = calloc (1, ENV_SIZE)) == NULL) {

fprintf (stderr,

"Not enough memory for environment (%ld bytes)n",

ENV_SIZE);

return (errno);

}

environment.data = addr2;

if (flash_io (O_RDONLY)) {

return (errno);

}

crc2_ok = ((crc2 = crc32 (0, environment.data, ENV_SIZE))

== environment.crc);

flag2 = environment.flags;

if (crc1_ok && !crc2_ok) {

environment.data = addr1;

environment.flags = flag1;

environment.crc = crc1;

curdev = 0;

free (addr2);

} else if (!crc1_ok && crc2_ok) {

environment.data = addr2;

environment.flags = flag2;

environment.crc = crc2;

curdev = 1;

free (addr1);

} else if (!crc1_ok && !crc2_ok) {

fprintf (stderr,

"Warning: Bad CRC, using default environmentn");

memcpy(environment.data, default_environment, sizeof default_environment);

curdev = 0;

free (addr1);

} else if (flag1 == active_flag && flag2 == obsolete_flag) {

environment.data = addr1;

environment.flags = flag1;

environment.crc = crc1;

curdev = 0;

free (addr2);

} else if (flag1 == obsolete_flag && flag2 == active_flag) {

environment.data = addr2;

environment.flags = flag2;

environment.crc = crc2;

curdev = 1;

free (addr1);

} else if (flag1 == flag2) {

environment.data = addr1;

environment.flags = flag1;

environment.crc = crc1;

curdev = 0;

free (addr2);

} else if (flag1 == 0xFF) {

environment.data = addr1;

environment.flags = flag1;

environment.crc = crc1;

curdev = 0;

free (addr2);

} else if (flag2 == 0xFF) {

environment.data = addr2;

environment.flags = flag2;

environment.crc = crc2;

curdev = 1;

free (addr1);

}

}

return (0);

}

//如果参数中设置了波特率则利用参数用设置的波特率,否则利用默认的CONFIG_BAUDRATE(115200)

static int init_baudrate (void)

{

char tmp[64]; /* long enough for environment variables */

int i = getenv_r ("baudrate", tmp, sizeof (tmp));

gd->bd->bi_baudrate = gd->baudrate = (i > 0)

? (int) simple_strtoul (tmp, NULL, 10)

: CONFIG_BAUDRATE;

return (0);

}

int serial_init (void)

{

//该函数设置uart的几个寄存器,包括FIFO寄存器、控制寄存器、列控制寄存器和波特率约数寄存器等

serial_setbrg ();

return (0);

}

;设置gd->have_console

int console_init_f (void)

{

gd->have_console = 1;

#ifdef CONFIG_SILENT_CONSOLE

if (getenv("silent") != NULL)

gd->flags |= GD_FLG_SILENT;

#endif

return (0);

}

//打印当前一些状态信息

static int display_banner (void)

{

printf ("nn%snn", version_string);

debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lXn",

_armboot_start, _bss_start, _bss_end);

#ifdef CONFIG_MODEM_SUPPORT

debug ("Modem Support enabledn");

#endif

#ifdef CONFIG_USE_IRQ

debug ("IRQ Stack: %08lxn", IRQ_STACK_START);

debug ("FIQ Stack: %08lxn", FIQ_STACK_START);

#endif

return (0);

}

//初始化ram信息,设置起始地址和大小,从include/configs/smdk2410.h中获取这些信息

int dram_init (void)

{

gd->bd->bi_dram[0].start = PHYS_SDRAM_1;

gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

return 0;

}

//显示ram信息,其中的宏也是从include/configs/smdk2410.h中读取

static int display_dram_config (void)

{

int i;

#ifdef DEBUG

puts ("RAM Configuration:n");

for(i=0; iprintf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);

print_size (gd->bd->bi_dram[i].size, "n");

}

#else

ulong size = 0;

for (i=0; isize += gd->bd->bi_dram[i].size;

}

puts("DRAM:  ");

print_size(size, "n");

#endif

return (0);

}

//以上都是一些初始化的函数,可以看出以上这些函数都是为了初始化一个全局的结构体变量gd而执行的,

//该变量地址由寄存器r8指向,该结构体定义了开发板的相关硬件配置,在include/asm-arm/global_data.h中

//定义

/*

typedef struct global_data {

bd_t  *bd;//开发板参数

unsigned long flags;

unsigned long baudrate;

unsigned long have_console; /* serial_init() was called */

unsigned long reloc_off; /* Relocation Offset */

unsigned long env_addr; /* Address  of Environment struct */

unsigned long env_valid; /* Checksum of Environment valid? */

unsigned long fb_base; /* base address of frame buffer */

#ifdef CONFIG_VFD

unsigned char vfd_type; /* display type */

#endif

#if 0

unsigned long cpu_clk; /* CPU clock in Hz!  */

unsigned long bus_clk;

unsigned long ram_size; /* RAM size */

unsigned long reset_status; /* reset status register at boot */

#endif

void  **jt;  /* jump table */

} gd_t;

*/

void start_armboot (void)

{

init_fnc_t **init_fnc_ptr;

char *s;

#ifndef CFG_NO_FLASH

ulong size;

#endif

#if defined(CONFIG_VFD) || defined(CONFIG_LCD)

unsigned long addr;

#endif

/* Pointer is writable since we allocated a register for it */

//获取全局gd指针

gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

/* compiler optimization barrier needed for GCC >= 3.4 */

__asm__ __volatile__("": : :"memory");

//清空该结构体

memset ((void*)gd, 0, sizeof (gd_t));

//获取bd_info结构体指针

gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

memset (gd->bd, 0, sizeof (bd_t));

//整个代码区的长度

monitor_flash_len = _bss_start - _armboot_start;

//调用初始化函数,用来初始化gd结构体

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

if ((*init_fnc_ptr)() != 0) {

hang ();

}

}

#ifndef CFG_NO_FLASH

/* configure available FLASH banks */

//board/smdk2410/flash.c配置flash

//从其实现来看,好像只是配置nor flash

size = flash_init ();

//显示flash信息

display_flash_config (size);

#endif /* CFG_NO_FLASH */

//定义显示类型

#ifdef CONFIG_VFD

# ifndef PAGE_SIZE

#   define PAGE_SIZE 4096

# endif

/*

* reserve memory for VFD display (always full pages)

*/

/* bss_end is defined in the board-specific linker script */

//按页对其方式保留显存

addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

size = vfd_setmem (addr);

gd->fb_base = addr;

#endif /* CONFIG_VFD */

//显示器为LCD,同上

#ifdef CONFIG_LCD

# ifndef PAGE_SIZE

#   define PAGE_SIZE 4096

# endif

/*

* reserve memory for LCD display (always full pages)

*/

/* bss_end is defined in the board-specific linker script */

addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

size = lcd_setmem (addr);

gd->fb_base = addr;

#endif /* CONFIG_LCD */

//初始化CFG_MALLOC_LEN大小空间

/* armboot_start is defined in the board-specific linker script */

mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

//初始化nand flash,这是在nand flash启动的s3c2410移植u-boot的关键,根据flash时序编写函数即可

//在include/configs/smdk2410.h中的command definition中增加CONFIG_COMMANDS和CFG_CMD_NAND命令

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

puts ("NAND:  ");

nand_init();  //board/smdk2410/smdk2410.c

#endif

#ifdef CONFIG_HAS_DATAFLASH

AT91F_DataflashInit();

dataflash_print_info();

#endif

/* initialize environment */

//初始化环境参数

env_relocate ();

//framebuffer初始化

#ifdef CONFIG_VFD

/* must do this after the framebuffer is allocated */

drv_vfd_init();

#endif /* CONFIG_VFD */

//通过命令行参数传递获取ip地址

/* IP Address */

gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

//通过命令行参数传递获取物理地址

/* MAC Address */

{

int i;

ulong reg;

char *s, *e;

char tmp[64];

i = getenv_r ("ethaddr", tmp, sizeof (tmp));

s = (i > 0) ? tmp : NULL;

for (reg = 0; reg < 6; ++reg) {

gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;

if (s)

s = (*e) ? e + 1 : e;

}

#ifdef CONFIG_HAS_ETH1

i = getenv_r ("eth1addr", tmp, sizeof (tmp));

s = (i > 0) ? tmp : NULL;

for (reg = 0; reg < 6; ++reg) {

gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;

if (s)

s = (*e) ? e + 1 : e;

}

#endif

}

//调用相应驱动函数对硬件设备进行初始化

devices_init (); /* get the devices list going. */

#ifdef CONFIG_CMC_PU2

load_sernum_ethaddr ();

#endif /* CONFIG_CMC_PU2 */

jumptable_init ();

//初始化串口

console_init_r (); /* fully init console as a device */

#if defined(CONFIG_MISC_INIT_R)

/* miscellaneous platform dependent initialisations */

misc_init_r ();

#endif

/* enable exceptions */

//启用中断

enable_interrupts ();

/* Perform network card initialisation if necessary */

//初始化网卡

#ifdef CONFIG_DRIVER_CS8900

cs8900_get_enetaddr (gd->bd->bi_enetaddr);

#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)

if (getenv ("ethaddr")) {

smc_set_mac_addr(gd->bd->bi_enetaddr);

}

#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

/* Initialize from environment */

if ((s = getenv ("loadaddr")) != NULL) {

load_addr = simple_strtoul (s, NULL, 16);

}

#if (CONFIG_COMMANDS & CFG_CMD_NET)

if ((s = getenv ("bootfile")) != NULL) {

copy_filename (BootFile, s, sizeof (BootFile));

}

#endif /* CFG_CMD_NET */

#ifdef BOARD_LATE_INIT

board_late_init ();

#endif

#if (CONFIG_COMMANDS & CFG_CMD_NET)

#if defined(CONFIG_NET_MULTI)

puts ("Net:   ");

#endif

eth_initialize(gd->bd);

#endif

/* main_loop() can return to retry autoboot, if so just run it again. */

for (;;) {

main_loop ();

}

/* NOTREACHED - no way out of command loop except booting */

}

//在board/smdk2410/smdk2410.c中增加nand flash初始化代码

/*

* NAND flash initialization.

*/

//在include/s3c24x0.h中由S3C2410_NAND结构体的定义,也就是定义了NFCONF、NFCMD、NFADDR和NFSTAT这四个//寄存器,由于2410有flash控制器,因此可以直接通过flash控制器来对flash器件进行操作,如果芯片没有//flash控制器,有的利用I/O端口来同flash交换数据,就必须利用I/O口来模式时序。比如44B0X就是利用GPIO

//来进行flash读写的

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

typedef enum {

NFCE_LOW,

NFCE_HIGH,

} NFCE_STATE;

extern unsigned long nand_probe(unsigned long physadr);

static inline void NF_Reset(void)

{

int i;

//使能

NF_SetCE(NFCE_LOW);

//写入命令

NF_Cmd(0xFF); // reset command

//延时

for(i = 0; i < 10; i++); // tWB = 100ns.

//通过R/B信号线,判断flash内部操作是否完成,

NF_WaitRB(); // wait 200~500us;

//芯片禁用

NF_SetCE(NFCE_HIGH);

}

static inline void NF_Init(void)

{

#if 0 // a little bit too optimistic

#define TACLS 0

#define TWRPH0 3

#define TWRPH1 0

#else

#define TACLS 0

#define TWRPH0 4

#define TWRPH1 2

#endif

//首先根据NFCONF寄存器的各位定义对Nand flash进行初始化

NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));

NF_Reset();

}

void nand_init(void)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

NF_Init();

//利用drivers/nand_legacy/nand_legacy.c,在该文件中也添加这几个同nand flash相关的函数

printf ("%4lu MBn", nand_probe((ulong)nand) >> 20);

}

//操作控制寄存器,该寄存器为16位寄存器

static  void NF_Conf(u16 conf)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCONF = conf;

}

//flash只有8位的输入、输出端口,直接向命令寄存器赋值即可写入命令

static  void NF_Cmd(u8 cmd)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCMD = cmd;

}

static void NF_CmdW(u8 cmd)

{

NF_Cmd(cmd);

udelay(1);

}

//写入地址

static  void NF_Addr(u8 addr)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFADDR = addr;

}

//芯片使能

static  void NF_SetCE(NFCE_STATE s)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

//Nand flash memroy chip enable,如果NFCONF的第11位为1则nFCE使能,为1则禁止

switch (s) {

case NFCE_LOW:

nand->NFCONF &= ~(1<<11);

break;

case NFCE_HIGH:

nand->NFCONF |= (1<<11);

break;

}

}

//等待flash内部操作完成

static void NF_WaitRB(void)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

while (!(nand->NFSTAT & 0x01));

}

//向数据寄存器写入数据

static  void NF_Write(u8 data)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFDATA = data;

}

//读取数据

static  u8 NF_Read(void)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

return(nand->NFDATA);

}

//校验

static  void NF_Init_ECC(void)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCONF |= (1<<12);

}

//获取ECC code

static  u32 NF_Read_ECC(void)

{

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

return(nand->NFECC);

}

#endif

通过上面的描述要移植U-Boot到s3c2410上,并要从nand flash启动,则需要修改的地方有:

1、在start.S中增加将U-Boot从flash复制到ram中的代码

2、在include/configs/smdk2410.h中增加相关定义,主要是nand flash寄存器的定义,并针对具体平台对其中的参数进行配置,比如ram的大小等。

3、在board/smdk2410/smdk2410.c中增加nand flash的相关操作函数,如复位、写指令、读数据、查看状态等。

再编译U-Boot则可以看到flash的定义,并能通过网络下载内核和文件系统等。

当U-Boot进入main_loop后将等待用户输入,或者在定时时间超过时调用do_bootm_linux来启动linux内核,

U-Boot为各个处理器的do_bootm_linux定义了固定的类型,定义了boot_os_Fcn函数类型。

typedef void boot_os_Fcn (cmd_tbl_t *cmdtp, int flag,

int argc, char *argv[],

ulong addr,  /* of image to boot */

ulong *len_ptr, /* multi-file image length table */

int verify); /* getenv("verify")[0] != 'n' */

cmdtp结构体用来保存命令以及参数,addr为启动镜像的地址,程序首先进入do_bootm函数

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

ulong iflag;

ulong addr;

ulong data, len, checksum;

ulong  *len_ptr;

//定义最大的解压空间为8M

uint unc_len = CFG_BOOTM_LEN;

int i, verify;

char *name, *s;

int (*appl)(int, char *[]);

//镜像文件的头部信息,传递给do_bootm_linux函数

image_header_t *hdr = &header;

s = getenv ("verify");

verify = (s && (*s == 'n')) ? 0 : 1;

//如果没有指定运行地址,则采用默认的地址,该地址在include/configs/smdk2410.h中定义为0x30008000

if (argc < 2) {

addr = load_addr;

} else {

//如果参数中指定了地址,则从指定地址开始运行

addr = simple_strtoul(argv[1], NULL, 16);

}

//在文件开头定义CONFIG_SHOW_BOOT_PROGRESS函数用来显示当前内核运行到哪一步了

SHOW_BOOT_PROGRESS (1);

printf ("## Booting image at %08lx ...n", addr);

//系统中没有atmel的数据flash

/* Copy header so we can blank CRC field for re-calculation */

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash(addr)){

read_dataflash(addr, sizeof(image_header_t), (char *)&header);

} else

#endif

//从镜像读取头部到结构header中

memmove (&header, (char *)addr, sizeof(image_header_t));

//通过头部结构体来获取magic、crc等数据

if (ntohl(hdr->ih_magic) != IH_MAGIC) {

//i386

#ifdef __I386__ /* correct image format not implemented yet - fake it */

//通过头部结构体,检测镜像的格式是否正确

if (fake_header(hdr, (void*)addr, -1) != NULL) {

/* to compensate for the addition below */

addr -= sizeof(image_header_t);

/* turnof verify,

* fake_header() does not fake the data crc

*/

verify = 0;

} else

#endif /* __I386__ */

//对于非i386平台

{

puts ("Bad Magic Numbern");

SHOW_BOOT_PROGRESS (-1);

return 1;

}

}

//magic正确为第2步

SHOW_BOOT_PROGRESS (2);

//校验crc

data = (ulong)&header;

len  = sizeof(image_header_t);

checksum = ntohl(hdr->ih_hcrc);

hdr->ih_hcrc = 0;

if (crc32 (0, (uchar *)data, len) != checksum) {

puts ("Bad Header Checksumn");

SHOW_BOOT_PROGRESS (-2);

return 1;

}

//校验成功为第3步

SHOW_BOOT_PROGRESS (3);

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash(addr)){

len  = ntohl(hdr->ih_size) + sizeof(image_header_t);

read_dataflash(addr, len, (char *)CFG_LOAD_ADDR);

addr = CFG_LOAD_ADDR;

}

#endif

//对于多文件镜像的处理,这个部分是很有用的,特别对于容量很小的系统,有时候需要将代码段和数据段放//在不同的文件中

//显示镜像文件的信息,包括文件大小、创建时间、入口等

print_image_hdr ((image_header_t *)addr);

//data为镜像文件头部后的第1个ulong数据,用来完成crc校验

data = addr + sizeof(image_header_t);

//len为镜像问价的大小

len  = ntohl(hdr->ih_size);

//是否进行crc校验

if (verify) {

puts ("   Verifying Checksum ... ");

if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) {

printf ("Bad Data CRCn");

SHOW_BOOT_PROGRESS (-3);

return 1;

}

puts ("OKn");

}

//校验成功为第4步

SHOW_BOOT_PROGRESS (4);

//数据指针

len_ptr = (ulong *)data;

//校验cpu的体系结构

#if defined(__PPC__)

if (hdr->ih_arch != IH_CPU_PPC)

#elif defined(__ARM__)

if (hdr->ih_arch != IH_CPU_ARM)

#elif defined(__I386__)

if (hdr->ih_arch != IH_CPU_I386)

#elif defined(__mips__)

if (hdr->ih_arch != IH_CPU_MIPS)

#elif defined(__nios__)

if (hdr->ih_arch != IH_CPU_NIOS)

#elif defined(__M68K__)

if (hdr->ih_arch != IH_CPU_M68K)

#elif defined(__microblaze__)

if (hdr->ih_arch != IH_CPU_MICROBLAZE)

#elif defined(__nios2__)

if (hdr->ih_arch != IH_CPU_NIOS2)

#elif defined(__blackfin__)

if (hdr->ih_arch != IH_CPU_BLACKFIN)

#else

# error Unknown CPU type

#endif

{

printf ("Unsupported Architecture 0x%xn", hdr->ih_arch);

SHOW_BOOT_PROGRESS (-4);

return 1;

}

//体系结构校验成功为第5步

SHOW_BOOT_PROGRESS (5);

//判断镜像文件类型

switch (hdr->ih_type) {

//如果是独立的应用程序则利用第2个参数来作为加载地址

case IH_TYPE_STANDALONE:

name = "Standalone Application";

/* A second argument overwrites the load address */

if (argc > 2) {

hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16));

}

break;

//单文件类型内核

case IH_TYPE_KERNEL:

name = "Kernel Image";

break;

//多文件类型内核

case IH_TYPE_MULTI:

name = "Multi-File Image";

//获取内核镜像大小

len  = ntohl(len_ptr[0]);

/* OS kernel is always the first image */

data += 8; /* kernel_len + terminator */

for (i=1; len_ptr[i]; ++i)

data += 4;

break;

default: printf ("Wrong Image Type for %s commandn", cmdtp->name);

SHOW_BOOT_PROGRESS (-5);

return 1;

}

//类型判断成功为第6步

SHOW_BOOT_PROGRESS (6);

/*

* We have reached the point of no return: we are going to

* overwrite all exception vector code, so we cannot easily

* recover from any failures any more...

*/

//关闭所有中断

iflag = disable_interrupts();

//处理cache

#ifdef CONFIG_AMIGAONEG3SE

/*

* We've possible left the caches enabled during

* bios emulation, so turn them off again

*/

icache_disable();

invalidate_l1_instruction_cache();

flush_data_cache();

dcache_disable();

#endif

//判断镜像压缩类型,并利用对应程序对内核压缩镜像进行解压

switch (hdr->ih_comp) {

case IH_COMP_NONE:

if(ntohl(hdr->ih_load) == addr) {

printf ("   XIP %s ... ", name);

} else {

#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)

size_t l = len;

void *to = (void *)ntohl(hdr->ih_load);

void *from = (void *)data;

printf ("   Loading %s ... ", name);

while (l > 0) {

size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;

WATCHDOG_RESET();

memmove (to, from, tail);

to += tail;

from += tail;

l -= tail;

}

#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */

memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */

}

break;

case IH_COMP_GZIP:

printf ("   Uncompressing %s ... ", name);

if (gunzip ((void *)ntohl(hdr->ih_load), unc_len,

(uchar *)data, &len) != 0) {

puts ("GUNZIP ERROR - must RESET board to recovern");

SHOW_BOOT_PROGRESS (-6);

do_reset (cmdtp, flag, argc, argv);

}

break;

#ifdef CONFIG_BZIP2

case IH_COMP_BZIP2:

printf ("   Uncompressing %s ... ", name);

/*

* If we've got less than 4 MB of malloc() space,

* use slower decompression algorithm which requires

* at most 2300 KB of memory.

*/

i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load),

&unc_len, (char *)data, len,

CFG_MALLOC_LEN < (4096 * 1024), 0);

if (i != BZ_OK) {

printf ("BUNZIP2 ERROR %d - must RESET board to recovern", i);

SHOW_BOOT_PROGRESS (-6);

udelay(100000);

do_reset (cmdtp, flag, argc, argv);

}

break;

#endif /* CONFIG_BZIP2 */

default:

//重新打开中断

if (iflag)

enable_interrupts();

//不能识别的压缩类型

printf ("Unimplemented compression type %dn", hdr->ih_comp);

SHOW_BOOT_PROGRESS (-7);

return 1;

}

puts ("OKn");

//解压成功为第7步

SHOW_BOOT_PROGRESS (7);

//如果是独立的应用程序,则根据autostart来确定是否自动启动程序

switch (hdr->ih_type) {

case IH_TYPE_STANDALONE:

if (iflag)

enable_interrupts();

/* load (and uncompress), but don't start if "autostart"

* is set to "no"

*/

if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) {

char buf[32];

sprintf(buf, "%lX", len);

setenv("filesize", buf);

return 0;

}

//hdr->ih_ep为程序的入口

appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);

//启动程序

(*appl)(argc-1, &argv[1]);

return 0;

case IH_TYPE_KERNEL:

case IH_TYPE_MULTI:

/* handled below */

break;

default:

if (iflag)

enable_interrupts();

printf ("Can't boot image type %dn", hdr->ih_type);

SHOW_BOOT_PROGRESS (-8);

return 1;

}

//成功为第8步

SHOW_BOOT_PROGRESS (8);

//判断操作系统类型

switch (hdr->ih_os) {

default:   /* handled by (original) Linux case */

case IH_OS_LINUX:

#ifdef CONFIG_SILENT_CONSOLE

fixup_silent_linux();

#endif

printf("boot linuxn");

//进入armlinux.c中的do_bootm_linux函数

do_bootm_linux  (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

case IH_OS_NETBSD:

do_bootm_netbsd (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#ifdef CONFIG_LYNXKDI

case IH_OS_LYNXOS:

do_bootm_lynxkdi (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#endif

case IH_OS_RTEMS:

do_bootm_rtems (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#if (CONFIG_COMMANDS & CFG_CMD_ELF)

case IH_OS_VXWORKS:

do_bootm_vxworks (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

case IH_OS_QNX:

do_bootm_qnxelf (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#endif /* CFG_CMD_ELF */

#ifdef CONFIG_ARTOS

case IH_OS_ARTOS:

do_bootm_artos  (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#endif

}

SHOW_BOOT_PROGRESS (-9);

#ifdef DEBUG

puts ("n## Control returned to monitor - resetting...n");

do_reset (cmdtp, flag, argc, argv);

#endif

return 1;

}

进入文件lib_arm/arm_linux.c中的do_bootm_linux

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

ulong addr, ulong *len_ptr, int verify)

{

ulong len = 0, checksum;

ulong initrd_start, initrd_end;

ulong data;

//内核调用入口

void (*theKernel)(int zero, int arch, uint params);

//获取镜像的头部信息,header在cmd_bootm.c中定义

image_header_t *hdr = &header;

//获取开发板信息

bd_t *bd = gd->bd;

#ifdef CONFIG_CMDLINE_TAG

//获取bootargs参数

char *commandline = getenv ("bootargs");

#endif

//调用内核入口函数,将内核入口函数指针赋给theKernel

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

/*

* Check if there is an initrd image

*/

//看是否为initrd镜像

if (argc >= 3) {

//如果为initrd为第9步

SHOW_BOOT_PROGRESS (9);

//获取initrd镜像地址

addr = simple_strtoul (argv[2], NULL, 16);

printf ("## Loading Ramdisk Image at %08lx ...n", addr);

/* Copy header so we can blank CRC field for re-calculation */

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash (addr)) {

read_dataflash (addr, sizeof (image_header_t),

(char *) &header);

} else

#endif

//获取initrd头部西你想

memcpy (&header, (char *) addr,

sizeof (image_header_t));

//校验magic

if (ntohl (hdr->ih_magic) != IH_MAGIC) {

printf ("Bad Magic Numbern");

SHOW_BOOT_PROGRESS (-10);

do_reset (cmdtp, flag, argc, argv);

}

//校验crc

data = (ulong) & header;

len = sizeof (image_header_t);

checksum = ntohl (hdr->ih_hcrc);

hdr->ih_hcrc = 0;

if (crc32 (0, (unsigned char *) data, len) != checksum) {

printf ("Bad Header Checksumn");

SHOW_BOOT_PROGRESS (-11);

do_reset (cmdtp, flag, argc, argv);

}

//校验成功为第10步

SHOW_BOOT_PROGRESS (10);

print_image_hdr (hdr);

data = addr + sizeof (image_header_t);

len = ntohl (hdr->ih_size);

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash (addr)) {

read_dataflash (data, len, (char *) CFG_LOAD_ADDR);

data = CFG_LOAD_ADDR;

}

#endif

//checksum

if (verify) {

ulong csum = 0;

printf ("   Verifying Checksum ... ");

csum = crc32 (0, (unsigned char *) data, len);

if (csum != ntohl (hdr->ih_dcrc)) {

printf ("Bad Data CRCn");

SHOW_BOOT_PROGRESS (-12);

do_reset (cmdtp, flag, argc, argv);

}

printf ("OKn");

}

//成功为第11步

SHOW_BOOT_PROGRESS (11);

//判断操作系统类型

if ((hdr->ih_os != IH_OS_LINUX) ||

(hdr->ih_arch != IH_CPU_ARM) ||

(hdr->ih_type != IH_TYPE_RAMDISK)) {

printf ("No Linux ARM Ramdisk Imagen");

SHOW_BOOT_PROGRESS (-13);

do_reset (cmdtp, flag, argc, argv);

}

#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)

/*

*we need to copy the ramdisk to SRAM to let Linux boot

*/

memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

data = ntohl(hdr->ih_load);

#endif /* CONFIG_B2 || CONFIG_EVB4510 */

/*

* Now check if we have a multifile image

*/

}

//判断是否为多文件内核镜像

else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {

ulong tail = ntohl (len_ptr[0]) % 4;

int i;

SHOW_BOOT_PROGRESS (13);

/* skip kernel length and terminator */

data = (ulong) (&len_ptr[2]);

/* skip any additional image length fields */

for (i = 1; len_ptr[i]; ++i)

data += 4;

/* add kernel length, and align */

data += ntohl (len_ptr[0]);

if (tail) {

data += 4 - tail;

}

len = ntohl (len_ptr[1]);

} else {

/*

* no initrd image

*/

//无initrd镜像

SHOW_BOOT_PROGRESS (14);

len = data = 0;

}

#ifdef DEBUG

if (!data) {

printf ("No initrdn");

}

#endif

//确定initrd的起始地址和终止地址

if (data) {

initrd_start = data;

initrd_end = initrd_start + len;

} else {

initrd_start = 0;

initrd_end = 0;

}

//成功为第15步

SHOW_BOOT_PROGRESS (15);

//进入linux内核

debug ("## Transferring control to Linux (at address %08lx) ...n",

(ulong) theKernel);

#if defined (CONFIG_SETUP_MEMORY_TAGS) ||

defined (CONFIG_CMDLINE_TAG) ||

defined (CONFIG_INITRD_TAG) ||

defined (CONFIG_SERIAL_TAG) ||

defined (CONFIG_REVISION_TAG) ||

defined (CONFIG_LCD) ||

defined (CONFIG_VFD)

//开始设置启动参数,该函数也在本文件中定义,见下面

setup_start_tag (bd);

#ifdef CONFIG_SERIAL_TAG

//设置串口参数

setup_serial_tag (&params);

#endif

#ifdef CONFIG_REVISION_TAG

//设置修订参数

setup_revision_tag (&params);

#endif

#ifdef CONFIG_SETUP_MEMORY_TAGS

//设置内存参数

setup_memory_tags (bd);

#endif

#ifdef CONFIG_CMDLINE_TAG

//设置命令行参数

setup_commandline_tag (bd, commandline);

#endif

#ifdef CONFIG_INITRD_TAG

//设置initrd参数

if (initrd_start && initrd_end)

setup_initrd_tag (bd, initrd_start, initrd_end);

#endif

#if defined (CONFIG_VFD) || defined (CONFIG_LCD)

//设置vfd、lcd参数

setup_videolfb_tag ((gd_t *) gd);

#endif

//结束参数设置

setup_end_tag (bd);

#endif

//启动内核

/* we assume that the kernel is in place */

printf ("nStarting kernel ...nn");

#ifdef CONFIG_USB_DEVICE

{

extern void udc_disconnect (void);

udc_disconnect ();

}

#endif

//在内核启动前的清除工作

cleanup_before_linux ();

//调用内核

theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

}

//开始设置启动参数

static void setup_start_tag (bd_t *bd)

{

params = (struct tag *) bd->bi_boot_params;

params->hdr.tag = ATAG_CORE;

params->hdr.size = tag_size (tag_core);

params->u.core.flags = 0;

params->u.core.pagesize = 0;

params->u.core.rootdev = 0;

params = tag_next (params);

}

php wecp 启动_U-boot启动详解相关推荐

  1. [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装、启动及PXE理论详解

    本篇blog主要讲述了[PXE] linux(centos)PXE无盘服务器搭建,安装,启动及pxe协议详解 , Kickstart (PXE+DHCP+TFTP+HTTP). PXE环境概述 作为中 ...

  2. Linux_arm_启动_c语言部分详解,[原创]Linux arm 启动 c语言部分详解第四讲

    Linux arm启动c语言部分详解第四讲(from setup_per_cpu_areas();) Written by leeming 上面的setup_arch花了我们大量的篇幅,现在我们要继续 ...

  3. U盘启动安装Ubuntu16.04详解

    U盘启动安装Ubuntu16.04详解 一.制作U盘启动Ubuntu16.04镜像文件 把"隐藏启动分区"(红色区域)设置为高级隐藏后烧制的系统盘会把U盘切分成两个分区,如下图: ...

  4. oracle如何启动和停止服务,CentOS启动和停止服务详解

    CentOS启动和停止服务详解 服务简介 Linux 系统服务是在Linux启 动时自动加载, 服务的添加.删除.自动运行及状态 CAMS 在安装过程中会自动添加相关的服务,例如: service c ...

  5. 怎么打开python shell_Python之使用adb shell命令启动应用的方法详解

    一直有一个心愿希望可以用Python做安卓自动化功能测试,在一步步摸索中,之前是用monkeyrunner,但是发现对于控件ID的使用非常具有局限性,尤其是ID的内容不便于区分 具有重复性时,后面又发 ...

  6. python调用adb shell命令_Python之使用adb shell命令启动应用的方法详解

    Python之使用adb shell命令启动应用的方法详解 一直有一个心愿希望可以用Python做安卓自动化功能测试,在一步步摸索中,之前是用monkeyrunner,但是发现对于控件ID的使用非常具 ...

  7. centos终止linux程序,CentOS启动和停止服务详解

    CAMS 在安装过程中, 1. 添加服务 添加服务的步骤为: (1) 将该服务的脚本文件拷入/etc/rc.d/init.d 文件夹下,例如: service camsd stop 停止 camsd ...

  8. 各版本VOS服务的停止、启动和重启命令详解

    各版本VOS服务的停止.启动和重启命令详解 V2.1.6.00 ~ V2.1.8.05 版本 -服务停止 /etc/init.d/vos3000d stop/etc/init.d/mbx3000d s ...

  9. spring boot配置文件详解

    spring boot配置文件详解 application.properties是spring-boot的核心配置文件,这个配置文件基本可以取代我们ssm或者ssh里面的所有的xml配置文件. 当我们 ...

  10. 《深入理解 Spring Cloud 与微服务构建》第十六章 Spring Boot Security 详解

    <深入理解 Spring Cloud 与微服务构建>第十六章 Spring Boot Security 详解 文章目录 <深入理解 Spring Cloud 与微服务构建>第十 ...

最新文章

  1. C#Winform版获取Excel文件的内容
  2. ubuntu 14.04下 horizon openstack_dashboard 的开发环境搭建
  3. VMWare虚拟机转换成KVM
  4. how does UI Framework get url of detail page - _router
  5. 运算放大器基本公式_运算放大器 - 产生的背景和解决的问题
  6. 单片机led闪烁代码_单片机驱动LED发光二极管的电路以及编程
  7. 《转》python学习(7) -列表
  8. LC-3 汇编语言 指令集
  9. 数模电路基础知识 —— 4. 常见电路符号说明(二极管)
  10. 中兴f460光猫资料
  11. 平均值绝对偏差最大c语言,请教平均值和最大偏差值得使用
  12. 海湾gst5000主机消防广播_海湾消防主机JB-QG_T-GST5000_JB-QB-GST500控制器说明书.doc
  13. 在线音乐网站毕业设计
  14. 利用openpose跑关键点
  15. android 支持最低版本是多少g,手机需要多少G的运行内存,才真正够用?
  16. 基于layui图片管理器
  17. cocos《破碎骑士》开发日志
  18. 牛客网嵌入式软件工程师面试题(一)
  19. 学生信息结构体数组拷贝和排序(结构体,结构体数组,结构体指针)
  20. Android 定位的实现

热门文章

  1. 20200705每日一句
  2. 德国铁路公司基于模型的铁路系统设计路线图 - 基于模型的系统开发在铁路部门的应用
  3. Atitit 可读性的艺术 目录 1. 原则类 1 2. 方法类 2 2.1. 1.8. 选择选择表格化 3 2 2.2. 体现了“声明式编程”的风格,即只要说明意图,而不需要写出处理细节。 2 2
  4. Atitit 调试工具模块 保存序列化map参数 mybatis调试sql selectid 查看mybatis真实sql 1.1. 对象序列化功能 序列化为bytearr 文件等 1 1.2.
  5. atitit.http原理与概论attilax总结
  6. 货币基金新规将出,限制T+0提现及支付额度
  7. 摆动定价机制连载系列之推出背景及工作原理介绍
  8. 知乎:学习分布式系统需要怎样的知识?
  9. 「转发领抱枕」40万奖金等你来挑战!阿里云ECS Cloudbuild开发者大赛重磅开启
  10. 开放、创新、合作,共赢多样性计算新时代