文章目录
1.分析start.S
2._start会跳转到start_code处
3.然后进入第一个C数:board_init_f()
4.接下来进入重定位
5.清除bss段
移植Uboot其他文章链接:
S3C2440移植uboot之编译烧写uboot
S3C2440移植uboot之新建单板_时钟_SDRAM_串口
S3C2440移植uboot之启动过程概述
S3C2440移植uboot之支持NAND启动
S3C2440移植uboot之支持NORFLASH
S3C2440移植uboot之支持NANDFLASH操作
S3C2440移植uboot之支持DM9000
S3C2440移植uboot之裁剪和修改默认参数
S3C2440移植uboot之支持烧写yaffs映像及制作补丁
下图为编译uboot后显示的最后一条链接命令。
1.分析start.S
打开uboot.lds,发现链接地址为0,所以新的uboot只能在nor flash运行。运行开始文件为start.o。
下面我们分析arch/arm/cpu/arm920t/start.S
从start_code开始运行
.globl _start //声明_start全局符号,这个符号会被lds链接脚本用到_start: b start_code //跳转到start_code符号处,0x00 ldr pc, _undefined_instruction //0x04 ldr pc, _software_interrupt //0x08 ldr pc, _prefetch_abort //0x0c ldr pc, _data_abort //0x10 ldr pc, _not_used //0x14 ldr pc, _irq //0x18 ldr pc, _fiq //0x20_undefined_instruction: .word undefined_instruction //定义_undefined_instruction指向undefined_instruction(32位地址)_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 //balignl使用,参考http://www.cnblogs.com/lifexy/p/7171507.html
2._start会跳转到start_code处
start_code:/*设置CPSR寄存器,让CPU进入管理模式*/ mrs r0, cpsr //读出cpsr的值 bic r0, r0, #0x1f //清位 orr r0, r0, #0xd3 //位或 msr cpsr, r0 //写入cpsr#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) /*
* relocate exception table
*/ ldr r0, =_start
ldr r1, =0x0 //r1等于异常向量基地址 mov r2, #16copyex: subs r2, r2, #1 //减16次,s表示每次减都要更新条件标志位 ldr r3, [r0], #4
str r3, [r1], #4 //将_start标号后的16个符号存到异常向量基地址0x0~0x3c处 bne copyex //直到r2减为0#endif#ifdef CONFIG_S3C24X0 /* 关看门狗*/# define pWTCON 0x53000000# define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */# define INTSUBMSK 0x4A00001C# define CLKDIVN 0x4C000014 /* clock divisor register */ ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0] //关看门狗,使WTCON寄存器=0 /*关中断*/ mov r1, #0xffffffff ldr r0, =INTMSK
str r1, [r0] //关闭所有中断# if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK
str r1, [r0] //关闭次级所有中断# endif/* 设置时钟频率, FCLK:HCLK:PCLK = 1:2:4 ,而FCLK默认为120Mhz*/ ldr r0, =CLKDIVN
mov r1, #3 str r1, [r0]
#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit //关闭mmu,并初始化各个bank#endifcall_board_init_f: ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) //CONFIG_SYS_INIT_SP_ADDR=0x30000f80 bic sp, sp, #7 //sp=0x30000f80 ldr r0,=0x00000000 bl board_init_f
上面的CONFIG_SYS_INIT_SP_ADDR =0x30000f80,是通过arm-linux-objdump -D u-boot>u-boot.dis生成反汇编,然后从u-boot.dis得到的。
3.然后进入第一个C数:board_init_f()
该函数主要工作是:
清空gd指向的结构体、通过init_sequence函数数组,来初 始化各个函数以及逐步填充gd结构体,最后划分内存区域, 将数据保存在gd里,然后调用relocate_code()对uboot重定位。
(gd是用来传递给内核的参数)
1)具体代码如下所示:
void board_init_f(ulong bootflag) // bootflag=0x00000000{ bd_t *bd; init_fnc_t **init_fnc_ptr; //函数指针 gd_t *id; ulong addr, addr_sp;#ifdef CONFIG_PRAM ulong reg;#endif bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f"); /* Pointer is writable since we allocated a register for it */ gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
其中gd是一个全局变量,用来传递给内核的参数用的,如下图所示,在arch/arn/include/asm/global_data.h中定义,*gd指向r8寄存器,所以r8专门提供给gd使用
而CONFIG_SYS_INIT_SP_ADDR,在之前得到=0x30000f80,所以gd=0x30000f80
2)继续来看board_init_f():
__asm__ __volatile__("": : :"memory"); //memory:让cpu重新读取内存的数据 memset((void *)gd, 0, sizeof(gd_t)); //将0x30000f80地址上的gd_t结构体清0 gd->mon_len = _bss_end_ofs;
// _bss_end_ofs =__bss_end__ - _start,在反汇编找到等于0xae4e0,所以mon_len等于uboot的数据长度 gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)//调用init_sequence[]数组里的各个函数 { if ((*init_fnc_ptr)() != 0) //执行函数,若函数执行出错,则进入hang() { hang (); //打印错误信息,然后一直while } }
上面的init_sequence[]数组里存了各个函数,比如有:
board_early_init_f():设置系统时钟,设置各个GPIO引脚
timer_init():初始化定时器
env_init():设置gd的成员变量
init_baudrate():设置波特率
dram_init():设置gd->ram_size= 0x04000000(64MB)
3)继续来看board_init_f():
addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; // addr=0x34000000 // CONFIG_SYS_SDRAM_BASE: SDRAM基地址,为0X30000000// gd->ram_size: 等于0x04000000 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) /* reserve TLB table */ addr -= (4096 * 4); //addr=33FFC000 addr &= ~(0x10000 - 1); // addr=33FF0000, gd->tlb_addr = addr; //将64kB分配给TLB,所以TLB地址为33FF0000~33FFFFFF#endif /* round down to next 4 kB limit */ addr &= ~(4096 - 1); //4kb对齐, addr=33FF0000 debug("Top of RAM usable for U-Boot at: %08lxn", addr); /*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/ addr -= gd->mon_len; // 在前面分析过gd->mon_len=0xae4e0, //所以addr=33FF0000 -0xae4e0=33F41B20, addr &= ~(4096 - 1); //4095=0xfff,4kb对齐, addr=33F41000 //所以分配给uboot各个段的重定位地址为33F41000~33FFFFFF debug("Reserving %ldk for U-Boot at: %08lxn", gd->mon_len >> 10, addr);#ifndef CONFIG_SPL_BUILD addr_sp = addr - TOTAL_MALLOC_LEN; //分配一段malloc空间给addr_sp //TOTAL_MALLOC_LEN=1024*1024*4,所以malloc空间为33BF1000~33F40FFF addr_sp -= sizeof (bd_t); //分配一段bd_t结构体大的空间 bd = (bd_t *) addr_sp; //bd指向刚刚分配出来的bd_t结构体 gd->bd = bd; // 0x30000f80处的gd变量的成员bd等于bd_t基地址 addr_sp -= sizeof (gd_t); //分配一个gd_t结构体大的空间 id = (gd_t *) addr_sp; //id指向刚刚分配的gd_t结构体 gd->irq_sp = addr_sp; //0x30000f80处的gd变量的成员irq_sp等于gd_t基地址 addr_sp -= 12; addr_sp &= ~0x07; ... ... relocate_code(addr_sp, id, addr); //进入relocate_code()函数,重定位代码,以及各个符号 // addr_sp: 栈顶,该栈顶向上的位置用来存放gd->irq_sp、id 、gd->bd、malloc、uboot、TLB(64kb), //id: 存放 gd_t结构体的首地址 // addr: 等于存放uboot重定位地址33F41000}
执行完board_init_f()后,最终内存会划分如下图所示:
其实此时uboot还在flash中运行,然后会进入start.S的relocate_code()里进行uboot重定位
4.接下来进入重定位
1)start.S的relocate_code()代码如下所示
relocate_code: mov r4, r0 /* save addr_sp */ // addr_sp栈顶值 mov r5, r1 /* save addr of gd */ // id值 mov r6, r2 /* save addr of destination */ // addr值:uboot重定位地址 /* Set up the stack */stack_setup: mov sp, r4 //设置栈addr_sp adr r0, _start //在顶层目录下system.map符号文件中找到_start =0,所以r0=0 cmp r0, r6 //判断_start(uboot重定位之前的地址)和addr(重定位地址)是否一样 beq clear_bss /* skip relocation */
上一篇:S3C2440移植uboot之支持DM9000
下一篇:S3C2440移植uboot之编译烧写uboot
推荐阅读最新更新时间:2024-10-25 20:33
设计资源 培训 开发板 精华推荐
- SI4731-DEMO,使用 SI4703 数字收音机调谐器的演示板
- 电池供电的荧光灯
- STEVAL-IDW001V1,STM32F0DISCOVERY 的 Wi-Fi 子板,为 SPWF01SA.11 Wi-Fi 模块的评估提供平台
- 用于计量的模拟放大
- 使用 ON Semiconductor 的 SPT7855 的参考设计
- EVAL-AD7853CB,使用 AD7853、12 位、200 kSPS 单通道、采样增量模数转换器的评估板
- LT6003 的典型应用 - 1.6V、1 uA 精密轨至轨输入和输出运算放大器
- LT1241、5V 大电流降压型开关
- WIFI台灯V3:模仿小米的台灯
- 采用 24V 壁式适配器和铅酸电池的 LTC3126IFE 3.3V/2.5A 电源的典型应用电路
- 【MPS有奖评论】一起聊聊选型的那些过往
- 美信基础模拟IC APP下载 助力您创新模拟设计!评论、抢楼全有礼!
- 夏末秋初,玩转EE芯积分,边赚边花+礼品兑换剧透
- 【已结束】R&S 直播【PCI Express Gen 3 一致性测试(含demo演示)】
- TI 嵌入式处理器最新产品发布会 全程在线直播 4月16日精彩为您呈现!预报名、看直播、享好礼
- EEWORLD社区7月明星人物出炉
- 有奖直播:8月21上午10:00 泰克助您应对现在及未来的测试挑战!
- 【中秋佳节话中秋】吃吃月饼聊聊天,还有抢楼好礼送给你!
- 【已结束】直播“戴”“芯”:英飞凌可穿戴设备保姆级解决方案
- 有奖直播:新科技、新课堂、新学期~ ADI软件定义无线电ADALM-Pluto入门实战