1 生成补丁 与 打补丁
生成补丁 diff -upNr old/ new/ > patch-x.y.z
diff -upNr u-boot-2014.07/ u-boot-2014.07_moveto9g25/ > moveto9g25-2015.08.25-ok.patch
打补丁 cd old
patch -p1 < ../patch-x.y.z
----------------------------------------------------------------------------------------------
2 修改boards.cfg 与 Makefile
Status, Arch, CPU:SPLCPU, SoC, Vendor, Board name, Target, Options, Maintainers
Active arm arm926ejs at91 atmel at91sam9g25jzq at91sam9g25jzq_nandflash
at91sam9g25jzq:AT91SAM9G25,SYS_USE_NANDFLASH Zhaigch <[email protected]>
修改Makefile,指定CROSS_COMPILE = arm-linux-
拷贝board/atmel/at91sam9x5ek 为 at91sam9g25jzq对应配置文件里的Board name
拷贝include/configs/at91sam9x5ek.h 为 at91sam9g25jzq.h
生成配置头文件 make <Target>_config
make at91sam9g20ek_nandflash_config
make at91sam9g25jzq_nandflash_config
make
make u-boot.dis //生成反汇编文件
----------------------------------------------------------------------------------------------
3 搜索字符串命令
grep -nR "xx" ./
使用4.3.2交叉编译器编译时出错 armv5te指令集不兼容,使用arm-none-gnueabi-4.7.3编译顺利通过。
修改 configs/at91sam9g25jzq.h 里的宏定义为“CONFIG_SYS_TEXT_BASE
0x22000000”
使程序编译后的运行地址为22000000开始,将nand中拷贝出的程序放到该地址后,直接跳转执行。
发现源码做的太好了,直接就跑起来了!
----------------------------------------------------------------------------------------------
4 启动分析一
arch/arm/lib/vectors.S //中断向量表,跳转到 reset,即:
arch/arm/cpu/arm926ejs/start.S //这里如果没有分两级引导的话,这里需要进行一些必要的初始化操作
//如关闭内部看门狗,初始化系统时钟,初始化ddr2内存,从nand中拷贝程序到内存中等操作。
//由于我们是二级启动uboot,以上这些已经被1级引导程序完成,因此 通过宏CONFIG_SKIP_LOWLEVEL_INIT
//直接跳过这些过程直接调用 _main
arch/arm/lib/crt0.S // _main在该文件中定义
//初始化sp为 CONFIG_SYS_INIT_SP_ADDR = 0x20000000 + 4096 - GENERATED_GBL_DATA_SIZE
//sub sp, sp, #GD_SIZE ,接着在sp上方又分配出 GD_SIZE大小的内存
//mov r9, sp,此时r9保存的就是GD_SIZE大小的内存的起始地址,也可以认为是某个全局变量结构体的指针
//调用 board_init_f,根据配置头文件中的宏 CONFIG_SYS_GENERIC_BOARD,common/board_f.c被编译
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r9")
common/board_f.c //如果没有该宏,arm/lib/board.c会被编译,该文件以后会被踢出源码,尽量不要链接它
bl board_init_f //板初始化,完成什么操作呢?
----------------------------------------------------------------------------------------------
5 启动分析二
board_init_f
gd = &data; // gd全局数据指针指向在堆栈里定义的结构体,这里不使用上一步在堆栈外分配的内存
// 为什么?以后再分析
initcall_run_list(init_sequence_f) //调用init_sequence_f数组中的全部函数
setup_mon_len, //填充 gd->mon_len 程序长度
setup_fdt, //填充 gd->fdt_blob = 0
trace_early_init, //空
arch_cpu_init, //调用at91_clock_init,填充gd->arch 时钟相关数据
mark_bootstage, //"board_init_f"字符串放入record[]数组记录表中
timer_init, //初始化pit,填充gd->arch.timer_rate_hz gd->arch.tbu = gd->arch.tbl = 0
env_init, //根据配置文件中宏 CONFIG_ENV_IS_IN_NAND, env_nand.c被编译连接
//env_init被调用,填充gd->env_addr环境变量存放地址
//填充gd->env_valid环境变量有效标识
init_baud_rate,
//填充gd->baudrate
serial_init,
/* serial communications setup */
console_init_f, //填充gd->have_console = 1,初始化print缓冲,从此可以使用printf打印功能
display_options, //console中打印 uboot版本信息与编译日期
display_text_info,
/* show debugging info if required */
print_cpuinfo, //打印处理器型号,主时钟,系统时钟,外设时钟
announce_dram_init,//puts("DRAM: ");
dram_init, //填充gd->ram_size = 0x4000000
setup_dest_addr, //填充gd->relocaddr = gd->ram_top = 0x24000000
reserve_round_4k, //4k对齐gd->relocaddr &= ~(4096 - 1);
reserve_trace, //null
reserve_uboot, //gd->relocaddr -= gd->mon_len;留出uboot的代码空间
//gd->relocaddr &= ~(4096 - 1);4K对齐
//gd->start_addr_sp = gd->relocaddr;堆栈空间
setup_machine, //gd->bd->bi_arch_number = CONFIG_MACH_TYPE 设置板号
reserve_global_data,//gd->start_addr_sp -= sizeof(gd_t);堆栈下移,分配空间gd_t
//gd->new_gd = gd->start_addr_sp 指向新分配的内存地址
reserve_fdt, //gd->start_addr_sp -= gd->fdt_size; 为fdt分配内存空间
//gd->new_fdt = gd->start_addr_sp 指向新分配的fdt内存空间
reserve_stacks, //2字节对齐,为IRQ中断分配内存
setup_dram_config, //null
show_dram_config, //打印出dram的大小
display_new_sp, //调试时打印 gd->start_addr_sp
reloc_fdt, //重定位fdt,进行数据拷贝
setup_reloc, //gd->reloc_off = gd->relocaddr - 0x22000000;
//memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); 将gd内的数据拷贝到新的地址
----------------------------------------------------------------------------------------------
6 启动分析三
在调用board_init_f()完成板卡与全局结构体变量 gd 的初始化后将其拷贝到在代码段下重新分配的全局结构
体中。接下来进行sp的重新设置,将r9指向重新分配的全局变量gd,然后进行代码的重定位。
ldr sp, [r9, #GD_START_ADDR_SP]
/* sp = gd->start_addr_sp */
bic sp, sp, #7
/* 8-byte alignment for ABI compliance */
ldr r9, [r9, #GD_BD]
/* r9 = gd->bd */
sub r9, r9, #GD_SIZE
修改代码返回值,使其值为重定位后的地址
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF]
/* r0 = gd->reloc_off */
add lr, lr, r0
ldr r0, [r9, #GD_RELOCADDR]
/* r0 = gd->relocaddr */
拷贝代码到重定位的地址空间去
b relocate_code
arch/arm/lib/relocate.S
将链接脚本中代码段从 __image_copy_start 到 __image_copy_end之间的 代码段、数据段和命令行段
拷贝到重定位的地址 gd->relocaddr 处
拷贝完成后,还需要将从 __rel_dyn_start到 __rel_dyn_end之间的 .rel.dyn段(代码重定位时使用,默认应该
是由编译器产生的相关寻址相关的数据)
完成代码的重定义后,返回到重定位后的代码中
bl c_runtime_cpu_setup //arch/arm/cpu/arm926ejs/start.S 无其它需要初始化的操作,直接返回
接下来初始化bss段
接下来调用board_init_r函数
mov r0, r9 //将重定位后新的gd指针作为参数0传入函数
ldr r1, [r9, #GD_RELOCADDR] //重定位后代码段的起始地址作为参数1传入函数
ldr pc, =board_init_r //绝对地址跳转,由于代码重定位后,同时根据重定位后相对于之前程序的偏移值
对程序的运行地址进行了修正,从而保证重定位后,通过绝对地址跳转时的正确运行。
----------------------------------------------------------------------------------------------
7 启动分析四
board_init_r
initcall_run_list(init_sequence_r) //循环调用结构体 init_sequence_r 中的全部函数
initr_caches //打开处理器的数据和指令cache,需要自己添加
board_init //与具体的板卡相关的外设的初始化,以及gd->bd相关的元素进行初始设置,需要移植修改
initr_serial //再次初始化串口
initr_malloc //初始化分配的堆空间内存,
bootstage_relocate //启动阶段重定位,干嘛的 未知
power_init_board //空,如果需要自定义相关操作
initr_flash // nor flash的初始化,如果板上没有Nor flash需要配置宏 CONFIG_SYS_NO_FLASH
initr_nand //nand flash的初始化,需要配置宏 CONFIG_CMD_NAND
initr_env //初始化环境变量
set_default_env() //如果从flash中没有读到环境变量则使用默认的的环境变量default_environment
"bootargs=" CONFIG_BOOTARGS "\0"
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
"nfsboot=" CONFIG_NFSBOOTCOMMAND
"\0"
"bootdelay=" __stringify(CONFIG_BOOTDELAY)
"\0"
"baudrate=" __stringify(CONFIG_BAUDRATE)
"\0"
"ethaddr=" __stringify(CONFIG_ETHADDR)
"\0"
"ipaddr=" __stringify(CONFIG_IPADDR)
"\0"
"serverip=" __stringify(CONFIG_SERVERIP)
"\0"
"gatewayip=" __stringify(CONFIG_GATEWAYIP)
"\0"
"netmask=" __stringify(CONFIG_NETMASK)
"\0"
initr_secondary_cpu //空,__weak标记的虚弱函数,如果编译的程序里有相同函数名的函数则用它代替自己
stdio_init //标准输入输出初始化
initr_jumptable //初始化跳转表,干嘛的 未知
console_init_r //控制命令行相关的初始化操作,不需要移植,不用关心它。
interrupt_init //中断初始化,不关心中断,能引导linux内核就行了,
initr_ethaddr //初始化网卡地址,需要配置宏 CONFIG_CMD_NET
initr_net //初始化网卡,需要配置宏 CONFIG_CMD_NET
run_main_loop //主循环,死循环中运行main_loop,去解析用户输入的命令行,或系统自动运行的命令
main_loop
----------------------------------------------------------------------------------------------
8 启动分析五
由于在9g25处理器的引导过程中,在uboot之前有一个初始的引导程序,该程序完成了 中断向量表的初始化
fiq irq的中断场景记录和sp的设置,ddr内存初始化,系统时钟工作在399Mhz,外设时钟工作在133Mhz,调试
串口bps为115200,然后将nand的0x40000开始的0x80000(512k)长的数据拷贝到ddr内存0x23000000处,然后
通过ldr pc,=0x23000000 绝对地址跳转到23000000地址运行拷贝到些处的uboot程序.
由于在uboot中会执行一些关于协处理的操作(MMU、Icache、Dcache)指令MRC(读协处理器),MCR(写协处理器),
这两条指令必须在特权模式下执行,因此在跳转到uboot前先让处理器工作在svc管理模式,否则在执行到这
样的命令时会触发 未定义 指令的中断。
打补丁测试
tar xjf u-boot-2014.07.tar.bz2
cd u-boot-2014.07/
patch -p1 < ../moveto9g25-2015.08.25-ok.patch
make at91sam9g25jzq_nandflash_config
make
make u-boot.dis
nfs 22000000 192.168.0.1:/home/terminal/workspace/nfs/image/uImage_1
版权声明:本文为博主原创文章,未经博主允许不得转载。