每日一贴,今天的容内关键字为地址代码
/arch/arm920t/cpu/start.s件文就是uboot的第一阶段,uboot的前4K容内,即nandflash中的前4K容内会被拷贝到cpu中的SRAM中运行,这一小段代码担任初始化硬件环境,并将残余的Uboot代码加载到内存中去。从而跳到转第二阶段,在第二阶段运行之前要需建立栈堆。
IRQ_STACK_START .word 0x0badc0de
FRQ_STACK_START .word 0x0badc0de
/*
* armboot - Startup Code for ARM920 CPU-core
*
*/
#include <config.h>
#include <version.h>
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start
_start: b reset //b是跳转指令,即跳到转reset标签处。接着返回到此处。
ldr pc, _undefined_instruction置设断中向量表 0x0 0x4.....0x8 0xc
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
利用.word来在以后位置放置一个值,这个值实际上就用对应的断中理处函数的地址
;.word的义意为在以后地址处放入一个16bits值
.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 //从英文注释中可以看出starts.o的作用。
*
*************************************************************************
*/
_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
*/
_start:入口处,马上跳到转reset处,在SVC状态下要关闭有所断中。
reset:
/*
* set the cpu to SVC32 mode //超等用户态,操纵统系用使的保护模式。统系复位和软件断中时进入该模式。
*/
mrs r0,cpsr //将以后cpsr的状态为保存到r0中。
bic r0,r0,#0x1f //bic,位清零指令。0x1f=00011111,相当于清除低5位。刚好是模式位。
orr r0,r0,#0xd3 //或指令。很明显是置模式位。0xd3=11010011以及置设5,6,7位的状态位。制止FIQ,IRQ,处于arm状态。低5位为10011,则对应超等用户态。
msr cpsr,r0 //在将r0中的值赋给状态寄存器cpsr
/* 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)我们的是2410,如果移植其它的,则可以添加关相的基地址
# define pWTCON 0x53000000 //pWTCON 看门狗寄存器的基地址,手册上就是WTCON,这里多一个p
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C 断中子掩码寄存器
# define CLKDIVN 0x4C000014 /* clock divisor register */
#endif
将看门狗寄存器清空,其各位含意为,第0位为1则当看门狗定时器溢出时重启,为0则不重启,初始值为1
第2位为断中使能位,初值为0
第3,4位为时钟频分银子,初值为00
第5位为看门狗的使能位,初值为1
第8~15位为比例因子,初值为0x80
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON //将pWTCON寄存器的地址赋给r0
mov r1, #0x0
str r1, [r0] //将pWTCON有所位置为0,就关闭看门狗了,实际上只要将第5位置0可即。
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK //蔽屏有所的断中
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x7ff 011111111111,很多料资上是0x3ff。手册上定规有13位可用
ldr r0, =INTSUBMSK如果是2410,这个寄存器也要蔽屏
str r1, [r0] //将低13位全都置1 13位可用 而不是12位
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* 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!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT 避免重复用引cpu_init_crit函数。
bl cpu_init_crit
#endif
橙色的分部代码,是针对从nor flash中启动的设备。对于不是从nandflash中启动的设备,没什么用。这一段似乎也能行执代码制复.
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
查看以后代码的地址信息,若从ram中运行,则_start=_TEXT_BASE,否则_start = 0x00000000
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup 若相称,则建立栈堆
ldr r2, _armboot_start 若不等,则表现从flash中运行,重定向代码
ldr r3, _bss_start 获得未初始化数据段地址
sub r2, r3, r2 /* r2 <- size of armboot */代码段的度长
add r2, r0, r2 /* r2 <- source end address */代码的度长
copy_loop:
制复代码,r0为代码的始起地址,r1为ram中地址,r2为代码的终止地址,每次copy后将r0的值递增同r2较比来判断是不是制复成完。
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:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area 192K */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo 配分128节字来存储开发板信息 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif再减去12节字用于栈点起
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
当初的设别,大都是利用SDRAM与NANDFLASH独特作用,因此为了支撑能从nand_flash中启动,要需添加面下的红色代码。
#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
on_the_ram
#endif
ldr pc, _start_armboot
_start_armboot: .word start_armboot
#ifdef CONFIG_S3C2410_NAND_BOOT
copy_myself:
mov r10.lr 将以后的lr保存到r10中,保存断点地址
@reset nand
mov r1,#NAND_CTL_BASE nandflash基地址
ldr r2,0xf830 r2 = 1111,1000,0011,0000 第15位为nandflash控制器使能位,第12位初始化ECC,第11位nFCE使能?????有问题
str r2,[r1,#oNFCONF]
ldr r2,[r1,#oNFCONF]
bic r2,r2,#0x800 将第11位清零指令,使能片芯
str r2,[r1,#oNFCONF]
写入令命
mov r2,#0xff @reset command
strb r2,[r1,#oNFCMD]
mov r3,#0
1:
add r3, r3, #0x1
//
循环等待
cmp r3, #0xa
blt 1b
2:
利用状态寄存器试测flash部内操纵是不是成完,如果成完则状态寄存器将返回1.NFSTAT最后位一为0时,表现正在忙,为1表现闲暇
ldr r2, [r1, #oNFSTAT]
@ wait ready
tst r2, #0x1
//tst
位试测指令
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
。r0 r1 r2为传入到Nand_read_ll中的三个参数,
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
可知,
ldr r0, =UBOOT_RAM_BASE
mov r1, #0x0
//mov r2, #0x20000 //UBOOT
巨细为128K 这三个参数传入到nand_read_ll中
mov r2. #0x30000
//
置设为192k。
bl nand_read_ll
tst r0, #0x0
r0
为返回值nand_read_ll的返回值
beq ok_nand_read
bad_nand_read:
loop2: b loop2 @ infinite loop
ok_nand_read:
nand_flash
通过ecc验校来保障拷贝到SDRAM中的容内是确正的
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400
@ 4 bytes * 1024 = 4K-bytes
,每条指令占4个节字,共挪动0x400即1024次,加起来就挪动了4*1024即4K的巨细
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 @ CONFIG_S3C2410_NAND_BOOT
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu的置设,楚清I/D cache,清除TLB
cpu_init_crit:
/*
* flush v4 I/D 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.
*/
mov ip, lr //返回到reset
bl lowlevel_init
mov lr, ip
mov pc, lr //从lowlevel_init中,返回到reset
#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
文章结束给大家分享下程序员的一些笑话语录: 腾讯总舵主马化腾,有人曾经戏称如果在Z国选举总统,马化腾一定当选,因为只要QQ来一个弹窗”投马总,送Q币”即可。