U-BOOT-2016.07移植 (第三篇) 代码重定位
来源:互联网 发布:安卓淘宝秒杀器 编辑:程序博客网 时间:2024/06/05 14:22
U-BOOT-2016.07移植 (第一篇) 初步分析
U-BOOT-2016.07移植 (第二篇) 添加单板
U-BOOT-2016.07移植 (第三篇) 代码重定位
目录
原文链接:http://blog.csdn.net/funkunho/article/details/52474373?utm_source=itdadao&utm_medium=referral
- U-BOOT-201607移植 第一篇 初步分析
- U-BOOT-201607移植 第二篇 添加单板
- U-BOOT-201607移植 第三篇 代码重定位
- 目录
- 分析board_init_f
- 1 common board_fc 1035 1067
- 2 common board_fc 829 1033
- 3 内存分配图
- 分析relocate_code
- 1 archarmlibcrt0S 95 122
- 2 archarmlibrelocateS 79 130
- 分析board_init_f
1. 分析board_init_f()
在我写的第一篇文章中,已经对u-boot-2016.07的启动流程有了初步的了解,现在我们开始分析crt0.S中,_main函数在设置好栈和GD后调用的board_init_f(),从而了解u-boot是如何对内存空间进行分配,然后进行重定位的。
1.1 common/ board_f.c (1035 ~ 1067):
void board_init_f(ulong boot_flags){#ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA //没有定义这个宏,不关心 /* * For some archtectures, global data is initialized and used before * calling this function. The data should be preserved. For others, * CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack * here to host global data until relocation. */ gd_t data; gd = &data; /* * Clear global data before it is accessed at debug print * in initcall_run_list. Otherwise the debug print probably * get the wrong vaule of gd->have_console. */ zero_global_data();#endif gd->flags = boot_flags; gd->have_console = 0; if (initcall_run_list(init_sequence_f)) //调用initcall_run_list函数, //这个函数在lib/initcall.c中定义, //作用就是调用init_sequence_f函数数组中 //存放的各初始化函数 hang();#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \ //我们有定义CONFIG_ARM,不关心 !defined(CONFIG_EFI_APP) /* NOTREACHED - jump_to_copy() does not return */ hang();#endif}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
下面我们分析init_sequence_f数组中的各函数
1.2 common/ board_f.c (829 ~ 1033):
这里我直接将被宏开关关掉的函数剔除掉,留下最终会被调用的函数:
static init_fnc_t init_sequence_f[] = { setup_mon_len, //gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE; //CONFIG_SYS_MONITOR_BASE = _start = 0 //设置gd->mon_len为编译出来的u-boot.bin+bss段的大小 arch_cpu_init, /* basic arch cpu dependent setup */ //这个函数应该是留给移植人员使用的,里面什么都没做,而且被__weak修饰, //所以我们可以在别的地方重新定义这个函数来取代它 arch_cpu_init_dm, //同上 mark_bootstage, /* need timer, go after init dm */#if defined(CONFIG_BOARD_EARLY_INIT_F) board_early_init_f, //在smdk2440.c中定义,初始化CPU时钟和各种IO(待修改)#endif /* TODO: can any of this go into arch_cpu_init()? */#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || \ defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || \ defined(CONFIG_SPARC) timer_init, /* 初始化定时器 */ #endif env_init, /* 初始化环境变量 */ init_baud_rate, /* 初始化波特率为: 115200 */ serial_init, /* 设置串口通讯 */ console_init_f, /* stage 1 init of console */ display_options, /* 打印版本信息,你可以修改include/version.h中的CONFIG_IDENT_STRING选项, * 加入你的身份信息 */ display_text_info, /* show debugging info if required */ //打印bss段信息及text_base, //需要 #define DEBUG print_cpuinfo, /* 打印CPUID和时钟频率 */ INIT_FUNC_WATCHDOG_INIT INIT_FUNC_WATCHDOG_RESET announce_dram_init, //输出"DRAM: " 然后在下面进行SDRAM参数设置 /* TODO: unify all these dram functions? */#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || \ defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) dram_init, /* 在smdk2440.c中定义,配置SDRAM大小,大家可根据实际进行修改 */#endif INIT_FUNC_WATCHDOG_RESET INIT_FUNC_WATCHDOG_RESET INIT_FUNC_WATCHDOG_RESET /* * Now that we have DRAM mapped and working, we can * relocate the code and continue running from DRAM. * * Reserve memory at end of RAM for (top down in that order): * - area that won't get touched by U-Boot and Linux (optional) * - kernel log buffer * - protected RAM * - LCD framebuffer * - monitor code * - board info struct */ setup_dest_addr, //将gd->relocaddr、gd->ram_top指向SDRAM最顶端 reserve_round_4k, //gd->relocaddr 4K对齐#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \ defined(CONFIG_ARM) reserve_mmu, //gd->arch.tlb_size = PGTABLE_SIZE; 预留16kb的MMU页表 //gd->relocaddr -= gd->arch.tlb_size; //gd->relocaddr &= ~(0x10000 - 1); 64kb对齐 //gd->arch.tlb_addr = gd->relocaddr;#endif reserve_trace,#if !defined(CONFIG_BLACKFIN) reserve_uboot, //gd->relocaddr -= gd->mon_len; 一开始设置的u-boot.bin + bss段长度 //gd->relocaddr &= ~(4096 - 1); 4k对齐,这是最终重定位地址 //gd->start_addr_sp = gd->relocaddr; 设置重定位后的栈指针#endif#ifndef CONFIG_SPL_BUILD reserve_malloc, //gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN; //预留4MB MALLOC内存池 reserve_board, //gd->start_addr_sp -= sizeof(bd_t); 预留空间给重定位后的gd_t->bd //gd->bd = (bd_t *)gd->start_addr_sp; 指定重定位bd地址 //memset(gd->bd, '\0', sizeof(bd_t)); 清零#endif setup_machine, //gd->bd->bi_arch_number = CONFIG_MACH_TYPE; //对于S3C2440来说就是MACH_TYPE_S3C2440 (arch/arm/include/asm/mach-types.h) reserve_global_data, //gd->start_addr_sp -= sizeof(gd_t); //gd->new_gd = (gd_t *)gd->start_addr_sp; 指定重定位GD地址 reserve_fdt, reserve_arch, reserve_stacks, //gd->start_addr_sp -= 16; 栈指针16字节对齐 //gd->start_addr_sp &= ~0xf; setup_dram_config, //gd->bd->bi_dram[i].start = addr; 设置sdram地址和大小 //gd->bd->bi_dram[i].size = size; show_dram_config, //打印SDRAM大小,与上面的announce_dram_init相对应 display_new_sp, //若 #define DEBUG 则打印新的栈地址 INIT_FUNC_WATCHDOG_RESET reloc_fdt, setup_reloc, //gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; 计算重定位偏移地址 //memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); //将原来的gd复制到重定位后的gd地址上去 NULL,};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
1.3 内存分配图
根据1.1、1.2的分析,可以得出以下的内存分配图:
2. 分析relocate_code
2.1 arch/arm/lib/crt0.S (95 ~ 122)
同样,这里将无关紧要的宏开关去掉
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 /* new GD is below bd */ /* * 上面这一段代码是将board_init_f中设置好的start_addr_sp地址值赋给栈指针,使其指向重定位后的栈顶 * 8字节对齐后,将r9设为新的GD地址(对照内存分配图: gd地址=bd地址-sizeof(gd_t)) */ adr lr, here //设置返回地址为下面的here,重定位到sdram后返回here运行 ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off 取重定位地址偏移值 */ add lr, lr, r0 //返回地址加偏移地址等于重定位后在sdram中的here地址 ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr 传入参数为重定位地址 */ b relocate_code //跳到arch/arm/lib/relocate.S中执行here: //返回后跳到sdram中运行
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2.2 arch/arm/lib/relocate.S (79 ~ 130)
ENTRY(relocate_code) ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start 这是u-boot.bin起始链接地址, * 定义在u-boot.lds中 (编译后在顶层目录生成) * 原文件是arch/arm/cpu/u-boot.lds,大家可以自行分析 */ subs r4, r0, r1 /* r4 <- relocation offset r0是crt0.S中传入的重定位地址, * 这里是算出偏移值 */ beq relocate_done /* skip relocation 如果r4为0,则认为重定位已完成 */ ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end 同第一条指令,在u-boot.lds中定义*/copy_loop: /* r1是源地址__image_copy_start,r0是目的地址relocaddr, * size = __image_copy_start - __image_copy_end */ ldmia r1!, {r10-r11} /* copy from source address [r1] */ stmia r0!, {r10-r11} /* copy to target address [r0] */ cmp r1, r2 /* until source end address [r2] */ blo copy_loop /* * fix .rel.dyn relocations 定义了"-PIE"选项就会执行下面这段代码 * 目的是为了让位置相关的资源(代码、参数、变量)的地址在重定位后仍然能被寻址到,所以让他们加上偏移地址, * 即等于他们重定位后的真正地址 * 这些 "存放(资源的地址)的地址" 存放在.rel.dyn这个段中,每个参数后面都会跟着一个起标志作用的参数, * 如果这个标志参数为23,即0x17,则表示这个 (资源的地址) 是位置相关的,需要加上重定位偏移值 * 这一段代码首先让.rel.dyn这个段中的存放的地址值加上偏移值,使其在sdram中取出(资源的地址) * 然后再让这些(资源的地址)加上偏移值,存回rel.dyn中存放这些地址的地址中, * 比较拗口,抽象,大家多研究研究代码,或看看我下面发的图来帮助理解 */ ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */ ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */fixloop: ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) r0为"存放(资源的地址)的地址", * 这个地址里存放的是需要用到的(资源的地址),r1为标志值 */ and r1, r1, #0xff //r1取低八位 cmp r1, #23 /* relative fixup? 和23比较,如果相等则继续往下,否则跳到fixnext */ bne fixnext /* relative fix: increase location by offset */ add r0, r0, r4 //r4存放的是重定位偏移值,r0这个地址存放的是位置相关的(资源的地址), //r4+r0即为重定位后的"存放(资源的地址)的地址", ldr r1, [r0] //在sdram中取出还未修改的(资源的地址) add r1, r1, r4 //加上偏移值 str r1, [r0] //存回去fixnext: //跳到下一个继续检测是否需要重定位 cmp r2, r3 blo fixlooprelocate_done: /* ARMv4- don't know bx lr but the assembler fails to see that */#ifdef __ARM_ARCH_4__ mov pc, lr //ARM920T用的汇编指令集是ARMv4,所以使用这条返回指令, //返回重定位后的here标志#else bx lr#endifENDPROC(relocate_code)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 原谅博主表达能力太渣,我发一下图吧
到这里,代码重定位的分析就结束了,下一篇内容将开始修改代码使u-boot能从nor flash启动
阅读全文
0 0
- U-BOOT-2016.07移植 (第三篇) 代码重定位
- U-BOOT-2016.07移植 (第三篇) 代码重定位
- U-BOOT-2016.07移植 (第三篇) 代码重定位
- U-Boot重定位代码分析
- U-Boot重定位代码分析
- U-Boot重定位代码分析
- U-Boot重定位代码分析
- U-Boot重定位代码分析
- u-boot重定位
- u-boot-2016.05移植:(2)、修改时钟 初始化sdram 重定位u-boot 配置smdk2440.h 修改u-boot.lds
- u-boot中重定位
- U-Boot源码(u-boot-2012.04.01)分析start.S中重定位代码
- u-boot-2009.11移植(适用于TQ2440和MINI2440)第三篇:修改初始化代码
- 移植u-boot学习笔记3-----分析启动过程之重定位
- 嵌入式u-boot重定位问题
- uboot移植---代码重定位
- U-Boot中关于TEXT_BASE,代码重定位,链接地址相关说明
- U-Boot中关于TEXT_BASE,代码重定位,链接地址相关说明
- Activity与Fragment生命流程
- 超链接<a>标签
- c
- 学习环境
- IPC机制系列之三 Android中的IPC方式 (AIDL)
- U-BOOT-2016.07移植 (第三篇) 代码重定位
- Queue与Topic区别
- javascript中的for循环
- java网络编程面试题
- 自定义组合控件
- 浅析C语言的由来
- Android硬件加速
- bzoj 4521: [Cqoi2016]手机号码
- Python爬虫-爬取集思录的金融信息,并写入文件和检测数据变化发送邮件通知