微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm 嵌入式LINUX启动过程(1)

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等指定文件系统的设备或内存大小,在

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top