U-boot第二阶段分析
2015-06-03 14:14
274 查看
一、U-boot第二阶段概述
上面有两篇文关于u-boot第一阶段的介绍,这两篇文章是从网上找到的,由于分析的很详细,看完这后觉得对这两篇文章u-boot第一阶段的介绍已经比较完美了,所以分享出来。从这篇文章开始分析u-boot的第二阶段。
如果你只把u-boot理解成引导kernel的一段代码的话,u-boot完全没有必要设计成现在这样的一种软件框架,直接写几个文件就能完成kernel的引导和启动。U-boot的功能很大一部还有起到调试的作用,也就是u-boot命令行的部分。所以它才有了现在这种相对比较复杂的框架。U-boot的第二阶段可以认为是初始化u-boot的软件框架,并实现引导kernel启动和命令行调试环境的过程
U-boot第二阶段总结来说主要可以概括为下面几点
1、硬件的初始化
2、运行环境的初始化
3、载入内核并启动内核
4、运行u-boot调试的命令机制
其中1和2阶段可以看成是u-boot软件框架的初始化过程,只不过包括了硬件设备的初始化和软件相关结构体的初始化。而3就是引导kernel启动过程,而4是调试的命令行环境运行过程。
本文首先沿着第一阶段调用_start_armboot函数开始第二阶段的分析。首先完成一个概述,之后会对一些关键的问题做专题分析。
二、硬件和软件框架的初始化
首先初始化一个全局性的数据结构gd_t
我们看到这里u-boot动态的分配了gd_t和bd_t这两个数据结构,只是比较疑惑的是这两个数据结构完全可以定义成全局的数据,何必这样动态的分配呢?由于这个时候完全没有malloc这样的环境,u-boot只好跑马圈地,很野蛮的在_armboot_start前面画出一块位置作为上面结构体区域。这里我们就两个疑问?1、u-boot到底被第一阶段的代码拷贝到什么地方去执行了?第二个疑问就是u-boot在内存区域中相关代码和数据区域是怎么分布的?
Question1:
Answer:
查看一下下面的配置文件就可以知道,mini2440开发板sdram的地址范围是3000’0000到3400’0000,一共是64M。U-boot首先把自己载入了最后的512K的地址空间中,坐在墙角的位置。
u-boot-1.1.6\board\open24x0\config.mk
#
# SMDK2410 has 1 bank of 64 MB DRAM
#
# 3000'0000 to 3400'0000
#
# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000
# optionally with a ramdisk at 3080'0000
#
# we load ourself to 33F8'0000
#
# download area is 3300'0000
#
TEXT_BASE = 0x33F80000
Question2:
Answer:
U-boot被完全载入到内存后,各部分在内存中的位置如下图所示:
需要注意的是图中TEXT_BASE的地址在整个SDRAM空间的最后512K位置了。
初始化函数调用
接着u-boot对单板的硬件和软件框架做相应的初始化
U-boot软件框架定义了这样的一个初始化表,不同的单板具体实现下面的函数进行相应的初始化动作
后续的文章会将上面的初始化函数做逐一的分析,但是本篇本意是想对第二阶段的处理过程做一个提纲挈领的描述,所以暂时举一个例子分析如下:
Cpu_init函数基本上就是初始化了一下栈区空间和软件中断的栈空间
在完成了单板相应硬件初始化之后,u-boot在后继的代码里可以自由的使用u-boot框架提供的一些服务接口,比如从串口获取输入,从nandflash读写数据,网络接口通信等等。然后u-boot进入了一个大的循环中
在main_loop函数中,有两条比较关键的路径需要分析,一条路径就是引导内核启动,另外一条路径就是用户通过串口输入中断了u-boot启动内核过程而进入了u-boot的命令行调试运行环境中。
三、u-boot引导内核启动的过程。
首先我们来分析一下u-boot引导内核启动的过程
1、首先获取等待用户串口按键中断引导kernel的时间,一般为3秒
2、获取启动内核的命令,这个靠编译u-boot之前开发者的配置
而这条启动命令在mini2440的配置就是如下,其实是两条命令组成的
#define CONFIG_BOOTCOMMAND "nand read.jffs2 0x32000000 kernel; bootm 0x32000000"
3、调用abortboot函数检查在等待的3s中内是不是从串口有用户输入了空格,如果有就说明用户想进入命令行调试模式,如果没有就说明可以开始运行启动内核的命令。
4、abortboot中比较关键的代码就是在一个循环中不断检测是不是有用户的串口输入,使用了一个udelay函数,10000us等于10ms,循环100次就是1s
5、用户不中断kernel引导过程的话,最后会调用到run_command函数,这个函数不需要怎么分析,它的作用就就是解析输入的命令,然后根据命令的名字查找相应的命令执行函数进行调用,上面我们看到,启动的时候需要调用两个命令,一个是nand命令一个bootm命令。
6、Nand命令完成将kernel载入到内存中指定的位置,而bootm则是最后调用固定位置的一个kernel启动函数进入kernel的代码中开始执行。
7、执行nand命令,u-boot在其软件框架中定义了一个命令nand如下所示,执行这个命令最后会调用到函数do_nand
这里也没有必要去深入探究do_nand的作用,它完成的工作就是将kernel从nandflash中准确的载入到内存指定的位置。
当nand命令将kernel读入到内存后,接着执行bootm命令,最后执行linux内核的code
这个命令的执行最后会调用到do_bootm函数
最后调用do_linux_bootm完成内核启动,这个函数主要做三个工作,首先是拷贝inird到确定位置,然后初始化内核参数到确定的位置,最后调用内核的启动函数,并传递两个参数给内核一个是cpu number,一个是内核参数位置。
四、U-boot命令行调试状态
上面是对u-boot载入引导kernel的分析。如果用户通过串口打断引导过程,或者引导过程失败了,就会进入u-boot命令行调试状态。U-boot进入一个无限的for循环等待用户从串口输入命令,找到匹配的命令后执行相应的操作。
上面有两篇文关于u-boot第一阶段的介绍,这两篇文章是从网上找到的,由于分析的很详细,看完这后觉得对这两篇文章u-boot第一阶段的介绍已经比较完美了,所以分享出来。从这篇文章开始分析u-boot的第二阶段。
如果你只把u-boot理解成引导kernel的一段代码的话,u-boot完全没有必要设计成现在这样的一种软件框架,直接写几个文件就能完成kernel的引导和启动。U-boot的功能很大一部还有起到调试的作用,也就是u-boot命令行的部分。所以它才有了现在这种相对比较复杂的框架。U-boot的第二阶段可以认为是初始化u-boot的软件框架,并实现引导kernel启动和命令行调试环境的过程
U-boot第二阶段总结来说主要可以概括为下面几点
1、硬件的初始化
2、运行环境的初始化
3、载入内核并启动内核
4、运行u-boot调试的命令机制
其中1和2阶段可以看成是u-boot软件框架的初始化过程,只不过包括了硬件设备的初始化和软件相关结构体的初始化。而3就是引导kernel启动过程,而4是调试的命令行环境运行过程。
本文首先沿着第一阶段调用_start_armboot函数开始第二阶段的分析。首先完成一个概述,之后会对一些关键的问题做专题分析。
二、硬件和软件框架的初始化
首先初始化一个全局性的数据结构gd_t
/* Pointer is writable since we allocated a register for it */ gd = (gd_t *)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); memset ((void *)gd, 0, sizeof (gd_t)); gd->bd = (bd_t *)((char *)gd - sizeof(bd_t)); memset (gd->bd, 0, sizeof (bd_t)); monitor_flash_len = _bss_start - _armboot_start; |
Question1:
Answer:
查看一下下面的配置文件就可以知道,mini2440开发板sdram的地址范围是3000’0000到3400’0000,一共是64M。U-boot首先把自己载入了最后的512K的地址空间中,坐在墙角的位置。
u-boot-1.1.6\board\open24x0\config.mk
#
# SMDK2410 has 1 bank of 64 MB DRAM
#
# 3000'0000 to 3400'0000
#
# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000
# optionally with a ramdisk at 3080'0000
#
# we load ourself to 33F8'0000
#
# download area is 3300'0000
#
TEXT_BASE = 0x33F80000
Question2:
Answer:
U-boot被完全载入到内存后,各部分在内存中的位置如下图所示:
需要注意的是图中TEXT_BASE的地址在整个SDRAM空间的最后512K位置了。
初始化函数调用
接着u-boot对单板的硬件和软件框架做相应的初始化
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } } |
init_fnc_t *init_sequence[] = { cpu_init, /* basic cpu dependent setup */ board_init, /* basic board dependent setup */ interrupt_init, /* set up exceptions */ env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */ console_init_f, /* stage 1 init of console */ display_banner, /* say that we are here */ #if defined(CONFIG_DISPLAY_CPUINFO) print_cpuinfo, /* display cpu info (and speed) */ #endif #if defined(CONFIG_DISPLAY_BOARDINFO) checkboard, /* display board info */ #endif dram_init, /* configure available RAM banks */ display_dram_config, NULL, }; |
int cpu_init (void) { /* * setup up stacks if necessary */ #ifdef CONFIG_USE_IRQ IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4; FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ; FREE_RAM_END = FIQ_STACK_START - CONFIG_STACKSIZE_FIQ - CONFIG_STACKSIZE; FREE_RAM_SIZE = FREE_RAM_END - PHYS_SDRAM_1; #else FREE_RAM_END = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4 - CONFIG_STACKSIZE; FREE_RAM_SIZE = FREE_RAM_END - PHYS_SDRAM_1; #endif return 0; } |
在完成了单板相应硬件初始化之后,u-boot在后继的代码里可以自由的使用u-boot框架提供的一些服务接口,比如从串口获取输入,从nandflash读写数据,网络接口通信等等。然后u-boot进入了一个大的循环中
for (;;) { main_loop (); } |
三、u-boot引导内核启动的过程。
首先我们来分析一下u-boot引导内核启动的过程
1、首先获取等待用户串口按键中断引导kernel的时间,一般为3秒
s = getenv ("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; |
s = getenv ("bootcmd"); |
#define CONFIG_BOOTCOMMAND "nand read.jffs2 0x32000000 kernel; bootm 0x32000000"
3、调用abortboot函数检查在等待的3s中内是不是从串口有用户输入了空格,如果有就说明用户想进入命令行调试模式,如果没有就说明可以开始运行启动内核的命令。
if (bootdelay >= 0 && s && !abortboot (bootdelay)) { { printf("Booting Linux ...\n"); run_command (s, 0); } } |
while ((bootdelay > 0) && (!abort)) { int i; --bootdelay; /* delay 100 * 10ms */ for (i = 0; !abort && i < 100; ++i) { if (tstc()) /* we got a key press */ { # ifdef CONFIG_MENUKEY abort = 1; /* don't auto boot */ bootdelay = 0; /* no more delay */ menukey = getc(); break; # else /* consume input */ if (getc() == ' ') { abort = 1; /* don't auto boot */ bootdelay = 0; /* no more delay */ break; } # endif } udelay (10000); } printf ("\b\b\b%2d ", bootdelay); } |
6、Nand命令完成将kernel载入到内存中指定的位置,而bootm则是最后调用固定位置的一个kernel启动函数进入kernel的代码中开始执行。
7、执行nand命令,u-boot在其软件框架中定义了一个命令nand如下所示,执行这个命令最后会调用到函数do_nand
U_BOOT_CMD(nand, 5, 1, do_nand, "nand - NAND sub-system\n", "info - show available NAND devices\n" "nand device [dev] - show or set current device\n" "nand read[.jffs2] - addr off|partition size\n" "nand write[.jffs2] - addr off|partiton size - read/write `size' bytes starting\n" " at offset `off' to/from memory address `addr'\n" "nand read.yaffs addr off size - read the `size' byte yaffs image starting\n" " at offset `off' to memory address `addr'\n" "nand write.yaffs addr off size - write the `size' byte yaffs image starting\n" " at offset `off' from memory address `addr'\n" "nand read.raw addr off size - read the `size' bytes starting\n" " at offset `off' to memory address `addr', without oob and ecc\n" "nand write.raw addr off size - write the `size' bytes starting\n" " at offset `off' from memory address `addr', without oob and ecc\n" "nand erase [clean] [off size] - erase `size' bytes from\n" " offset `off' (entire device if not specified)\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n" "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" "nand markbad off - mark bad block at offset (UNSAFE)\n" "nand biterr off - make a bit error at offset (UNSAFE)\n" "nand lock [tight] [status] - bring nand to lock state or display locked pages\n" "nand unlock [offset] [size] - unlock section\n"); |
当nand命令将kernel读入到内存后,接着执行bootm命令,最后执行linux内核的code
U_BOOT_CMD( bootm, CFG_MAXARGS, 1, do_bootm, "bootm - boot application image from memory\n", "[addr [arg ...]]\n - boot application image stored in memory\n" "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" "\t'arg' can be the address of an initrd image\n" #ifdef CONFIG_OF_FLAT_TREE "\tWhen booting a Linux kernel which requires a flat device-tree\n" "\ta third argument is required which is the address of the of the\n" "\tdevice-tree blob. To boot that kernel without an initrd image,\n" "\tuse a '-' for the second argument. If you do not pass a third\n" "\ta bd_info struct will be passed instead\n" #endif ); |
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ulong iflag; ulong addr; ulong data, len, checksum; ulong *len_ptr; uint unc_len = CFG_BOOTM_LEN; int i, verify; char *name, *s; int (*appl)(int, char *[]); image_header_t *hdr = &header; s = getenv ("verify"); verify = (s && (*s == 'n')) ? 0 : 1; /*argv[1]传入的是从nandflash中载入到内存的地址0x32000000是32M的位置*/ if (argc < 2) { addr = load_addr; } else { addr = simple_strtoul(argv[1], NULL, 16); } SHOW_BOOT_PROGRESS (1); printf ("## Booting image at %08lx ...\n", addr); /*使用u-boot启动的内核在制作镜像的时候会增加一个64byte的头,这里要对这个头做相应的处理*/ memmove (&header, (char *)addr, sizeof(image_header_t)); /*检查这个header中的幻数对不对*/ if (ntohl(hdr->ih_magic) != IH_MAGIC) { { puts ("Bad Magic Number\n"); SHOW_BOOT_PROGRESS (-1); return 1; } } SHOW_BOOT_PROGRESS (2); data = (ulong)&header; len = sizeof(image_header_t); /*对这个header进行crc校验,比较原来保存的crc看是不是一致*/ checksum = ntohl(hdr->ih_hcrc); hdr->ih_hcrc = 0; if (crc32 (0, (uchar *)data, len) != checksum) { puts ("Bad Header Checksum\n"); SHOW_BOOT_PROGRESS (-2); return 1; } SHOW_BOOT_PROGRESS (3); /* for multi-file images we need the data part, too */ print_image_hdr ((image_header_t *)addr); data = addr + sizeof(image_header_t); len = ntohl(hdr->ih_size); if (verify) { puts (" Verifying Checksum ... "); if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { printf ("Bad Data CRC\n"); SHOW_BOOT_PROGRESS (-3); return 1; } puts ("OK\n"); } SHOW_BOOT_PROGRESS (4); len_ptr = (ulong *)data; /*cpu体系结构玛是不是正确*/ #if defined(__PPC__) if (hdr->ih_arch != IH_CPU_PPC) #elif defined(__ARM__) if (hdr->ih_arch != IH_CPU_ARM) #elif defined(__I386__) if (hdr->ih_arch != IH_CPU_I386) #elif defined(__mips__) if (hdr->ih_arch != IH_CPU_MIPS) #elif defined(__nios__) if (hdr->ih_arch != IH_CPU_NIOS) #elif defined(__M68K__) if (hdr->ih_arch != IH_CPU_M68K) #elif defined(__microblaze__) if (hdr->ih_arch != IH_CPU_MICROBLAZE) #elif defined(__nios2__) if (hdr->ih_arch != IH_CPU_NIOS2) #elif defined(__blackfin__) if (hdr->ih_arch != IH_CPU_BLACKFIN) #elif defined(__avr32__) if (hdr->ih_arch != IH_CPU_AVR32) #else # error Unknown CPU type #endif { printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch); SHOW_BOOT_PROGRESS (-4); return 1; } SHOW_BOOT_PROGRESS (5); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: name = "Standalone Application"; /* A second argument overwrites the load address */ if (argc > 2) { hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16)); } break; case IH_TYPE_KERNEL: name = "Kernel Image"; break; case IH_TYPE_MULTI: name = "Multi-File Image"; len = ntohl(len_ptr[0]); /* OS kernel is always the first image */ data += 8; /* kernel_len + terminator */ for (i = 1; len_ptr[i]; ++i) data += 4; break; default: printf ("Wrong Image Type for %s command\n", cmdtp->name); SHOW_BOOT_PROGRESS (-5); return 1; } SHOW_BOOT_PROGRESS (6); /* * We have reached the point of no return: we are going to * overwrite all exception vector code, so we cannot easily * recover from any failures any more... */ iflag = disable_interrupts(); #ifdef CONFIG_AMIGAONEG3SE /* * We've possible left the caches enabled during * bios emulation, so turn them off again */ icache_disable(); invalidate_l1_instruction_cache(); flush_data_cache(); dcache_disable(); #endif /*这个位置需要注意,ih_load表示内核自己希望运行的位置,如果这个位置和 boot载入内核到内存的位置data不一样,叫进行拷贝*/ switch (hdr->ih_comp) { case IH_COMP_NONE: if(ntohl(hdr->ih_load) == data) { printf (" XIP %s ... ", name); } else { memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); } break; case IH_COMP_GZIP: printf (" Uncompressing %s ... ", name); if (gunzip ((void *)ntohl(hdr->ih_load), unc_len, (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: printf (" Uncompressing %s ... ", name); /* * 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, 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); } break; #endif /* CONFIG_BZIP2 */ default: if (iflag) enable_interrupts(); printf ("Unimplemented compression type %d\n", hdr->ih_comp); SHOW_BOOT_PROGRESS (-7); return 1; } puts ("OK\n"); SHOW_BOOT_PROGRESS (7); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: if (iflag) enable_interrupts(); /* load (and uncompress), but don't start if "autostart" * is set to "no" */ if (((s = getenv("autostart")) != NULL) && (strcmp(s, "no") == 0)) { char buf[32]; sprintf(buf, "%lX", len); setenv("filesize", buf); return 0; } appl = (int ( *)(int, char * []))ntohl(hdr->ih_ep); (*appl)(argc - 1, &argv[1]); return 0; case IH_TYPE_KERNEL: case IH_TYPE_MULTI: /* handled below */ break; default: if (iflag) enable_interrupts(); printf ("Can't boot image type %d\n", hdr->ih_type); SHOW_BOOT_PROGRESS (-8); return 1; } SHOW_BOOT_PROGRESS (8); /*最后我们一般启动的linux内核,调用do_bootm_linux进行处理*/ switch (hdr->ih_os) { default: /* handled by (original) Linux case */ case IH_OS_LINUX: #ifdef CONFIG_SILENT_CONSOLE fixup_silent_linux(); #endif do_bootm_linux (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_NETBSD: do_bootm_netbsd (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #ifdef CONFIG_LYNXKDI case IH_OS_LYNXOS: do_bootm_lynxkdi (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif case IH_OS_RTEMS: do_bootm_rtems (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #if (CONFIG_COMMANDS & CFG_CMD_ELF) case IH_OS_VXWORKS: do_bootm_vxworks (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_QNX: do_bootm_qnxelf (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif /* CFG_CMD_ELF */ #ifdef CONFIG_ARTOS case IH_OS_ARTOS: do_bootm_artos (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif } SHOW_BOOT_PROGRESS (-9); #ifdef DEBUG puts ("\n## Control returned to monitor - resetting...\n"); do_reset (cmdtp, flag, argc, argv); #endif return 1; } |
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], ulong addr, ulong *len_ptr, int verify) { ulong len = 0, checksum; ulong initrd_start, initrd_end; ulong data; void (*theKernel)(int zero, int arch, uint params); image_header_t *hdr = &header; bd_t *bd = gd->bd; #ifdef CONFIG_CMDLINE_TAG char *commandline = getenv ("bootargs"); #endif /*ih_ep的值正是kernel启动的第一条code的位置*/ theKernel = (void ( *)(int, int, uint))ntohl(hdr->ih_ep); /* * Check if there is an initrd image */ if (argc >= 3) { SHOW_BOOT_PROGRESS (9); addr = simple_strtoul (argv[2], NULL, 16); printf ("## Loading Ramdisk Image at %08lx ...\n", addr); /* Copy header so we can blank CRC field for re-calculation */ #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash (addr)) { read_dataflash (addr, sizeof (image_header_t), (char *) &header); } else #endif memcpy (&header, (char *) addr, sizeof (image_header_t)); if (ntohl (hdr->ih_magic) != IH_MAGIC) { printf ("Bad Magic Number\n"); SHOW_BOOT_PROGRESS (-10); do_reset (cmdtp, flag, argc, argv); } data = (ulong) & header; len = sizeof (image_header_t); checksum = ntohl (hdr->ih_hcrc); hdr->ih_hcrc = 0; if (crc32 (0, (unsigned char *) data, len) != checksum) { printf ("Bad Header Checksum\n"); SHOW_BOOT_PROGRESS (-11); do_reset (cmdtp, flag, argc, argv); } SHOW_BOOT_PROGRESS (10); print_image_hdr (hdr); data = addr + sizeof (image_header_t); len = ntohl (hdr->ih_size); #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash (addr)) { read_dataflash (data, len, (char *) CFG_LOAD_ADDR); data = CFG_LOAD_ADDR; } #endif if (verify) { ulong csum = 0; printf (" Verifying Checksum ... "); csum = crc32 (0, (unsigned char *) data, len); if (csum != ntohl (hdr->ih_dcrc)) { printf ("Bad Data CRC\n"); SHOW_BOOT_PROGRESS (-12); do_reset (cmdtp, flag, argc, argv); } printf ("OK\n"); } SHOW_BOOT_PROGRESS (11); if ((hdr->ih_os != IH_OS_LINUX) || (hdr->ih_arch != IH_CPU_ARM) || (hdr->ih_type != IH_TYPE_RAMDISK)) { printf ("No Linux ARM Ramdisk Image\n"); SHOW_BOOT_PROGRESS (-13); do_reset (cmdtp, flag, argc, argv); } #if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO) /* *we need to copy the ramdisk to SRAM to let Linux boot */ memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); data = ntohl(hdr->ih_load); #endif /* CONFIG_B2 || CONFIG_EVB4510 */ /* * Now check if we have a multifile image */ } else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) { ulong tail = ntohl (len_ptr[0]) % 4; int i; SHOW_BOOT_PROGRESS (13); /* skip kernel length and terminator */ data = (ulong) (&len_ptr[2]); /* skip any additional image length fields */ for (i = 1; len_ptr[i]; ++i) data += 4; /* add kernel length, and align */ data += ntohl (len_ptr[0]); if (tail) { data += 4 - tail; } len = ntohl (len_ptr[1]); } else { /* * no initrd image */ SHOW_BOOT_PROGRESS (14); len = data = 0; } #ifdef DEBUG if (!data) { printf ("No initrd\n"); } #endif if (data) { initrd_start = data; initrd_end = initrd_start + len; } else { initrd_start = 0; initrd_end = 0; } SHOW_BOOT_PROGRESS (15); debug ("## Transferring control to Linux (at address %08lx) ...\n", (ulong) theKernel); /*设置要传递的内核参数到内存开始的512字节位置,然后启动linux内核,并 向linux 内核传递两个参数,一个参数是cpu类型,一个参数是内核参数位置*/ #if defined (CONFIG_SETUP_MEMORY_TAGS) || \ defined (CONFIG_CMDLINE_TAG) || \ defined (CONFIG_INITRD_TAG) || \ defined (CONFIG_SERIAL_TAG) || \ defined (CONFIG_REVISION_TAG) || \ defined (CONFIG_LCD) || \ defined (CONFIG_VFD) setup_start_tag (bd); #ifdef CONFIG_SERIAL_TAG setup_serial_tag (?ms); #endif #ifdef CONFIG_REVISION_TAG setup_revision_tag (?ms); #endif #ifdef CONFIG_SETUP_MEMORY_TAGS setup_memory_tags (bd); #endif #ifdef CONFIG_CMDLINE_TAG setup_commandline_tag (bd, commandline); #endif #ifdef CONFIG_INITRD_TAG if (initrd_start && initrd_end) setup_initrd_tag (bd, initrd_start, initrd_end); #endif #if defined (CONFIG_VFD) || defined (CONFIG_LCD) setup_videolfb_tag ((gd_t *) gd); #endif setup_end_tag (bd); #endif /* we assume that the kernel is in place */ printf ("\nStarting kernel ...\n\n"); #ifdef CONFIG_USB_DEVICE { extern void udc_disconnect (void); //udc_disconnect (); // cancled by www.arm9.net } #endif cleanup_before_linux (); theKernel (0, bd->bi_arch_number, bd->bi_boot_params); } |
上面是对u-boot载入引导kernel的分析。如果用户通过串口打断引导过程,或者引导过程失败了,就会进入u-boot命令行调试状态。U-boot进入一个无限的for循环等待用户从串口输入命令,找到匹配的命令后执行相应的操作。
for (;;) { /*从串口读出命令*/ len = readline (CFG_PROMPT); flag = 0; /* assume no special flags for now */ if (len > 0) strcpy (lastcommand, console_buffer); else if (len == 0) flag |= CMD_FLAG_REPEAT; #ifdef CONFIG_BOOT_RETRY_TIME else if (len == -2) { /* -2 means timed out, retry autoboot */ puts ("\nTimed out waiting for command\n"); # ifdef CONFIG_RESET_TO_RETRY /* Reinit board to run initialization code again */ do_reset (NULL, 0, 0, NULL); # else return; /* retry autoboot */ # endif } #endif /*执行相应的命令*/ if (len == -1) puts ("<INTERRUPT>\n"); else rc = run_command (lastcommand, flag); if (rc <= 0) { /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } } #endif /*CFG_HUSH_PARSER*/ |
相关文章推荐
- HDU 4497 GCD and LCM (分解质因数)
- 用户注册验证_基于jquery validate
- 如何得知当前机器上安装的PowerShell是什么版本的?
- js-函数eval
- dom兼容性问题3 元素操作
- linux下建立软链接
- Leetcode Max Points on a line
- Windows 2012 R2设置同一用户同时多点远程系统
- Objective-c之Singletone模式
- Java JMX
- C++实现PING命令
- 【C语言】C语言写的简单的定时关机程序
- AudioSystem类
- 编写自己的Matcher与如何让编译器识别被mock的重载函数
- MySql提示:The server quit without updating PID file(…)失败
- U-boot第一阶段分析
- Spring mvc原理
- Lua查找表元素过程(元表、__index方法是如何工作的)
- Android学习 - 使用及实现系统分享接口
- js对dom对象的操作之select元素:js不能获取select对象