RTOS设备驱动向嵌人式Linux的移植
发布时间:2008/5/27 0:00:00 访问次数:533
嵌入式linux新应用不会凭空从开发者的头脑中冒出来,大部分项目都是由成千上万行,甚至数百万行的代码组成。成千上百的嵌入式项目已经成功地把现有的其它平台的代码移植到linux下,比如wind river vxworks 和 psos, vrtx, nucleus 和其它rtos。这些移植工作有着重要的价值和现实意义。
到目前为止,大多数关于移植已有的rtos应用到嵌入式linux的文献,关注rtos 接口(api)、任务、调度模式以及如何把他们映射到相应得用户空间去。同样重要的是,在i/o调用密集的嵌入式程序中怎么样把rtos的硬件接口代码移植到更加规范的linux设备驱动程序中去。
本文把概述几种常用的经常出现于现有嵌入式应用中的内存映射i/o方法。它们涵盖的范围从对中断服务例程的特殊使用及用户线程对硬件访问到出现于有些rots中的半规范化驱动程序模型。这对于移植rtos 代码到规范化的linux设备启动程序具有一定启发作用,并且介绍了一些移植方法。特别地,本文会重点讨论rtos和linux中的内存映射,基于i/o调度队列的移植,把rtos i/o重定义到linux下的驱动程序和守护进程里。
rtos i/o 概念
“不规范”是描述大多数rtos系统i/o的最佳词语。多数rtos是针对较早的无mmu的cpu而设计,所以忽略了内存管理部分,即使当mmu问世后也是这样:不区分物理地址和逻辑地址。大多数 rtos还全部运行在特权模式,虽然表面上看来是增强了性能。全部的rtos 应用和系统代码都能够访问整个地址空间、内存映射过的设备、以及其他i/o操作。这样,即使存在差别,也是很难把rtos应用程序代码同驱动程序代码区分开来。
不规范的结构导致了i/o实现的特殊性。在很多情况下,缺乏设备驱动程序模型的认同。根据这种无层次的特性,回顾一下基于rtos软件中使用的一些重要概念和习惯用法非常有指导意义。
内嵌的内存访问
上个世纪八十年代中期商业化的rtos产品中,多数嵌入式软件都有一个对执行时间有严格需求的,采用i/o查询和中断服务例程的大循环。开发人员在项目采用rtos和执行程序,主要为了加强并行性和多任务同步,绕开其它有碍实现该目标的程序结构。这样,即使rtos提供了i/o 调用形式化方法,嵌入式程序员继续使用直接的i/o操作:
#define data_register 0xf00000f5
char getchar(void) {
return (*((char *) data_register)); /* read from port */
}
void putchar(char c) {
*((char *) data_register) = c; /* write to port */
}
多数受过训练的开发者常会把这样的直接i/o代码从硬件代码中分离开来。但是我还是经常看到诸如此类的i/o调用代码。
当开始使用直接内存映射i/o的时候,新接触linux的嵌入式开发人员总是想把这类代码移到用户空间,通过mmap()调用来替代定义寄存器地址的#define 语句。这种处理方法对于一些原型是可以的,但不能支持中断处理,限制了实时响应,特别不安全,不适合商业化产品的发布。
rtos 中断服务例程
在 linux里, 中断服务属于内核层; 在一个 rtos里, 中断服务例程代码没有特殊规定且常与应用程序代码没什么区别(不外乎返回序列异同)。很多 rtos提供系统调用或者宏来让代码自己检测它自己的切换状态(比如 wind river vxworks的 intcontext())。中断服务例程通常也使用标准的库函数,随之而来也有可重入性和移植性等问题。
大多数rtos支持注册中断服务例程代码、中断判断和中断服务调用。一些简单的嵌入式程序,仅仅支持在硬件矢量表里插入中断服务例程的起始地址。
如果试图直接在用户程序空间执行读和写操作,你不得不把linux中断服务例程放入内核程序空间。
rtos i/o 子系统
大多数rtos会提供一个定制的标准c运行库 (比如 psos 的prepc),或者修改编译器提供商的c库(libc)或修改glibc。在尽量最小化情况下,多数的 rtos支持标准c的i/o子集(open/close/read/write/ioctl). 大多数情况下,这些调用和从衍生出来的调用转化为基本i/o简单封装.有趣的是,因为大多数的 rtos不支持文件系统,这些平台不提供针对flash和其他存储介质的文件存储,常采用完全不同的代码实现或者其他应用程序接口(api) (比如 psos 的phile).
wind river vxworks 在这方面比其它rtos做得好些,它提供功能丰富的i/o子集,有效广泛集成网络接口及网络媒体。
延时处理
很多rtos也支
嵌入式linux新应用不会凭空从开发者的头脑中冒出来,大部分项目都是由成千上万行,甚至数百万行的代码组成。成千上百的嵌入式项目已经成功地把现有的其它平台的代码移植到linux下,比如wind river vxworks 和 psos, vrtx, nucleus 和其它rtos。这些移植工作有着重要的价值和现实意义。
到目前为止,大多数关于移植已有的rtos应用到嵌入式linux的文献,关注rtos 接口(api)、任务、调度模式以及如何把他们映射到相应得用户空间去。同样重要的是,在i/o调用密集的嵌入式程序中怎么样把rtos的硬件接口代码移植到更加规范的linux设备驱动程序中去。
本文把概述几种常用的经常出现于现有嵌入式应用中的内存映射i/o方法。它们涵盖的范围从对中断服务例程的特殊使用及用户线程对硬件访问到出现于有些rots中的半规范化驱动程序模型。这对于移植rtos 代码到规范化的linux设备启动程序具有一定启发作用,并且介绍了一些移植方法。特别地,本文会重点讨论rtos和linux中的内存映射,基于i/o调度队列的移植,把rtos i/o重定义到linux下的驱动程序和守护进程里。
rtos i/o 概念
“不规范”是描述大多数rtos系统i/o的最佳词语。多数rtos是针对较早的无mmu的cpu而设计,所以忽略了内存管理部分,即使当mmu问世后也是这样:不区分物理地址和逻辑地址。大多数 rtos还全部运行在特权模式,虽然表面上看来是增强了性能。全部的rtos 应用和系统代码都能够访问整个地址空间、内存映射过的设备、以及其他i/o操作。这样,即使存在差别,也是很难把rtos应用程序代码同驱动程序代码区分开来。
不规范的结构导致了i/o实现的特殊性。在很多情况下,缺乏设备驱动程序模型的认同。根据这种无层次的特性,回顾一下基于rtos软件中使用的一些重要概念和习惯用法非常有指导意义。
内嵌的内存访问
上个世纪八十年代中期商业化的rtos产品中,多数嵌入式软件都有一个对执行时间有严格需求的,采用i/o查询和中断服务例程的大循环。开发人员在项目采用rtos和执行程序,主要为了加强并行性和多任务同步,绕开其它有碍实现该目标的程序结构。这样,即使rtos提供了i/o 调用形式化方法,嵌入式程序员继续使用直接的i/o操作:
#define data_register 0xf00000f5
char getchar(void) {
return (*((char *) data_register)); /* read from port */
}
void putchar(char c) {
*((char *) data_register) = c; /* write to port */
}
多数受过训练的开发者常会把这样的直接i/o代码从硬件代码中分离开来。但是我还是经常看到诸如此类的i/o调用代码。
当开始使用直接内存映射i/o的时候,新接触linux的嵌入式开发人员总是想把这类代码移到用户空间,通过mmap()调用来替代定义寄存器地址的#define 语句。这种处理方法对于一些原型是可以的,但不能支持中断处理,限制了实时响应,特别不安全,不适合商业化产品的发布。
rtos 中断服务例程
在 linux里, 中断服务属于内核层; 在一个 rtos里, 中断服务例程代码没有特殊规定且常与应用程序代码没什么区别(不外乎返回序列异同)。很多 rtos提供系统调用或者宏来让代码自己检测它自己的切换状态(比如 wind river vxworks的 intcontext())。中断服务例程通常也使用标准的库函数,随之而来也有可重入性和移植性等问题。
大多数rtos支持注册中断服务例程代码、中断判断和中断服务调用。一些简单的嵌入式程序,仅仅支持在硬件矢量表里插入中断服务例程的起始地址。
如果试图直接在用户程序空间执行读和写操作,你不得不把linux中断服务例程放入内核程序空间。
rtos i/o 子系统
大多数rtos会提供一个定制的标准c运行库 (比如 psos 的prepc),或者修改编译器提供商的c库(libc)或修改glibc。在尽量最小化情况下,多数的 rtos支持标准c的i/o子集(open/close/read/write/ioctl). 大多数情况下,这些调用和从衍生出来的调用转化为基本i/o简单封装.有趣的是,因为大多数的 rtos不支持文件系统,这些平台不提供针对flash和其他存储介质的文件存储,常采用完全不同的代码实现或者其他应用程序接口(api) (比如 psos 的phile).
wind river vxworks 在这方面比其它rtos做得好些,它提供功能丰富的i/o子集,有效广泛集成网络接口及网络媒体。
延时处理
很多rtos也支