一、重定位
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 处执行 */
二、代码流程
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