博文

Linux启动过程中硬件模块的加载(2009-03-26 16:19:00)

摘要:  前言:我觉得我的文章相对来说都是比较浅显的。一些初学者可以看看,对于高手来说,如果你们不吝啬时间的话,希望也能帮我看看,指点一下其中的错误。这也是我到这里来和大家交流的目的。
  阅读Linux内核启动代码的直接动力是我想编写RTL8019AS的网卡驱动程序(2.4.18内核只支持了CS8900A)。既然要写驱动,我就想知道它是怎么样被加载的,好奇心驱使我先去搞定这个问题。
  拿到2.4.18的软件包,一万多个文件,我不知怎么下手。所幸手头有这么三件工具助我入门:
  1,一块移植好linux的开发板,通过它可以看到linux启动过程打印的消息。
  2, google,网上关于linux的资料真是太多了!!!
  3, Windows文件搜索引擎,通过它可以知道在那些文件中打印出那些消息。
  很快,我就找到了linux启动的总的入口,/arch/arm/boot/compressed/head.s。
  head.s完成的工作主要是底层寄存器、MMU的一些设定以及kernel的解压缩。汇编文件中调用的C代码大多位于该目录下misc.c文件,比如decompress_kernel。
  当然,这部分不是重点,head执行完毕以后就跳到start_kernel(),这才是我们的重点所在,这个函数位于文件/init/main.c中。这个文件是启动的主线!!!
  在start_kernel中,依次执行各个初始话函数,这里具体我没有看,一直到最后rest_init(),在这个函数里启动了一个init线程,而主线程自己则进入了IDLE状态。所以我们关心一下init线程做了什么事情,看文件最后init函数。
  在这个函数里面,先lock_kernel,然后调用do_basic_setup,在这个函数里面又是一堆的初始化,有一个函数要引起我们的注意:do_initcalls。看看它干了什么:(这之后的东西在下文文件系统中讲解)static void __init do_initcalls(void){initcall_t *call;call = &__initcall_start;do {(*call)( );call ;} while (call < &__initcall_end)......

阅读全文(3357) | 评论:0

Linux启动过程中文件系统的加载(2009-03-26 16:14:00)

摘要:  前言:我觉得我的文章相对来说都是比较浅显的。一些初学者可以看看,这也是我不在嵌入式那个版上发文的原因。对于高手来说,如果你们不吝啬时间的话,希望也能帮我看看,指点一下其中的错误。这也是我到这里来和大家交流的目的。
  在完成了模块驱动后,就要挂载文件系统了。我一直以为:
  我编译的内核是采用了initrd的模式,设备是在RAM DISK文件系统下的/linuxrc脚本程序加载的,因此在这上面浪费了很多时间。不过对initrd算是有了比较深的理解,这个等一下再说。
  其实,内核挂载的第一个文件系统就是nand flash中的root.cramfs,关于挂载相关的代码mount_root()在文件/fs/super.c里面。随后将devcie文件系统挂载到/dev目录下面,代码为mount_devfs_fs()。因为采用了noninitrd的模式,因此文件系统的挂载就完毕了,init进程继续往下走到一直到运行:

  if (execute_command)execve(execute_command,argv_init,envp_init);这里init切换成另外一个线程,运行程序在execute_command中定义。execute_command是vivi传进来的命令行,启动过程中可以看到:
  Kernel command line: noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0因此execute_command对应/linuxrc,因此程序运行根目录下的脚本linuxrc,在我的系统中他对应:
  #!/bin/shecho "mount /etc as ramfs"/bin/mount -n -t ramfs ramfs /etc/bin/cp -a /mnt/etc/* /etcecho "re-create the /etc/mtab entries"/bin/mount -f -t cramfs -o remount,ro /dev/mtdblock/3 //bin/mount -f -t ramfs ramfs /etcexec /sbin/init这个就不解释了(最后是启动bash),大家可以在linux下把root.cramfs挂载到......

阅读全文(3827) | 评论:0

如何在非实时linux上实现实时应用程序与内核模块之间共享存储器(2009-03-26 16:12:00)

摘要:linux并不是严格意义上的实时操作系统,为了实际需要,工程师们必须想尽办法来祢补这一不足,于是出现了rtlinux和rtai等并不强调商业性的软件。免费的rtlinux显然庞大而并不兼容大部分的嵌入式平台,最新版本的rtlinux也只能支持I386和PPC而已。Rtai是不错的选择,但要把它移植到你的平台上去,为了适应你的linux版本,你的CPU,你必须的花费许多的工作,比如说最近比较流行的AT91RM9200DK,光修改linux版本补丁就要花费许多的功夫。Rtlinux和rtai为了增强linux操作系统的实时性,主要是通过开辟内核模块与应用程序之间可以共享的内存快来实现的。它们在内核空间控制硬实时任务的运行,并通过一个名为FIFO的共享内存块来与应用程序进行通信。他们是很不错的软件,我想用不了多久他们就会具备更强大的可移植性。但我在本文主要是想详细的介绍一个适合小型嵌入式系统使用的增强linux操作系统实时性的方法。当然,原理也是开辟一个实时应用程序与内核模块之间可以共享的内存。 众所周知,内核空间和用户空间只能通过系统调用来共享数据,如果进程要等待一个中断的发生,它所能做的就是把自己挂在等待队列里,直到中断服务程序来唤醒它。然后,进程才把内核空间的的数据通过特定的系统调用写到用户空间里。大部分程序员为了避免这样造成的不可忍耐的延时,都会把对数据的操作都放在内核空间里运行,也就是扩大中断服务程序的功能。但如果开辟两个空间可以共享的内存块,程序员就不必要这么为难了。我以AT91RM9200DK的平台为例,linux操作系统版本为2.4.19-rmk7,不需要半天时间,就可以实现两个空间的共享内存。 AT91RM9200DK的SDRAM的大小为31Mbyte,正常情况下,System RAM的大小也是31Mbyte,我们要把31Mbyte的高端地址空出2M来作为我们的共享内存块,这个内存块是独立的,不能为linux操作系统的内存管理所用了。首先必须通知内核它的内存只有30Mbyte了,我的方法是在u-boot的环境变量里设置mem=29M。然后在include/asm-arm/目录下建立头文件:new_fifo.h,代码如下:
#ifndef NEW_FIFO
#define NEW_FIFO
#endif
#ifdef ......

阅读全文(3022) | 评论:0

linux 使用的一些问题杂集(2009-03-26 16:09:00)

摘要:linux的推广对于从事计算机开发,或者嵌入式设计的工程师而言是非常总要的。虽然linux看来陌生,但是也是有些问题可以简化,个人在学习的过程中感觉,体会linux对于分区的要求以及命名,是重要的,这样你就会对简单的字符界面望文生义,容易理解了。
其实系统的启动关键还是掌握linux对待设备是以文件为起点的,任何东西都是一个文件夹而已。当然理解是需要一个过程,如果安装单机的linux可能让你感觉顺手,可是不容易加深你对系统的理解,最好是安装多系统的,对比思考,事半功倍。

下面是一些问题集锦,虽然小,可是的确非常有用,虽然是入门级的,可是不积硅步,无以千里呀。
我在使用redhat 8.0 感觉不错。

NO1》
linux 下访问windows系统的命令:

mount -t vfat /dev/hda1 /mnt/c
在windows下访问linux的文件:

请大虾给我详细介绍一下rh8.0如果访问fat32分区 (2003-02-10 19:38:58)
--------------------------------------------------------------------------------
mount -t vfat /dev/hda? /mnt/*
其中的‘?’为你要挂接的分区 ‘*

No2》
不能进入图形登陆格式 (2003-02-10 18:44:22)

--------------------------------------------------------------------------------
我在linux下改变了它的启动,就是在/etc/inittab 中把它的启动程序从X11变为了Full Mutiluser Mode
,然后重启计算机,之后只能进入它的命令格式,请教各位怎样才能把它恢复到图形登陆形式。
--------------------------------
运行 startx 就可以进入图形界面
进入后再对 /etc/inittab文件修改 就可以了

No3》
我的机器装有98,2000

后来安装redha......

阅读全文(2722) | 评论:0

BSP 概念解析(2009-03-19 11:29:00)

摘要:Drew在这里按照自己的理解来解释一下BSP( Board Support Package),仅供参考:

BSP是板级支持包,是介于主板硬件和操作系统之间的一层,应该说是属于操作系统的一部分,主要目的是为了支持操作系统,使之能够更好的运行于硬件主板。BSP是相对于操作系统而言的,不同的操作系统对应于不同定义形式的BSP,例如VxWorks的BSP和Linux的BSP相对于某一CPU来说尽管实现的功能一样,可是写法和接口定义是完全不同的,所以写BSP一定要按照该系统BSP的定义形式来写(BSP的编程过程大多数是在某一个成型的BSP模板上进行修改)。这样才能与上层OS保持正确的接口,良好的支持上层OS。

例如:

在VxWorks中的网卡驱动,首先在config.h中包含该网卡,然后将网卡含网卡的信息的参数放入数组 END_TBL_ENTRY endDevTbl [] 中,系统通过函数muxDevLoad( )调用这个数组来安装网卡驱动。

而在Linux中的网卡驱动,是在space.c中声明该网络设备,再把网卡驱动的一些函数加到dev结构中,由函数ether_setup()来完成网卡驱动的安装。


纯粹的BSP所包含的内容一般说来是和系统有关的驱动和程序,如网络驱动和系统中网络协议有关,串口驱动和系统下载调试有关等等。离开这些驱动系统就不能正常工作。

Tornado中BSP的编译和上层应用程序不同,用命令行或直接在Tornado环境下Build,在Tornado下不能跟踪调试。

用户也可以添加自己的程序到BSP中,但严格来说不应该算BSP.一般来说这种做法不建议。因为一旦操作系统能良好运行于最终的主板硬件后,BSP也就固定了,不需要做任何改动。而用户自己在BSP中的程序还会不断的升级更新,这样势必对BSP有不好的影响,对系统造成影响,同时由于BSP调试编译环境较差,也不利于程序的编译调试。

上层程序

Tools - Applications
--------------
I/O System
VxWorks Libraries
TCP/IP 
Wind Kernel

BSP
--......

阅读全文(3481) | 评论:0

Linux嵌入式系统开发平台选型探讨(2009-03-19 11:28:00)

摘要:1 嵌入式系统与Linux   按照电气工程师协会的一个定义:嵌入式系统是用来控制或监视机器、装置或工厂等的大规模系统的设备。具体说来,它是电脑软件和硬件的综合体;是以应用为中心,以计算机技术为基础,软硬件可裁减,从而能够适应实际应用中对功能、可靠性、成本、体积、功耗等严格要求的专用计算机系统。一般来说,嵌入式系统不能使用通用型计算机,而且运行的是固化的软件,终端用户很难或者不可能改变固件。而Linux也早已成为IT界家喻户晓的一个名字。概括说来,将Linux应用于嵌入式系统的开发有如下一些优点: ① Linux自身具备一整套工具链,容易自行建立嵌入式系统的开发环境和交叉运行环境,并且可以跨越在嵌入式系统开发中仿真工具(ICE)的障碍。 ② 内核的完全开放,使得可以自己设计和开发出真正的硬实时系统;对于软实时系统,在Linux中也容易得到实现。 ③ 强大的网络支持,使得可以利用Linux的网络协议栈将其开发成为嵌入式的TCP/IP网络协议栈。 2 嵌入式系统设计的过程   按照嵌入式系统的工程设计方法,嵌入式系统的设计可以分成三个阶段:分析、设计和实现。分析阶段是确定要解决的问题及需要完成的目标,也常常被称为“需求阶段”;设计阶段主要是解决如何在给定的约束条件下完成用户的要求;实现阶段主要是解决如何在所选择的硬件和软件的基础上进行整个软、硬件系统的协调实现。在分析阶段结束后,通常开发者面临的一个棘手的问题就是硬件平台和软件平台的选择,因为它的好坏直接影响着实现阶段的任务完成。   通常硬件和软件的选择包括:处理器、硬件部件、操作系统、编程语言、软件开发工具、硬件调试工具、软件组件等。   在上述选择中,通常,处理器是最重要的,同时操作系统和编程语言也是非常关键的。处理器的选择往往同时会限制操作系统的选择,操作系统的选择又会限制开发工具的选择。 3 硬件平台的选择 3.1 处理器的选择   嵌入式系统的核心部件是各种类型的嵌入式处理器。据不完全统计,目前全世界嵌入式处理器的品种总量已经超过1000多种,流行体系结构有30几个系列。但与全球PC市场不同的是,没有一种微处理器和微处理器公司可以主导嵌入式系统,仅以32位的CPU而言,就有100种以上嵌入式微处理器。由于嵌入式系统设计的差异性极大,因此选择是多样化的。   调查上市的CPU供应商,......

阅读全文(3392) | 评论:0

gcc手册,看linux内核不可缺少的handbook(2009-03-19 11:17:00)

摘要:里面包含了gcc扩展c语言的所有用法.篇幅不是很多.我原本想找中文版的.可惜找不到.后来发觉英文版非常不错.扩展的用法其实也不是非常的多. http://www.hzlitai.com.cn/bbs/viewthread.php?tid=2005&extra=page%3D1   若不能打开请点击查看原文:http://www.hzlitai.com.cn/article/ARM9-article/system/1541.html......

阅读全文(2990) | 评论:0

嵌入开发(WinCE)的一些经验(2009-03-19 11:15:00)

摘要:WindowsCE下Unicode和Ansi字符间互相转换的例子
纵所周知,WindowsCE下编程99%的问题都和Unicode有关.比如文件编辑,一般都保存为Ansi格式;无线通讯中控制Modem需要发送的AT指令,必须是Ansi格式;网络通讯中,PC端一般都是Ansi的,为了和PC上协议兼容,在WindowsCE中必须把要发送的一个指令从Unicode 转换成Ansi格式...等等.很多初学者对于这些问题总是感到很麻烦.其实WindowsCE中有标准的API实现了Unicode和Ansi字符间的互转.下面就是网络通讯中的程序片断.
m_psocket是指向一个从CCeSocket派生的类,如果没有连接的话其为NULL;
m_snd是要发送的CString,和一个EDIT相对应.
/发送函数片断
void CClient1Dlg::OnButtonSend()
{
  / TODO: Add your control notification handler code here
  if (!m_psocket) /无Socket连接,退出
  {
      MessageBox(TEXT("无连接!"),TEXT("信息"));
      return;
  }
  UpdateData(TRUE); /保存输入的字符串到m_snd
  unsigned char buf[129]; /发送缓冲区
  ZeroMemory(buf,sizeof(buf)); /缓冲区清零
  CString tmpstr(m_snd); /复制要发送的字符串
  int multibytelen=WideCharToMultiByte( /计算从Unicode转换到Ansi后需要的字节数
  CP_ACP, /根据ANSI code page转换
  WC_COMPOSITECHECK | WC_DEFAULTCHAR, /转换出错用缺省字符代替
  tmpstr.GetBuf......

阅读全文(2389) | 评论:0

嵌入式系统中的CACHE问题(2009-03-19 11:11:00)

摘要:随着社会的发展、人们生活水平的提高,人们对嵌入式计算机应用的要求也越来越高。因此,对嵌入式系统的性能要求也越来越高。明显体现在嵌入式系统的CPU速度的不断提高上。但问题也随之而来,嵌入式CPU的主频不断地提高,一方面加强了CPU的处理能力,另一方面,在速度上造成了与慢速的系统存储器极不相配的情况,从而影响了整个系统的性能。
为了解决这个问题,引入了CACHE技术。CACHE是一种高速缓冲存储器,是为了解决CPU和主存之间速度不匹配而采用的一项重要技术。通过在主存和高速CPU之间设置一个小容量的高速存储器,在其中存放CPU常用的指令和数据,CPU对存储器的访问主要体现在对SRAM的存取,CPU可以不必加等待状态而保持高速操作。   采用CACHE技术,解决了CPU与主存之间速度不匹配的问题;但它又带来了一些其它问题,如本文将提到的一致性问题。 1 问题的发现与原因 在进行某嵌入式系统项目的开发过程中,有一个环节需要使用DMA方式进行数据传输。当程序运行后,发现传到目的地的数据块中经常会有一些错误的字节。如:数据本应为00 01 02 03 04 05 06 07 08 09 0A 0B ...(16进制),结果却是00 01 02 03 00 00 00 00 08 09 0A 0B ...。在某些环节也出现了类似的问题。例如,通过HDLC通道向外发送数据,发送的总是缓冲区初始化时的内容,实际要发送的数据总是发不出去,但使用调试工具看内存中的数据,却是正确的。 经过一段时间的调试,发现出现这种现象的环节都使用了DMA传输数据。在通过HDLC通道发送数据的例子中,HDLC通道内部也是用DMA方式从内存直接读数据并向外发送。经过分析,认为问题的原因是出在CACHE上,是由于CACHE数据与内存数据的不一致性造成的。 所谓CACHE数据与内存数据的不一致性,是指:在采用CACHE的系统中,同样一个数据可能既存在于CACHE中,也存在于主存中,数据一样则具有一致性,数据若不一样就叫做不一致性。具体表现在两个方面: (1)更新时可能CACHE中的数据更新,而主存未更新,则造成数据丢失; (2)在有DMA控制器的系统和多处理器系统中,有多个部件可以访问主存。这时,可能其中有些部件是直接访问主存,也可能每个DMA部件和处理器配置一个CACHE。这样......

阅读全文(2118) | 评论:0

Windows CE下驱动开发基础(2009-03-10 14:28:00)

摘要: 这是我从1月6日开始主持天极网论坛嵌入式开发版以来第一次发表文章,加上以前琐碎的文章共计30篇。研究的越多就越感觉自己懂的太少,其实在驱动开发方面我还是个菜鸟,我是想再次抛砖引玉,让做驱动有N年经验的人奉献一点出来,让大家减少一些研究驱动源码而又缺少注释所带来的痛苦。
  我想即使读者看过微软的关于驱动开发的培训教材和CE帮助文档中的驱动部分,头脑中仍然一片茫然。要想真正了解驱动程序必须结合一些驱动程序源码,在此我以串口驱动程序(COM16550)中初始化过程为线索简单讲一讲驱动开发的基础知识。
Windows CE下的串口驱动程序能够处理所有I/O行为类似串口的设备,包括基于16450、16550 UART(通用异步收发芯片)的设备和一些采用DMA的设备,常见的有9针串口、红外I/O口、Modem等。在%_WINCEROOT%\Public\Common\OAK\Drivers\Serial目录下,COM_MDD2子目录包含新的串口驱动MDD层函数代码。COM16550子目录包含串口驱动PDD层代码。SER16550子目录包含的一系列函数专用于控制与16550兼容的UART,这样PDD层的主要工作就是调用SER16550中的函数。还有一个ISR16550子目录包含的是串口驱动程序专用的可安装ISR(中断服务例程),而很多硬件设备驱动程序采用CE默认的可安装ISR giisr.dll。一般串口设备相应的注册表设置例子及意义如下: 键 意义 "SysIntr"=dword:13 串口1的中断ID为十进制13 "IoBase"=dword:02F8 串口1的IO空间首地址为十六进制2F8 "IoLen"=dword:8 串口1的IO空间长度为8个字节 "DeviceArrayIndex"=dword:0 串口1的索引,是1的由来 "Order"=dword:0 串口1驱动的加载顺序 "DeviceType"=dword:0 串口1的设备类型 "DevConfig"=hex: 10,00 .... 串口1在与Modem设备通讯时的配置,如波特率、奇偶校检等 "FriendlyName"="COM1:" 串口1在拨号程序中显示的名字 "Tsp"="Unimodem.......

阅读全文(2884) | 评论:0