arm 嵌入式LINUX启动过程(1)
时间:11-09
来源:互联网
点击:
一位大师级的人物写的,不看要后悔的哟!!
LINUX启动过程
首先,portinglinux的时候要规划内存影像,如小弟的系统有64mSDRAM,
地址从0x08000000-0x0bffffff,32mflash,地址从0x0c000000-0x0dffffff.
规划如下:bootloader,linuxkernel,rootdisk放在flash里。
具体从0x0c000000开始的第一个1M放bootloader,
0x0c100000开始的2m放linuxkernel,从0x0c300000开始都给rootdisk。
启动:
首先,启动后arm920T将地址0x0c000000映射到0(可通过跳线设置),
实际上从0x0c000000启动,进入我们的bootloader,但由于flash速度慢,
所以bootloader前面有一小段程序把bootloader拷贝到SDRAM中的0x0AFE0100,
再从0x08000000运行bootloader,我们叫这段小程序为flashloader,
flashloader必须要首先初始化SDRAM,不然往那放那些东东:
.equSOURCE,0x0C000100bootloader的存放地址
.equTARGET,0x0AFE0100目标地址
.equSDCTL0,0x221000SDRAM控制器寄存器
//sizeisstoredinlocation0x0C0000FC
.global_start
_start://入口点
//;*
//;*InitSDRAM
//;*
//*
//*SDRAM
//*
LDRr1,=SDCTL0//
//SetPrechargeCommand
LDRr3,=0x92120200
//ldrr3,=0x92120251
STRr3,[r1]
//IssuePrechargeAllCommad
LDRr3,=0x8200000
LDRr2,[r3]
//SetAutoRefreshCommand
LDRr3,=0xA2120200
STRr3,[r1]
//IssueAutoRefreshCommand
LDRr3,=0x8000000
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
//SetModeRegister
LDRr3,=0xB2120200
STRr3,[r1]
//IssueModeRegisterCommand
LDRr3,=0x08111800//;ModeRegistervalue
LDRr2,[r3]
//SetNormalMode
LDRr3,=0x82124200
STRr3,[r1]
//;*
//;*EndofSDRAMandSyncFlashInit*
//;*
//copycodefromFLASHtoSRAM
_CopyCodes:
ldrr0,=SOURCE
ldrr1,=TARGET
subr3,r0,#4
ldrr2,[r3]
_CopyLoop:
ldrr3,[r0]
strr3,[r1]
addr0,r0,#4
addr1,r1,#4
subr2,r2,#4
teqr2,#0
beq_EndCopy
b_CopyLoop
_EndCopy:
ldrr0,=TARGET
movpc,r0
上回书说到flashloader把bootloaderload到0x0AFE0100,然回跳了过去,
其实0x0AFE0100就是烧在flash0x0C000100中的真正的bootloader:
bootloader有几个文件组成,先是START.s,也是唯一的一个汇编程序,其余的都是C写成的,START.s主要初始化堆栈:
_start:
ldrr1,=StackInit
ldrsp,[r1]
bmain
//此处我们跳到了C代码的main函数,当C代码执行完后,还要调用
//下面的JumpToKernel0x跳到LINXUkernel运行
.equStackInitvalue,__end_data+0x1000//4K__end_data在连结脚本中指定
StackInit:
.longStackInitvalue
.globalJumpToKernel
JumpToKernel:
//jumptothecopycode(gettheargumentsright)
movpc,r0
.globalJumpToKernel0x
//r0=jumpaddress
//r1-r4=argumentstouse(thesegetshifted)
JumpToKernel0x:
//jumptothecopycode(gettheargumentsright)
movr8,r0
movr0,r1
movr1,r2
movr2,r3
movr3,r4
movpc,r8
.section".data.boot"
.section".bss.boot"
下面让我们看看bootloader的c代码干了些什么。main函数比较长,让我们分段慢慢看。
intmain()
{
U32*pSource,*pDestin,count;
U8countDown,bootOption;
U32delayCount;
U32fileSize,i;
charc;
char*pCmdLine;
char*pMem;
init();//初始化FLASH控制器和CPU时钟
EUARTinit();//串口初始化
EUARTputString("/n/nDBMX1LinuxBootloaderver0.2.0/n");
EUARTputString("Copyright(C)2002MotorolaLtd./n/n");
EUARTputString((U8*)cmdLine);
EUARTputString("/n/n");
EUARTputString("Pressanykeyforalternateboot-upoptions...");
小弟的bootloader主要干这么几件事:init();初始化硬件,打印一些信息和提供一些操作选项:
0.Programbootloaderimage
1.Programkernelimage
2.Programroot-diskimage
3.DownloadkernelandbootfromRAM
4.Downloadkernelandbootwithver0.1.xbootloaderformat
5.Bootaver0.1.xkernel
6.Bootwithadifferentcommandline
也就是说,可以在bootloader里选择重新下载kernel,rootdisk并写入flash,
下载的方法是用usb连接,10m的rootdisk也就刷的一下。关于usb下载的讨论请参看先前的贴子“为arm开发平台增加usb下载接口“。
如果不选,直接回车,就开始把整个linux的内核拷贝到SDRAM中运行。
列位看官,可能有人要问,在flashloader中不是已经初始化过sdram控制器了吗?怎么init();中还要初始化呢,各位有所不知,小弟用的是syncflash,
可以直接使用sdram控制器的接口,切记:在flash中运行的代码是不能初始化连接flash的sdram控制器的,不然绝对死掉了。所以,当程序在flash中运行的时候,去初始化sdram,而现在在sdram中运行,可放心大胆地初始化flash了,主要是设定字宽,行列延时,因为缺省都是最大的。
另外,如果列位看官的cpu有足够的片内ram,完全可以先把bootloader放在片内ram,干完一切后再跳到LINUX,小弟着也是不得已而为之啊。
如果直接输入回车,进入kernel拷贝工作:
EUARTputString("CopyingkernelfromFlashtoRAM.../n");
count=0x200000;//2Mbytes
pSource=(U32*)0x0C100000;
pDestin=(U32*)0x08008000;
do
{
*(pDestin++)=*(pSource++);
count-=4;
}while(count>0);
}
EUARTputString("Bootingkernel.../n/n");
这一段没有什么可说的,运行完后kernel就在0x08008000了,至于为什么要
空出0x8000的一段,主要是放kelnel的一些全局数据结构,如内核页表,arm的页目录要有16k大。
我们知道,linux内核启动的时候可以传入参数,如在PC上,如果使用LILO,
当出现LILO:,我们可以输入root=/dev/hda1.或mem=128M等指定文件系统的设备或内存大小,在
LINUX启动过程
首先,portinglinux的时候要规划内存影像,如小弟的系统有64mSDRAM,
地址从0x08000000-0x0bffffff,32mflash,地址从0x0c000000-0x0dffffff.
规划如下:bootloader,linuxkernel,rootdisk放在flash里。
具体从0x0c000000开始的第一个1M放bootloader,
0x0c100000开始的2m放linuxkernel,从0x0c300000开始都给rootdisk。
启动:
首先,启动后arm920T将地址0x0c000000映射到0(可通过跳线设置),
实际上从0x0c000000启动,进入我们的bootloader,但由于flash速度慢,
所以bootloader前面有一小段程序把bootloader拷贝到SDRAM中的0x0AFE0100,
再从0x08000000运行bootloader,我们叫这段小程序为flashloader,
flashloader必须要首先初始化SDRAM,不然往那放那些东东:
.equSOURCE,0x0C000100bootloader的存放地址
.equTARGET,0x0AFE0100目标地址
.equSDCTL0,0x221000SDRAM控制器寄存器
//sizeisstoredinlocation0x0C0000FC
.global_start
_start://入口点
//;*
//;*InitSDRAM
//;*
//*
//*SDRAM
//*
LDRr1,=SDCTL0//
//SetPrechargeCommand
LDRr3,=0x92120200
//ldrr3,=0x92120251
STRr3,[r1]
//IssuePrechargeAllCommad
LDRr3,=0x8200000
LDRr2,[r3]
//SetAutoRefreshCommand
LDRr3,=0xA2120200
STRr3,[r1]
//IssueAutoRefreshCommand
LDRr3,=0x8000000
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
LDRr2,[r3]
//SetModeRegister
LDRr3,=0xB2120200
STRr3,[r1]
//IssueModeRegisterCommand
LDRr3,=0x08111800//;ModeRegistervalue
LDRr2,[r3]
//SetNormalMode
LDRr3,=0x82124200
STRr3,[r1]
//;*
//;*EndofSDRAMandSyncFlashInit*
//;*
//copycodefromFLASHtoSRAM
_CopyCodes:
ldrr0,=SOURCE
ldrr1,=TARGET
subr3,r0,#4
ldrr2,[r3]
_CopyLoop:
ldrr3,[r0]
strr3,[r1]
addr0,r0,#4
addr1,r1,#4
subr2,r2,#4
teqr2,#0
beq_EndCopy
b_CopyLoop
_EndCopy:
ldrr0,=TARGET
movpc,r0
上回书说到flashloader把bootloaderload到0x0AFE0100,然回跳了过去,
其实0x0AFE0100就是烧在flash0x0C000100中的真正的bootloader:
bootloader有几个文件组成,先是START.s,也是唯一的一个汇编程序,其余的都是C写成的,START.s主要初始化堆栈:
_start:
ldrr1,=StackInit
ldrsp,[r1]
bmain
//此处我们跳到了C代码的main函数,当C代码执行完后,还要调用
//下面的JumpToKernel0x跳到LINXUkernel运行
.equStackInitvalue,__end_data+0x1000//4K__end_data在连结脚本中指定
StackInit:
.longStackInitvalue
.globalJumpToKernel
JumpToKernel:
//jumptothecopycode(gettheargumentsright)
movpc,r0
.globalJumpToKernel0x
//r0=jumpaddress
//r1-r4=argumentstouse(thesegetshifted)
JumpToKernel0x:
//jumptothecopycode(gettheargumentsright)
movr8,r0
movr0,r1
movr1,r2
movr2,r3
movr3,r4
movpc,r8
.section".data.boot"
.section".bss.boot"
下面让我们看看bootloader的c代码干了些什么。main函数比较长,让我们分段慢慢看。
intmain()
{
U32*pSource,*pDestin,count;
U8countDown,bootOption;
U32delayCount;
U32fileSize,i;
charc;
char*pCmdLine;
char*pMem;
init();//初始化FLASH控制器和CPU时钟
EUARTinit();//串口初始化
EUARTputString("/n/nDBMX1LinuxBootloaderver0.2.0/n");
EUARTputString("Copyright(C)2002MotorolaLtd./n/n");
EUARTputString((U8*)cmdLine);
EUARTputString("/n/n");
EUARTputString("Pressanykeyforalternateboot-upoptions...");
小弟的bootloader主要干这么几件事:init();初始化硬件,打印一些信息和提供一些操作选项:
0.Programbootloaderimage
1.Programkernelimage
2.Programroot-diskimage
3.DownloadkernelandbootfromRAM
4.Downloadkernelandbootwithver0.1.xbootloaderformat
5.Bootaver0.1.xkernel
6.Bootwithadifferentcommandline
也就是说,可以在bootloader里选择重新下载kernel,rootdisk并写入flash,
下载的方法是用usb连接,10m的rootdisk也就刷的一下。关于usb下载的讨论请参看先前的贴子“为arm开发平台增加usb下载接口“。
如果不选,直接回车,就开始把整个linux的内核拷贝到SDRAM中运行。
列位看官,可能有人要问,在flashloader中不是已经初始化过sdram控制器了吗?怎么init();中还要初始化呢,各位有所不知,小弟用的是syncflash,
可以直接使用sdram控制器的接口,切记:在flash中运行的代码是不能初始化连接flash的sdram控制器的,不然绝对死掉了。所以,当程序在flash中运行的时候,去初始化sdram,而现在在sdram中运行,可放心大胆地初始化flash了,主要是设定字宽,行列延时,因为缺省都是最大的。
另外,如果列位看官的cpu有足够的片内ram,完全可以先把bootloader放在片内ram,干完一切后再跳到LINUX,小弟着也是不得已而为之啊。
如果直接输入回车,进入kernel拷贝工作:
EUARTputString("CopyingkernelfromFlashtoRAM.../n");
count=0x200000;//2Mbytes
pSource=(U32*)0x0C100000;
pDestin=(U32*)0x08008000;
do
{
*(pDestin++)=*(pSource++);
count-=4;
}while(count>0);
}
EUARTputString("Bootingkernel.../n/n");
这一段没有什么可说的,运行完后kernel就在0x08008000了,至于为什么要
空出0x8000的一段,主要是放kelnel的一些全局数据结构,如内核页表,arm的页目录要有16k大。
我们知道,linux内核启动的时候可以传入参数,如在PC上,如果使用LILO,
当出现LILO:,我们可以输入root=/dev/hda1.或mem=128M等指定文件系统的设备或内存大小,在
arm嵌入式LINUX启动过 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)