查看完整版本: ArmLinux BOOTLOADER全程详解

wdefu 2007-3-10 10:04

ArmLinux BOOTLOADER全程详解

[size=3][color=#000000][font=Times New Roman]ArmLinux BOOTLOADER[/font][font=宋体]全程详解[/font][font=Times New Roman]    [/font][/color][/size]
[size=3][color=#000000][font=宋体]网上关于[/font][font=Times New Roman]Linux[/font][font=宋体]的[/font][font=Times New Roman]BOOTLOADER[/font][font=宋体]文章不少了[/font][font=Times New Roman],[/font][font=宋体]但是大都是[/font][font=Times New Roman]vivi,blob[/font][font=宋体]等比较庞大的程序[/font][font=Times New Roman],[/font][font=宋体]读起来不太方便[/font][font=Times New Roman],[/font][font=宋体]编译出的文件也比较大[/font][font=Times New Roman],[/font][font=宋体]而且更多的是面向开发用的引导代码[/font][font=Times New Roman],[/font][font=宋体]做成产品时还要裁减[/font][font=Times New Roman],[/font][font=宋体]这一定程度影响了开发速度[/font][font=Times New Roman],[/font][font=宋体]对初学者学习开销也比较大[/font][font=Times New Roman],[/font][font=宋体]在此分析一种简单的[/font][font=Times New Roman]BOOTLOADER,[/font][font=宋体]是在三星公司提供的[/font][font=Times New Roman]2410 BOOTLOADER[/font][font=宋体]上稍微修改后的结果[/font][font=Times New Roman],[/font][font=宋体]编译出来的文件大小不超过[/font][font=Times New Roman]4k,[/font][font=宋体]希望对大家有所帮助[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
1.[/font][font=宋体]几个重要的概念[/font][font=Times New Roman] [/font][/color][/size]
[font=Times New Roman][size=3][color=#000000]COMPRESSED KERNEL and DECOMPRESSED KERNEL
[/color][/size][/font][size=3][color=#000000][font=宋体]压缩后的[/font][font=Times New Roman]KERNEL,[/font][font=宋体]按照文档资料[/font][font=Times New Roman],[/font][font=宋体]现在不提倡使用[/font][font=Times New Roman]DECOMPRESSED KERNEL,[/font][font=宋体]而要使用[/font][font=Times New Roman]COMPRESSED KERNEL,[/font][font=宋体]它包括了解压器[/font][font=Times New Roman].[/font][font=宋体]因此要在[/font][font=Times New Roman]ram[/font][font=宋体]分配时给压缩和解压的[/font][font=Times New Roman]KERNEL[/font][font=宋体]提供足够空间[/font][font=Times New Roman],[/font][font=宋体]这样它们不会相互覆盖[/font][font=Times New Roman].[/font][font=宋体]当执行指令跳转到[/font][font=Times New Roman] COMPRESSED KERNEL[/font][font=宋体]后[/font][font=Times New Roman],[/font][font=宋体]解压器就开始工作[/font][font=Times New Roman],[/font][font=宋体]如果解压器探测到解压的代码会覆盖掉[/font][font=Times New Roman]COMPRESSED KERNEL,[/font][font=宋体]那它会直接跳到[/font][font=Times New Roman]COMPRESSED KERNEL[/font][font=宋体]后存放数据[/font][font=Times New Roman],[/font][font=宋体]并且重新定位[/font][font=Times New Roman]KERNEL,[/font][font=宋体]所以如果没有足够空间[/font][font=Times New Roman],[/font][font=宋体]就会出错[/font][/color][/size][size=3][color=#000000][font=Times New Roman].

Jffs2 File System
[/font][font=宋体]可以使[/font][font=Times New Roman]armlinux[/font][font=宋体]应用中产生的数据保存在[/font][font=Times New Roman]FLASH[/font][font=宋体]上[/font][font=Times New Roman],[/font][font=宋体]我的板子还没用到这个[/font][/color][/size][size=3][color=#000000][font=Times New Roman].

RAMDISK
[/font][font=宋体]使用[/font][font=Times New Roman]RAMDISK[/font][font=宋体]可以使[/font][font=Times New Roman]ROOT FILE SYSTEM[/font][font=宋体]在没有其他设备的情况下启动[/font][font=Times New Roman].[/font][font=宋体]一般有两种加载方式[/font][font=Times New Roman],[/font][font=宋体]我就介绍最常用的吧[/font][font=Times New Roman],[/font][font=宋体]把[/font][font=Times New Roman]COMPRESSED RAMDISK IMAGE[/font][font=宋体]放到指定地址[/font][font=Times New Roman],[/font][font=宋体]然后由[/font][font=Times New Roman]BOOTLOADER[/font][font=宋体]把这个地址通过启动参数的方式[/font][font=Times New Roman]ATAG_INITRD2[/font][font=宋体]传递给[/font][font=Times New Roman]KERNEL.[/font][font=宋体]具体看代码分析[/font][/color][/size][size=3][color=#000000][font=Times New Roman].

[/font][font=宋体]启动参数[/font][font=Times New Roman]([/font][font=宋体]摘自[/font][/color][/size][size=3][color=#000000][font=Times New Roman]IBM developer)
[/font][font=宋体]在调用内核之前,应该作一步准备工作,即:设置[/font][font=Times New Roman] Linux [/font][font=宋体]内核的启动参数。[/font][font=Times New Roman]Linux 2.4.x [/font][font=宋体]以后的内核都期望以标记列表[/font][font=Times New Roman](tagged list)[/font][font=宋体]的形式来传递启动参数。启动参数标记列表以标记[/font][font=Times New Roman] ATAG_CORE [/font][font=宋体]开始,以标记[/font][font=Times New Roman] ATAG_NONE [/font][font=宋体]结束。每个标记由标识被传递参数的[/font][font=Times New Roman] tag_header [/font][font=宋体]结构以及随后的参数值数据结构来组成。数据结构[/font][font=Times New Roman] tag [/font][font=宋体]和[/font][font=Times New Roman] tag_header [/font][font=宋体]定义在[/font][font=Times New Roman] Linux [/font][font=宋体]内核源码的[/font][font=Times New Roman]include/asm/setup.h [/font][font=宋体]头文件中[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
[/font][font=宋体]在嵌入式[/font][font=Times New Roman] Linux [/font][font=宋体]系统中,通常需要由[/font][font=Times New Roman] BOOTLOADER [/font][font=宋体]设置的常见启动参数有:[/font][font=Times New Roman]ATAG_CORE[/font][font=宋体]、[/font][font=Times New Roman]ATAG_MEM[/font][font=宋体]、[/font][font=Times New Roman]ATAG_CMDLINE[/font][font=宋体]、[/font][font=Times New Roman]ATAG_RAMDISK[/font][font=宋体]、[/font][font=Times New Roman]ATAG_INITRD[/font][font=宋体]等。[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
([/font][font=宋体]注[/font][font=Times New Roman])[/font][font=宋体]参数也可以用[/font][font=Times New Roman]COMMANDLINE[/font][font=宋体]来设定[/font][font=Times New Roman],[/font][font=宋体]在我的[/font][font=Times New Roman]BOOTLOADER[/font][font=宋体]里[/font][font=Times New Roman],[/font][font=宋体]我两种都用了[/font][/color][/size][size=3][color=#000000][font=Times New Roman].

2.[/font][font=宋体]开发环境和开发板配置[/font][/color][/size][size=3][color=#000000][font=Times New Roman]:
CPU:S3C2410,BANK6[/font][font=宋体]上有[/font][font=Times New Roman]64M[/font][font=宋体]的[/font][font=Times New Roman]SDRAM([/font][font=宋体]两块[/font][font=Times New Roman]),BANK0[/font][font=宋体]上有[/font][font=Times New Roman]32M NOR FLASH,[/font][font=宋体]串口当然是逃不掉的[/font][font=Times New Roman].[/font][font=宋体]这样[/font][font=Times New Roman],[/font][font=宋体]按照数据手册[/font][font=Times New Roman],[/font][font=宋体]地址分配如下[/font][/color][/size][size=3][color=#000000][font=Times New Roman]:
0x4000_0000[/font][font=宋体]开始是[/font][font=Times New Roman]4k[/font][font=宋体]的片内[/font][/color][/size][size=3][color=#000000][font=Times New Roman]DRAM.
0x0000_0000[/font][font=宋体]开始是[/font][font=Times New Roman]32M FLASH 16bit[/font][font=宋体]宽度[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
0x3000_0000[/font][font=宋体]开始是[/font][font=Times New Roman]64M SDRAM 32bit[/font][font=宋体]宽度[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
[/font][font=宋体]注意[/font][font=Times New Roman]:[/font][font=宋体]控制寄存器中的[/font][font=Times New Roman]BANK6[/font][font=宋体]和[/font][font=Times New Roman]BANK7[/font][font=宋体]部分必须相同[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
0x4000_0000([/font][font=宋体]片内[/font][font=Times New Roman]DRAM)[/font][font=宋体]存放[/font][font=Times New Roman]4k[/font][font=宋体]以内的[/font][/color][/size][size=3][color=#000000][font=Times New Roman]BOOTLOADER IMAGE
0x3000_0100[/font][font=宋体]开始存放启动参数[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
0x3120_0000 [/font][font=宋体]存放[/font][/color][/size][size=3][color=#000000][font=Times New Roman]COMPRESSED KERNEL IMAGE
0x3200_0000 [/font][font=宋体]存放[/font][/color][/size][size=3][color=#000000][font=Times New Roman]COMPRESSED RAMDISK
0x3000_8000 [/font][font=宋体]指定为[/font][/color][/size][size=3][color=#000000][font=Times New Roman]DECOMPRESSED KERNEL IMAGE ADDRESS
0x3040_0000 [/font][font=宋体]指定为[/font][/color][/size][size=3][color=#000000][font=Times New Roman]DECOMPRESSED RAMDISK IMAGE ADDRESS
[/font][font=宋体]开发环境[/font][/color][/size][size=3][color=#000000][font=Times New Roman]:Redhat Linux,armgcc toolchain, armlinux KERNEL
[/font][font=宋体]如何建立[/font][font=Times New Roman]armgcc[/font][font=宋体]的编译环境[/font][font=Times New Roman]:[/font][font=宋体]建议使用[/font][font=Times New Roman]toolchain,[/font][font=宋体]而不要自己去编译[/font][font=Times New Roman]armgcc,[/font][font=宋体]偶试过好多次[/font][font=Times New Roman],[/font][font=宋体]都以失败告终[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
[/font][font=宋体]先下载[/font][/color][/size][size=3][color=#000000][font=Times New Roman]arm-gcc 3.3.2 toolchain
[/font][font=宋体]将[/font][font=Times New Roman]arm-linux-gcc-3.3.2.tar.bz2 [/font][font=宋体]解压到[/font][/color][/size][size=3][color=#000000][font=Times New Roman] /toolchain
# tar jxvf arm-linux-gcc-3.3.2.tar.bz2
# mv /usr/local/arm/3.3.2 /toolchain
[/font][font=宋体]在[/font][font=Times New Roman]makefile [/font][font=宋体]中在把[/font][font=Times New Roman]arch=arm CROSS_COMPILE[/font][font=宋体]设置成[/font][font=Times New Roman]toolchain[/font][font=宋体]的路径还有就是[/font][font=Times New Roman]INCLUDE = -I ../include -I /root/my/usr/local/arm/3.3.2/include.,[/font][font=宋体]否则库函数就不能用了[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
3.[/font][font=宋体]启动方式[/font][/color][/size][size=3][color=#000000][font=Times New Roman]:
[/font][font=宋体]可以放在[/font][font=Times New Roman]FLASH[/font][font=宋体]里启动[/font][font=Times New Roman],[/font][font=宋体]或者用[/font][font=Times New Roman]Jtag[/font][font=宋体]仿真器[/font][font=Times New Roman].[/font][font=宋体]由于使用[/font][font=Times New Roman]NOR FLASH,[/font][font=宋体]根据[/font][font=Times New Roman]2410[/font][font=宋体]的手册[/font][font=Times New Roman],[/font][font=宋体]片内的[/font][font=Times New Roman]4K DRAM[/font][font=宋体]在不需要设置便可以直接使用[/font][font=Times New Roman],[/font][font=宋体]而其他存储器必须先初始化[/font][font=Times New Roman],[/font][font=宋体]比如告诉[/font][font=Times New Roman]memory controller,BANK6[/font][font=宋体]里有两块[/font][font=Times New Roman]SDRAM,[/font][font=宋体]数据宽度是[/font][font=Times New Roman]32bit,= =.[/font][font=宋体]否则[/font][font=Times New Roman]memory control[/font][font=宋体]会按照复位后的默认值来处理存储器[/font][font=Times New Roman].[/font][font=宋体]这样读写就会产生错误[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
[/font][font=宋体]所以第一步[/font][font=Times New Roman],[/font][font=宋体]通过仿真器把执行代码放到[/font][font=Times New Roman]0x4000_0000,([/font][font=宋体]在编译的时候[/font][font=Times New Roman],[/font][font=宋体]设定[/font][/color][/size][size=3][color=#000000][font=Times New Roman]TEXT_BASE=0x40000000)
[/font][font=宋体]第二步[/font][font=Times New Roman],[/font][font=宋体]通过[/font][font=Times New Roman] AxD[/font][font=宋体]把[/font][font=Times New Roman]linux KERNEL IMAGE[/font][font=宋体]放到目标地址[/font][font=Times New Roman](SDRAM)[/font][font=宋体]中[/font][font=Times New Roman],[/font][font=宋体]等待调用[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
[/font][font=宋体]第三步[/font][font=Times New Roman],[/font][font=宋体]执行[/font][font=Times New Roman]BOOTLOADER[/font][font=宋体]代码[/font][font=Times New Roman],[/font][font=宋体]从串口得到调试数据[/font][font=Times New Roman],[/font][font=宋体]引导[/font][/color][/size][size=3][color=#000000][font=Times New Roman]armlinux

4.[/font][font=宋体]代码分析[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
[/font][font=宋体]讲了那么多执行的步骤[/font][font=Times New Roman],[/font][font=宋体]是想让大家对启动有个大概印象[/font][font=Times New Roman],[/font][font=宋体]接着就是[/font][font=Times New Roman]BOOTLOADER[/font][font=宋体]内部的代码分析了[/font][font=Times New Roman],BOOTLOADER[/font][font=宋体]文章内容网上很多[/font][font=Times New Roman],[/font][font=宋体]我这里精简了下[/font][font=Times New Roman],[/font][font=宋体]删除了不必要的功能[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
BOOTLOADER[/font][font=宋体]一般分为[/font][font=Times New Roman]2[/font][font=宋体]部分[/font][font=Times New Roman],[/font][font=宋体]汇编部分和[/font][font=Times New Roman]c[/font][font=宋体]语言部分[/font][font=Times New Roman],[/font][font=宋体]汇编部分执行简单的硬件初始化[/font][font=Times New Roman],C[/font][font=宋体]部分负责复制数据[/font][font=Times New Roman],[/font][font=宋体]设置启动参数[/font][font=Times New Roman],[/font][font=宋体]串口通信等功能[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
BOOTLOADER[/font][font=宋体]的生命周期[/font][/color][/size][size=3][color=#000000][font=Times New Roman]:
1. [/font][font=宋体]初始化硬件[/font][font=Times New Roman],[/font][font=宋体]比如设置[/font][font=Times New Roman]UART([/font][font=宋体]至少设置一个[/font][font=Times New Roman]),[/font][font=宋体]检测存储器[/font][/color][/size][size=3][color=#000000][font=Times New Roman]= =.
2. [/font][font=宋体]设置启动参数[/font][font=Times New Roman],[/font][font=宋体]这是为了告诉内核硬件的信息[/font][font=Times New Roman],[/font][font=宋体]比如用哪个启动界面[/font][font=Times New Roman],[/font][font=宋体]波特率[/font][/color][/size][size=3][color=#000000][font=Times New Roman] = =.
3. [/font][font=宋体]跳转到[/font][font=Times New Roman]Linux KERNEL[/font][font=宋体]的首地址[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
4. [/font][font=宋体]消亡[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
[/font][font=宋体]当然[/font][font=Times New Roman],[/font][font=宋体]在引导阶段[/font][font=Times New Roman],[/font][font=宋体]象[/font][font=Times New Roman]vivi[/font][font=宋体]等[/font][font=Times New Roman],[/font][font=宋体]都用虚地址[/font][font=Times New Roman],[/font][font=宋体]如果你嫌烦的话[/font][font=Times New Roman],[/font][font=宋体]就用实地址[/font][font=Times New Roman],[/font][font=宋体]都一样[/font][/color][/size][size=3][color=#000000][font=Times New Roman].
[/font][font=宋体]我们来看代码[/font][/color][/size][size=3][color=#000000][font=Times New Roman]:
2410init.s
.global _start//[/font][font=宋体]开始执行处[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
_start:
//[/font][font=宋体]下面是中断向量[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
b reset @ Supervisor Mode//[/font][font=宋体]重新启动后的跳转[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
??
??
reset:
ldr r0,=WTCON /WTCON[/font][font=宋体]地址为[/font][font=Times New Roman]53000000,watchdog[/font][font=宋体]的控制寄存器[/font][/color][/size][size=3][color=#000000][font=Times New Roman] */
ldr r1,=0x0 /*[/font][font=宋体]关[/font][/color][/size][size=3][color=#000000][font=Times New Roman]watchdog*/
str r1,[r0]
ldr r0,=INTMSK
ldr r1,=0xffffffff /*[/font][font=宋体]屏蔽所有中断[/font][/color][/size][size=3][color=#000000][font=Times New Roman]*/
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x3ff /*[/font][font=宋体]子中断也一样[/font][/color][/size][size=3][color=#000000][font=Times New Roman]*/
str r1,[r0]
/*Initialize Ports...for display LED.*/
ldr r0, =GPFCON
ldr r1, =0x55aa
str r1, [r0]
ldr r0, =GPFUP
ldr r1, =0xff
str r1, [r0]
ldr r0,=GPFDAT
ldr r1,=POWEROFFLED1
str r1,[r0]
/* Setup clock Divider control register
* you must configure CLKDIVN before LOCKTIME or MPLL UPLL
* because default CLKDIVN 1,1,1 set the SDMRAM Timing Conflictnop
* FCLK:HCLK:PCLK = 1:2:4 in this case
*/
ldr r0,=CLKDIVN
ldr r1,=0x3
str r1,[r0]
/*To reduce PLL lock time, adjust the LOCKTIME register. */
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]
/*Configure MPLL */
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) //Fin=12MHz,Fout=203MHz
str r1,[r0]
ldr r1,=GSTATUS2
ldr r10,[r1]
tst r10,#OFFRST
bne 1000f
//[/font][font=宋体]以上这段[/font][font=Times New Roman],[/font][font=宋体]我没动[/font][font=Times New Roman],[/font][font=宋体]就用三星写的了[/font][font=Times New Roman],[/font][font=宋体]下面是主要要改的地方[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
/* MEMORY C0NTROLLER(MC)[/font][font=宋体]设置[/font][/color][/size][size=3][color=#000000][font=Times New Roman]*/
add r0,pc,#MCDATA - (.+8)// r0[/font][font=宋体]指向[/font][font=Times New Roman]MCDATA[/font][font=宋体]地址[/font][font=Times New Roman],[/font][font=宋体]那里存放着[/font][font=Times New Roman]MC[/font][font=宋体]初始化要用到的数据[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
ldr r1,=BWSCON // r1[/font][font=宋体]指向[/font][font=Times New Roman]MC[/font][font=宋体]控制器寄存器的首地址[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
add r2,r0,#52 // [/font][font=宋体]复制次数[/font][font=Times New Roman],[/font][font=宋体]偏移[/font][font=Times New Roman]52[/font][font=宋体]字[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
1: //[/font][font=宋体]按照偏移量进行循环复制[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
ldr r3,[r0],#4
str r3,[r1],#4
cmp r2,r0
bne 1b
.align 2
MCDATA:
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
[/font][font=宋体]上面这行就是[/font][font=Times New Roman]BWSCON[/font][font=宋体]的数据[/font][font=Times New Roman],[/font][font=宋体]具体参数意义如下[/font][/color][/size][size=3][color=#000000][font=Times New Roman]:
[/font][font=宋体]需要更改设置[/font][font=Times New Roman]DW6 [/font][font=宋体]和[/font][font=Times New Roman]DW7[/font][font=宋体]都设置成[/font][font=Times New Roman]10,[/font][font=宋体]即[/font][font=Times New Roman]32bit,DW0 [/font][font=宋体]设置成[/font][font=Times New Roman]01,[/font][font=宋体]即[/font][/color][/size][size=3][color=#000000][font=Times New Roman]16bit
[/font][font=宋体]下面都是每个[/font][font=Times New Roman]BANK[/font][font=宋体]的控制器数据[/font][font=Times New Roman],[/font][font=宋体]大都是时钟相关[/font][font=Times New Roman],[/font][font=宋体]可以用默认值[/font][font=Times New Roman],[/font][font=宋体]设置完[/font][font=Times New Roman]MC[/font][font=宋体]后[/font][font=Times New Roman],[/font][font=宋体]就跳到调用[/font][font=Times New Roman]main[/font][font=宋体]函数的部分[/font][font=Times New Roman] [/font][/color][/size]

[font=Times New Roman][size=3][color=#000000].word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0xB2 /* REFRESH Control Register */
.word 0x30 /* BANKSIZE Register : Burst Mode */
.word 0x30 /* SDRAM Mode Register */
.align 2
.global call_main //[/color][/size][/font][size=3][color=#000000][font=宋体]调用[/font][font=Times New Roman]main[/font][font=宋体]函数[/font][font=Times New Roman],[/font][font=宋体]函数参数都为[/font][/color][/size][font=Times New Roman][size=3][color=#000000]0
call_main:
ldr sp,STACK_START
mov fp,#0 /* no previous frame, so fp=0*/
mov a1, #0 /* set argc to 0*/
mov a2, #0 /* set argv to NUL*/
bl main /* call main*/
STACK_START:
.word STACK_BASE
undefined_instruction:
software_interrupt:
prefetch_abort:
data_abort:
not_used:
irq:
fiq: [/color][/size][/font]

[font=Times New Roman][size=3][color=#000000]/*[/color][/size][/font][size=3][color=#000000][font=宋体]以上是主要的汇编部分[/font][font=Times New Roman],[/font][font=宋体]实现了时钟设置[/font][font=Times New Roman],[/font][font=宋体]串口设置[/font][font=Times New Roman]watchdog[/font][font=宋体]关闭[/font][font=Times New Roman],[/font][font=宋体]中断关闭功能[/font][font=Times New Roman]([/font][font=宋体]如果有需要还可以降频使用[/font][font=Times New Roman]),[/font][font=宋体]然后转入[/font][font=Times New Roman]main*/ [/font][/color][/size]

[font=Times New Roman][size=3][color=#000000]2410init.c file
int main(int argc,char **argv)
{
u32 test = 0;
void (*theKERNEL)(int zero, int arch, unsigned long params_addr) = (void (*)(int, int, unsigned long))RAM_COMPRESSED_KERNEL
_BASE; //[/color][/size][/font][size=3][color=#000000][font=宋体]压缩后的[/font][font=Times New Roman]IMAGE[/font][font=宋体]地址[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
int i,k=0;
// downPt=(RAM_COMPRESSED_KERNEL_BASE);
chkBs=(_RAM_STARTADDRESS);//SDRAM[/font][font=宋体]开始的地方[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
// fromPt=(FLASH_LINUXKERNEL);
MMU_EnableICache();
ChangeClockDivider(1,1); // 1:2:4
ChangeMPllValue(M_MDIV,M_PDIV,M_SDIV); //Fin=12MHz FCLK=200MHz
Port_Init();//[/font][font=宋体]设置[/font][font=Times New Roman]I/O[/font][font=宋体]端口[/font][font=Times New Roman],[/font][font=宋体]在使用[/font][font=Times New Roman]com[/font][font=宋体]口前[/font][font=Times New Roman],[/font][font=宋体]必须调用这个函数[/font][font=Times New Roman],[/font][font=宋体]否则通信芯片根本得不到数据[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
Uart_Init(PCLK, 115200);//PCLK[/font][font=宋体]使用默认的[/font][font=Times New Roman]200000,[/font][font=宋体]拨特率[/font][/color][/size][size=3][color=#000000][font=Times New Roman]115200
/*******************([/font][font=宋体]检查[/font][font=Times New Roman]ram[/font][font=宋体]空间[/font][/color][/size][font=Times New Roman][size=3][color=#000000])*******************/
Uart_SendString("ntLinux S3C2410 Nor BOOTLOADERn");
Uart_SendString("ntChecking SDRAM 2410loader.c...n");
for(;chkBs<0x33FA0140;chkBs=chkBs+0x4,test++)// [/color][/size][/font]

[font=Times New Roman][size=3][color=#000000]//[/color][/size][/font][size=3][color=#000000][font=宋体]根据我的经验[/font][font=Times New Roman],[/font][font=宋体]最好以一个字节为递增[/font][font=Times New Roman],[/font][font=宋体]我们的板子[/font][font=Times New Roman],[/font][font=宋体]在[/font][font=Times New Roman]256byte[/font][font=宋体]递增检测的时候是没问题的[/font][font=Times New Roman],[/font][font=宋体]但是[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
//[/font][font=宋体]以[/font][font=Times New Roman]1byte[/font][font=宋体]递增就出错了[/font][font=Times New Roman],[/font][font=宋体]第[/font][font=Times New Roman]13[/font][font=宋体]跟数据线随几的会冒[/font][font=Times New Roman]”1”,[/font][font=宋体]检测出来是硬件问题[/font][font=Times New Roman],[/font][font=宋体]现象如下[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
//[/font][font=宋体]用仿真器下代码测试[/font][font=Times New Roman]SDRAM[/font][font=宋体],开始没贴[/font][font=Times New Roman]28F128A3J FLASH[/font][font=宋体]片子,测试结果很好,但在上了[/font][font=Times New Roman]FLASH[/font][font=宋体]片子[/font][font=Times New Roman]//[/font][font=宋体]之后,测试数据([/font][font=Times New Roman]data[/font][font=宋体])为[/font][/color][/size][size=3][color=#000000][font=Times New Roman]0x00000400
[/font][font=宋体]连续成批写入读出时,操作大约[/font][font=Times New Roman]1k[/font][font=宋体]左右内存空间就会出错,[/font][font=Times New Roman]//[/font][font=宋体]而且随机。那个出错数据总是变为[/font][font=Times New Roman]0x00002400[/font][font=宋体],数据总线[/font][font=Times New Roman]10[/font][font=宋体]位和[/font][font=Times New Roman]13[/font][font=宋体]位又没短路[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
[/font][font=宋体]发生。用其他数据[/font][font=Times New Roman]//[/font][font=宋体]测试比如[/font][font=Times New Roman]0x00000200[/font][font=宋体];[/font][font=Times New Roman]0x00000800[/font][font=宋体]没这问题。[/font][font=Times New Roman]dx[/font][font=宋体]帮忙。[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
//[/font][font=宋体]至今没有解决[/font][font=Times New Roman],[/font][font=宋体]所以我用不了[/font][/color][/size][size=3][color=#000000][font=Times New Roman]Flash.
{
chkPt1 = chkBs;
*(u32 *)chkPt1 = test;//[/font][font=宋体]写数据[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
if(*(u32 *)chkPt1==1024))//[/font][font=宋体]读数据和写入的是否一样[/font][/color][/size][size=3][color=#000000][font=Times New Roman]?
{
chkPt1 += 4;
Led_Display(1);
Led_Display(2);
Led_Display(3);
Led_Display(4);
}
else
goto error;
}
Uart_SendString("ntSDRAM Check Successful!ntMemory Maping...");
get_memory_map();
//[/font][font=宋体]获得可用[/font][font=Times New Roman]memory [/font][font=宋体]信息[/font][font=Times New Roman],[/font][font=宋体]做成列表[/font][font=Times New Roman],[/font][font=宋体]后面会作为启动参数传给[/font][/color][/size][size=3][color=#000000][font=Times New Roman]KERNEL
//[/font][font=宋体]所谓内存映射就是指在[/font][font=Times New Roman]4GB [/font][font=宋体]物理地址空间中有哪些地址范围被分配用来寻址系统的[/font][font=Times New Roman] RAM [/font][font=宋体]单元。[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
Uart_SendString("ntMemory Map Successful!n");
//[/font][font=宋体]我用仿真器把[/font][font=Times New Roman]KERNEL,RAMDISK[/font][font=宋体]直接放在[/font][font=Times New Roman]SDRAM[/font][font=宋体]上[/font][font=Times New Roman],[/font][font=宋体]所以下面这段是不需要的[/font][font=Times New Roman],[/font][font=宋体]但是如果[/font][font=Times New Roman]KERNEL,RAMDISK[/font][font=宋体]在[/font][font=Times New Roman]FLASH[/font][font=宋体]里[/font][font=Times New Roman],[/font][font=宋体]那就需要[/font][font=Times New Roman]. [/font][/color][/size]

[font=Times New Roman][size=3][color=#000000]/*******************(copy linux KERNEL)*******************/
Uart_SendString("tLoading KERNEL IMAGE from FLASH... n ");
Uart_SendString("tand copy KERNEL IMAGE to SDRAM at 0x31000000n");
Uart_SendString("ttby LEIJUN DONG dongleijun4000@hotmail.com n");
for(k = 0;k < 196608;k++,downPt += 1,fromPt += 1)//3*1024*1024/32linux KERNEL des,src,length=3M
* (u32 *)downPt = * (u32 *)fromPt;
/*******************(load RAMDISK)*******************/
Uart_SendString("ttloading COMPRESSED RAMDISK...n");
downPt=(RAM_COMPRESSED_RAMDISK_BASE);
fromPt=(FLASH_RAMDISK_BASE);
for(k = 0;k < 196608;k++,downPt += 1,fromPt += 1)//3*1024*1024/32linux KERNEL des,src,length=3M
* (u32 *)downPt = * (u32 *)fromPt;
/******jffs2[/color][/size][/font][size=3][color=#000000][font=宋体]文件系统[/font][font=Times New Roman],[/font][font=宋体]在开发中如果用不到[/font][font=Times New Roman]FLASH,[/font][font=宋体]这段也可以不要[/font][/color][/size][size=3][color=#000000][font=Times New Roman]********/
Uart_SendString("ttloading jffs2...n");
downPt=(RAM_JFFS2);
fromPt=(FLASH_JFFS2);
for(k = 0;k < (1024*1024/32);k++,downPt += 1,fromPt += 1)
* (u32 *)downPt = * (u32 *)fromPt;
Uart_SendString( "Load Success...Run...n ");
/*******************(setup param)*******************/
setup_start_tag();//[/font][font=宋体]开始设置启动参数[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
setup_memory_tags();//[/font][font=宋体]内存印象[/font][font=Times New Roman] [/font][/color][/size]
[font=Times New Roman][size=3][color=#000000]setup_commandline_tag("console=ttyS0,115200n8");//[/color][/size][/font][font=宋体][size=3][color=#000000]启动命令行[/color][/size][/font][size=3][color=#000000][font=Times New Roman]
setup_initrd2_tag();//root device
setup_RAMDISK_tag();//ramdisk image
setup_end_tag();
/*[/font][font=宋体]关[/font][/color][/size][font=Times New Roman][size=3][color=#000000]I-cache */
asm ("mrc p15, 0, %0, c1, c0, 0": "=r" (i));
i &= ~0x1000;
asm ("mcr p15, 0, %0, c1, c0, 0": : "r" (i));
/* flush I-cache */
asm ("mcr p15, 0, %0, c7, c5, 0": : "r" (i)); [/color][/size][/font]

[font=Times New Roman][size=3][color=#000000]//[/color][/size][/font][size=3][color=#000000][font=宋体]下面这行就跳到了[/font][font=Times New Roman]COMPRESSED KERNEL[/font][font=宋体]的首地址[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
theKERNEL(0, ARCH_NUMBER, (unsigned long *)(RAM_BOOT_PARAMS));
//[/font][font=宋体]启动[/font][font=Times New Roman]kernel[/font][font=宋体]时候[/font][font=Times New Roman],I-cache[/font][font=宋体]可以开也可以关[/font][font=Times New Roman],r0[/font][font=宋体]必须是[/font][font=Times New Roman]0,r1[/font][font=宋体]必须是[/font][font=Times New Roman]CPU[/font][font=宋体]型号[/font][/color][/size][size=3][color=#000000][font=Times New Roman]
([/font][font=宋体]可以从[/font][font=Times New Roman]linux/arch/arm/tools/mach-types[/font][font=宋体]中找到[/font][font=Times New Roman]),r2[/font][font=宋体]必须是参数的物理开始地址[/font][font=Times New Roman] [/font][/color][/size]

[font=Times New Roman][size=3][color=#000000]/*******************END*******************/
error:
Uart_SendString("nnPanic SDRAM check error!n");
return 0;
}
static void setup_start_tag(void)
{
params = (struct tag *)RAM_BOOT_PARAMS;//[/color][/size][/font][font=宋体][size=3][color=#000000]启动参数开始的地址[/color][/size][/font][size=3][color=#000000][font=Times New Roman]
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);
}
static void setup_memory_tags(void)
{
int i;
for(i = 0; i < NUM_MEM_AREAS; i++) {
if(memory_map[i].used) {
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size(tag_mem32);
params->u.mem.start = memory_map[i].start;
params->u.mem.size = memory_map[i].len;
params = tag_next(params);
}
}
}
static void setup_commandline_tag(char *commandline)
{
int i = 0;
/* skip non-existent command lines so the kernel will still
* use its default command line.
*/
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size = 8;
//console=ttyS0,115200n8
strcpy(params->u.cmdline.cmdline, p);
params = tag_next(params);
}
static void setup_initrd2_tag(void)
{
/* an ATAG_INITRD node tells the kernel where the compressed
* ramdisk can be found. ATAG_RDIMG is a better name, actually.
*/
params->hdr.tag = ATAG_INITRD2;
params->hdr.size = tag_size(tag_initrd);
params->u.initrd.start = RAM_COMPRESSED_RAMDISK_BASE;
params->u.initrd.size = 2047;//k byte
params = tag_next(params);
}
static void setup_ramdisk_tag(void)
{
/* an ATAG_RAMDISK node tells the kernel how large the
* decompressed ramdisk will become.
*/
params->hdr.tag = ATAG_RAMDISK;
params->hdr.size = tag_size(tag_ramdisk);
params->u.ramdisk.start = RAM_DECOMPRESSED_RAMDISK_BASE;
params->u.ramdisk.size = 7.8*1024; //k byte
params->u.ramdisk.flags = 1; // automatically load ramdisk
params = tag_next(params);
}
static void setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
} void Uart_Init(int pclk,int baud)//[/font][font=宋体]串口是很重要的[/font][/color][/size][font=Times New Roman][size=3][color=#000000]
{
int i;
if(pclk == 0)
pclk = PCLK;
rUFCON0 = 0x0; //UART channel 0 FIFO control register, FIFO d[/color][/size][/font][url=http://www.dz863.com/interface-circuits/ISA.htm][font=Times New Roman][size=3][color=#000000]ISA[/color][/size][/font][/url][font=Times New Roman][size=3][color=#000000]ble
rUMCON0 = 0x0; //UART chaneel 0 MODEM control register, AFC d[/color][/size][/font][url=http://www.dz863.com/interface-circuits/ISA.htm][font=Times New Roman][size=3][color=#000000]ISA[/color][/size][/font][/url][font=Times New Roman][size=3][color=#000000]ble
//UART0
rULCON0 = 0x3; //Line control register : Normal,No parity,1 stop,8 bits
[/color][/size][/font][size=3][color=#000000][font=宋体]下面这段[/font][font=Times New Roman]samsung[/font][font=宋体]好象写的不太对[/font][font=Times New Roman],[/font][font=宋体]但是我按照[/font][font=Times New Roman]Normal,No parity,1 stop,8 bits[/font][font=宋体]算出来的确是[/font][/color][/size][font=Times New Roman][size=3][color=#000000]0x245
// [10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
// Clock Sel, Tx Int, Rx Int, Rx Time Out, Rx err, Loop-back, Send break, Transmit Mode, Receive Mode
// 0 1 0 , 0 1 0 0 , 01 01
// PCLK Level Pulse D[/color][/size][/font][url=http://www.dz863.com/interface-circuits/ISA.htm][font=Times New Roman][size=3][color=#000000]ISA[/color][/size][/font][/url][font=Times New Roman][size=3][color=#000000]ble Generate Normal Normal Interrupt or Polling
rUCON0 = 0x245; // Control register
rUBRDIV0=( (int)(PCLK/16./ baud) -1 ); //Baud rate divisior register 0
delay(10);
} [/color][/size][/font]
页: [1]
查看完整版本: ArmLinux BOOTLOADER全程详解