[ZLG-ARM] ArmLinux bootloader 全程详解

[复制链接]
 楼主| tmake 发表于 2009-7-11 13:46 | 显示全部楼层 |阅读模式
网上关于Linux的BOOTLOADER**不少了,但是大都是vivi,blob等比较庞大的程序,读起来不太方便,编译出的文件也比较大,而且更多的是面向开发用的引导代码,做成产品时还要裁减,这一定程度影响了开发速度,对初学者学习开销也比较大,在此分析一种简单的BOOTLOADER,是在三星公司提供的2410&nbsp;BOOTLOADER上稍微修改后的结果,编译出来的文件大小不超过4k,希望对大家有所帮助.<br /><br />1.几个重要的概念<br /><br />COMPRESSED&nbsp;KERNEL&nbsp;and&nbsp;DECOMPRESSED&nbsp;KERNEL<br /><br />压缩后的KERNEL,按照文档资料,现在不提倡使用DECOMPRESSED&nbsp;KERNEL,而要使用COMPRESSED&nbsp;KERNEL,它包括了解压器.因此要在ram分配时给压缩和解压的KERNEL提供足够空间,这样它们不会相互覆盖.<br /><br />当执行指令跳转到COMPRESSED&nbsp;KERNEL后,解压器就开始工作,如果解压器探测到解压的代码会覆盖掉COMPRESSEDKERNEL,那它会直接跳到COMPRESSED&nbsp;KERNEL后存放数据,并且重新定位KERNEL,所以如果没有足够空间,就会出错.<br /><br />Jffs2&nbsp;File&nbsp;System<br /><br />可以使armlinux应用中产生的数据保存在FLASH上,我的板子还没用到这个.<br /><br />RAMDISK<br /><br />使用RAMDISK可以使ROOT&nbsp;FILESYSTEM在没有其他设备的情况下启动.一般有两种加载方式,我就介绍最常用的吧,把COMPRESSED&nbsp;RAMDISKIMAGE放到指定地址,然后由BOOTLOADER把这个地址通过启动参数的方式ATAG_INITRD2传递给KERNEL.具体看代码分析.<br /><br />启动参数(摘自IBM&nbsp;developer)<br /><br />在调用内核之前,应该作一步准备工作,即:设置&nbsp;Linux&nbsp;内核的启动参数。Linux&nbsp;2.4.x&nbsp;以后的内核都期望以标记列表(taggedlist)的形式来传递启动参数。启动参数标记列表以标记&nbsp;ATAG_CORE&nbsp;开始,以标记&nbsp;ATAG_NONE&nbsp;结束。每个标记由标识被传递参数的tag_header&nbsp;结构以及随后的参数值数据结构来组成。数据结构&nbsp;tag&nbsp;和&nbsp;tag_header&nbsp;定义在&nbsp;Linux内核源码的include/asm/setup.h&nbsp;头文件中.<br /><br />在嵌入式&nbsp;Linux&nbsp;系统中,通常需要由&nbsp;BOOTLOADER&nbsp;设置的常见启动参数有:ATAG_CORE、ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等。<br /><br />(注)参数也可以用COMMANDLINE来设定,在我的BOOTLOADER里,我两种都用了.<br /><br />2.开发环境和开发板配置:<br /><br />CPU:S3C2410,BANK6上有64M的SDRAM(两块),BANK0上有32M&nbsp;NOR&nbsp;FLASH,串口当然是逃不掉的.这样,按照数据手册,地址分配如下:<br /><br />0x4000_0000开始是4k的片内DRAM.<br /><br />0x0000_0000开始是32M&nbsp;FLASH&nbsp;16bit宽度<br /><br />0x3000_0000开始是64M&nbsp;SDRAM&nbsp;32bit宽度<br /><br />注意:控制寄存器中的BANK6和BANK7部分必须相同.<br /><br />0x4000_0000(片内DRAM)存放4k以内的BOOTLOADER&nbsp;IMAGE<br /><br />0x3000_0100开始存放启动参数<br /><br />0x3120_0000&nbsp;存放COMPRESSED&nbsp;KERNEL&nbsp;IMAGE<br /><br />0x3200_0000&nbsp;存放COMPRESSED&nbsp;RAMDISK<br /><br />0x3000_8000&nbsp;指定为DECOMPRESSED&nbsp;KERNEL&nbsp;IMAGE&nbsp;ADDRESS<br /><br />0x3040_0000&nbsp;指定为DECOMPRESSED&nbsp;RAMDISK&nbsp;IMAGE&nbsp;ADDRESS<br /><br />开发环境:Redhat&nbsp;Linux,armgcc&nbsp;toolchain,&nbsp;armlinux&nbsp;KERNEL<br /><br />如何建立armgcc的编译环境:建议使用toolchain,而不要自己去编译armgcc,偶试过好多次,都以失败告终.<br /><br />先下载arm-gcc&nbsp;3.3.2&nbsp;toolchain<br /><br />将arm-linux-gcc-3.3.2.tar.bz2&nbsp;解压到&nbsp;/toolchain<br /><br />#&nbsp;tar&nbsp;jxvf&nbsp;arm-linux-gcc-3.3.2.tar.bz2<br /><br />#&nbsp;mv&nbsp;/usr/local/arm/3.3.2&nbsp;/toolchain<br /><br />在makefile&nbsp;中在把arch=arm&nbsp;CROSS_COMPILE设置成toolchain的路径<br /><br />还有就是INCLUDE&nbsp;=&nbsp;-I&nbsp;../include&nbsp;-I&nbsp;/root/my/usr/local/arm/3.3.2/include.,否则库函数就不能用了<br /><br />3.启动方式:<br /><br />可以放在FLASH里启动,或者用Jtag仿真器.由于使用NOR&nbsp;FLASH,根据2410的手册,片内的4KDRAM在不需要设置便可以直接使用,而其他存储器必须先初始化,比如告诉memorycontroller,BANK6里有两块SDRAM,数据宽度是32bit,=&nbsp;=.否则memorycontrol会按照复位后的默认值来处理存储器.这样读写就会产生错误.<br /><br />所以第一步,通过仿真器把执行代码放到0x4000_0000,(在编译的时候,设定TEXT_BAS<br /><br />E=0x40000000)<br /><br />第二步,通过&nbsp;AxD把linux&nbsp;KERNEL&nbsp;IMAGE放到目标地址(SDRAM)中,等待调用<br /><br />第三步,执行BOOTLOADER代码,从串口得到调试数据,引导armlinux<br /><br />4.代码分析<br /><br />讲了那么多执行的步骤,是想让大家对启动有个大概印象,接着就是BOOTLOADER内部的代码分析了,BOOTLOADER**内容网上很多,我这里精简了下,删除了不必要的功能.<br /><br />BOOTLOADER一般分为2部分,汇编部分和c语言部分,汇编部分执行简单的硬件初始化,C部分负责复制数据,设置启动参数,串口通信等功能.<br /><br />BOOTLOADER的生命周期:<br /><br />1.&nbsp;初始化硬件,比如设置UART(至少设置一个),检测存储器=&nbsp;=.<br /><br />2.&nbsp;设置启动参数,这是为了告诉内核硬件的信息,比如用哪个启动界面,波特率&nbsp;=&nbsp;=.<br /><br />3.&nbsp;跳转到Linux&nbsp;KERNEL的首地址.<br /><br />4.&nbsp;消亡<br /><br /><br /><br />当然,在引导阶段,象vivi等,都用虚地址,如果你嫌烦的话,就用实地址,都一样.<br /><br />我们来看代码:<br /><br />2410init.s<br /><br />.global&nbsp;_start//开始执行处<br /><br />_start:<br /><br />//下面是中断向量<br /><br />b&nbsp;reset&nbsp;@&nbsp;Supervisor&nbsp;Mode//重新启动后的跳转<br /><br />……<br /><br />……<br /><br />reset:<br /><br />ldr&nbsp;r0,=WTCON&nbsp;/WTCON地址为53000000,watchdog的控制寄存器&nbsp;*/<br /><br />ldr&nbsp;r1,=0x0&nbsp;/*关watchdog*/<br /><br />str&nbsp;r1,[r0]<br /><br /><br /><br />ldr&nbsp;r0,=INTMSK<br /><br />ldr&nbsp;r1,=0xffffffff&nbsp;/*屏蔽所有中断*/<br /><br />str&nbsp;r1,[r0]<br /><br /><br /><br />ldr&nbsp;r0,=INTSUBMSK<br /><br />ldr&nbsp;r1,=0x3ff&nbsp;/*子中断也一样*/<br /><br />str&nbsp;r1,[r0]<br /><br />/*Initialize&nbsp;Ports...for&nbsp;display&nbsp;LED.*/<br /><br />ldr&nbsp;r0,&nbsp;=GPFCON<br /><br />ldr&nbsp;r1,&nbsp;=0x55aa<br /><br />str&nbsp;r1,&nbsp;[r0]<br /><br />ldr&nbsp;r0,&nbsp;=GPFUP<br /><br />ldr&nbsp;r1,&nbsp;=0xff<br /><br />str&nbsp;r1,&nbsp;[r0]<br /><br />ldr&nbsp;r0,=GPFDAT<br /><br />ldr&nbsp;r1,=POWEROFFLED1<br /><br />str&nbsp;r1,[r0]<br /><br />/*&nbsp;Setup&nbsp;clock&nbsp;Divider&nbsp;control&nbsp;register<br /><br />*&nbsp;you&nbsp;must&nbsp;configure&nbsp;CLKDIVN&nbsp;before&nbsp;LOCKTIME&nbsp;or&nbsp;MPLL&nbsp;UPLL<br /><br />*&nbsp;because&nbsp;default&nbsp;CLKDIVN&nbsp;1,1,1&nbsp;set&nbsp;the&nbsp;SDMRAM&nbsp;Timing&nbsp;Conflict<br /><br />nop<br /><br />*&nbsp;FCLK:HCLKCLK&nbsp;=&nbsp;1:2:4&nbsp;in&nbsp;this&nbsp;case<br /><br />*/<br /><br />ldr&nbsp;r0,=CLKDIVN<br /><br />ldr&nbsp;r1,=0x3<br /><br />str&nbsp;r1,[r0]<br /><br /><br /><br />/*To&nbsp;reduce&nbsp;PLL&nbsp;lock&nbsp;time,&nbsp;adjust&nbsp;the&nbsp;LOCKTIME&nbsp;register.&nbsp;*/<br /><br />ldr&nbsp;r0,=LOCKTIME<br /><br />ldr&nbsp;r1,=0xffffff<br /><br />str&nbsp;r1,[r0]<br /><br />/*Configure&nbsp;MPLL&nbsp;*/<br /><br />ldr&nbsp;r0,=MPLLCON<br /><br />ldr&nbsp;r1,=((M_MDIV&lt&lt12)+(M_PDIV&lt&lt4)+M_SDIV)&nbsp;//Fin=12MHz,Fout=203MHz<br /><br />str&nbsp;r1,[r0]<br /><br />ldr&nbsp;r1,=GSTATUS2<br /><br />ldr&nbsp;r10,[r1]<br /><br />tst&nbsp;r10,#OFFRST<br /><br />bne&nbsp;1000f<br /><br />//以上这段,我没动,就用三星写的了,下面是主要要改的地方<br /><br />/*&nbsp;MEMORY&nbsp;C0NTROLLER(MC)设置*/<br /><br />add&nbsp;r0,pc,#MCDATA&nbsp;-&nbsp;(.+8)//&nbsp;r0指向MCDATA地址,那里存放着MC初始化要用到的数据<br /><br />ldr&nbsp;r1,=BWSCON&nbsp;//&nbsp;r1指向MC控制器寄存器的首地址<br /><br />add&nbsp;r2,r0,#52&nbsp;//&nbsp;复制次数,偏移52字<br /><br /><br /><br />1:&nbsp;//按照偏移量进行循环复制<br /><br />ldr&nbsp;r3,[r0],#4<br /><br />str&nbsp;r3,[r1],#4<br /><br />cmp&nbsp;r2,r0<br /><br />bne&nbsp;1b<br /><br />.align&nbsp;2<br /><br /><br /><br />MCDATA:<br /><br />.word(0+(B1_BWSCON&lt&lt4)+(B2_BWSCON&lt&lt8)+(B3_BWSCON&lt&lt12)+(B4_BWSCON&lt&lt16)+(B5_BWSCON&lt&lt20)+(B6_BWSCON&lt&lt24)+(B7_BWSCON&lt&lt28))<br /><br />上面这行就是BWSCON的数据,具体参数意义如下:<br /><br /><br /><br />需要更改设置DW6&nbsp;和DW7都设置成10,即32bit,DW0&nbsp;设置成01,即16bit<br /><br />下面都是每个BANK的控制器数据,大都是时钟相关,可以用默认值,设置完MC后,就跳到调用main函数的部分<br /><br />.word((B0_Tacs&lt&lt13)+(B0_Tcos&lt&lt11)+(B0_Tacc&lt&lt8)+(B0_Tcoh&lt&lt6)+(B0_Tah&lt&lt4)+(B0_Tacp&lt&lt2)+(B0_PMC))<br /><br />.word((B1_Tacs&lt&lt13)+(B1_Tcos&lt&lt11)+(B1_Tacc&lt&lt8)+(B1_Tcoh&lt&lt6)+(B1_Tah&lt&lt4)+(B1_Tacp&lt&lt2)+(B1_PMC))<br /><br />.word((B2_Tacs&lt&lt13)+(B2_Tcos&lt&lt11)+(B2_Tacc&lt&lt8)+(B2_Tcoh&lt&lt6)+(B2_Tah&lt&lt4)+(B2_Tacp&lt&lt2)+(B2_PMC))<br /><br />.word((B3_Tacs&lt&lt13)+(B3_Tcos&lt&lt11)+(B3_Tacc&lt&lt8)+(B3_Tcoh&lt&lt6)+(B3_Tah&lt&lt4)+(B3_Tacp&lt&lt2)+(B3_PMC))<br /><br />.word((B4_Tacs&lt&lt13)+(B4_Tcos&lt&lt11)+(B4_Tacc&lt&lt8)+(B4_Tcoh&lt&lt6)+(B4_Tah&lt&lt4)+(B4_Tacp&lt&lt2)+(B4_PMC))<br /><br />.word((B5_Tacs&lt&lt13)+(B5_Tcos&lt&lt11)+(B5_Tacc&lt&lt8)+(B5_Tcoh&lt&lt6)+(B5_Tah&lt&lt4)+(B5_Tacp&lt&lt2)+(B5_PMC))<br /><br />.word&nbsp;((B6_MT&lt&lt15)+(B6_Trcd&lt&lt2)+(B6_SCAN))<br /><br />.word&nbsp;((B7_MT&lt&lt15)+(B7_Trcd&lt&lt2)+(B7_SCAN))<br /><br />.word&nbsp;((REFEN&lt&lt23)+(TREFMD&lt&lt22)+(Trp&lt&lt20)+(Trc&lt&lt18)+(Tchr&lt&lt16)+REFCNT)<br /><br />.word&nbsp;0xB2&nbsp;/*&nbsp;REFRESH&nbsp;Control&nbsp;Register&nbsp;*/<br /><br />.word&nbsp;0x30&nbsp;/*&nbsp;BANKSIZE&nbsp;Register&nbsp;:&nbsp;Burst&nbsp;Mode&nbsp;*/<br /><br />.word&nbsp;0x30&nbsp;/*&nbsp;SDRAM&nbsp;Mode&nbsp;Register&nbsp;*/<br /><br /><br /><br />.align&nbsp;2<br /><br />.global&nbsp;call_main&nbsp;//调用main函数,函数参数都为0<br /><br />call_main:<br /><br />ldr&nbsp;sp,STACK_START<br /><br />mov&nbsp;fp,#0&nbsp;/*&nbsp;no&nbsp;previous&nbsp;frame,&nbsp;so&nbsp;fp=0*/<br /><br />mov&nbsp;a1,&nbsp;#0&nbsp;/*&nbsp;set&nbsp;argc&nbsp;to&nbsp;0*/<br /><br />mov&nbsp;a2,&nbsp;#0&nbsp;/*&nbsp;set&nbsp;argv&nbsp;to&nbsp;NUL*/<br /><br />bl&nbsp;main&nbsp;/*&nbsp;call&nbsp;main*/<br /><br />STACK_START:<br /><br />.word&nbsp;STACK_BASE<br /><br />undefined_instruction:<br /><br />software_interrupt:<br /><br />prefetch_abort:<br /><br />data_abort:<br /><br />not_used:<br /><br />irq:<br /><br />fiq:<br /><br />/*以上是主要的汇编部分,实现了时钟设置,串口设置watchdog关闭,中断关闭功能(如果有需要还可以降频使用),然后转入main*/<br /><br />2410init.c&nbsp;file<br /><br />int&nbsp;main(int&nbsp;argc,char&nbsp;**argv)<br /><br />{<br /><br />u32&nbsp;test&nbsp;=&nbsp;0;<br /><br />void(*theKERNEL)(int&nbsp;zero,&nbsp;int&nbsp;arch,&nbsp;unsigned&nbsp;long&nbsp;params_addr)&nbsp;=&nbsp;(void(*)(int,&nbsp;int,&nbsp;unsigned&nbsp;long))RAM_COMPRESSED_KERNEL_BASE;&nbsp;//压缩后的IMAGE地址<br /><br />int&nbsp;i,k=0;<br /><br />//&nbsp;downPt=(RAM_COMPRESSED_KERNEL_BASE);<br /><br />chkBs=(_RAM_STARTADDRESS);//SDRAM开始的地方<br /><br />//&nbsp;fromPt=(FLASH_LINUXKERNEL);<br /><br />MMU_EnableICache();<br /><br />ChangeClockDivider(1,1);&nbsp;//&nbsp;1:2:4<br /><br />ChangeMPllValue(M_MDIV,M_PDIV,M_SDIV);&nbsp;//Fin=12MHz&nbsp;FCLK=200MHz<br /><br />Port_Init();//设置I/O端口,在使用com口前,必须调用这个函数,否则通信芯片根本得不到数据<br /><br />Uart_Init(PCLK,&nbsp;115200);//PCLK使用默认的200000,拨特率115200<br /><br />/*******************(检查ram空间)*******************/<br /><br />Uart_SendString('\\n\\tLinux&nbsp;S3C2410&nbsp;Nor&nbsp;BOOTLOADER\\n');<br /><br />Uart_SendString('\\n\\tChecking&nbsp;SDRAM&nbsp;2410loader.c...\\n');<br /><br />for(;chkBs&lt0x33FA0140;chkBs=chkBs+0x4,test++)//<br /><br /><br /><br />//根据我的经验,最好以一个字节为递增,我们的板子,在256byte递增检测的时候是没问题的,但是<br /><br />//以1byte递增就出错了,第13跟数据线随几的会冒”1”,检测出来是硬件问题,现象如下<br /><br />//用仿真器下代码测试SDRAM,开始没贴28F128A3JFLASH片子,测试结果很好,但在上了FLASH片子//之后,测试数据(data)为0x00000400连续成批写入读出时,操作大约1k左右内存空间就会出错,//而且随机。那个出错数据总是变为0x00002400,数据总线10位和13位又没短路发生。用其他数据//测试比如0x00000200;0x00000800没这问题。dx帮忙。<br /><br />//至今没有解决,所以我用不了Flash.<br /><br />{<br /><br />chkPt1&nbsp;=&nbsp;chkBs;<br /><br />*(u32&nbsp;*)chkPt1&nbsp;=&nbsp;test;//写数据<br /><br />if(*(u32&nbsp;*)chkPt1==1024))//读数据和写入的是否一样?<br /><br />{<br /><br />chkPt1&nbsp;+=&nbsp;4;<br /><br />Led_Display(1);<br /><br />Led_Display(2);<br /><br />Led_Display(3);<br /><br />Led_Display(4);<br /><br />}<br /><br />else<br /><br />goto&nbsp;error;<br /><br />}<br /><br />Uart_SendString('\\n\\tSDRAM&nbsp;Check&nbsp;Successful!\\n\\tMemory&nbsp;Maping...');<br /><br />get_memory_map();<br /><br />//获得可用memory&nbsp;信息,做成列表,后面会作为启动参数传给KERNEL<br /><br />//所谓内存映射就是指在4GB&nbsp;物理地址空间中有哪些地址范围被分配用来寻址系统的&nbsp;RAM&nbsp;单元。<br /><br />Uart_SendString('\\n\\tMemory&nbsp;Map&nbsp;Successful!\\n');<br /><br />//我用仿真器把KERNEL,RAMDISK直接放在SDRAM上,所以下面这段是不需要的,但是如果KERNEL,RAMDISK在FLASH里,那就需要.<br /><br />/*******************(copy&nbsp;linux&nbsp;KERNEL)*******************/<br /><br />Uart_SendString('\\tLoading&nbsp;KERNEL&nbsp;IMAGE&nbsp;from&nbsp;FLASH...&nbsp;\\n');<br /><br />Uart_SendString('\\tand&nbsp;copy&nbsp;KERNEL&nbsp;IMAGE&nbsp;to&nbsp;SDRAM&nbsp;at&nbsp;0x31000000\\n');<br /><br />Uart_SendString('\\t\\tby&nbsp;LEIJUN&nbsp;DONG&nbsp;dongleijun4000@hotmail.com&nbsp;\\n');<br /><br />for(k&nbsp;=&nbsp;0;k&lt&nbsp;196608;k++,downPt&nbsp;+=&nbsp;1,fromPt&nbsp;+=&nbsp;1)//3*1024*1024/32linux&nbsp;KERNEL&nbsp;des,src,length=3M<br /><br />*&nbsp;(u32&nbsp;*)downPt&nbsp;=&nbsp;*&nbsp;(u32&nbsp;*)fromPt;<br /><br />/*******************(load&nbsp;RAMDISK)*******************/<br /><br />Uart_SendString('\\t\\tloading&nbsp;COMPRESSED&nbsp;RAMDISK...\\n');<br /><br />downPt=(RAM_COMPRESSED_RAMDISK_BASE);<br /><br />fromPt=(FLASH_RAMDISK_BASE);<br /><br />for(k&nbsp;=&nbsp;0;k&lt&nbsp;196608;k++,downPt&nbsp;+=&nbsp;1,fromPt&nbsp;+=&nbsp;1)//3*1024*1024/32linux&nbsp;KERNEL&nbsp;des,src,length=3M<br /><br />*&nbsp;(u32&nbsp;*)downPt&nbsp;=&nbsp;*&nbsp;(u32&nbsp;*)fromPt;<br /><br />/******jffs2文件系统,在开发中如果用不到FLASH,这段也可以不要********/<br /><br />Uart_SendString('\\t\\tloading&nbsp;jffs2...\\n');<br /><br />downPt=(RAM_JFFS2);<br /><br />fromPt=(FLASH_JFFS2);<br /><br />for(k&nbsp;=&nbsp;0;k&lt&nbsp;(1024*1024/32);k++,downPt&nbsp;+=&nbsp;1,fromPt&nbsp;+=&nbsp;1)<br /><br />*&nbsp;(u32&nbsp;*)downPt&nbsp;=&nbsp;*&nbsp;(u32&nbsp;*)fromPt;<br /><br />Uart_SendString('Load&nbsp;Success...Run...\\n');<br /><br />/*******************(setup&nbsp;param)*******************/<br /><br />setup_start_tag();//开始设置启动参数<br /><br />setup_memory_tags();//内存印象<br /><br />setup_commandline_tag('console=ttyS0,115200n8');//启动命令行<br /><br />setup_initrd2_tag();//root&nbsp;device<br /><br />setup_RAMDISK_tag();//ramdisk&nbsp;image<br /><br />setup_end_tag();<br /><br />/*关I-cache&nbsp;*/<br /><br />asm&nbsp;('mrc&nbsp;p15,&nbsp;0,&nbsp;%0,&nbsp;c1,&nbsp;c0,&nbsp;0':'=r'&nbsp;(i));<br /><br />i&=&nbsp;~0x1000;<br /><br />asm&nbsp;('mcr&nbsp;p15,&nbsp;0,&nbsp;%0,&nbsp;c1,&nbsp;c0,&nbsp;0':&nbsp;:'r'&nbsp;(i));<br /><br />/*&nbsp;flush&nbsp;I-cache&nbsp;*/<br /><br />asm&nbsp;('mcr&nbsp;p15,&nbsp;0,&nbsp;%0,&nbsp;c7,&nbsp;c5,&nbsp;0':&nbsp;:'r'&nbsp;(i));<br /><br />//下面这行就跳到了COMPRESSED&nbsp;KERNEL的首地址<br /><br />theKERNEL(0,&nbsp;ARCH_NUMBER,&nbsp;(unsigned&nbsp;long&nbsp;*)(RAM_BOOT_PARAMS));<br /><br />//启动kernel时候,I-cache可以开也可以关,r0必须是0,r1必须是CPU型号<br /><br />(可以从linux/arch/arm/tools/mach-types中找到),r2必须是参数的物理开始地址<br /><br />/*******************END*******************/<br /><br />error:<br /><br />Uart_SendString('\\n\\nPanic&nbsp;SDRAM&nbsp;check&nbsp;error!\\n');<br /><br />return&nbsp;0;<br /><br />}<br /><br />static&nbsp;void&nbsp;setup_start_tag(void)<br /><br />{<br /><br />params&nbsp;=&nbsp;(struct&nbsp;tag&nbsp;*)RAM_BOOT_PARAMS;//启动参数开始的地址<br /><br />params-&gthdr.tag&nbsp;=&nbsp;ATAG_CORE;<br /><br />params-&gthdr.size&nbsp;=&nbsp;tag_size(tag_core);<br /><br />params-&gtu.core.flags&nbsp;=&nbsp;0;<br /><br />params-&gtu.core.pagesize&nbsp;=&nbsp;0;<br /><br />params-&gtu.core.rootdev&nbsp;=&nbsp;0;<br /><br />params&nbsp;=&nbsp;tag_next(params);<br /><br />}<br /><br /><br /><br /><br /><br />static&nbsp;void&nbsp;setup_memory_tags(void)<br /><br />{<br /><br />int&nbsp;i;<br /><br /><br /><br />for(i&nbsp;=&nbsp;0;&nbsp;i&lt&nbsp;NUM_MEM_AREAS;&nbsp;i++)&nbsp;{<br /><br />if(memory_map.used)&nbsp;{<br /><br />params-&gthdr.tag&nbsp;=&nbsp;ATAG_MEM;<br /><br />params-&gthdr.size&nbsp;=&nbsp;tag_size(tag_mem32);<br /><br />params-&gtu.mem.start&nbsp;=&nbsp;memory_map.start;<br /><br />params-&gtu.mem.size&nbsp;=&nbsp;memory_map.len;<br /><br />params&nbsp;=&nbsp;tag_next(params);<br /><br />}<br /><br />}<br /><br />}<br /><br /><br /><br /><br /><br />static&nbsp;void&nbsp;setup_commandline_tag(char&nbsp;*commandline)<br /><br />{<br /><br />int&nbsp;i&nbsp;=&nbsp;0;<br /><br />/*&nbsp;skip&nbsp;non-existent&nbsp;command&nbsp;lines&nbsp;so&nbsp;the&nbsp;kernel&nbsp;will&nbsp;still<br /><br />*&nbsp;use&nbsp;its&nbsp;default&nbsp;command&nbsp;line.<br /><br />*/<br /><br />params-&gthdr.tag&nbsp;=&nbsp;ATAG_CMDLINE;<br /><br />params-&gthdr.size&nbsp;=&nbsp;8;<br /><br />//console=ttyS0,115200n8<br /><br />strcpy(params-&gtu.cmdline.cmdline,&nbsp;p);<br /><br />params&nbsp;=&nbsp;tag_next(params);<br /><br />}<br /><br /><br /><br /><br /><br />static&nbsp;void&nbsp;setup_initrd2_tag(void)<br /><br />{<br /><br />/*&nbsp;an&nbsp;ATAG_INITRD&nbsp;node&nbsp;tells&nbsp;the&nbsp;kernel&nbsp;where&nbsp;the&nbsp;compressed<br /><br />*&nbsp;ramdisk&nbsp;can&nbsp;be&nbsp;found.&nbsp;ATAG_RDIMG&nbsp;is&nbsp;a&nbsp;better&nbsp;name,&nbsp;actually.<br /><br />*/<br /><br />params-&gthdr.tag&nbsp;=&nbsp;ATAG_INITRD2;<br /><br />params-&gthdr.size&nbsp;=&nbsp;tag_size(tag_initrd);<br /><br />params-&gtu.initrd.start&nbsp;=&nbsp;RAM_COMPRESSED_RAMDISK_BASE;<br /><br />params-&gtu.initrd.size&nbsp;=&nbsp;2047;//k&nbsp;byte<br /><br />params&nbsp;=&nbsp;tag_next(params);<br /><br />}<br /><br /><br /><br /><br /><br />static&nbsp;void&nbsp;setup_ramdisk_tag(void)<br /><br />{<br /><br />/*&nbsp;an&nbsp;ATAG_RAMDISK&nbsp;node&nbsp;tells&nbsp;the&nbsp;kernel&nbsp;how&nbsp;large&nbsp;the<br /><br />*&nbsp;decompressed&nbsp;ramdisk&nbsp;will&nbsp;become.<br /><br />*/<br /><br />params-&gthdr.tag&nbsp;=&nbsp;ATAG_RAMDISK;<br /><br />params-&gthdr.size&nbsp;=&nbsp;tag_size(tag_ramdisk);<br /><br />params-&gtu.ramdisk.start&nbsp;=&nbsp;RAM_DECOMPRESSED_RAMDISK_BASE;<br /><br />params-&gtu.ramdisk.size&nbsp;=&nbsp;7.8*1024;&nbsp;//k&nbsp;byte<br /><br />params-&gtu.ramdisk.flags&nbsp;=&nbsp;1;&nbsp;//&nbsp;automatically&nbsp;load&nbsp;ramdisk<br /><br />params&nbsp;=&nbsp;tag_next(params);<br /><br />}<br /><br /><br /><br /><br /><br />static&nbsp;void&nbsp;setup_end_tag(void)<br /><br />{<br /><br />params-&gthdr.tag&nbsp;=&nbsp;ATAG_NONE;<br /><br />params-&gthdr.size&nbsp;=&nbsp;0;<br /><br />}&nbsp;void&nbsp;Uart_Init(int&nbsp;pclk,int&nbsp;baud)//串口是很重要的<br /><br />{<br /><br />int&nbsp;i;<br /><br />if(pclk&nbsp;==&nbsp;0)<br /><br />pclk&nbsp;=&nbsp;PCLK;<br /><br />rUFCON0&nbsp;=&nbsp;0x0;&nbsp;//UART&nbsp;channel&nbsp;0&nbsp;FIFO&nbsp;control&nbsp;register,&nbsp;FIFO&nbsp;disable<br /><br />rUMCON0&nbsp;=&nbsp;0x0;&nbsp;//UART&nbsp;chaneel&nbsp;0&nbsp;MODEM&nbsp;control&nbsp;register,&nbsp;AFC&nbsp;disable<br /><br /><br /><br />//UART0<br /><br />rULCON0&nbsp;=&nbsp;0x3;&nbsp;//Line&nbsp;control&nbsp;register&nbsp;:&nbsp;Normal,No&nbsp;parity,1&nbsp;stop,8&nbsp;bits<br /><br />下面这段samsung好象写的不太对,但是我按照Normal,No&nbsp;parity,1&nbsp;stop,8&nbsp;bits算出来的确是0x245<br /><br /><br /><br />//&nbsp;[10]&nbsp;[9]&nbsp;[8]&nbsp;[7]&nbsp;[6]&nbsp;[5]&nbsp;[4]&nbsp;[3:2]&nbsp;[1:0]<br /><br />//&nbsp;Clock&nbsp;Sel,&nbsp;Tx&nbsp;Int,&nbsp;Rx&nbsp;Int,&nbsp;Rx&nbsp;Time&nbsp;Out,&nbsp;Rx&nbsp;err,&nbsp;Loop-back,&nbsp;Send&nbsp;break,&nbsp;Transmit&nbsp;Mode,&nbsp;Receive&nbsp;Mode<br /><br />//&nbsp;0&nbsp;1&nbsp;0&nbsp;,&nbsp;0&nbsp;1&nbsp;0&nbsp;0&nbsp;,&nbsp;01&nbsp;01<br /><br />//&nbsp;PCLK&nbsp;Level&nbsp;Pulse&nbsp;Disable&nbsp;Generate&nbsp;Normal&nbsp;Normal&nbsp;Interrupt&nbsp;or&nbsp;Polling<br /><br />rUCON0&nbsp;=&nbsp;0x245;&nbsp;//&nbsp;Control&nbsp;register<br /><br />rUBRDIV0=(&nbsp;(int)(PCLK/16./&nbsp;baud)&nbsp;-1&nbsp;);&nbsp;//Baud&nbsp;rate&nbsp;divisior&nbsp;register&nbsp;0<br /><br />delay(10);<br /><br />}<br /><br />经过以上的折腾,接下来就是kernel的活了.能不能启动kernel,得看你编译kernel的水平了.<br /><br />这个BOOTLOADER不象blob那样需要交互信息,使用虚拟地址,总的来说非常简洁明了.<br />
postcode 发表于 2009-7-13 13:35 | 显示全部楼层

收藏了

  
armqt 发表于 2009-7-15 13:01 | 显示全部楼层

解说的很详细

  
pumpkin227 发表于 2010-11-2 17:58 | 显示全部楼层
虽然看不懂,但也收藏了,以备后用!
3B1105 发表于 2010-11-2 21:45 | 显示全部楼层
写的不错
思行合一 发表于 2010-11-3 21:46 | 显示全部楼层
bootloader  需要自己改动的地方多吗?还是一个地方都不需要改动!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

40

主题

179

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

40

主题

179

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部