




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Good is good, but better carries it.精益求精,善益求善。linux课程设计之bootloader的移植-嵌入式Linux课程设计报告课题:嵌入式Linux下的bootloader之u-boot的移植姓名:胡欢专业班级:电信三班学号:080102031122指导老师:刘小洋时间:2011-10-12一概述:(1)BootLoader是什么?系统上电之后,需要一段程序来进行初始化:关闭WATCHDOG、改变系统时钟、初始化存储控制器、将更多的代码复制到内存中等。如果它能将操作系统内核复制到内存中运行,无论从本地,比如Flash;还是从远端,比如网络,就称这段程序
2、为Bootloader。简单地说,BootLoader就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序,因此整个系统的加载启动任务就完全由BootLoader来完成。Bootloader是可以添加功能的,比如网络功能。通过串口或网络从PC下载烧写文件、将存储在Flash上压缩的文件解压后再运行等,这样的Bootloader是比较强大的,也称为Monitor。实际上,在最终产品中用户并不需要使用这些功能,
3、它们只是为了方便开发。Bootloader的实现非常依赖于具体硬件,在嵌入式系统中硬件配置千差万别,即使是相同的CPU,它的外设也可能不同,比如Flash不同,所以不可能有一个Bootloader支持所有的CPU、所有的电路板。即使是支持CPU架构比较多的U-Boot,也不是一拿来就可以使用的,需要进行一些移植。(2)为什么需要BootLoader?引导加载程序是系统加电后运行的第一段软件代码。PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的OSBootLoader(比如,LILO和GRUB等)一起组成。BIOS在完成硬件检测和资源分配后,将硬盘MBR中的Boot
4、Loader读到系统的RAM中,然后将控制权交给OSBootLoader。BootLoader的主要运行任务就是将内核映象从硬盘上读到RAM中,然后跳转到内核的入口点去运行,也即开始启动操作系统。而在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。比如在一个基于ARM7TDMIcore的嵌入式系统中,系统在上电或复位时通常都从地址0 x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。简单地说,BootLoader就是在操作系统内核运行之前运行
5、的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。二:系统总体设计和模块结构知识:(一)嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中的软件主要分为以下及部分:(1)引导加载程序:其中包括内部ROM中的固化启动代码和BootLoader两部分。而这个内部固化ROM是厂家在芯片生产时候固化的,作用基本上是引导BootLoader。有的芯片比较复杂,比如Omap3,他在flash中没有代码的时候有许多启动方式:USB、UART或以太网等等。而S3C24x0则很简单,只有
6、Norboot和Nandboot。(2)Linuxkernel和drivers。(3)文件系统。包括根文件系统和建立于Flash内存设备之上的文件系统(EXT4、UBI、CRAMFS等等)。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好运行环境的载体。(4)应用程序。用户自定义的应用程序,存放于文件系统之中。在Flash存储器中,他们的一般分布如下:(二)U-Boot主要目录结构-board目标板相关文件,主要包含SDRAM、FLASH驱动;-common独立于处理器体系结构的通用代码,如内存大小探测与故障检测;-cpu与处理器相关的文件。如mpc8xx子目录下含串口、网口、LC
7、D驱动及中断初始化等文件;-driver通用设备驱动,如CFIFLASH驱动(目前对INTELFLASH支持较好)-docU-Boot的说明文档;-examples可在U-Boot下运行的示例程序;如hello_world.c,timer.c;-includeU-Boot头文件;尤其configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;-lib_xxx处理器体系相关的文件,如lib_ppc,lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;-net与网络功能相关的文件目录,如bootp,nfs,tftp;-post上电自检文件目录。尚有待于进一步完善;
8、-rtcRTC驱动程序;-tools用于创建U-BootS-RECORD和BIN镜像文件的工具;(三)U-Boot启动过程:Stage1工作流程:Stage1的代码都是与平台相关的,使用汇编语言编写占用空间小而且执行速度快。以ARM920为例,Stage1阶段主要是设置各模式程序异常向量表,初始化处理器相关的关键寄存器以及系统内存。Stage1负责建立Stage1阶段使用的堆栈和代码段,然后复制Stage2阶段的代码到内存。Stage2工作流程:Stage2阶段一般包括:初始化Flash器件、检测系统内存映射、初始化网络设备、进入命令循环,接收用户从串口发送的命令然后进行相应的处理。Stage
9、2使用C语言编写,用于加载操作系统内核,该阶段主要是board.c中的start_armboot()函数实现。三原理介绍与系统实现:(一)工作原理及代码分析:1第一阶段(Stage1)中断向量表的设置.globl_start_start:bresetldrpc,_undefined_instructionldrpc,_software_interruptldrpc,_prefetch_abortldrpc,_data_abortldrpc,_not_usedldrpc,_irqldrpc,_fiq_undefined_instruction:.wordundefined_instruction
10、_software_interrupt:.wordsoftware_interrupt_prefetch_abort:.wordprefetch_abort_data_abort:.worddata_abort_not_used:.wordnot_used_irq:.wordirq_fiq:.wordfiq.balignl16,0 xdeadbeefStart.s文件一开始,就定义了_start的全局变量。也即,在别的文件,照样能引用这个_start变量。这段代码验证了我们之前学过的arm体系的理论知识:中断向量表放在从0 x0开始的地方。其中,每个异常中断的摆放次序,是事先规定的。比如第一个
11、必须是reset异常,第二个必须是未定义的指令异常等等。需要注意的是,在这里,我们也可以理解:为何系统一上电,会自动运行代码。因为系统上电后,会从0 x0地方取指令,而0 x0处放置的是reset标签,直接就跳去reset标签处去启动系统了。另外,这里使用了ldr指令。而ldr指令中的label,分别用一个.word伪操作来定义。比如:_undefined_instruction:.wordundefined_instruction我们用sourceinsight跟踪代码后,发现,undefined_instruction在start.s的后面给出了具体的操作,如下:undefined_ins
12、truction:get_bad_stackbad_save_user_regsbldo_undefined_instruction在跳转到中断服务子程序之前,先有两个宏代码,一个是对stack的操作,一个是用户regs的保存。然后才能跳转如中断服务子程序中执行。读者若不理解进入中断之前做的“现场保护”,请参考ARM体系结构与编程等相关书籍,自然能获得详细的答案。值得一提的是,当发生异常时,都将执行u-boot-1.2.0cpuarm920tinterrupts.c中定义的中断函数。也就是说,start.s中要跳转的这些中断子程序的代码,均在u-boot-1.2.0cpuarm920tinte
13、rrupts.c中定义。U-Boot存储器映射定义该代码段主要是定义u-boot需要使用的一些映射区的label,比如用户堆区、用户栈区、全局数据结构区等。_TEXT_BASE:.wordTEXT_BASE.globl_armboot_start_armboot_start:.word_start*Thesearedefinedintheboard-specificlinkerscript.*/.globl_bss_start_bss_start:.word_bss_start.globl_bss_end_bss_end:.word_end#ifdefCONFIG_USE_IRQ/*IRQst
14、ackmemory(calculatedatrun-time)*/.globlIRQ_STACK_STARTIRQ_STACK_START:.word0 x0badc0de/*IRQstackmemory(calculatedatrun-time)*/.globlFIQ_STACK_STARTFIQ_STACK_START:.word0 x0badc0de#endif从上图也可以清晰地发现,堆和栈是有区别的。而且可以看到,用户栈区是向下递减的,即地址减少的方向生长。上电后CPU为SVC模式reset:/*setthecputoSVC32mode*/mrsr0,cpsrbicr0,r0,#0 x
15、1forrr0,r0,#0 xd3msrcpsr,r0这是系统复位后执行的“第一个代码段”(严格来说不是)。CPU复位后,系统会立即被设置成SVC模式。记得之前有网友发帖咨询这个问题,问系统复位后,cpu处于哪个处理器模式。这个代码,就回答了这个问题。从这个代码中,我们也可以得到一个对寄存器操作的经验:读修改-写。这里先把cpsr的值读到r0中,清除掉我们想修改的bit位,然后用orr指令来保证其他bit位不被改动,并达到修改寄存器低5位值的目的。最后用msr指令把r0的值给cpsr寄存器达到我们的修改目的。关闭看门狗#ifdefined(CONFIG_S3C2400)|defined(CON
16、FIG_S3C2410)ldrr0,=pWTCONmovr1,#0 x0strr1,r0根据S3C2440的datasheet文档,系统启动后,看门狗寄存器是被使能的,所以,如果不在预计的时间内“喂狗”,就有“被狗咬”的可能。别说啥了,赶紧先喂狗。上面这段代码即为喂狗代码。u-boot代码编写者把它放在CPU上电修改SVC模式后的第一个代码,是可以理解的。这个代码,也是修改寄存器的代码,它的思路依旧是:读修改写。实际上,u-boot-1.2.0代码在喂狗代码之前,还有一段代码,如下:#ifdefined(CONFIG_S3C2400)#definepWTCON0 x15300000#defin
17、eINTMSK0 x14400008/*Interupt-Controllerbaseaddresses*/#defineCLKDIVN0 x14800014/*clockdivisorregister*/#elifdefined(CONFIG_S3C2410)#definepWTCON0 x53000000/*喂狗寄存器*/#defineINTMSK0 x4A000008/*Interupt-Controllerbaseaddresses*/#defineINTSUBMSK0 x4A00001C#defineCLKDIVN0 x4C000014/*clockdivisorregister*/
18、#endif这是定义寄存器用的。比如根据S3C2440的datasheet文档,喂狗寄存器pWTCON的寄存器地址是0 x15300000,需要定义后才能使用。同理,这里还定义了时钟除数寄存器CLKDIVN和中断掩码的INTMSK寄存器的地址。在后续代码中会陆续用到。关掉中断*maskallIRQsbysettingallbitsintheINTMR-default*/movr1,#0 xffffffffldrr0,=INTMSKstrr1,r0#ifdefined(CONFIG_S3C2410)ldrr1,=0 x3ffldrr0,=INTSUBMSKstrr1,r0#endif从注释可以看
19、出此段代码的作用:屏蔽掉所有的irq中断。为了屏蔽这些中断,我们只要把INTMSK的所有的bit位都置1即可。INTMSK寄存器共32bit位,每个bit对应着不同的中断源。事实上,笔者认为这个代码是多余的,只是为了“心里更踏实”而已。因为S3C2440的datasheet文档里明确指出,cpu在复位的时候,这个寄存器的值就是0XFFFFFFFF,以防止发生异常中断。3.2.6修改时钟除数寄存器/*FCLK:HCLK:PCLK=1:2:4*/*defaultFCLKis120MHz!*/ldrr0,=CLKDIVNmovr1,#0/*原先的值是3,现在是1:1:1*/strr1,r0在u-bo
20、ot-1.2.0源码中,给CLKDIVN寄存器赋值的是#0 x3,表示FCLK:HCLK:PCLK=1:2:4,这里笔者将其比例改为1:1:1,没啥特殊的目的,调试代码的时候试验用的,后来调试完毕,就没有再修改了。调用cpu_init_crit#ifndefCONFIG_SKIP_LOWLEVEL_INITblcpu_init_crit#endif此段代码指明:若未定义CONFIG_SKIP_LOWLEVEL_INIT,就执行cpu_init_crit。我们当然不会跳过底层的初始化。因为LOWLEVEL_INIT会对我们的SDRAM进行初始化,这对我们的cpu是必要的。根据sourceinsi
21、ght的索引,我们转到了cpu_init_crit的代码中:#ifndefCONFIG_SKIP_LOWLEVEL_INITcpu_init_crit:/*flushv4I/Dcaches*/movr0,#0mcrp15,0,r0,c7,c7,0/*flushv3/v4cache*/mcrp15,0,r0,c8,c7,0/*flushv4TLB*/*disableMMUstuffandcaches*/mrcp15,0,r0,c1,c0,0bicr0,r0,#0 x00002300clearbits13,9:8(-V-RS)bicr0,r0,#0 x00000087clearbits7,2:0(
22、B-CAM)orrr0,r0,#0 x00000002setbit2(A)Alignorrr0,r0,#0 x00001000setbit12(I)I-Cachemcrp15,0,r0,c1,c0,0/*beforerelocating,wehavetosetupRAMtiming*becausememorytimingisboard-dependend,youwill*findalowlevel_init.Sinyourboarddirectory.*/movip,lrbllowlevel_initmovlr,ipmovpc,lr#endif/*CONFIG_SKIP_LOWLEVEL_IN
23、IT*/非常符合我们的思维,我们无效掉了指令cache和数据cache,并禁止MMU与cache。为什么会有这一步呢?笔者曾经深受cache的伤害。在调试代码的时候,下载完修改的bin文件后,如果只按复位键,而不关掉板子重新上电,就会造成cache中可能残留之前对cache操作的数据。我们称之为“脏数据”,它会映像我们的调试结果,造成假象。当然,在这里无效cache和MMU肯定还有别的原因。比如在初始化阶段,可以认为我们只有一个任务在跑,没有必要,也不允许使用地址变换。因此最好应该无效掉MMU。由于在cpu_init_cri子程序中又一次调用子程序lowlevel_init,因此,需要事先保护
24、好lr寄存器的内容。当返回时候,再恢复它。在进入lowlevel_init之前,有必要详细说一下movip,lr,这个语句的ip。为了使单独编译的C语言程序和汇编程序之间能相互调用,必须为子程序间的调用规定一定的规则。这就是ATPCS规则。它规定了一些子程序间调用的基本规则。在寄存器的使用规则里,寄存器R12作用子程序间的scratch寄存器,记做ip。movip,lr语句的ip由此而来。笔者认为,这里使用别的通用寄存器来代替ip,实现的功能也是一样的。详情请参考ARM体系结构与编程第6章ATPCS介绍。调用lowlevel_init这个函数在u-boot-1.2.0boardsmdk2410
25、lowlevel_init.S文件中。这是对SDRAM的初始化。_TEXT_BASE:.wordTEXT_BASE.globllowlevel_initlowlevel_init:/*memorycontrolconfiguration*/*maker0relativethecurrentlocationsothatit*/*readsSMRDATAoutofFLASHratherthanmemory!*/ldrr0,=SMRDATAldrr1,_TEXT_BASEsubr0,r0,r1ldrr1,=BWSCON/*BusWidthStatusController*/addr2,r0,#13*
26、40:ldrr3,r0,#4strr3,r1,#4cmpr2,r0bne0b/*everythingisfinenow*/movpc,lr.ltorg/*theliteralpoolsorigin*/SMRDATA:.word(0+(B1_BWSCON4)+(B2_BWSCON8)+(B3_BWSCON12)+(B4_BWSCON16)+(B5_BWSCON20)+(B6_BWSCON24)+(B7_BWSCON28).word(B0_Tacs13)+(B0_Tcos11)+(B0_Tacc8)+(B0_Tcoh6)+(B0_Tah4)+(B0_Tacp2)+(B0_PMC).word(B1_
27、Tacs13)+(B1_Tcos11)+(B1_Tacc8)+(B1_Tcoh6)+(B1_Tah4)+(B1_Tacp2)+(B1_PMC).word(B2_Tacs13)+(B2_Tcos11)+(B2_Tacc8)+(B2_Tcoh6)+(B2_Tah4)+(B2_Tacp2)+(B2_PMC).word(B3_Tacs13)+(B3_Tcos11)+(B3_Tacc8)+(B3_Tcoh6)+(B3_Tah4)+(B3_Tacp2)+(B3_PMC).word(B4_Tacs13)+(B4_Tcos11)+(B4_Tacc8)+(B4_Tcoh6)+(B4_Tah4)+(B4_Tacp
28、2)+(B4_PMC).word(B5_Tacs13)+(B5_Tcos11)+(B5_Tacc8)+(B5_Tcoh6)+(B5_Tah4)+(B5_Tacp2)+(B5_PMC).word(B6_MT15)+(B6_Trcd2)+(B6_SCAN).word(B7_MT15)+(B7_Trcd2)+(B7_SCAN).word(REFEN23)+(TREFMD22)+(Trp20)+(Trc18)+(Tchr16)+REFCNT).word0 x32.word0 x30.word0 x30该段代码是对SDRAM控制器相关的寄存器赋值,赋值过程中,采用了一个巧妙的做法,把SDRAM控制器初始
29、化需要用到的13个寄存器的值先保存在文字池(literalpools)中,然后通过LDR伪指令以及.ltorg来访问这个文字池,获取寄存器的值赋值到对应的寄存器地址中去。很多同学对此代码的两个地址不理解:SMRDATA与_TEXT_BASE。不理解这两个地址相减之后,到底是一个什么值。为什么要相减呢?其实编译器进行编译,是按照链接文件进行的。也就是说,编译的时候所有的地址都是相对于这个TEXT_BASE计算出来的。而我们的程序是存放在Flash中的,ARM上电后,假设从nandflash模式启动,那么它会把Nandflash的前4K加载到内存中开始运行,当然是从0 x0这个地址开始运行,所以要
30、求我们的代码在还没有搬移到TEXT_BASE(0 x38f00000)这个位置以前是不能使用这些label的,只能找到一个相对于0 x0的地址出来,才能得到真正的数据。而且这时候,我们编译出来的bin文件是存放在0 x0000000的,而不是存放在0 x38f00000的。码的搬移#ifndefCONFIG_SKIP_RELOCATE_UBOOTrelocate:/*relocateU-BoottoRAM*/adrr0,_start/*r0-currentpositionofcode*/ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/cmpr0,r1/
31、*dontrelocduringdebug*/beqstack_setupldrr2,_armboot_startldrr3,_bss_startsubr2,r3,r2/*r2-sizeofarmboot*/addr2,r0,r2/*r2=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);如同使用变量之前,需要声明定义一样,这里使用全局变量gd和bd之前,我们需要先设置它的地址,并用memset函数
32、为它分配合适的空间。u-boot的注释告知我们,gd和bd是一个可写的指针,实际上不过是一个地址而已。代码中的这句话:_asm_volatile_(:memory);目的就是告诉编译器内存被修改过了执行初始化列表函数for(init_fnc_ptr=init_sequence;*init_fnc_ptr;+init_fnc_ptr)if(*init_fnc_ptr)()!=0)hang();这是一个for语句,却完成了板子初始化列表函数的功能。我们先来看一下for语句的初始值:init_sequence。用sourceinsight跟踪后发现,它是一个指针数组:init_fnc_t*init_
33、sequence=cpu_init,/*basiccpudependentsetup*/board_init,/*basicboarddependentsetup*/interrupt_init,/*setupexceptions*/env_init,/*initializeenvironment*/init_baudrate,/*initialzebaudratesettings*/serial_init,/*serialcommunicationssetup*/console_init_f,/*stage1initofconsole*/display_banner,/*saythatwea
34、rehere*/#ifdefined(CONFIG_DISPLAY_CPUINFO)print_cpuinfo,/*displaycpuinfo(andspeed)*/#endif#ifdefined(CONFIG_DISPLAY_BOARDINFO)checkboard,/*displayboardinfo*/#endifdram_init,/*configureavailableRAMbanks*/display_dram_config,NULL,;指针数组的每个成员都对应着一个函数名(函数指针),指向的是init_fnc_t类型的函数。For语句每次都会判断当前的函数是不是NULL,如果
35、是,则跳出for语句,完成当前的板子初始化列表函数的功能。可能大家都注意到了一个类型:init_fnc_t,它表示什么意思呢?我们看到了在初始化列表函数之前,有一个新的数据类型,它是个typedef语句:typedefint(init_fnc_t)(void);可能有的同学对此不太理解,为啥非得用一个typedef呢?笔者认为,可以不用typedef,但是用了init_fnc_t后,团队中别的成员来看代码的时候,会很轻松地知道,这是一个初始化(init)的函数(fnc),增加了代码的可读性。Cpu_init函数,并没有做实质性的工作,而且我们现在暂时没有定义CONFIG_USE_IRQ,因此,
36、代码执行到这里,直接就return0;Board_init函数,是初始化与硬件平台有关的函数。它的工作很明显:时钟的设置,引脚IO口的设置,并且在这里把数据cache和指令cache也打开了。以上工作的完成,标志着板子已经准备好工作了。当然,考虑到可能系统会发生意外中断,所以我们还需要初始化中断,让中断也准备好工作,因此u-boot代码中下一步就开始了中断的初始化。interrupt_init函数,这实际上是定时器的中断初始化。和我们之前的培训课程相符的是,我们看到了中断初始化中的那几个熟悉的寄存器,首先是两个配置寄存器TCFG0和TCFG1。晕倒,怎么代码中只有TCFG0的设置,没有TCFG
37、1的设置?很明显,TCFG1采用的是默认值。然后配置寄存器的下载值,最后打开启动开关,启动定时器工作。env_init函数,这是对我们板子的环境做出初始化配置。顺便提一下,我们修改的配置文件里,用的是nandflash来存放环境变量的值。#defineCFG_ENV_IS_IN_NAND1#defineCFG_ENV_OFFSET0 x40000#defineCFG_ENV_SIZE640 xc000/*TotalSizeofEnvironmentSector*/#defineCFG_ENV_SIZE0 x20000/*TotalSizeofEnvironmentSector*/因此,我们在进
38、入u-boot命令行之后,运行的关于环境变量的操作,只要它被保存,saveenv,肯定是save在nandflash中的某个位置。init_baudrate函数,初始化波特率。我们心里要很明确,初始化波特率,目的只有一个:让串口打印调试信息。因此,下一个函数,肯定是串口的初始化函数。所以,我们可以在调试的时候,先算好波特率的值,直接赋值给gd-bd-bi_baudrate,注释掉该函数中的其他代码。调试完毕,再恢复出原先的代码。这样,我们可以不用考虑别的因素导致串口打印不出信息。serial_init函数,串口的初始化函数。这里调用了另一个函数来配置串口寄存器:serial_setbrg();
39、在这个函数中,我们看到了关于串口的5个寄存器的配置。关于每个寄存器的更详细的配置信息,请参考ARM技术交流网推出的串口课程讲解部分。console_init_f函数,这个函数的功能只有一个,就是指出我们目前是使用串口的,因此有此句:gd-have_console=1;然后直接返回0。display_banner函数。OK,现在串口初始化完毕,我们可以打印信息了。这是u-boot代码中第一次打印信息。我们可以在这里加入我们自己的代码,比如笔者移植的u-boot代码中,就加入了如下“欢迎”的代码信息:printf(nn);printf(*n);printf(*n);printf(*n);print
40、f(*n);printf(*n);printf(*n);出现打印信息后,可以说,u-boot移植已经成功了一半。有了打印信息,我们可以随时用打印信息来调试。“点灯大法”,你可以睡觉去了。初始化列表函数中,还有几个函数,比较简单,我这里就不说了。随后开始的是一系列外设的初始化。配置可用的flash区:flash_init当您跟踪到flash_init函数的时候,您会发现,这里只兼容AMD系列的flash芯片,比如LV400及LV800。如果您的开发板上刚好就是AMD的芯片,那么恭喜,您可能就不需要修改flashID号了。可惜,笔者用的开发板上用的是EON生产的flash芯片。笔者只好把AMD的所
41、有代码,都改成EON的代码。#defineEN29LV160AB_ID0 x2249001c再来一个:#defineCONFIG_EON_29LV160AB1后面再修改FLASH_BANK_SIZE、CFG_MAX_FLASH_SECT、PHYS_FLASH_1等信息,来配置笔者的板子上可用的flash区域。初始化内存分配函数mem_malloc_init函数,这是非常关键的一步,请大家引起注意。我们必须配置好内存的起始地址和结束地址,然后把这块区域清零,以便后续来使用它。nandflash的初始化这部分代码,可能隐含是不执行的。如果您想使用它,需要自行打开,然后添加自己的nandflash驱
42、动的代码。笔者自己没有写nandflash的代码,而是直接copy别人的代码,拿过来改一改。如果想验证自己修改或者自己写的nandflash的驱动是否正确,可以试着从nandflash中读取或写入一个数据,并用串口打印出来(笔者修改的nandflash驱动代码,将在ARM技术交流网上公布,需要的可以随时下载)。后面的代码,一直到main_loop函数,我们都不需要修改。main_loop函数是进入命令循环的函数,它接受用户从串口输入的命令,然后执行相应的工作,这也是整个u-boot的工作循环。注意,它并没有使用中断来触发命令的操作,而是用循环来做这部分的工作:(二)目录文件:Common:U-
43、Boot支持的所有命令,都在这个目录中实现。每个命令放在该目录下的一个文件中。一般情况下,我们如果修改该目录下的文件代码,无非是加一些调试信息,打开或关闭一些宏。对于该目录下的C代码,我们无须大幅度修改。除非您想自己增加自己的u-boot命令Cpu:这个目录下,存放的是与cpu架构有关的目录。每个目录对应一个架构的cpu。比如我们想移植ARM9的S3C2440,就应该去找ARM920T的目录。其他目录实际上对我们是没有意义的。Disk:这是要对磁盘的支持。我们只移植u-boot的话,那这个对我们也没有意义。Doc:参考文档的意思,这是最没用的,也是最有用的。推荐想研究u-boot的同学抽时间阅
44、读一下,有好处。Driver:u-boot支持的所有的驱动代码,默认是放在这个目录下的。如果您需要添加自己的驱动代码,也可以放在这里。然后再makefile中加入相应的.o文件名。Fs:这个目录下放的是u-boot支持的文件系统。目前u-boot已经能支持包括cramfs、fat、fdos、jffs2等文件系统。Include:这个目录下存放的是头文件。U-boot使用的头文件以及对各种硬件平台的系统配置文件都放在这里。对于每款特定的开发板,我们都需要修改系统配置文件,它存放在include目录下的configs子目录中。比如我们研究2440的移植,那么可能就对SMDK2410.h感兴趣。Li
45、b_xxx:这是与体系结构相关的库文件。Net:此目录下存放的代码,是有关网络协议的实现的代码。比如TFTP协议的实现就在这里面。Post:上电自检的目录。该目录,我对此一点都没有研究。Tools:生成u-boot的工具的目录。比如创建bin镜像文件等。(三)初始化分析和移植过程分析:开发板的三种启动方式:nand:对于2440来说,CPU是不给nand-flash分配地址空间的,nand-flash只相当于CPU的一个外设,S3C2440做了一个从nand-flash启动的机制。开发板一上电,CPU就自动复制nand-flash里面的前4K-Bytes内容到S3C2440内部集成的SDRAM
46、,然后把4K内容所在的RAM映射到S3C2440的0地址,从0地址开始执行。这4K的内容主要负责下面这些工作:初始化中断矢量、设定CPU的工作模式为SVC32模式、屏蔽看门狗、屏蔽中断,初始化时钟、把整个u-boot重定向到外部SDRAM、跳到主要的C函数入口。nor:早期的时候利用nor-flash启动的方式比较多,就是把u-boot烧写到nor-flash里面,直接把nor-flash映射到S3C2440的0地址,上电从0地址开始执行。ram:直接把u-boot放到外部SDRAM上跑,这一般debug时候用到U-Boot移植的一般步骤从对U-Boot代码的分析可以看出,U-Boot移植工作
47、主要分成处理器相关部分和开发板相关部分。由于U-Boot已经支持目前绝大多数处理器,因此处理器移植的工作相对较少,主要是修改一些配置。对于开发板部分的移植,需要参考硬件线路的外围器件的手册。U-Boot移植大致可以分为下面的步骤:1检查U-Boot工程是否支持目标平台,主要检查U-Boot根目录下的Readme文件是否提到目标平台处理器,cpu目录下是否有目标平台的处理器目录,以及board目录下是否有目标平台类似的工程。如果U-Boot已经编写了与目标平台类似的工程文件,移植工作会大大减轻。2分析目标平台类似工程目录结构如果U-Boot有与目标平台类似的工程,需要分析一下目标板工程目录的结构
48、。不同的目标板可能差别很大,分析工程目录中有哪些文件可以被新的目标开发板利用。3分析目标平台代码目标平台代码分析可以按照前面介绍的UBoot启动流程分析,看哪些代码是额外的,是否需要去掉额外的代码。4建立新的开发板平台目录在board目录下建立新的开发板平台目录,目录下的文件可以从现有类似的开发板平台目录下复制得到。5对照手册修改平台差异部分代码对照硬件手册,按照U-Boot启动流程修改现有代码与新平台有差异的部分。6调试新代码新修改的代码很可能启动不了,需要通过JTag调试器跟踪调试。找出原因修改后再调试,直到正确启动。结合自己的目标板情况来分析以上分析的6个步骤并非必须严格遵守,这里仅是提
49、供一个一般的思路,读者在移植的时候需要结合自己的目标板情况来分析。具体实现过程:说明:先要完成交叉编译工具的制作,此处省略。修改Makefile文件打开makefile文件。如果您是在linux环境下开发,使用vimakefile命令可打开该文件。使用ctrl+F键,查找“smdk2400_config”,找到后,您会看到如下代码:smdk2400_config:unconfig$(MKCONFIG)$(:_config=)armarm920tsmdk2400NULLs3c24x0我们解释一下代码:arm,就表示现在用的是CPU的架构是arm体系结构。arm920t,指明这是cpu的内核类型,
50、它对应于cpu/arm920t目录。Smdk2400,这是开发板的型号,它的目录在board/smdk2400目录下。您也可以自己命名您的开发板。比如:ARM79。NULL,表示开发者或者经销商是谁(vender)。S3c24x0,表示开发板上的cpu是啥。对于我们的开发板,当然是S3C2440了。根据以上的解释,我们可以自己模仿着建立自己的编译项:arm79_config:unconfig$(MKCONFIG)$(:_config=)armarm920tarm79NULLs3c24x0OK,修改完毕,可以保存、退出makefile。建立自己的开发板文件为了使得u-boot具有自己的特征,我们
51、需要在board目录下建立自己的文件:1、复制board/smdk2410,并更名为board/arm79。2、复制board/smdk2410/smdk2410.c,并更名为board/arm79/arm79.cOK,我们的开发板是自己花钱买的,现在开发板上面跑的u-boot,我们也可以假装是自己写的代码了。建立自己的配置文件配置文件在:include/configs/smdk2410.h。大家还希望用别人的配置文件吗?当然不想!所以,改过来!复制include/configs/smdk2410.h,并更名为include/configs/arm79.h。这时候,可以暂时保留arm79.h中
52、的配置信息。一会再来修改它。我们现在有更重要的事情要做。修改交叉编译工具的路径交叉编译工具,您可以使用开发板公司为您提供的制作包即可。修改交叉编译工具的路径,请参考每个开发板公司的用户手册。这里无法给出一个定性的答案。一般都是在/etc/profile文件下修改,增加一个.bin目录。测试编译u-boot-1.2.0版本其实,u-boot虽然号称经典,但是有些版本在某些特定的arm平台或者powerpc平台是编译不通过的。笔者在实习时候,在公司产品上移植了一个u-boot版本,就是不行的。换成u-boot-1.2.0版本,可以编译通过。因此,笔者本次移植也采用了u-boot-1.2.0版本。c
53、du-boot-1.2.0/*切换到u-boot目录下*/makearm79_config这时候,命令行界面上会显示:Configuringforarm79board然后您再敲入make,回车。如果您的交叉编译工具安装正确的话,这时候就开始编译了,大约几分钟后,您就会看到窗口中出现了.bin文件的打印信息,回到您的u-bot根目录下,您就会发现,那里多出了一个u-boot.bin文件。当然,当您在调试的时候,或许您还想得到u-boot的反汇编代码,那么,请再次打开makefile文件,用ctrl+F键,查找到“u-boot.bin”所在的行,大约在第239行(如果您之前没有在makefile中
54、修改别的信息的话):ALL=$(obj)u-boot.srec$(obj)u-boot.bin$(obj)System.map$(U_BOOT_NAND)这行的代码,是指定编译后,输出啥文件的。可以看到,编译结果,会输出u-boot.srec文件,u-boot.bin文件,system.map文件,等等。这时候,您如果想让它输出u-boot的反汇编文件,只要这样做:ALL=$(obj)u-boot.srec$(obj)u-boot.bin$(obj)System.map$(obj)u-boot.dis$(U_BOOT_NAND)对比一下,发现我们现在增加了“$(obj)u-boot.dis”。
55、对了,这就是指定编译结果,要输出u-boot反汇编文件。修改配置文件之前已经提到,笔者的配置文件已经改为arm79.h,目录在include/configs/arm79.h。由于配置文件修改较多,而且是根据具体开发板进行配置的,因此笔者直接给出了修改完的配置文件,并作出详细的注释,希望对您有所帮助!#ifndef_CONFIG_H#define_CONFIG_H/*/*HighLevelConfigurationOptions*(easytochange)*/#defineCONFIG_ARM920T1/*ThisisanARM920TCore*/#defineCONFIG_S3C24101/
56、*inaSAMSUNGS3C2410SoC*/#defineCONFIG_SMDK24101/*onaSAMSUNGSMDK2410Board/*inputclockofPLL*/#defineCONFIG_SYS_CLK_FREQ12000000/*输入时钟12M*/#defineUSE_920T_MMU1#undefCONFIG_USE_IRQ/*暂时不使用IRQ*/*Sizeofmalloc()pool*/#defineCFG_MALLOC_LEN(CFG_ENV_SIZE+128*1024)#defineCFG_GBL_DATA_SIZE128/*sizeinbytesreserved
57、forinitialdata*/*网卡的配置信息*/#defineCONFIG_DRIVER_DM90001#defineCONFIG_DM9000_BASE0 x20000300#defineDM9000_IOCONFIG_DM9000_BASE#defineDM9000_DATA(CONFIG_DM9000_BASE+4)#defineCONFIG_DM9000_USE_16BIT/*selectserialconsoleconfiguration*/#defineCONFIG_SERIAL11/*使用串口*/*RTC#defineCONFIG_RTC_S3C24X01/*allowtoo
58、verwriteserialandethaddr*/#defineCONFIG_ENV_OVERWRITE#defineCONFIG_BAUDRATE38400/*波特率使用38400*/*Commanddefinition#defineCONFIG_COMMANDS(CONFIG_CMD_DFL|CFG_CMD_LOADS|CFG_CMD_LOADB|CFG_CMD_CACHE|CFG_CMD_NAND|CFG_CMD_FLASH|CFG_CMD_PING|/*CFG_CMD_EEPROM|*/*CFG_CMD_I2C|*/*CFG_CMD_USB|*/CFG_CMD_REGINFO|CFG
59、_CMD_DATE|CFG_CMD_ELF)/*thismustbeincludedAFTERthedefinitionofCONFIG_COMMANDS(ifany)*/#include#defineCONFIG_BOOTDELAY3/*进入命令行的等待时间3s*/*#defineCONFIG_BOOTARGSroot=ramfsdevfs=mountconsole=ttySA0,9600*/*#defineCONFIG_ETHADDR08:00:3e:26:0a:5b*/#defineCONFIG_NETMASK#defineCONFIG_IPADDR10#defineCONFIG_SER
60、VERIP/*#defineCONFIG_BOOTFILEelinos-lart*/*#defineCONFIG_BOOTCOMMANDtftp;bootm*/#if(CONFIG_COMMANDS&CFG_CMD_KGDB)#defineCONFIG_KGDB_BAUDRATE9600/*speedtorunkgdbserialport*/*whatsthis?itsnotusedanywhere*/#defineCONFIG_KGDB_SER_INDEX1/*whichserialporttouse*/#endif/*Miscellaneousconfigurableoptions*/#d
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 漫画的启示主题班会课件
- 2025青海海西州格尔木市紧密型城市医疗集团招聘工作人员39人笔试参考题库附带答案详解
- 湖南省五下信息技术课件
- 水利工程建设完工验收质量监督报告
- 小学生课件英语
- 家畜饲养工岗位实习报告
- 胶化工岗位实习报告
- 印染洗涤工职业技能模拟试卷含答案
- 保健刮痧师公司招聘笔试题库及答案
- 有线广播电视机线员安全技术操作规程
- (2025)纪检监察业务知识考试题及含答案
- 2025年大模型应用:从提示工程到AI智能体报告
- 大连智能巡检机器人项目投资计划书
- 2025届广东省佛山市南海中学七下数学期末学业水平测试试题含解析
- GB/T 24217-2025洗油
- 2025-2030中国坚果配料行业市场现状供需分析及投资评估规划分析研究报告
- 软件渠道销售协议书
- 康复理疗免责协议书
- 中医护理质量与安全管理职责
- 2025智能矿山暨无人驾驶行业蓝皮书-亿欧智库
- 2025护士条例专题培训
评论
0/150
提交评论