U-Boot启动内核分析.doc_第1页
U-Boot启动内核分析.doc_第2页
U-Boot启动内核分析.doc_第3页
U-Boot启动内核分析.doc_第4页
U-Boot启动内核分析.doc_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

U-Boot启动内核分析先来引用一下这篇介绍“ARM Linux内核启动要求”的文章ARM Linux Kernel Boot Requirements,是ARM Linux内核的维护者Russell King写的。 CPU register settings o r0 = 0. o r1 = machine type number. o r2 = physical address of tagged list in system RAM. CPU mode o All forms of interrupts must be disabled (IRQs and FIQs.) o The CPU must be in SVC mode. (A special exception exists for Angel.) Caches, MMUs o The MMU must be off. o Instruction cache may be on or off. o Data cache must be off and must not contain any stale data. Devices o DMA to/from devices should be quiesced. The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image.大致就是以上条件了,请特别关注一下第一条,这个基本上就是U-Boot的go命令和bootm命令之间的本质区别所在了。先来看看bootm命令的实现,在common/cmd_bootm.c的第119行开始有: #ifdef CONFIG_PPCstatic boot_os_Fcn do_bootm_linux;#elseextern boot_os_Fcn do_bootm_linux;#endif这里的预编译宏说明了,非 PPC体系结构的CPU的do_bootm_linux()函数都不是在这个文件内实现的(extern)。可想而知,这个函数的实现应该是和体系结构相 关的,具体到arm体系结构的实现就是在lib_arm/armlinux.c这个文件当中。可以看到从lib_arm/armlinux.c中的第77 行开始就是do_bootm_linux()函数的实现。其中第85行声明了这样一个函数指针theKernel:void (*theKernel)(int zero, int arch, uint params);看看它的名字和参数的命名我们 也可以猜到这个其实就是内核的入口函数的指针了。几个参数的命名也说明了上文提到的ARM Linux内核启动要求的第一条,因为根据ACPS(ARM/Thumb Procedure Call Standard)的规定,这三个参数就是依次使用r0,r1和r2来传递的。接下来第93行就是给这个函数指针赋值:theKernel = (void (*)(int, int, uint)ntohl(hdr-ih_ep);可以看到theKernel被 赋值为hdr-ih_ep,这个hdr是指使用tools/mkimage工具程序制作uImage时加在linux.bin.gz前面的一个头 部,而ih_ep结构体成员保存的就是使用mkimage时指定的-e参数的值,即内核的入口点(Entry Point)。 知道了hdr-ih_ep的意义之后,给theKernel赋这个值也就是理所当然的了。 最后是对内核入口函数的调用,发生在第270行:theKernel (0, bd-bi_arch_number, bd-bi_boot_params);调用的时候对参数进行赋值,r0=0,r1=bd-bi_arch_number,r2=bd-bi_boot_params,一个都不少。至此U-Boot的使命完成,开始进入ARM Linux的美丽新世界。 =要知道哪个地址是启动内核,哪个地址启动文件系统,要分析common/cmd_bootm.c中的函数do_bootm,因为引导kernel就是bootm这条命令的工作,do_bootm是命令bootm的执行函数。 现在我们来分析一下common/cmd_bootm.c中的函数do_bootm,这是bootm命令的处理函数。image_header_t header;ulong load_addr = CFG_LOAD_ADDR; /* Default Load Address */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 = 0x400000;int i, verify;char *name, *s;int (*appl)(int, char *);image_header_t *hdr = &header;读取uboot的环境变量verify,如果环境变量verify等于n,则局部变量verify赋值成为0;如果环境变量verify为空(即没有定义环境变量verify)或者环境变量verify不等于n,则局部变量verify赋值成为1。s = getenv (verify);verify = (s & (*s = n) ? 0 : 1;如果参数个数小于2(即只是输入了bootm),使用缺省加载地址CFG_LOAD_ADDR;否则使用第二个参数作为加载地址。if (argc ih_magic) != IH_MAGIC) #ifdef _I386_ /* correct image format not implemented yet - fake it */if (fake_header(hdr, (void*)addr, -1) != NULL) /* to compensate for the addition below */addr -= sizeof(image_header_t);/* turnof verify,* fake_header() does not fake the data crc*/verify = 0; else#endif /* _I386_ */puts (Bad Magic Numbern);SHOW_BOOT_PROGRESS (-1);return 1;SHOW_BOOT_PROGRESS (2);校验image header的CRC以及image data的CRC,如果校验不匹配,说明下载过程中发生了错误。data = (ulong)&header;len = sizeof(image_header_t);checksum = ntohl(hdr-ih_hcrc);hdr-ih_hcrc = 0;if (crc32 (0, (char *)data, len) != checksum) puts (Bad Header Checksumn);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);#ifdef CONFIG_HAS_DATAFLASHif (addr_dataflash(addr)read_dataflash(data, len, (char *)CFG_LOAD_ADDR);data = CFG_LOAD_ADDR;#endifif (verify) puts ( Verifying Checksum . );if (crc32 (0, (char *)data, len) != ntohl(hdr-ih_dcrc) printf (Bad Data CRCn);SHOW_BOOT_PROGRESS (-3);return 1;puts (OKn);SHOW_BOOT_PROGRESS (4);判断体系结构。len_ptr = (ulong *)data;#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)#else# error Unknown CPU type#endifprintf (Unsupported Architecture 0x%xn, hdr-ih_arch);SHOW_BOOT_PROGRESS (-4);return 1;SHOW_BOOT_PROGRESS (5);判断image类型。switch (hdr-ih_type) case IH_TYPE_STANDALONE:name = Standalone Application;/* A second argument overwrites the load address */if (argc 2) hdr-ih_load = simple_strtoul(argv2, NULL, 16);break;case IH_TYPE_KERNEL:name = Kernel Image;break;case IH_TYPE_MULTI:name = Multi-File Image;len = ntohl(len_ptr0);/* OS kernel is always the first image */data += 8; /* kernel_len + terminator */for (i=1; len_ptri; +i)data += 4;break;default: printf (Wrong Image Type for %s commandn, 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/* Weve 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判断image压缩类型switch (hdr-ih_comp) case IH_COMP_NONE: 没有压缩if(ntohl(hdr-ih_load) = addr) 如果image header中指示的加载地址和bootm命令中参数2指定的地址相同,则表示不需要copy,可以就地执行。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) */如果image header中指示的加载地址和bootm命令中参数2指定的地址不相同,则表示要从image header中指示的加载地址处把image data copy到bootm命令中参数2指定的地址处,然后再执行。memmove (void *) ntohl(hdr-ih_load), (uchar *)data, len);#endif /* CONFIG_HW_WATCHDOG | CONFIG_WATCHDOG */break;case IH_COMP_GZIP:printf ( Uncompressing %s . , name);if (gunzip (void *)ntohl(hdr-ih_load), unc_len,(uchar *)data, (int *)&len) != 0) puts (GUNZIP ERROR - must RESET board to recovern);SHOW_BOOT_PROGRESS (-6);do_reset (cmdtp, flag, argc, argv);break;#ifdef CONFIG_BZIP2case IH_COMP_BZIP2:printf ( Uncompressing %s . , name);/* If weve 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 ih_comp);SHOW_BOOT_PROGRESS (-7);return 1;puts (OKn);SHOW_BOOT_PROGRESS (7);根据image 执行type来决定如何引导。switch (hdr-ih_type) case IH_TYPE_STANDALONE:if (iflag)enable_interrupts();/* load (and uncompress), but dont start if autostart* is set to no*/if (s = getenv(autostart) != NULL) & (strcmp(s,no) = 0) char buf32;sprintf(buf, %lX, len);setenv(filesize, buf);return 0;appl = (int (*)(int, char *)ntohl(hdr-ih_ep);(*appl)(argc-1, &argv1);return 0;case IH_TYPE_KERNEL:case IH_TYPE_MULTI:/* handled below */break; 下面将有代码专门处理这两种image类型default:if (iflag)enable_interrupts();printf (Cant boot image type %dn, hdr-ih_type);SHOW_BOOT_PROGRESS (-8);return 1;SHOW_BOOT_PROGRESS (8);根据image 的OS type来决定如何引导switch (hdr-ih_os) default: /* handled by (original) Linux case */case IH_OS_LINUX:#ifdef CONFIG_SILENT_CONSOLEfixup_silent_linux();#endifdo_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_LYNXKDIcase IH_OS_LYNXOS:do_bootm_lynxkdi (cmdtp, flag, argc, argv,addr, len_ptr, verify);break;#endifcase 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_ARTOScase IH_OS_ARTOS:do_bootm_artos (cmdtp, flag, argc, argv,addr, len_ptr, verify);break;#endifSHOW_BOOT_PROGRESS (-9);#ifdef DEBUGputs (n# Control returned to monitor - resetting.n);do_reset (cmdtp, flag, argc, argv);#endifreturn 1;bootm命令是用来引导经过u-boot的工具mkimage打包后的kernel image的,什么叫做经过u-boot的工具mkimage打包后的kernel image,这个就要看mkimage的代码,看看它做了些什么,虽然我很希望大家不要偷懒,认真地去看看,但是我知道还是有很多人懒得去做这件,那么我 就j将分析mkimage代码后得到的总结告诉大家,mkimage做了些什么,怎么用这个工具。 mkimage的用法uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么rootGlym:/tftpboot# ./mkimageUsage: ./mkimage -l image-l = list image header information./mk

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论