热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>内核研究>

在ARMSYS上进行uClinux内核移植的总结

来源: 作者: 时间:2007-06-09 Tag: 点击:

如果在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;

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

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是未初始化的全局变量(对于GNU工具,对应的概念是 TEXT,DATA和BSS)。Bootloader要将RW段复制到RAM中,并将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

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

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

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

2.3.5 C语言中的硬件初始化

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

2.3.6 建立人机界面

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

2.4 加载uClinux内核

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

压缩格式的uClinux内核映像文件都是由开头的一段自解压代码和后面的压缩数据部分组成。对于Kernel而言,由于是以压缩格式存放,因次只能以非XIP方式执行。自解压类型的uClinux 内核映像文件首先存放在Flash Memory中,由Bootloader加载到SDRAM中的0xc100000地址处,然后将控制权交给它。可执行的uClinux Kernel将被解压到最终的执行空间,然后开始运行。压缩格式Image所占据的临时SDRAM空间可在随后由uClinux回收利用。

可以从flash拷贝到SDRAM解压运行,自然同样也可以直接下载到SDRAM运行。这对于调试内核都是非常方便的。对于压缩格式的内核映像文件(image.rom和image.ram)都可以直接下载到SDRAM的特定地址处,并从该地址开始运行(参考2.2节)。



相关文章:
精通initramfs构建step by step
Linux利用kexec迅速切换内核
进程上下文VS中断上下文
内核通知链 学习笔记
linux spi子系统驱动分析
menuconfig 配置选项
《Linux操作系统内核实习》之练习一
udev详解
什么叫微内核,宏内核?
Linux 信号signal处理机制
开发简单的 Linux2.6 内核模块
删除内核的perl脚本
Linux2.6内核usb gadget驱动移植
GCC hacks in the Linux kernel
iomem
kernel学习的想法
让自己的驱动支持udev
linux内核编译步骤
内核的等待队列
Linux内核wait_queue深入分析
升级和删除内核
SD卡驱动分析2
Linux Kernel VDSO本地权限提升漏洞
内核中的TCP的追踪分析-15-TCP(IPV4)的客户端与
linux 2.6内核可加载模块的编译
内核模块HelloWorld
在环回接口上发送一个数据报
ARP初始化
1分钟编译FreeBSD内核
linux设备模型之uart驱动架构分析