uboot之do_bootm_linux启动内核函数源码解析
当配置了CONFIG_PPC时将调用common/cmd_bootm.c中的do_bootm_linux。本处是调用libarm/armlinux.c中的。u-boot.h中static struct tagparams;typedef struct bd_info {int bi_baudrate; /serial console baudrate/波特率unsigned long bi_ip_addr; /IP Address/即服务器IP地址unsigned char bi_enetaddr[6]; /Ethernet adress */struct environment_sbi_env;//开发板机器ID即1008(MACH_TYPE_SMDK2440)gd-bd-bi_arch_number MACH_TYPE_SMDK2440; (smdk2440.c)ulong bi_arch_number; /unique id for this board///准确地说这是启动参数的地址gd-bd-bi_boot_params 0x30000100;(smdk2440.c)与内核中需要一致。ulong bi_boot_params; /where this board expects params/准确地说,这是启动参数的地址struct /RAM configuration/{ulong start;//内存起始地址ulong size;//内存大小} bi_dram[CONFIG_NR_DRAM_BANKS];#ifdef CONFIG_HAS_ETH1/second onboard ethernet port */unsigned char bi_enet1addr[6];#endif} bd_t;在u-boot下输入bd就可以查看开发板的一些信息uplooking # bdarch_number 0x0000065Aenv_t 0x00000000boot_params 0x50000100DRAM bank 0x00000000- start 0x50000000- size 0x08000000ethaddr 00:40:5C:26:0A:5Bip_addr 192.168.1.20baudrate 115200 bps///////////////////////////////////////////////////////////////////////////////////////command.h/*Monitor Command Table*/struct cmd_tbl_s {charname; /Command Name//命令名/int maxargs; /maximum number of arguments//命令的最大参数个数/int repeatable; /autorepeat allowed?//是否自动重复//Implementation function */int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);/命令执行函数/charusage; /Usage message (short) */ /简单的使用说明/#ifdef CFG_LONGHELPcharhelp; /Help message (long)/ /详细使用说明/#endif#ifdef CONFIG_AUTO_COMPLETE /自动补全参数//do auto completion on the arguments */int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);#endif};在文件include/command.h中定义了结构体cmd_tbl_s各成员含义如上面注释。U-boot的每一条命令都将封装成结构体 cmd_tbl_s存到链接文件中指定的.u_boot_cmd区。当向u-boot中添加命令时都将调用宏 U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)来初始化一个cmd_tbl_s 结构体。typedef struct cmd_tbl_s cmd_tbl_t;////////////////////////////////////////////////////////////////////////////当定义了CONFIG_PPC时将使用common/cmd_bootm.c文件中的do_bootm_linux函数当系统中没有定义该宏时系统将使用lib_arm/armlinux.c文件中定义的do_bootm_linux函数。注意这两个函数有很大的区别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_thdr header;bd_tbd gd-bd;#ifdef CONFIG_CMDLINE_TAGcharcommandline getenv (“bootargs”);//调用了getenv将bootargs环境变量保存在commandline#endif//uboot set参数命令行bootm 50008000;//打印出来发现 hdr-ih_ep 0x800050 也就是必须ntohl之后才是50008000theKernel (void ()(int, int, uint))ntohl(hdr-ih_ep);//打印出来发现theKernel 0x50008000//设置内核入口地址(不是加载地址加载是程序存储地址)入口地址是PC指针倒是后程序跳到这个地址运行//mkimage.c//#define ntohl(a) SWAP_LONG(a)//#define htonl(a) SWAP_LONG(a)/#define SWAP_LONG(x)((__u32)((((__u32)(x) (__u32)0x000000ffUL) 24) |(((__u32)(x) (__u32)0x0000ff00UL) 8) |(((__u32)(x) (__u32)0x00ff0000UL) 8) |(((__u32)(x) (__u32)0xff000000UL) 24) ))***//Check if there is an initrd image //跳过 不是initrd镜像/if (argc 3) {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_DATAFLASHif (addr_dataflash (addr)) {read_dataflash (addr, sizeof (image_header_t), (char *) header);}else#endifmemcpy (header, (char *) addr, sizeof (image_header_t));if (ntohl (hdr-ih_magic) ! IH_MAGIC) {printf (“Bad Magic Number\n”);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”);do_reset (cmdtp, flag, argc, argv);}print_image_hdr (hdr);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;}#endif/**do_bootm函数中** s getenv (“verify”);verify (s (*s ‘n’)) ? 0 : 1;//为是否对镜像头做校验做准备读取uboot的环境变量verify如果环境变量verify等于’n’则局部变量verify赋值成为0如果环境变量verify为空即没有定义环境变量verify或者环境变量verify不等于’n’则局部变量verify赋值成为1。****/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”);do_reset (cmdtp, flag, argc, argv);}printf (“OK\n”);}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”);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);//与上文的memcpy (header, (char) addr, sizeof (image_header_t));区别data ntohl(hdr-ih_load);#endif /CONFIG_B2 || CONFIG_EVB4510//Now check if we have a multifile image/} //end of if (argc 3) {else if ((hdr-ih_type IH_TYPE_MULTI) (len_ptr[1])) {ulong tail ntohl (len_ptr[0]) % 4;int i;/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*/len data 0;}#ifdef DEBUGif (!data) {printf (“No initrd\n”);}#endifif (data) {initrd_start data;initrd_end initrd_start len;} else {initrd_start 0;initrd_end 0;}debug (“## Transferring control to Linux (at address %08lx) …\n”,(ulong) theKernel);#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_TAGsetup_serial_tag (?ms);#endif#ifdef CONFIG_REVISION_TAGsetup_revision_tag (?ms);#endif#ifdef CONFIG_SETUP_MEMORY_TAGSsetup_memory_tags (bd);#endif#ifdef CONFIG_CMDLINE_TAGsetup_commandline_tag (bd, commandline); //设置启动命令行tags#endif#ifdef CONFIG_INITRD_TAGif (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);#endifsetup_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 ();}#endifcleanup_before_linux ();//传递的参数//R0必须为0 //R1机器类型ID 本机为ARMbd- bi_arch_number//R2:启动参数列表在内存中的位置bd- bi_boot_paramstheKernel (0, bd-bi_arch_number, bd-bi_boot_params);//嵌入式linux应用开发P264 bd-bi_boot_params就是标记列表的开始地址。}///image.h/*all data in network byte order (aka natural aka bigendian)/typedef struct image_header {uint32_t ih_magic; /Image Header Magic Number/ /镜像幻数/uint32_t ih_hcrc; /Image Header CRC Checksum/ /镜像头CRC校验值*/uint32_t ih_time; /* Image Creation Timestamp/ /镜像创建时间*/uint32_t ih_size; /* Image Data Size//镜像大小*/uint32_t ih_load; /* Data Load Address//数据加载地址*/uint32_t ih_ep; /* Entry Point Address/ //theKernel函数指针指向这个地址也就是从uboot跳到内核的地址,镜像入口*/uint32_t ih_dcrc; /* Image Data CRC Checksum/ /镜像数据区的CRC校验值*/uint8_t ih_os; /* Operating System//操作系统类型*/uint8_t ih_arch; /* CPU architecture//CPU架构*/uint8_t ih_type; /* Image Type/ /镜像类型*/uint8_t ih_comp; /* Compression Type/ /压缩类型*/uint8_t ih_name[IH_NMLEN]; /* Image Name//镜像名*/} image_header_t;Linux编译出的二进制文件是zImageuboot中提供mkimage工具可将zImage制作成uImage实际上就是在zImage前加一个image_header头。制作uImage的命令如下。./mkimage -n ‘linux-2.6.36’ -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage uImage.binMkimage工具参数的含义如下-A 设置体系架构类型-O 设置操作系统类型-T 设置镜像类型-C 设置压缩类型-a 设置加载地址-e 设置镜像入口位置-n 设置镜像名-d 设置生成最终镜像所需的文件-x 设置片上执行
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2430484.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!