Bootm的流程分析.docx
《Bootm的流程分析.docx》由会员分享,可在线阅读,更多相关《Bootm的流程分析.docx(18页珍藏版)》请在冰豆网上搜索。
Bootm的流程分析
Bootm的流程分析
Bootm的流程分析
一、在开始之前先说明一下bootm相关的东西。
1、首先说明一下,S3C2410架构下的bootm只对sdram中的内核镜像文件进行操作(好像AT91架构提供了一段从flash复制内核镜像的代码,不过针对s3c2410架构就没有这段代码,虽然可以在u-boot下添加这段代码,不过好像这个用处不大),所以请确保你的内核镜像下载到sdram中,或者在bootcmd下把flash中的内核镜像复制到sdram中。
2、-a参数后是内核的运行地址,-e参数后是入口地址。
3、
1)如果我们没用mkimage对内核进行处理的话,那直接把内核下载到0x30008000再运行就行,内核会自解压运行(不过内核运行需要一个tag来传递参数,而这个tag建议是由bootloader提供的,在u-boot下默认是由bootm命令建立的)。
2)如果使用mkimage生成内核镜像文件的话,会在内核的前头加上了64byte的信息,供建立tag之用。
bootm命令会首先判断bootmxxxx这个指定的地址xxxx是否与-a指定的加载地址相同。
(1)如果不同的话会从这个地址开始提取出这个64byte的头部,对其进行分析,然后把去掉头部的内核复制到-a指定的load地址中去运行之
(2)如果相同的话那就让其原封不同的放在那,但-e指定的入口地址会推后64byte,以跳过这64byte的头部。
bootm用于加载并启动U-Boot能辨识的操作系统映像,即bootm加载的映像必须是用mkimage工具打过包的映像,bootm不能启动直接的内核映像,因为bootm必须从映像的头获取映像的一些信息,比如操作系统的类型,映像是否压缩,映像的加载地址和压缩地址等。
更详细的映像头信息可以查看mkimage工具的说明。
而bootm的详细用法可通过helpbootm
获得。
=>helpbootm
bootm[addr[arg...]]
-bootapplicationimagestoredinmemorypassingarguments'arg...';whenbootingaLinux
kernel,'arg'canbetheaddressofaninitrdimage
Bootm用于将内核映像加载到指定的地址,如果需要还要进行解压映像。
然后根据操作系统和体系结构的不同给内核传递不同的内核参数,最后启动内核。
bootm可以有两个参数,第一个参数为内核映像的地址,它可以是RAM地址或者Flash地址。
第二个参数是可选参数,即initrd映像的地址,当采用Ramdisk作为根文件系统时需要使用bootm的第二个参数。
当需要加载initrd映像时,首先U-Boot把内核映像加载到指定地址,然后再把Ramdisk映像加载到指定地址,同时把Ramdisk映像的大小和地址告知内核。
Bootm命令后U-Boot会将控制权交给Kernel。
common/cmd_bootm.c是bootm的命令实现代码,下面结合U-Boob引导内核启动信息来分析bootm代码,下面是我的开发板的启动信息:
U-Boot2009.11(Jun252010-08:
28:
06)
DRAM:
64MB
Flash:
2MB
NAND:
64MiB
In:
serial
Out:
serial
Err:
serial
Net:
dm9000
Hitanykeytostopautoboot:
0
NANDread:
device0offset0x80000,size0x500000
5242880bytesread:
OK
##BootingkernelfromLegacyImageat30008000...
ImageName:
mark
Created:
2010-07-0215:
37:
07UTC
ImageType:
ARMLinuxKernelImage(uncompressed)
DataSize:
1800624Bytes=1.7MB
LoadAddress:
30008000
EntryPoint:
30008040
VerifyingChecksum...OK
XIPKernelImage...OK
OK
Startingkernel...
UncompressingLinux..................................................................................................................done,bootingthekernel.
Linuxversion2.6.29.1(root@ubuntu)(gccversion4.3.2(SourceryG++Lite2008q3-72))#64FriJul208:
30:
03PDT2010
CPU:
ARM920T[41129200]revision0(ARMv4T),cr=c0007177
CPU:
VIVTdatacache,VIVTinstructioncache
Machine:
Study-S3C2440
Memorypolicy:
ECCdisabled,Datacachewriteback
…
cmd_bootm.c
先分析bootm命令在U-Boot中是如何添加的:
U_BOOT_CMD(
bootm,CONFIG_SYS_MAXARGS,1,do_bootm,
"bootapplicationimagefrommemory",
"[addr[arg...]]\n-bootapplicationimagestoredinmemory\n"
"\tpassingarguments'arg...';whenbootingaLinuxkernel,\n"
"\t'arg'canbetheaddressofaninitrdimage\n"
#ifdefined(CONFIG_OF_LIBFDT)
"\tWhenbootingaLinuxkernelwhichrequiresaflatdevice-tree\n"
"\tathirdargumentisrequiredwhichistheaddressofthe\n"
"\tdevice-treeblob.Tobootthatkernelwithoutaninitrdimage,\n"
"\tusea'-'forthesecondargument.Ifyoudonotpassathird\n"
"\tabd_infostructwillbepassedinstead\n"
#endif
#ifdefined(CONFIG_FIT)
"\t\nForthenewmulticomponentuImageformat(FIT)addresses\n"
"\tmustbeextenedtoincludecomponentorconfigurationunitname:
\n"
"\taddr:
-directcomponentimagespecification\n"
"\taddr#-configurationspecification\n"
"\tUseiminfocommandtogetthelistofexistingcomponent\n"
"\timagesandconfigurations.\n"
#endif
"\nSub-commandstodopartofthebootmsequence.Thesub-commands"
"mustbe\n"
"issuedintheorderbelow(it'soktonotissueallsub-commands):
\n"
"\tstart[addr[arg...]]\n"
"\tloados-loadOSimage\n"
#ifdefined(CONFIG_PPC)||defined(CONFIG_M68K)||defined(CONFIG_SPARC)
"\tramdisk-relocateinitrd,setenvinitrd_start/initrd_end\n"
#endif
#ifdefined(CONFIG_OF_LIBFDT)
"\tfdt-relocateflatdevicetree\n"
#endif
"\tcmdline-OSspecificcommandlineprocessing/setup\n"
"\tbdt-OSspecificbd_tprocessing\n"
"\tprep-OSspecificprepbeforerelocationorgo\n"
"\tgo-startOS"
);
宏U_BOOT_CMD用于定义U-Boot命令,它的定义如下:
#defineU_BOOT_CMD(name,maxargs,rep,cmd,usage,help)\
cmd_btl_t__u_boot_cmd##nameStruct_Section={#name,maxargs,rep,cmd,usage,help|
#defineStructSection__attribute__((unused,section(".u_boot_cmd")))
宏U_BOOT_CMD展开后如下所示:
cmd_tlb_t__u_boot_cmd_bootm__a
见—嵌入式liinux应用开发完全手册
do_bootm函数分析
staticboot_os_fn*boot_os[]={
#ifdefCONFIG_BOOTM_LINUX
[IH_OS_LINUX]=do_bootm_linux,//由于我使用的是linux内核,编译时将会选择该函数
#endif
intdo_bootm(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[])//这里的argc和argv就是bootm命令行参数
{
boot_os_fn*boot_fn;//定义跳转到操作系统执行的指针
…
if(bootm_start(cmdtp,flag,argc,argv))//调用bootm_start函数
return1;
…
iflag=disable_interrupts();//禁止中断
…
ret=bootm_load_os(images.os,&load_end,1);//调用bootm_load_os函数
…
boot_fn=boot_os[images.os.os];//根据OS类型去选择启动操作系统的函数
…
boot_fn(0,argc,argv,&images);//执行do_bootm_linux函数
…
}
do_bootm函数中调用的几个重要的函数是bootm_start、bootm_load_os、do_bootm_linux,下面一一分析。
bootm_start
staticbootm_headers_timages;/*pointerstoos/initrd/fdtimages*/
staticintbootm_start(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[])
{
void*os_hdr;
…
/*getkernelimageheader,startaddressandlength*/
os_hdr=boot_get_kernel(cmdtp,flag,argc,argv,
&images,&images.os.image_start,&images.os.image_len);
….
/*getimageparameters*/
switch(genimg_get_format(os_hdr)){//获取image头格式类型
caseIMAGE_FORMAT_LEGACY:
//老的image头格式
images.os.type=image_get_type(os_hdr);//获取image的类型
p=image_get_comp(os_hdr);//获取image的压缩类型
images.os.os=image_get_os(os_hdr);//获取image的OS类型
images.os.end=image_get_image_end(os_hdr);//获取image开始地址
images.os.load=image_get_load(os_hdr);//获取image结束地址
break;
…
/*findkernelentrypoint*/
if(images.legacy_hdr_valid){
images.ep=image_get_ep(&images.legacy_hdr_os_copy);//获取image入口指针
…
}
ulongload_addr=CONFIG_SYS_LOAD_ADDR;/*DefaultLoadAddress*/
//寻找内核映像、校验它的完整性和定位内核数据位置
staticvoid*boot_get_kernel(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[],
bootm_headers_t*images,ulong*os_data,ulong*os_len)
{
image_header_t*hdr;
…
/*findoutkernelimageaddress*/
if(argc<2){//bootm命令后面不带参数时
img_addr=load_addr;//使用默认加载地址
debug("*kernel:
defaultimageloadaddress=0x%08lx\n",
load_addr);
…
switch(genimg_get_format((void*)img_addr)){//获取image头类型
caseIMAGE_FORMAT_LEGACY:
//早期的image头类型
printf("##BootingkernelfromLegacyImageat%08lx...\n",img_addr);//该打印信息出现在U-Boot启动信息里
hdr=image_get_kernel(img_addr,images->verify);//获取image头
…
}
//校验早期格式内核映像
staticimage_header_t*image_get_kernel(ulongimg_addr,intverify)
{
image_header_t*hdr=(image_header_t*)img_addr;
if(!
image_check_magic(hdr)){//校验MAGICnumber
puts("BadMagicNumber\n");
show_boot_progress(-1);
returnNULL;
}
show_boot_progress
(2);
if(!
image_check_hcrc(hdr)){//image头校验
puts("BadHeaderChecksum\n");
show_boot_progress(-2);
returnNULL;
}
show_boot_progress(3);
image_print_contents(hdr);//该函数内将打印imag头信息“
ImageName:
mark
Created:
2010-07-0215:
37:
07UTC
ImageType:
ARMLinuxKernelImage(uncompressed)
DataSize:
1800624Bytes=1.7MB
LoadAddress:
30008000
EntryPoint:
30008040
”
if(verify){
puts("VerifyingChecksum...");//出现在U-Boot启动信息中
if(!
image_check_dcrc(hdr)){//校验image数据
printf("BadDataCRC\n");
show_boot_progress(-3);
returnNULL;
}
puts("OK\n");//出现在U-Boot启动信息中
}
show_boot_progress(4);
if(!
image_check_target_arch(hdr)){//ARM、i386、MIPS等架构检查
printf("UnsupportedArchitecture0x%x\n",image_get_arch(hdr));
show_boot_progress(-4);
returnNULL;
}
returnhdr;
}
//打印image头信息
voidimage_print_contents(constvoid*ptr)
{
constimage_header_t*hdr=(constimage_header_t*)ptr;
constchar*p;
#ifdefUSE_HOSTCC
p="";
#else
p="";//打印空格
#endif
//打印image名字
printf("%sImageName:
%.*s\n",p,IH_NMLEN,image_get_name(hdr));
#ifdefined(CONFIG_TIMESTAMP)||defined(CONFIG_CMD_DATE)||defined(USE_HOSTCC)
printf("%sCreated:
",p);//打印image创建日期
genimg_print_time((time_t)image_get_time(hdr));
#endif
printf("%sImageType:
",p);//打印image类型
image_print_type(hdr);
printf("%sDataSize:
",p);//打印image大小
genimg_print_size(image_get_data_size(hdr));
printf("%sLoadAddress:
%08x\n",p,image_get_load(hdr));//打印image加载地址
printf("%sEntryPoint:
%08x\n",p,image_get_ep(hdr));//打印image入口指针
…
}
typedefstructbootm_headers{
/*
*Legacyosimageheader,ifitisamulticomponentimage
*thenboot_get_ramdisk()andget_fdt()willattempttoget
*datafromsecondandthirdcomponentaccordingly.
*/
image_header_t*legacy_hdr_os;/*imageheaderpointer*/
image_header_tlegacy_hdr_os_copy;/*headercopy*/
ulonglegacy_hdr_valid;
…
#ifndefUSE_HOSTCC
image_info_tos;/*osimageinfo*/
ulongep;/*entrypointofOS*/
ulongrd_start,rd_end;/*ramdiskstart/end*/
…
ulongft_len;/*lengthofflatdevicetree*/
ulonginitrd_start;
ulonginitrd_end;
ulongcmdline_start;
ulongcmdline_end;
bd_t*kbd;
#endif
intverify;/*getenv("verify")[0]!
='n'*/
#defineBOOTM_STATE_START(0x00000001)
#defineBOOTM_STATE_LOADOS(0x00000002)
#defineBOOTM_STATE_RAMDISK(0x00000004)
#defineBOOTM_STATE_FDT(0x00000008)
#defineBOOTM_STATE_OS_CMDLINE(0x00000010)
#defineBOOTM_STATE_OS_BD_T(0x00000020)
#defineBOOTM_STATE_OS_PREP(0x00000040)
#defineBOOTM_STATE_OS_GO(0x00000080)
intstate;
#ifndefUSE_HOSTCC
structlmblmb;/*formemorymgmt*/
#endif
}bootm_headers_t;
bootm_load_os
staticintbootm_load_os(image_info_tos,ulong*load_end,intbo