u-boot启动过程分解 1
来源:互联网 发布:小米5如何备份数据 编辑:程序博客网 时间:2024/06/05 13:08
这篇文章是tiny6410到手以后分析的第一个程序后写下的记录,由于各种原因整理一半以后就被搁置了,有些未解决问题,
U-Boot启动代码分析第一部分(汇编语言):
主要完成cpu初始化所涉及到寄存器设置,并将第二部分C语言代码复制到RAM中;
此部分内容起始于/cpu/s3c64xx/S3c6410/start.S;
涉及文件:
/cpu/s3c64xx/S3c6410/start.S
/board/Samsung/Mini6410/lowlevel_init.S
Note:此文件夹为FriendlyARM针对Mini6410修改代码,移植于Smdk6410
/include/s3c6410.h
定义中断向量表
/cpu/start.S
_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
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack_swi
bad_save_user_regs
bl do_software_interrupt
在跳转中断服务程序前,首先要有两个宏操作,一个是对stack的操作,一个是对用户reg保存;
.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
#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
对应的中断子程序将在 /cpu/$(ARCH)/interrupts.c中执行
存储器映射定义:
_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
#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
上电后执行动作:
1. 上电后执行reset:设置CPU为SVC模式:
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
2. CPU初始化循环:
2.1 无效caches,关闭caches和MMU:
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
/* Peri port setup bank0 and bank1 set to 1 as 16bits mode*/
ldr r0, =0x70000000 /*70000000-SROM bus width and wait control*/
orr r0, r0, #0x13 /*bank0 and bank1 setting 16-bit*/
mcr p15,0,r0,c15,c2,4
@ 256M(0x70000000-0x7fffffff)
注:此处无效掉I/D caches,关闭caches和MMU,同时设置用于bank0和bank1的数据总线宽度控制器为16-bit模式;
S3c64xx与s3c24xx此处初始化有些诧异:在S3c64xx中强制进行了cpu_init_crit,
而s3c24xx中首先判断,若未定义CONFIG_SKIP_LOWLEVEL_INIT,则进入cpu_init_crit
2.2 配置ONENAND控制器:
#ifdef CONFIG_BOOT_ONENAND
ldr r0, =0x70000000 @ onenand controller setup
orr r0, r0, #0x100000
ldr r1, =0x4000
orr r1, r1, #0xe0
str r1, [r0]
#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430)
orr r0, r0, #300 @ disable watchdog
mov r1, #1
str r1, [r0]
mov r1, #0x23000000 @ start buffer register
orr r1, r1, #0x30000
orr r1, r1, #0xc800
#else
mov r1, =0x20000000 @ start buffer register
orr r1, r1, #0xc30000
orr r1, r1, #0xc800
#endif
sub r0, r1, #0x0400 @ start address1 register
ldr r2, [r1, #0x84] @ ecc bypass
orr r2, r2, #0x100
str r2, [r1, #0x84]
mov r3, #0x0 @ DFS, FBA
str r3, [r0, #0x00]
str r3, [r0, #0x04] @ select dataram for DDP as 0
mov r4, #0x104 @ interrupt register
mov r5, #0x0002 @ FPA, FSA
mov r6, #0x0800 @ BSA
onenand_bl1_load:
str r5, [r0, #0x1c] @ save FPA, FSA
orr r6, r6, #0x02 @ BSC
str r6, [r1, #0x00] @ save BSA, BSC
str r3, [r1, r4] @ clear interrupt
str r3, [r1, #0x80] @ write load command
mov r7, #0x100 @ need small delay
onenand_wait_loop1:
subs r7, r7, #0x1
bne onenand_wait_loop1
add r5, r5, #0x2 @ next FPA, FSA
sub r6, r6, #0x2
add r6, r6, #0x200 @ next BSA
cmp r5, #0x8
bne onenand_bl1_load
#endif
若启动定义了CONFIG_BOOT_ONENAND,对ONENAND flash初始化,此类型ROM暂时不涉及,内容跳过。
2.3 调用lowlevel_init对底层的初始化:
lowlevel_init:
mov r12, lr /*保存程序返回地址,待调用执行完成后返回原地址*/
/* LED on only #8 */
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x55540000
str r1, [r0, #GPNCON_OFFSET]
ldr r1, =0x55555555
str r1, [r0, #GPNPUD_OFFSET]
ldr r1, =0xf000
str r1, [r0, #GPNDAT_OFFSET]
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x1
str r1, [r0, #GPECON_OFFSET]
ldr r1, =0x0
str r1, [r0, #GPEDAT_OFFSET]
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x2A5AAAAA
str r1, [r0, #GPPCON_OFFSET]
ldr r1, =0x0
str r1, [r0, #GPPDAT_OFFSET]
ldr r1, =0x55555555
str r1, [r0, #MEM1DRVCON_OFFSET]
/*以上为配置GPNIO、GPEIO、GPPIO端口输出*/
/* Disable Watchdog关闭看门狗 */
ldr r0, =0x7e000000 @0x7e004000
orr r0, r0, #0x4000
mov r1, #0
str r1, [r0]
@ External interrupt pending clear清除外部中断标志
ldr r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET) /*EINTPEND*/
ldr r1, [r0]
str r1, [r0]
ldr r0, =ELFIN_VIC0_BASE_ADDR @0x71200000
ldr r1, =ELFIN_VIC1_BASE_ADDR @0x71300000
@ Disable all interrupts (VIC0 and VIC1)关闭中断
mvn r3, #0x0
str r3, [r0, #oINTMSK]
str r3, [r1, #oINTMSK]
@ Set all interrupts as IRQ设置所有中断类型为IRQ
mov r3, #0x0
str r3, [r0, #oINTMOD]
str r3, [r1, #oINTMOD]
@ Pending Interrupt Clear清除中断标志
mov r3, #0x0
str r3, [r0, #oVECTADDR]
str r3, [r1, #oVECTADDR]
/*
* 以下为系统时钟初始化、串口初始化、NAND flash初始化调用,均为
* 对寄存器相应位设置,参考用户手册
*/
/*
* init system clock :关闭看门狗、屏蔽中断、设置FCLK:HCLK:PCLK时*钟比例
*/
bl system_clock_init
/* for UART */
bl uart_asm_init
#if defined(CONFIG_NAND)
/* simple init for NAND */
bl nand_asm_init
#endif
/*
* 猜测:此部分已屏蔽判断初始化地址,转为跳转至电源唤醒模式处
*/
#if 0
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 1f /* r0 == r1 then skip sdram init */
#endif
bl mem_ctrl_asm_init
#if 1
ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
ldr r1, [r0]
bic r1, r1, #0xfffffff7
cmp r1, #0x8
beq wakeup_reset
#endif
/*
* UART channel 0 transmit buffer register setting 0x4b4b4b4b
*/
1:
ldr r0, =ELFIN_UART_BASE
ldr r1, =0x4b4b4b4b
str r1, [r0, #UTXH_OFFSET]
mov lr, r12
mov pc, lr
此刻lowlevle_inti执行完成,返回start.S中line240
2.4 判断启动地址并复制程序至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 */
此处判断程序运行地址是否在RAM中,如果没有,复制启动程序否则调用after_copy;
2.5 不同ROM设备的程序复制工作
Line252-line364针对NOR FLASH/NAND FLASH/MOVINAND FLASH/ONE NAND FLASH设备启动的代码复制进行区分设置,此部分代码量较大,不再附上;
2.6 copy code 后进行的工作(line365-line393):
1. GPP输出0xc00(why??)
2. enable domain access(why??)
3. 设置TTB寄存器
4. 使能MMU
2.7 清除RAM空间(line397-line423):
1. 通过_TEXT_BASE地址推算出映像的起始地址;
2. 设置_bss_start、_bss_end地址;
3. 清除bss空间;
2.8 程序跳转到_start_armboot处。
U-Boot启动第二部分(C语言):
继续汇编程序后的_start_armboot衔接部分,此部分已复制到RAM中,转为C语言启动过程继续;
此部分内容起始于:/Lib_arm/Board.c
涉及文件:
/Lib_arm/Board.c
C语言的入口函数:/board/Lib_arm/board.c void start_armboot(void);
1. 定义所需变量并为全局变量指针gd初始化:
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
#if defined(CONFIG_BOOT_MOVINAND)
uint *magic = (uint *) (PHYS_SDRAM_1);
#endif
/* Pointer is writable since we allocated a register for it */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
ulong gd_base;
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
#ifdef CONFIG_USE_IRQ
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif
gd = (gd_t*)gd_base;
#else
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
#endif
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;
此处定义init_fnc_ptr,s指针;
如果未定义CFG_NO_FLASH定义size;
如果定义CONFIG_VFD或CONFIG_LCD则定义addr;
如果定义CONFIG_BOOT_MOVI_NAND则定义magic并初始化为PHYS_SDRAM_1;
如果定义CONFIG_MEMORY_UPPER_ CODE则定义gd_base并初始化为SDRAM起始地址;如果定义CONFIG_USE_IRQ重新计算,减去IRQ和FIQ长度,并将gd_base计算值作为地址对gd初始化;
对gd指针初始化设置内存空间;
对gd->bd指针初始化地址,并设置内存空间;
- u-boot启动过程分解 1
- U-Boot启动过程分解 2
- u-boot启动过程【1】
- U-Boot启动过程(1)
- U-Boot启动过程
- u-boot启动过程
- U-Boot启动过程
- U-Boot启动过程
- U-Boot启动过程
- U-Boot启动过程
- u-boot启动过程
- U-boot启动过程
- U-Boot启动过程
- U-Boot启动过程
- U-Boot 启动过程
- U-boot启动过程
- u-boot启动过程
- U-BOOT启动过程
- jquery 遍历table
- Thread-Per-Message Pattern
- android UI效果三: 滚动切换屏幕
- WP开发的基础知识小结
- 关于功率计算单位
- u-boot启动过程分解 1
- android UI效果四: 动态填充Bitmap像素信息
- 编程之美-最短摘要
- Demo整理(一)----- 字体竖直排版的实现
- Java设计模式圣经连载(01)-简单工厂模式
- sql2000导出数据字典表(含字段名、格式、长度、备注等),可保存到excel
- 参加软件设计大赛的点点思绪
- ajax 实现无刷新实现省市县(区)三级联动
- (02)-工厂方法(Factory Method)模式