logo资料库

Uboot启动流程(国嵌视频里的文档).doc

第1页 / 共7页
第2页 / 共7页
第3页 / 共7页
第4页 / 共7页
第5页 / 共7页
第6页 / 共7页
第7页 / 共7页
资料共7页,全文预览结束
U-Boot 启动过程 (国嵌) 开发板上电后,执行 U-Boot 的第一条指令,然后顺序执行 U-Boot 启动函数。 看一下 board/smdk2410/u-boot.lds 这个链接脚本,可以知道目标程序的各部 分链接顺序。第一个要链接的是 cpu/arm920t/start.o,那么 U-Boot 的入口指 令一定位于这个程序中。下面分两阶段介绍启动流程: 第一阶段 1.cpu/arm920t/start.S 这个汇编程序是 U-Boot 的入口程序,开头就是复位向量的代码。 _start: b reset //复位向量 pc, _undefined_instruction pc, _software_interrupt pc, _prefetch_abort pc, _data_abort pc, _not_used pc, _irq pc, _fiq //中断向量 //中断向量 ldr ldr ldr ldr ldr ldr ldr … /* the actual reset code */ reset: //复位启动子程序 /* 设置 CPU 为 SVC32 模式 */ mrs bic orr msr r0,cpsr r0,r0,#0x1f r0,r0,#0xd3 cpsr,r0 /* 关闭看门狗 */ …… …… r0, _start r1, _TEXT_BASE r0, r1 relocate: adr ldr cmp RAM */ beq /* 把 U-Boot 重新定位到 RAM */ /* r0 是代码的当前位置 */ /*_TEXT_BASE 是 RAM 中的地址 */ /* 比较 r0 和 r1,判断当前是从 Flash 启动,还是 stack_setup /* 如果 r0 等于 r1,跳过重定位代码 */ r2, _armboot_start r3, _bss_start r2, r3, r2 r2, r0, r2 /* 准备重新定位代码 */ ldr ldr sub add copy_loop: /* 重新定位代码 */ ldmia r0!, {r3-r10} /* r2 得到 armboot 的大小 */ /* r2 得到要复制代码的末尾地址 */ /*从源地址[r0]复制 */
stmia r1!, {r3-r10} cmp ble r0, r2 copy_loop /* 复制到目的地址[r1] */ /* 复制数据块直到源数据末尾地址[r2] */ */ r0, _TEXT_BASE /* 上面是 128 KiB 重定位的 u-boot */ r0, r0, #CFG_MALLOC_LEN /* 向下是内存分配空间 */ r0, r0, #CFG_GBL_DATA_SIZE /* 然后是 bdinfo 结构体地址空间 */ /* 初始化堆栈等 stack_setup: ldr sub sub #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif sub clear_bss: ldr ldr mov clbss_l:str r2, [r0] /* bss 段地址空间清零循环... /* 找到 bss 段起始地址 */ /* bss 段末尾地址 */ /* 为 abort-stack 预留 3 个字 */ r0, _bss_start r1, _bss_end r2, #0x00000000 sp, r0, #12 /* 清零 */ */ r0, r0, #4 r0, r1 add cmp clbss_l bne pc, _start_armboot /* 跳转到 start_armboot 函数入口,_start_armboot 字保存函数入口指针 */ ldr _start_armboot: lib_arm/board.c 中实现 .word start_armboot //start_armboot 函 数 在 2.lib_arm/board.c start_armboot 是 U-Boot 执行的第一个 C 语言函数,完成系统初始化工作, 进入主循环,处理用户输入的命令。 第二阶段 3.init_sequence[] init_sequence[]数组保存着基本的初始化函数指针。 /* 基本的处理器相关配置 -- cpu/arm920t/cpu.c */ init_fnc_t *init_sequence[] = { cpu_init, board_init, /* 基本的板级相关配置 -- board/smdk2410/smdk2410.c */ interrupt_init, env_init, init_baudrate, serial_init, console_init_f, /* 初始化中断处理 -- cpu/arm920t/s3c24x0/interrupt.c */ /* 初始化环境变量 -- common/cmd_flash.c */ /* 初始化波特率设置 -- lib_arm/board.c */ /* 串口通讯设置 -- cpu/arm920t/s3c24x0/serial.c */ /* 控制台初始化阶段 1 -- common/console.c */
/* 打印 u-boot 信息 -- lib_arm/board.c */ /* 配置可用的 RAM -- board/smdk2410/smdk2410.c */ /* 显示 RAM 的配置大小 -- lib_arm/board.c */ display_banner, dram_init, display_dram_config, NULL, }; void start_armboot (void) { /* 顺序执行 init_sequence 数组中的初始化函数 */ for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } } /*配置可用的 Flash */ size = flash_init (); display_flash_config (size); /* _armboot_start 在 u-boot.lds 链接脚本中定义 */ mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); /* 配置环境变量*/ env_relocate (); /* 从环境变量中获取 IP 地址 */ gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); /* 以太网接口 MAC 地址 */ …… devices_init (); jumptable_init (); console_init_r (); enable_interrupts (); /* 使能中断处理 */ /* 获取列表中的设备 */ /* 完整地初始化控制台设备 */ if ((s = getenv ("loadaddr")) != NULL) { load_addr = simple_strtoul (s, NULL, 16); /* 通过环境变量初始化 */ } /* main_loop()循环不断执行 */ for (;;) { main_loop (); common/main.c */ } /* 主 循 环 函 数 处 理 执 行 用 户 命 令 -- 命令实现 U-Boot 作为 Bootloader,具备多种引导内核启动的方式。常用的 go 和 bootm 命令可以直接引导内核映像启动。U-Boot 与内核的关系主要是内核启动过程中
参数的传递。 1.go 命令的实现 /* common/cmd_boot.c */ int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ulong addr, rc; int if (argc < 2) { rcode = 0; printf ("Usage:\n%s\n", cmdtp->usage); return 1; } addr = simple_strtoul(argv[1], NULL, 16); printf ("## Starting application at 0x%08lX ...\n", addr); rc = ((ulong (*)(int, char []))addr) (--argc, &argv[1]); */ } if (rc != 0) rcode = 1; printf ("## Application terminated, rc = 0x%lX\n", rc); 行 linux,这条指令是否能运行?*/ return rcode; /* 运行程序 /*如果是运 go 命令调用 do_go()函数,跳转到某个地址执行的。如果在这个地址准备好了 自引导的内核映像,就可以启动了。尽管 go 命令可以带变参,实际使用时不用 来传递参数。 2.bootm 命令的实现 /* common/cmd_bootm.c */ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { …… …… /* 检查头部 */ if (crc32 (0, (uchar *)data, len) != checksum) { puts ("Bad Header Checksum\n"); SHOW_BOOT_PROGRESS (-2); return 1; } …… /*解压缩*/ …… switch (hdr->ih_comp) { case IH_COMP_NONE: if(ntohl(hdr->ih_load) == addr) { printf (" XIP %s ... ", name);
} else { #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) size_t l = len; void *to = (void *)ntohl(hdr->ih_load); void *from = (void *)data; printf (" Loading %s ... ", name); while (l > 0) { size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; WATCHDOG_RESET(); memmove (to, from, tail); to += tail; from += tail; l -= tail; } #else/* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ len); #endif } break; case IH_COMP_GZIP: printf (" if (gunzip ((void *)ntohl(hdr->ih_load), unc_len, Uncompressing %s ... ", name); (uchar *)data, &len) != 0) { puts ("GUNZIP ERROR - must RESET board to recover\n"); SHOW_BOOT_PROGRESS (-6); do_reset (cmdtp, flag, argc, argv); } break; #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: Uncompressing %s ... ", name); printf (" /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load), &unc_len, (char *)data, len,
#endif /* CONFIG_BZIP2 */ } break; default: if (iflag) enable_interrupts(); printf ("Unimplemented compression type %d\n", CFG_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i); SHOW_BOOT_PROGRESS (-6); udelay(100000); do_reset (cmdtp, flag, argc, argv); hdr->ih_comp); } } …… SHOW_BOOT_PROGRESS (-7); return 1; …… …… switch (hdr->ih_os) { default: case IH_OS_LINUX: /* handled by (original) Linux case */ do_bootm_linux (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_NETBSD: break; case IH_OS_RTEMS: do_bootm_netbsd (cmdtp, flag, argc, argv, addr, len_ptr, verify); do_bootm_rtems (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_VXWORKS: do_bootm_vxworks (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_QNX: break; } do_bootm_qnxelf (cmdtp, flag, argc, argv, addr, len_ptr, verify);
bootm 命令调用 do_bootm 函数。这个函数专门用来引导各种操作系统映像, 可以支持引导 Linux、vxWorks、QNX 等操作系统。引导 Linux 的时候,调用 do_bootm_linux()函数。 3.do_bootm_linux 函数的实现 /* lib_arm/armlinux.c */ void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], ulong addr, ulong *len_ptr, int verify) { theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep); … … … … /* we assume that the kernel is in place */ printf ("\nStarting kernel ...\n\n"); … … … … theKernel (0, bd->bi_arch_number, bd->bi_boot_params); /*启动 内核,传递启动参数*/ } do_bootm_linux()函数是专门引导 Linux 映像的函数,它还可以处理 ramdisk 文件系统的映像。这里引导的内核映像和 ramdisk 映像,必须是 U-Boot 格式 的。U-Boot 格式的映像可以通过 mkimage 工具来转换,其中包含了 U-Boot 可以识别的符号。
分享到:
收藏