基于jz2440的uboot分析.docx
《基于jz2440的uboot分析.docx》由会员分享,可在线阅读,更多相关《基于jz2440的uboot分析.docx(10页珍藏版)》请在冰豆网上搜索。
![基于jz2440的uboot分析.docx](https://file1.bdocx.com/fileroot1/2022-12/6/58286d46-8bf2-4221-8c85-5be43afab4c5/58286d46-8bf2-4221-8c85-5be43afab4c51.gif)
基于jz2440的uboot分析
一、一般步骤:
1、拷贝u-boot源文件至目标目录,解压,得到源代码树
2、配置u-boot,执行命令make100ask24x0_config
3、执行make生成可执行的二进制文件u-boot.bin
4、Tftp0x30000000u-boot.bin或者NFS模式
5、Go0x30000000,或者烧写到nandflash中
2、配置过程:
make100ask24x0_config
查找顶层Makefile的100ask24x0_config目标:
100ask24x0_config:
unconfig
@$(MKCONFIG)$(@:
_config=)armarm920t100ask24x0NULLs3c24x0
MKCONFIG:
MKCONFIG:
=$(SRCTREE)/mkconfig
$(@:
_config=)
将目标字符串的_config替代为空格,即$(@:
_config=)为100ask24x0
则上面的一句话变成:
$(@:
_config=)
100ask24x0_config:
unconfig
mkconfig100ask24x0armarm920t100ask24x0NULLs3c24x0
查找源根目录下的文件mkconfig,执行完上述命令后得到:
A、BOARD_NAME=100ask24x0
打印这句话“Configuringfor100ask24x0board..”
B、.创建三个链接:
cd./include
ln-sasm-$2asm,即ln-sasm-armasm,在include目录下创建一个链接asm-arm指向asm
ln-s${LNPREFIX}arch-$6asm-$2/arch,即ln-sarch-s3c24x0asm-arm/arch
ln-s${LNPREFIX}proc-armvasm-$2/proc即ln-sproc-armvasm-arm/proc
C、配置config.mk
#
#CreateincludefileforMake
#
echo"ARCH=$2">config.mk
echo"CPU=$3">>config.mk
echo"BOARD=$4">>config.mk
即在config.mk文件中:
ARCH=arm
CPU=arm920t
BOARD=100ask24x0
SOC=s3c24x0
D、创建相关的头文件
#
#Createboardspecificheaderfile
#创建相关的头文件
#
创建config.h头文件
echo"/*Automaticallygenerated-donotedit*/">>config.h
echo"#include">>config.h
即在头文件config.h中输入;
/*Automaticallygenerated-donotedit*/
#include
”>”表示新建一个文件
三、分析make过程
1、首先指定一些常数,如版本等等,使用前面的配置文件mkconfig,得到一些参数如CPU,arch等。
include$(OBJTREE)/include/config.mk
exportARCHCPUBOARDVENDORSOC
2、指定交叉编译器exportCROSS_COMPILE
3、接着就是一系列需要编译的文件和库文件
OBJS=cpu/$(CPU)/start.o
OBJS:
=$(addprefix$(obj),$(OBJS))
LIBS=lib_generic/libgeneric.a
LIBS+=....
LIBS:
=$(addprefix$(obj),$(LIBS))//给$(LIBS)加前缀$(obj),即$(LIBS)=$(obj)$(LIBS),
$(obj)u-boot:
dependversion$(SUBDIRS)$(OBJS)$(LIBS)$(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP)-x$(LIBS)|sed-n-e's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd$(LNDIR)&&$(LD)$(LDFLAGS)$$UNDEF_SYM$(__OBJS)\
--start-group$(__LIBS)--end-group$(PLATFORM_LIBS)\
-Mapu-boot.map-ou-boot
cd/home/linux/soft/u-boot-1.1.6&&arm-linux-ld-Bstatic-T/home/linux/soft/u-boot-1.1.6/board/100ask24x0/u-boot.lds-Ttext0x33F80000$UNDEF_SYMcpu/arm920t/start.o\
--start-grouplib_generic/libgeneric.aboard/100ask24x0/lib100ask24x0.acpu/arm920t/libarm920t.acpu/arm920t/s3c24x0/libs3c24x0.alib_arm/libarm.afs/cramfs/libcramfs.afs/fat/libfat.afs/fdos/libfdos.afs/jffs2/libjffs2.afs/reiserfs/libreiserfs.afs/ext2/libext2fs.anet/libnet.adisk/libdisk.artc/librtc.adtt/libdtt.adrivers/libdrivers.adrivers/nand/libnand.adrivers/nand_legacy/libnand_legacy.adrivers/usb/libusb.adrivers/sk98lin/libsk98lin.acommon/libcommon.a--end-group-L/home/linux/toolchain/gcc-3.4.5-glibc-2.3.6/bin/../lib/gcc/arm-linux/3.4.5-lgcc\
-Mapu-boot.map-ou-boot
从中可以看出链接文件为u-boot.lds
SECTIONS
{
.=0x00000000;//u-boot.bin文件的安放的起始位置
.=ALIGN(4);
.text:
{
cpu/arm920t/start.o(.text)
board/100ask24x0/boot_init.o(.text)
*(.text)
}
.=ALIGN(4);
.rodata:
{*(.rodata)}
.=ALIGN(4);
.data:
{*(.data)}
.=ALIGN(4);
.got:
{*(.got)}
.=.;
__u_boot_cmd_start=.;
.u_boot_cmd:
{*(.u_boot_cmd)}
__u_boot_cmd_end=.;
.=ALIGN(4);
__bss_start=.;
.bss:
{*(.bss)}
_end=.;
}
其中:
__u_boot_cmd_start=.;
.u_boot_cmd:
{*(.u_boot_cmd)}
__u_boot_cmd_end=.;
自定义的u_boot_cmd段
#defineStruct_Section__attribute__((unused,section(".u_boot_cmd")))
#defineU_BOOT_CMD(name,maxargs,rep,cmd,usage,help)\
cmd_tbl_t__u_boot_cmd_##nameStruct_Section={#name,maxargs,rep,cmd,usage,help}
U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)
展开即是:
cmd_tbl_t__u_boot_cmd_name
__attribute__((unused,section(".u_boot_cmd")))={name,maxargs,rep,cmd,usage,help}
即将结构体__u_boot_cmd_name按照给定参数初始化
structcmd_tbl_s{
char*name;/*CommandName*/
intmaxargs;/*maximumnumberofarguments*/
intrepeatable;/*autorepeatallowed?
*/
/*Implementationfunction*/
int(*cmd)(structcmd_tbl_s*,int,int,char*[]);
char*usage;/*Usagemessage(short)*/
#ifdefCFG_LONGHELP
char*help;/*Helpmessage(long)*/
#endif
#ifdefCONFIG_AUTO_COMPLETE
/*doautocompletiononthearguments*/
int(*complete)(intargc,char*argv[],charlast_char,intmaxv,char*cmdv[]);
#endif
};
Run_command()
将所有命令放在u-boot.cmd段中,(以结构体形式存在),run_command()运行时,根据传进来的参数,find_command()函数来查找命令,之后进行一系列的处理后运行一些可执行的程序。
自己写u_boot命令:
在comcom目录下仿照其他文件的编写,在修改该目录下的Makefile,增加该文件
环境参数的设置(以此结构体存放):
typedefstructenvironment_s
{
unsignedlongcrc;/*CRC32overdatabytes*/
#ifdefCFG_REDUNDAND_ENVIRONMENT
unsignedcharflags;/*active/obsoleteflags*/
#endif
unsignedchardata[ENV_SIZE];/*Environmentdata*/
}env_t;
/*最开始,调用env_init函数对环境变量进行初始化,
这里暂时不考虑ENV_IS_EMBEDDED的情况,所以,初始化
工作就是设置env_addr地址,并设置env_valid为有限
*/
intenv_init(void)
初始化环境变量地址为default值之后,调用下面env_relocate函数具体分配内存空间,将环境变量从flash中读到内存中来,完成初始化过程.
前面介绍了环境变量初始化的过程,在完成了初始化之后。
U-boot其它部分的代码在要调用环境变的时候可以调用相应的接口读取。
这个接口就是getenv
Getenv函数就是在gd->env_addr这个buffer中不断的寻找name相对应的字符串,找到这个字符串”name=xxxxxx”之后将第一个x的地址返回。
本文还需要分析一下的就是对环境参数的保存,如果通过u-boot命令setenv修改了环境参数,我们必须还要通过saveenv将修改的参数保存在能在下次启动是继续使用设置的参数
这个函数比较简单,首先就是擦除相应部分的flash,然后将环境变量结构体写到对应的flash部分,我分析的mini2440中环境变量的偏移地址是256K,总共大小为64K.
向linux内核传递参数:
./common/cmd_bootm.c文件调用./uboot/arch/arm/lib/bootm.c文件中的do_nand_boot函数来启动Linuxkernel。
在do_nand_boot函数中:
intdo_nand_boot(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[])
{
DECLARE_GLOBAL_DATA_PTR;
intret;
bd_t*bd=gd->bd;
ulongaddr,data,len,initrd_start,initrd_end;
void(*theKernel)(intzero,intarch,uintparams);
intstrlen;
char*commandline=getenv("bootargs");
setup_start_tag(bd);//初始化第一个kerneltag结构体
setup_serial_tag(¶ms);
setup_revision_tag(¶ms);
setup_memory_tags(bd);
theKernel(0,
machid,
bd->bi_boot_params//传给Kernel的参数=(structtag*)型的bd->bi_boot_params
);
}
setup_start_tag和setup_memory_tags函数说明
函数setup_start_tag也在此文件中定义,如下:
staticvoidsetup_start_tag(bd_t*bd)
{
params=(structtag*)bd->bi_boot_params;
/*初始化(structtag*)型的全局变量params为bd->bi_boot_params的地址,
*之后的setuptags相关函数如下面的setup_memory_tags
*就把其它tag的数据放在此地址的偏移地址上。
*/
params->hdr.tag=ATAG_CORE;
params->hdr.size=tag_size(tag_core);
params->u.core.flags=0;
params->u.core.pagesize=0;
params->u.core.rootdev=0;
params=tag_next(params);
}
RAM相关参数在函数setup_memory_tags中初始化:
staticvoidsetup_memory_tags(bd_t*bd)
{
inti;
for(i=0;iparams->hdr.tag=ATAG_MEM;
params->hdr.size=tag_size(tag_mem32);
params->u.mem.start=bd->bi_dram[i].start;
params->u.mem.size=bd->bi_dram[i].size;
params=tag_next(params);
}//初始化内存相关tag
}
Kernel读取U-boot传递的ATAG参数,
Head.s中最终调用start_kernel
init/main.c中的start_kernel函数中会调用setup_arch函数来处理各种平台相关的动作,包括了u-boot传递过来参数的分析和保存
其中,setup_arch函数在arch/arm/kernel/setup.c文件中实现,如下:
void__initsetup_arch(char**cmdline_p)
{
structtag*tags=(structtag*)&init_tags;
structmachine_desc*mdesc;
char*from=default_command_line;
setup_processor();
mdesc=setup_machine(machine_arch_type);
machine_name=mdesc->name;
if(mdesc->soft_reboot)
reboot_setup("s");
if(__atags_pointer)
//指向各种tag起始位置的指针,定义如下:
//unsignedint__atags_pointer__initdata;
//此指针指向__initdata段,各种tag的信息保存在这个段中。
tags=phys_to_virt(__atags_pointer);
elseif(mdesc->boot_params)
tags=phys_to_virt(mdesc->boot_params);
if(tags->hdr.tag!
=ATAG_CORE)
convert_to_tag_list(tags);
if(tags->hdr.tag!
=ATAG_CORE)
tags=(structtag*)&init_tags;
if(mdesc->fixup)
mdesc->fixup(mdesc,tags,&from,&meminfo);
if(tags->hdr.tag==ATAG_CORE){
if(meminfo.nr_banks!
=0)
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags);
//处理各种tags,其中包括了RAM参数的处理。
//这个函数处理如下tags:
__tagtable(ATAG_MEM,parse_tag_mem32);
__tagtable(ATAG_VIDEOTEXT,parse_tag_videotext);
__tagtable(ATAG_RAMDISK,parse_tag_ramdisk);
__tagtable(ATAG_SERIAL,parse_tag_serialnr);
__tagtable(ATAG_REVISION,parse_tag_revision);
__tagtable(ATAG_CMDLINE,parse_tag_cmdline);
}
init_mm.start_code=(unsignedlong)&_text;
init_mm.end_code=(unsignedlong)&_etext;
init_mm.end_data=(unsignedlong)&_edata;
init_mm.brk=(unsignedlong)&_end;
memcpy(boot_command_line,from,COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1]='/0';
parse_cmdline(cmdline_p,from);//处理编译内核时指定的cmdline或u-boot传递的cmdline
paging_init(&meminfo,mdesc);
request_standard_resources(&meminfo,mdesc);
#ifdefCONFIG_SMP
smp_init_cpus();
#endif
……
}