ARMLinux启动代码分析.docx

上传人:b****0 文档编号:9847665 上传时间:2023-05-21 格式:DOCX 页数:17 大小:26.02KB
下载 相关 举报
ARMLinux启动代码分析.docx_第1页
第1页 / 共17页
ARMLinux启动代码分析.docx_第2页
第2页 / 共17页
ARMLinux启动代码分析.docx_第3页
第3页 / 共17页
ARMLinux启动代码分析.docx_第4页
第4页 / 共17页
ARMLinux启动代码分析.docx_第5页
第5页 / 共17页
ARMLinux启动代码分析.docx_第6页
第6页 / 共17页
ARMLinux启动代码分析.docx_第7页
第7页 / 共17页
ARMLinux启动代码分析.docx_第8页
第8页 / 共17页
ARMLinux启动代码分析.docx_第9页
第9页 / 共17页
ARMLinux启动代码分析.docx_第10页
第10页 / 共17页
ARMLinux启动代码分析.docx_第11页
第11页 / 共17页
ARMLinux启动代码分析.docx_第12页
第12页 / 共17页
ARMLinux启动代码分析.docx_第13页
第13页 / 共17页
ARMLinux启动代码分析.docx_第14页
第14页 / 共17页
ARMLinux启动代码分析.docx_第15页
第15页 / 共17页
ARMLinux启动代码分析.docx_第16页
第16页 / 共17页
ARMLinux启动代码分析.docx_第17页
第17页 / 共17页
亲,该文档总共17页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

ARMLinux启动代码分析.docx

《ARMLinux启动代码分析.docx》由会员分享,可在线阅读,更多相关《ARMLinux启动代码分析.docx(17页珍藏版)》请在冰点文库上搜索。

ARMLinux启动代码分析.docx

ARMLinux启动代码分析

首先,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

欲知后事如何,下回分解:

长篇连载--armlinux演艺---第二回

--------------------------------------------------------------------------------

上回书说到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代码如何运行,请看下集

书接上回:

下面让我们看看bootloader的c代码干了些什么。

main函数比较长,让我们分段慢慢看。

intmain()

{

U32*pSource,*pDestin,count;

U8countDown,bootOption;

U32delayCount;

U32fileSize,i;

charc;

char*pCmdLine;

char*pMem;

init();//初始化FLASH控制器和CPU时钟

EUARTinit();//串口初始化

EUARTputString("

DBMX1linuxBootloaderver0.2.0

");

EUARTputString("Copyright(C)2002MotorolaLtd.

");

EUARTputString((U8*)cmdLine);

EUARTputString("

");

EUARTputString("

ressanykeyforalternateboot-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...

");

count=0x200000;//2Mbytes

pSource=(U32*)0x0C100000;

pDestin=(U32*)0x08008000;

do

{

*(pDestin++)=*(pSource++);

count-=4;

}while(count>0);

}

EUARTputString("Bootingkernel...

");

这一段没有什么可说的,运行完后kernel就在0x08008000了,至于为什么要

空出0x8000的一段,主要是放kelnel的一些全局数据结构,如内核页表,arm的页目录要有16k大。

我们知道,linux内核启动的时候可以传入参数,如在PC上,如果使用LILO,

当出现LILO:

,我们可以输入root=/dev/hda1.或mem=128M等指定文件系统的设备或内存大小,在嵌入式系统上,参数的传入是要靠bootloader完成的,

pMem=(char*)0x083FF000;//参数字符串的目标存放地址

pCmdLine=(char*)&cmdLine;//定义的静态字符串

while((*(pMem++)=*(pCmdLine++))!

=0);//拷贝

JumpToKernel((void*)0x8008000,0x083FF000);//跳转到内核

return(0);

JumpToKernel在前文中的start.S定义过:

JumpToKernel:

//jumptothecopycode(gettheargumentsright)

movpc,r0

.globalJumpToKernel0x

//r0=jumpaddress

//r1=argumentstouse(thesegetshifted)

由于arm-GCC的c参数调用的顺序是从左到右R0开始,所以R0是KERNKEL的地址,

r1是参数字符串的地址:

到此为止,为linux引导做的准备工作就结束了,下一回我们就正式进入linux的代码。

困了。

好,从本节开始,我们走过了bootloader的漫长征途,开始进入linux的内核:

说实话,linux宝典的确高深莫测,洋人花了十几年修炼,各种内功心法层处不穷。

有些地方反复推敲也领悟不了其中奥妙,炼不到第九重啊。

linux的入口是一段汇编代码,用于基本的硬件设置和建立临时页表,对于

ARMLINUX是linux/arch/arm/kernle/head-armv.S,走!

#ifdefined(CONFIG_MX1)

movr1,#MACH_TYPE_MX1

#endif

这第一句话好像就让人看不懂,好像葵花宝典开头的八个字:

欲练神功。

那来的MACH_TYPE_MX1?

其实,在head-armv.S

中的一项重要工作就是设置内核的临时页表,不然mmu开起来也玩不转,但是内核怎么知道如何映射内存呢?

linux的内核将映射到虚地址0xCxxxxxxx处,但他怎么知道把哪一片ram映射过去呢?

因为不通的系统有不通的内存影像,所以,LINUX约定,内核代码开始的时候,

R1放的是系统目标平台的代号,对于一些常见的,标准的平台,内核已经提供了支持,只要在编译的时候选中就行了,例如对X86平台,内核是从物理地址1M开始映射的。

如果老兄是自己攒的平台,只好麻烦你自己写了。

小弟拿人钱财,与人消灾,用的是摩托的MX1,只好自己写了,定义了#MACH_TYPE_MX1,当然,还要写一个描述平台的数据结构:

MACHINE_START(MX1ADS,"MotorolaMX1ADS")

MAINTAINER("SPSMotorola")

BOOT_MEM(0x08000000,0x00200000,0xf0200000)

FIXUP(mx1ads_fixup)

MAPIO(mx1ads_map_io)

INITIRQ(mx1ads_init_irq)

MACHINE_END

看起来怪怪的,但现在大家只要知道他定义了基本的内存映象:

RAM从0x08000000开始,i/o空间从0x00200000开始,i/o空间映射到虚拟地址空间

0xf0200000开始处。

摩托的芯片i/o和内存是统一编址的。

其他的项,在下面的初始化过程中会逐个介绍到。

好了好了,再看下面的指令:

movr0,#F_BIT|I_BIT|MODE_SVC@makesuresvcmode//设置为SVC模式,允许中断和快速中断

//此处设定系统的工作状态,arm有7种状态

//每种状态有自己的堆栈

msrcpsr_c,r0@andallirqsdiabled

bl__lookup_processor_type

//定义处理器相关信息,如value,mask,mmuflags,

//放在proc.info段中

//__lookup_processor_type取得这些信息,在下面

//__lookup_architecture_type中用

这一段是查询处理器的种类,大家知道arm有arm7,arm9等类型,如何区分呢?

在arm协处理器中有一个只读寄存器,存放处理器相关信息。

__lookup_processor_type将返回如下的结构:

__arm920_proc_info:

.long0x41009200//CPUid

.long0xff00fff0//cpumask

.long0x00000c1e@mmuflags

b__arm920_setup

.longcpu_arch_name

.longcpu_elf_name

.longHWCAP_SWP|HWCAP_HALF|HWCAP_26BIT

.longcpu_arm920_info

.longarm920_processor_functions

第一项是CPUid,将与协处理器中读出的id作比较,其余的都是与处理器相关的

信息,到下面初始化的过程中自然会用到。

第五回终。

查询到了处理器类型和系统的内存映像后就要进入初始化过程中比较关键的一步了,开始设置mmu,但首先要设置一个临时的内核页表,映射4m的内存,这在初始化过程中是足够了:

//r5=08000000ram起始地址r6=00200000io地址,r7=f0200000虚io

teqr7,#0@invalidarchitecture?

moveqr0,#'a'@yes,error'a'

beq__error

bl__create_page_tables

其中__create_page_tables为:

__create_page_tables:

pgtblr4

//r4=08004000临时页表的起始地址

//r5=08000000,ram的起始地址

//r6=00200000,i/o寄存器空间的起始地址

//r7=00003c08

//r8=00000c1e

//thepagetablein08004000isjusttempbasepage,wheninit_task'ssweaper_page_dirready,

//thetemppagewillbeuseless

//thehigh12bitofvirtualaddressisbasetableindex,soweneed4kx4=16ktempbasepage,

movr0,r4

movr3,#0

addr2,r0,#0x4000@16kofpagetable

1:

strr3,[r0],#4@Clearpagetable

strr3,[r0],#4

strr3,[r0],#4

strr3,[r0],#4

teqr0,r2

bne1b

/*

*CreateidentitymappingforfirstMBofkernel.

*Thisismarkedcacheableandbufferable.

*

*Theidentitymappingwillberemovedby

*/

//由于linux编译的地址是0xC0008000,load的地址是0x08008000,我们需要将虚地址0xC0008000映射到0800800一段

//同时,由于部分代码也要直接访问0x08008000,所以0x08008000对应的表项也要填充

//页表中的表象为section,AP=11表示任何模式下可访问,domain为0。

addr3,r8,r5@mmuflags+startofRAM

//r3=08000c1e

addr0,r4,r5,lsr#18

//r0=08004200

strr3,[r0]@identitymapping

//*08004200=08000c1e0x200表象对应的是08000000的1m

/*

*Nowsetupthepagetablesforourkerneldirect

*mappedregion.WeroundTEXTADDRdowntothe

*nearestmegabyteboundary.

*/

//下面是映射4M

addr0,r4,#(TEXTADDR&0xfff00000)>>18@startofkernel

//r0=r4+0x3000=08004000+3000=08007000

strr3,[r0],#4@PAGE_OFFSET+0MB

//*08007004=08000c1e

addr3,r3,#1<<20

//r3=08100c1e

strr3,[r0],#4@PAGE_OFFSET+1MB

//*08007008=08100c1e

addr3,r3,#1<<20

strr3,[r0],#4

//*0800700c=08200c1e@PAGE_OFFSET+2MB

addr3,r3,#1<<20

strr3,[r0],#4@PAGE_OFFSET+3MB

//*08007010=08300c1e

bicr8,r8,#0x0c@turnoffcacheable

//r8=00000c12@andbufferablebits

movpc,lr//子程序返回。

下一回就要开始打开mmu的操作了

上回书讲到已经设置好了内核的页表,然后要跳转到__arm920_setup,

这个函数在arch/arm/mm/proc-arm929.s

__arm920_setup:

movr0,#0

mcrp15,0,r0,c7,c7@invalidateI,Dcachesonv4

mcrp15,0,r0,c7,c10,4@drainwritebufferonv4

mcrp15,0,r0,c8,c7@invalidateI,DTLBsonv4

mcrp15,0,r4,c2,c0@loadpagetablepointer

movr0,#0x1f@Domains0,1=client

mcrp15,0,r0,c3,c0@loaddomainaccessregister

mrcp15,0,r0,c1,c0@getcontrolregisterv4

/*

*Clearout'unwanted'bits(thenputtheminifweneedthem)

*/

@VIZFRSBLDPWCAM

bicr0,r0,#0x0e00

bicr0,r0,#0x0002

bicr0,r0,#0x000c

bicr0,r0,#0x1000@...0000.....000.

/*

*Turnonwhatwewant

*/

orrr0,r0,#0x0031

orrr0,r0,#0x2100@..1....1..11...1

#ifdefCONFIG_CPU_ARM920_D_CACHE_ON

orrr0,r0,#0x0004@.............1..

#endif

#ifdefCONFIG_CPU_ARM920_I_CACHE_ON

orrr0,r0,#0x1000@...1...........

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 教学研究 > 教学反思汇报

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2