针对系统的改进ARM开发了板上uClinux内核移植

时间:2011-09-04

  1.简述:

  引导加载程序是系统加电后运行的段软件代码。PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的OS BootLoader(比如,LILO和GRUB等)一起组成。BIOS在完成硬件检测和资源分配后,将硬盘MBR中的BootLoader读到系统的RAM中,然后将控制权交给OS BootLoader。BootLoader的主要运行任务就是将内核映象从硬盘上读到 RAM 中,然后跳转到内核的入口点去运行。

  2.1Bootloader概述

  Boot Loader 就是在操作系统内核运行之前运行的一段程序。通过这段程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为终调用操作系统内核准备好正确的环境。ARMSYS开发板提供了这样一个uClinux专用的Bootloader,该Bootloader程序烧录在系统的地址0x0处,每次上电即运行,能够正确完成硬件系统的初始化和uClinux的引导。理论上,uClinux引导时并非一定需要一个独立于内核的Bootloader。然而,将Bootloader与内核分开设计能够使软件架构更加清晰。

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

  1.硬件初始化;

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

  3.烧写NorFlash和Nandflash;

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

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

  2.2存储空间分布

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

  内容                      起始地址

  存储介质Bootloader程序空间         0x00000000

  Flash压缩内核映像                     0x00010000

  FlashROM文件系统映像               0x000e0000

  Flash内核运行地址                     0x0c008000

  SDRAM压缩内核解压地址             0x0c100000

  SDRAM文件系统加载                     0x0c700000

  2.3Bootloader的工作

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

  硬件初始化阶段一

  1 硬件初始化

  2 复制二级中断异常矢量表

  3 初始化各种处理器模式

  4 复制RO和RW,清零ZI

  硬件初始化阶段二

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

  6 建立人机界面

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

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

  2.3.1 硬件初始化

  板子上电或复位后,程序从位于地址0x0的Reset Exception Vector处开始执行,因此需要在这里放置Bootloader的条指令:b ResetHandler,跳转到标号为ResetHandler处进行阶段的硬件初始化,主要内容为:关Watchdog Timer,关中断,初始化PLL和时钟,初始化存储器控制器。比较重要的是PLL的输出频率要计算正确,ARMSYS中把它设置为64MHz;

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

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

  在编写 Bootloader时,地址0x0处的异常中断矢量表只需简单地包含向二级异常中断矢量表的跳转指令就可以。对于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必须在同样的地址xc000000)处配置自己的二级异常中断矢量表。如表所示流程:

  存放矢量表:

  ;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;

  可以使中断发生后正确跳转到自己编写的处理程序上。

  2.3.3 初始化各种处理器模式

  ARM7TDMI支持7种Operation Mode:User,FIQ,IRQ,Supervisor,Abort,System和Undefined。Bootloader需要依次切换到每种模式,初始化其程序状态寄存器(SPSR)和堆栈指针(SP)。

  2.3.4 复制RO和RW,清零ZI

  一个ARM由RO,RW和ZI三个段组成,其中RO为代码段,RW是已初始化的全局变量,ZI是未初始化的全局变量。编译器使用下列符号来记录各段的起始和结束地址:

  |Image$$RO$$Base| :RO段起始地址

  |Image$$RO$$Limit| :RO段结束地址加1

  |Image$$RW$$Base| :RW段起始地址

  |Image$$RW$$Limit| :ZI段结束地址加1

  |Image$$ZI$$Base| :ZI段起始地址

  |Image$$ZI$$Limit| :ZI段结束地址加1

  我们的Bootloader的对应设置是:ro-base = 0xc000000, rw-base = 0xc5f0000。

  2.3.5 C语言中的硬件初始化

  继续对硬件进行初始化,主要包括对以下设备的初始化:GPIO,Cache,Interrupt Controller,Watchdog Timer和UARTs。S3C44B0X处理器内置data/instruction合一的8KB Cache,且允许按地址范围设置两个Non-Cacheable区间。合理的配置是打开对RAM区间的Cache,关闭对其它地址区间的Cache。所有硬件初始化完毕之后,开中断。

  2.3.6 建立人机界面

  引导过程的一步是在串行终端上建立人机界面,并等待用户输入命令。如果接收到用户输入,则显示菜单模式或命令行模式的交互界面,等待用户进一步的命令。

  2.4加载uClinux内核

  ARMSYS提供的Bootloader支持两种uClinux启动运行方式:直接从SDRAM中的内核映像中运行;从flash将压缩格式的内核映像加载到SDRAM,再从SDRAM运行。前者需要利用Bootloader提供的对映像文件的工具;后者则需要利用Bootloader提供的flash烧录工具进行烧录,才可以加载运行。

  自解压类型的uClinux内核映像文件首先存放在Flash Memory中,由Bootloader加载到SDRAM中的0xc100000地址处,然后将控制权交给它。可执行的uClinux Kernel将被解压到终的执行空间,然后开始运行。

  2.5调用Kernel

  采用C语句:((void (*)(void))ram_addr)();

  2.6工具

  ARMSYS 的Bootloader在人机界面上提供了8个功能项目,其中包括支持从主机通过USB口文件到目标板的SDRAM和Nandflash上;用SDRAM中的数据烧写Flash Memory。

  3.uClinux2.4.24内核组成

  ◎arch:arch目录下有多个子目录,它的每一个子目录都代表内核支持的一种CPU体系结构,每个子目录中又进一步分解为boot、mm、 kernel等子目录,分别包含与系统引导、内存管理、系统调用的进入和返回、终端处理以及其它内核中依赖于CPU和系统结构的底层代码。与ARM处理器(不带有MMU)相关的代码放在目录arch/armnommu下,与S3C44B0X相关的代码则放在目录arch/armnommu/match- S3C44B0X。

  ◎ include:include子目录包括编译所需要的大部分头文件。与平台无关的头文件在include/linux子目录下,与ARM处理器(不带MMU)相关的头文件在include/asm-armnommu子目录下,与S3C44B0X相关的代码在include/asm-armnommu/arch-S3C44B0X目录下;

  ◎ init:这个目录包含的初始化代码(注意:不是系统的引导代码),包含两个文件main.c和Version.c,这是研究如何工作的一个非常好的起点。

  ◎ kernel:主要的代码,此目录下的文件实现了大多数linux系统的内核函数,其中重要的文件当属sched.c;同样,和体系结构相关的代码在arch/*/kernel中;

  ◎ drivers: 放置系统所有的设备驱动程序;每种驱动程序又各占用一个子目录:如,/block 下为块设备驱动程序,比如ide(ide.c)。

  ◎ 其他:例如mm ,这个目录包括所有独立于处理器体系结构的内存管理代码;lib放置的库代码;net,与网络相关的代码;ipc,这个目录包含的进程间通讯的代码;fs,所有的文件系统代码和各种类型的文件操作代码,它的每一个子目录支持一个文件系统。

  uClinux-dist-20040408发行包中的内核对S3C44B0X处理器的支持是不完整的,因此,我们不能够希望在make config配置选项中选中44B0X目标板后,直接编译它来得到一个很好地支持44B0X开发板的内核映像,我们必须为内核打上补丁。这样就可以让让处理器更加完美,这样就可以针对更多的客户进行运用。



  
上一篇:设计热电表流量自动标定系统
下一篇:教你如何学习Windows CE 模拟器和远程调试工具

免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

相关技术资料