Chinaunix首页 | 论坛 | 博客
  • 博客访问: 348864
  • 博文数量: 120
  • 博客积分: 4010
  • 博客等级: 上校
  • 技术积分: 1810
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-11 17:50
文章分类

全部博文(120)

文章存档

2008年(120)

我的朋友

分类:

2008-03-20 16:26:10

在前面:这篇很猛,将了Arm7cuLinux内核移植的整个过程,非常详细。在配置菜单部分讲的有些少,但是那些基本都是不涉及太多技术方面的,只要能理解英文的意思基本不会出现错误的设置。就算设置错了也只是一些设备不能用或者多了一些你不需要的功能。

1.概述

本文是针对如何在以S3C44B0X为核心的ARMSYS开发板上建立ucLinux内核移植的一个总结,其内容包括对Bootloader的功能分析和ucLinux2.4.24发行版内核基础上针对S3C44B0X开发板进行修改的重点内容的逐一列举。

 

2Bootloader

 

2.1 Bootloader概述

Boot Loader 就是在操作系统内核运行之前运行的一段程序。通过这段程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。因此,正确建立ucLinux的移植的前提条件是具备一个与ucLinux配套、易于使用的 Bootloader

ARMSYS开发板提供了这样一个ucLinux专用的Bootloader,该Bootloader程序烧录在系统的地址0x0处,每次上电即运行,能够正确完成硬件系统的初始化和ucLinux的引导。

理论上,ucLinux引导时并非一定需要一个独立于内核的Bootloader。然而,将Bootloader与内核分开设计能够使软件架构更加清晰,也有助于灵活地支持多种引导方式,实现一些有用的辅助功能。

ARMSYS提供的Bootloader的主要任务可以概括如下:

1.硬件初始化;

2.从主机下载新的内核映像和文件系统映像;

3.烧写NorFlashNandflash

4.加载ucLinux 内核映像并启动运行;

5.提供串行超级终端上的人机操作界面。

 

22存储空间分布

Bootloader采用默认的存储空间分布地址来加载ucLinux内核、文件系统,并按照正确引导ucLinux的运行。在ARMSYSBootloader中,默认的存储空间分布如下表:

内容                        起始地址        存储介质

Bootloader程序空间          0x00000000      Flash

压缩内核映像                0x00010000      Flash

ROM文件系统映像             0x000e0000      Flash

内核运行地址                0x0c008000      SDRAM

压缩内核解压地址            0x0c100000      SDRAM

文件系统加载                0x0c700000      SDRAM

这个存储空间的分配方式也不是固定不变的,可以通过修改Bootloader中的相关代码来改变。

 

23Bootloader的工作

完整的Bootloader引导流程可描述如下:

硬件初始化阶段一

硬件初始化

复制二级中断异常矢量表

初始化各种处理器模式

复制RORW,清零ZI (跳转到C代码入口函数)

硬件初始化阶段二

初始化本阶段使用到的硬件设备;

建立人机界面

实现映像文件的下载和烧录工具

实现映像文件的加载和运行工具

下面对上述各步骤进行逐一说明,并对与ucLinux相关的内容详细加以说明。

 

231 硬件初始化

板子上电或复位后,程序从位于地址0x0Reset Exception Vector处开始执行,因此需要在这里放置Bootloader的第一条指令:b ResetHandler,跳转到标号为ResetHandler处进行第一阶段的硬件初始化,主要内容为:关Watchdog Timer,关中断,初始化PLL和时钟,初始化存储器控制器。比较重要的是PLL的输出频率要计算正确,ARMSYS中把它设置为64MHz;这实际上就是处理器的工作主频,这个时间参数在第二阶段计算SDRAM的刷新计数值和UART的波特率等参数时还要用到。

 

232建立二级异常中断矢量表

异常中断矢量表(Exception Vector Table)是BootloaderucLinux内核发生联系关键的地方之一。即使ucLinux内核已经得到处理器的控制权运行,一旦发生中断,处理器还是会自动跳转到从0x0地址开始的第一级异常中断矢量表中的某个表项(依据于中断类型)处读取指令运行。

在编写Bootloader时,地址0x0处的一级异常中断矢量表只需简单地包含向二级异常中断矢量表的跳转指令就可以。这样,就能够正确地将发生的事件交给ucLinux的中断处理程序来处理。对于ucLinux内核,它在RAM空间中基地址为0xc000000处建立了自己的二级异常中断矢量表,因此,Bootloader的第一级异常中断矢量表如下所示:

b ResetHandler ;Reset Handler

ldr pc,=0x0c000004 ;Undefined Instruction Handler

ldr pc,=0x0c000008 ;Software Interrupt Handler

ldr pc,=0x0c00000c ;Prefetch Abort Handler

ldr pc,=0x0c000010 ;Data Abort Handler

b .

ldr pc,=0x0c000018 ;IRQ Handler

ldr pc,=0x0c00001c ;FIQ Handler

LTORG

如果在Bootloader执行的全过程中都不必响应中断,那么上面的设置已能满足要求。但在我们的ARMSYS上提供了USB下载器,需要用到中断,那么Bootloader必须在同样的地址(0xc000000)处配置自己的二级异常中断矢量表,以便同ucLinux兼容。这张表事先存放在 Flash Memory里,引导过程中由Bootloader将其复制到RAM地址0x0C000000

 

存放矢量表:

;IRQ ==the program put this phrase to 0xc000000

ExceptionHanlderBegin

b .

ldr pc, MyHandleUndef     ; HandlerUndef

ldr pc, MyHandleSWI       ; HandlerSWI

ldr pc, MyHandlePabort    ; HandlerPabort

ldr pc, MyHandleDabort    ; HandlerDAbort

b .                       ; HandlerReserved

ldr pc, MyHandleIRQ       ; HandlerIRQ

ldr pc, MyHandleFIQ       ; HandlerFIQ

MyHandleUndef DCD HandleUndef      ;reserve a word(32bit)

MyHandleSWI DCD HandleSWI

MyHandlePabort DCD HandlePabort

MyHandleDabort DCD HandleDabort

MyHandleIRQ DCD HandleIRQ

MyHandleFIQ DCD HandleFIQ

ExceptionHanlderEnd

 

建立二级矢量表:

;****************************************************

;* Setup IRQ handler *

;****************************************************

ldr r0,=(_IRQ_BASEADDRESS + 0x100)

ldr r2,=_IRQ_BASEADDRESS

add r3,r0, #0x100

0

CMP r0, r3

STRCC r2, [r0], #4;cc:Carry clear;save R2 to R0 address, R0 =R0+ 4

BCC %B0

ldr r1,=_IRQ_BASEADDRESS

ldr r0,=ExceptionHanlderBegin ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c

ldr r3,=ExceptionHanlderEnd

0

CMP r0, r3 ;put the vector table at _IRQ_BASEADDRESS(0xc000000)

LDRCC r2, [r0], #4

STRCC r2, [r1], #4

BCC %B0

ldr r1,=DIsrIRQ;put the IRQ judge program at _IRQ_BASEADDRESS+0x80(0xc000080)

ldr r0,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c

ldr r3,=IsrIRQEnd

0

CMP r0, r3

LDRCC r2, [r0], #4

STRCC r2, [r1], #4

BCC %B0

ldr r1, =MyHandleIRQ ;MyHandleIRQ point to DIsrIRQ

ldr r0, =ExceptionHanlderBegin

ldr r4, =_IRQ_BASEADDRESS;

sub r0, r1, r0

add r0, r0,r4

ldr r1, =DIsrIRQ

str r1, [r0]

定义Handlexxx

^ (_IRQ_BASEADDRESS)

HandleReset # 4

HandleUndef # 4

HandleSWI # 4

HandlePabort # 4

HandleDabort # 4

HandleReserved # 4

HandleIRQ # 4

HandleFIQ # 4

^ (_IRQ_BASEADDRESS+0x80)

DIsrIRQ # 4

;IntVectorTable

^ (_IRQ_BASEADDRESS+0x100)

HandleADC # 4

HandleRTC # 4

HandleUTXD1 # 4

HandleUTXD0 # 4

HandleSIO # 4

HandleIIC # 4

HandleURXD1 # 4

HandleURXD0 # 4

HandleTIMER5 # 4

HandleTIMER4 # 4

HandleTIMER3 # 4

HandleTIMER2 # 4

HandleTIMER1 # 4

HandleTIMER0 # 4

HandleUERR01 # 4

HandleWDT # 4

HandleBDMA1 # 4

HandleBDMA0 # 4

HandleZDMA1 # 4

HandleZDMA0 # 4

HandleTICK # 4

HandleEINT4567 # 4

HandleEINT3 # 4

HandleEINT2 # 4

HandleEINT1 # 4

HandleEINT0 # 4

将异常中断矢量重构到SDRAM,这样的好处就是可以在其它的功能程序内对中断处理程序的地址任意赋值。为此,我们在44b.h文件中定义:

/* ISR */

#define pISR_RESET (*(unsigned *)(_IRQ_BASEADDRESS+0x0))

#define pISR_UNDEF (*(unsigned *)(_IRQ_BASEADDRESS+0x4))

#define pISR_SWI (*(unsigned *)(_IRQ_BASEADDRESS+0x8))

#define pISR_PABORT (*(unsigned *)(_IRQ_BASEADDRESS+0xc))

#define pISR_DABORT (*(unsigned *)(_IRQ_BASEADDRESS+0x10))

#define pISR_RESERVED (*(unsigned *)(_IRQ_BASEADDRESS+0x14))

#define pISR_IRQ (*(unsigned *)(_IRQ_BASEADDRESS+0x18))

#define pISR_FIQ (*(unsigned *)(_IRQ_BASEADDRESS+0x1c))

#define pISR_ADC (*(unsigned *)(_IRQ_BASEADDRESS+0x100))//0x20))

#define pISR_RTC (*(unsigned *)(_IRQ_BASEADDRESS+0x104))//0x24))

#define pISR_UTXD1 (*(unsigned *)(_IRQ_BASEADDRESS+0x108))//0x28))

#define pISR_UTXD0 (*(unsigned *)(_IRQ_BASEADDRESS+0x10c))//0x2c))

#define pISR_SIO (*(unsigned *)(_IRQ_BASEADDRESS+0x110))//0x30))

#define pISR_IIC (*(unsigned *)(_IRQ_BASEADDRESS+0x114))//0x34))

#define pISR_URXD1 (*(unsigned *)(_IRQ_BASEADDRESS+0x118))//0x38))

#define pISR_URXD0 (*(unsigned *)(_IRQ_BASEADDRESS+0x11c))//0x3c))

#define pISR_TIMER5 (*(unsigned *)(_IRQ_BASEADDRESS+0x120))//0x40))

#define pISR_TIMER4 (*(unsigned *)(_IRQ_BASEADDRESS+0x124))//0x44))

#define pISR_TIMER3 (*(unsigned *)(_IRQ_BASEADDRESS+0x128))//0x48))

#define pISR_TIMER2 (*(unsigned *)(_IRQ_BASEADDRESS+0x12c))//0x4c))

#define pISR_TIMER1 (*(unsigned *)(_IRQ_BASEADDRESS+0x130))//0x50))

#define pISR_TIMER0 (*(unsigned *)(_IRQ_BASEADDRESS+0x134))//0x54))

#define pISR_UERR01 (*(unsigned *)(_IRQ_BASEADDRESS+0x138))//0x58))

#define pISR_WDT (*(unsigned *)(_IRQ_BASEADDRESS+0x13c))//0x5c))

#define pISR_BDMA1 (*(unsigned *)(_IRQ_BASEADDRESS+0x140))//0x60))

#define pISR_BDMA0 (*(unsigned *)(_IRQ_BASEADDRESS+0x144))//0x64))

#define pISR_ZDMA1 (*(unsigned *)(_IRQ_BASEADDRESS+0x148))//0x68))

#define pISR_ZDMA0 (*(unsigned *)(_IRQ_BASEADDRESS+0x14c))//0x6c))

#define pISR_TICK (*(unsigned *)(_IRQ_BASEADDRESS+0x150))//0x70))

#define pISR_EINT4567 (*(unsigned *)(_IRQ_BASEADDRESS+0x154))//0x74))

#define pISR_EINT3 (*(unsigned *)(_IRQ_BASEADDRESS+0x158))//0x78))

#define pISR_EINT2 (*(unsigned *)(_IRQ_BASEADDRESS+0x15c))//0x7c))

#define pISR_EINT1 (*(unsigned *)(_IRQ_BASEADDRESS+0x160))//0x80))

#define pISR_EINT0 (*(unsigned *)(_IRQ_BASEADDRESS+0x164))//0x84))

例如,我们要使用到Exint4567中断,定义好中断处理程序Meint4567Isr()后,仅需要一条语句:

pISR_EINT4567=(int)MEint4567Isr;

就能使中断发生后正确跳转到我们编写的处理程序上。

 

233 初始化各种处理器模式

ARM7TDMI支持7Operation ModeUserFIQIRQSupervisorAbortSystemUndefinedBootloader需要依次切换到每种模式,初始化其程序状态寄存器(SPSR)和堆栈指针(SP)

 

234 复制RORW,清零ZI

一个ARMRO(Read Only)RW(Read Write)ZI三个段组成,其中RO为代码段,RW是已初始化的全局变量,ZI是未初始化的全局变量(对于GNU工具,对应的概念是 TEXTDATABSS)Bootloader要将RW段复制到RAM中,并将ZI段清零。编译器使用下列符号来记录各段的起始和结束地址:

|Image$$RO$$Base| RO段起始地址        ;ads中设置

|Image$$RO$$Limit| RO段结束地址加1   ;是连接器根据实际代码和数据长度计算出的

|Image$$RW$$Base| RW段起始地址        ;ads中设置

|Image$$RW$$Limit| ZI段结束地址加1   ;是连接器根据实际代码和数据长度计算出的

|Image$$ZI$$Base| ZI段起始地址        ;一般不设置,紧跟RW地址

|Image$$ZI$$Limit| ZI段结束地址加1   ;是连接器根据实际代码和数据长度计算出的

(小呆:以上注释我加的,应该没有错)

需要注意的是,这些标号的值是根据链接器中设置的中ro-baserw-base的设置来计算的,我们的Bootloader的对应设置是:ro-base = 0xc000000, rw-base = 0xc5f0000

完成这个步骤后,第一阶段的硬件初始化就完成了。

BL Main 跳转到C语言程序,开始第二阶段的初始化和系统引导。

 

235 C语言中的硬件初始化

继续对硬件进行初始化,主要包括对以下设备的初始化:GPIOCacheInterrupt ControllerWatchdog TimerUARTsS3C44B0X处理器内置data/instruction合一的8KB Cache,且允许按地址范围设置两个Non-Cacheable区间。合理的配置是打开对RAM区间的Cache,关闭对其它地址区间(非存储器设备,I/O设备 )Cache。所有硬件初始化完毕之后,开中断。

 

236 建立人机界面

引导过程的最后一步是在串行终端上建立人机界面,并等待用户输入命令。若接收到用户输入,则显示菜单模式或命令行模式的交互界面,等待用户进一步的命令。这里就不对此详细讨论了。

 

阅读(741) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~