一、重定位
1.以前版本的重定位
2.新版本
我们的程序不只涉及一个变量和函数,我们若想访问程序里面的地址,则必须使用SDRAM处的新地址,即我们的程序里面的变量和函数必须修改地址。我们要修改地址,则必须知道程序的地址,就需要在链接的时候加上PIE选项:
加上PIE选项后,链接时候的地址就会生成,然后存储在段里面,如下段(u-boot.lds):
然后我们根据这些地址的信息来修改代码,程序就可以复制到SDRAM的任何地方去。
二、代码流程
start.S中执行到了 bl _main,跳转到_main,_main函数入口在crt0.S (archarmlib) 中。
1.crt0.S
1 ENTRY(_main) 2 3 /* 4 * Set up initial C runtime environment and call board_init_f(0). 5 * 初始化C运行环境并且调用 board_init_f(0) 函数 6 */ 7 8 /* 9 * 初始化栈地址 10 */ 11 /* Generic-asm-offsets.h (includegenerated) 12 * #define GENERATED_GBL_DATA_SIZE 192 13 * JZ2440.h(includeconfig) 14 * #define PHYS_SDRAM_1 0x30000000 15 * #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 16 * #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - GENERATED_GBL_DATA_SIZE) 17 * 18 * CONFIG_SYS_INIT_SP_ADDR = 0x30000000 + 0x1000 - 192(0xc0) = 0x30000f40 19 */ 20 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) /* 设置CFIG_SYS_INIT_SP_ADDR定义的地址,include/configs/jz2440.h中定义 */ 21 22 /* sp 的8字节对齐 */ 23 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 24 25 mov r0, sp /* r0 = sp */ 26 bl board_init_f_mem /*跳转到 board_init_f_mem 执行*/ 27 mov sp, r0 28 29 mov r0, #0 30 bl board_init_f /* 调用单板的初始化函数,跳转到 borad_init_f 处执行 */
执行到 board_init_f 处,则跳转到Board_f.c (common) 中去执行。
2.baord_init_f
1 /* 2 * 单板的初始化函数 3 */ 4 void board_init_f(ulong boot_flags) 5 { 6 gd->flags = boot_flags; 7 gd->have_console = 0; 8 9 if (initcall_run_list(init_sequence_f)) 10 hang(); 11 12 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && 13 !defined(CONFIG_EFI_APP) 14 /* NOTREACHED - jump_to_copy() does not return */ 15 hang(); 16 #endif 17 }
在其中最重要的函数则是 initcall_run_list(init_sequence_f) ,init_sequence_f 执行单板的各种初始化任务,如下:
1 static init_fnc_t init_sequence_f[] = { 2 //gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE; 3 //CONFIG_SYS_MONITOR_BASE = _start = 0 4 //设置gd->mon_len为编译出来的u-boot.bin+bss段的大小 5 setup_mon_len, 6 initf_malloc, 7 initf_console_record, 8 //这个函数应该是留给移植人员使用的,里面什么都没做,而且被__weak修饰, 9 //所以我们可以在别的地方重新定义这个函数来取代它 10 arch_cpu_init, /* basic arch cpu dependent setup:CPU初始化*/ 11 initf_dm, 12 arch_cpu_init_dm, //同上 13 mark_bootstage, /* need timer, go after init dm */ 14 #if defined(CONFIG_BOARD_EARLY_INIT_F) 15 /* 初始化CPU时钟和各种IO(待修改) */ 16 board_early_init_f, 17 #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || 18 defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || 19 defined(CONFIG_SPARC) 20 /* 初始化定时器 */ 21 timer_init, /* 初始化定时器 */ 22 #endif 23 env_init, /* 初始化环境变量 */ 24 init_baud_rate, /* 初始化波特率为: 115200 */ 25 serial_init, /* 设置串口通讯 */ 26 console_init_f, /* stage 1 init of console */ 27 // 打印版本信息,你可以修改include/version.h中的CONFIG_IDENT_STRING选项, 28 // 加入自己的身份信息 29 display_options, /* say that we are here */ 30 //打印bss段信息及text_base, 需要 #define DEBUG 31 display_text_info, /* show debugging info if required */ 32 print_cpuinfo, /* 打印CPUID和时钟频率 */ 33 INIT_FUNC_WATCHDOG_INIT 34 INIT_FUNC_WATCHDOG_RESET 35 announce_dram_init, //输出"DRAM: " 然后在下面进行SDRAM参数设置 36 /* TODO: unify all these dram functions? */ 37 #if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || 38 defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) 39 dram_init, /* 在smdk2440.c中定义,配置SDRAM大小,可根据实际进行修改 */ 40 #endif 41 INIT_FUNC_WATCHDOG_RESET 42 INIT_FUNC_WATCHDOG_RESET 43 /* 44 * Now that we have DRAM mapped and working, we can 45 * relocate the code and continue running from DRAM. 46 * 47 * Reserve memory at end of RAM for (top down in that order): 48 * - area that won't get touched by U-Boot and Linux (optional) 49 * - kernel log buffer 50 * - protected RAM 51 * - LCD framebuffer 52 * - monitor code 53 * - board info struct 54 */ 55 setup_dest_addr, //将gd->relocaddr、gd->ram_top指向SDRAM最顶端 56 reserve_round_4k, //gd->relocaddr 4K对齐 57 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && 58 defined(CONFIG_ARM) 59 //gd->arch.tlb_size = PGTABLE_SIZE; 预留16kb的MMU页表 60 //gd->relocaddr -= gd->arch.tlb_size; 61 //gd->relocaddr &= ~(0x10000 - 1); 64kb对齐 62 //gd->arch.tlb_addr = gd->relocaddr; 63 reserve_mmu, 64 #endif 65 #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && 66 !defined(CONFIG_ARM) && !defined(CONFIG_X86) && 67 !defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K) 68 reserve_video, 69 #endif 70 #if !defined(CONFIG_BLACKFIN) 71 //gd->relocaddr -= gd->mon_len; 一开始设置的u-boot.bin + bss段长度 72 //gd->relocaddr &= ~(4096 - 1); 4k对齐,这是最终重定位地址 73 //gd->start_addr_sp = gd->relocaddr; 设置重定位后的栈指针 74 reserve_uboot, 75 #endif 76 #ifndef CONFIG_SPL_BUILD 77 //gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN; 78 //预留4MB MALLOC内存池 79 reserve_malloc, 80 //gd->start_addr_sp -= sizeof(bd_t); 预留空间给重定位后的gd_t->bd 81 //gd->bd = (bd_t *)gd->start_addr_sp; 指定重定位bd地址 82 //memset(gd->bd, ' ', sizeof(bd_t)); 清零 83 reserve_board, 84 #endif 85 //gd->bd->bi_arch_number = CONFIG_MACH_TYPE; 86 //对于S3C2440来说就是MACH_TYPE_S3C2440 (arch/arm/include/asm/mach-types.h) 87 setup_machine, 88 reserve_global_data, 89 reserve_fdt, 90 reserve_arch, 91 //gd->start_addr_sp -= 16; 栈指针16字节对齐 92 //gd->start_addr_sp &= ~0xf; 93 reserve_stacks, 94 //gd->bd->bi_dram[i].start = addr; 设置sdram地址和大小 95 //gd->bd->bi_dram[i].size = size; 96 setup_dram_config, 97 show_dram_config,//打印SDRAM大小,与上面的announce_dram_init相对应 98 display_new_sp, 99 INIT_FUNC_WATCHDOG_RESET 100 reloc_fdt, 101 //gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; 计算重定位偏移地址 102 //memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); 103 //将原来的gd复制到重定位后的gd地址上去 104 setup_reloc, 105 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) 106 /* 重定位代码 */ 107 jump_to_copy, 108 #endif 109 NULL, 110 }
3.relocate_code
jump_to_copy中调用重定位代码relocate_code:C语言调用汇编代码,relocate_code 定义在 relocate.S (archarmlib) 。
relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);
内存分布图如下:
gd->start_addr_sp所在位置也看的出来了。gd->start_addr_sp 代码(内存分布代码):
1 Jz2440.h (includeconfigs)
2 #define PHYS_FLASH_1 0x00000000 /* Flash Bank #0 */
3 #define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
4 #define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE
5 static int setup_mon_len(void)
6 {
7 /* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
8 gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
9 return 0;
10 }
11
12 Jz2440.h (includeconfigs)
13 #define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
14
15 int dram_init(void)
16 {
17 /* dram_init must store complete ramsize in gd->ram_size */
18 gd->ram_size = PHYS_SDRAM_1_SIZE;
19 return 0;
20 }
21
22 Jz2440.h (includeconfigs)
23 #define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */
24 #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
25
26 static int setup_dest_addr(void)
27 {
28 gd->ram_size = board_reserve_ram_top(gd->ram_size); //64M ram_size
29
30 #ifdef CONFIG_SYS_SDRAM_BASE
31 gd->ram_top = CONFIG_SYS_SDRAM_BASE; //gd->ram_top = 0x30000000
32 #endif
33 gd->ram_top += get_effective_memsize(); //gd->ramtop = 0x30000000 + 64M
34 gd->ram_top = board_get_usable_ram_top(gd->mon_len);//gd->ram_top值不变
35 gd->relocaddr = gd->ram_top;//gd->relocaddr = 0x30000000 + 64M
36 return 0;
37 }
38
39 static int reserve_round_4k(void) //gd->relocaddr 4K对齐
40 {
41 gd->relocaddr &= ~(4096 - 1);
42 return 0;
43 }
44
45 static int reserve_mmu(void)
46 {
47 /* reserve TLB table */
48 gd->arch.tlb_size = PGTABLE_SIZE; //预留16kb的MMU页表
49 gd->relocaddr -= gd->arch.tlb_size; //gd->relocaddr = gd->relocaddr - 16K = 0x33ffc000
50
51 /* round down to next 64 kB limit */
52 gd->relocaddr &= ~(0x10000 - 1); //64kb对齐 gd->relocaddr = 0x33ff0000
53
54 gd->arch.tlb_addr = gd->relocaddr; //gd->arch.tlb_addr = 0x33ff0000
55 debug("TLB table from %08lx to %08lx
", gd->arch.tlb_addr,
56 gd->arch.tlb_addr + gd->arch.tlb_size);
57 return 0;
58 }
59
60
61 static int reserve_uboot(void)
62 {
63 /*
64 * reserve memory for U-Boot code, data & bss
65 * round down to next 4 kB limit
66 */
67 gd->relocaddr -= gd->mon_len; // 一开始设置的u-boot.bin + bss段长度
68 //gd->relocaddr=gd->relocaddr-4kb=0x33fef000
69 gd->relocaddr &= ~(4096 - 1); // 4k对齐,这是最终重定位地址 0x33fef000
70
71 gd->start_addr_sp = gd->relocaddr; //设置重定位后的栈指针gd->start_addr_sp=0x33fef000
72
73 return 0;
74 }
75
76 Jz2440.h (includeconfigs)
77 #define CONFIG_SYS_MALLOC_LEN (4 * 1024 * 1024) //4M 0x400000 4194304
78
79 Common.h (include)
80 #define TOTAL_MALLOC_LEN CONFIG_SYS_MALLOC_LEN
81
82 static int reserve_malloc(void)
83 { //gd->start_addr_sp = gd->start_addr_sp - 4 * 1024 * 1024 =0x33bef000
84 gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN; //预留4MB MALLOC内存池
85 return 0;
86 }
87
88 static int reserve_board(void)
89 {
90 if (!gd->bd) {
91 gd->start_addr_sp -= sizeof(bd_t); //预留空间给重定位后的gd_t->bd
92 gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t)); //指定重定位bd地址
93 memset(gd->bd, '