跳至主要内容

博文

目前显示的是 一月 4, 2009的博文

【转】第一个简单的内核编程实验:hello.c

文章说明:calmarrow(lqm)原创 文章引自: http://piaoxiang.cublog.cn   《Linux设备驱动程序》       内核编程入门,就以最为简单的hello.c为例。     环境:Redhat 9.0,内核版本2.4.20-8。       虽然现在2.6.x的内核很早就就发布了,但是毕竟很多公司还在使用2.4.x的内核。作为新手,从2.4.x的内核入手是可行的。原因有如下几条:     (1)2.4.x比较成熟。可能你遇到的绝大多数问题,网上都有解决方案。在这个过程中,你可以节省大量的时间,同时还可以对比网上的解决方案,加深认识,总结解决问题的方法,调整自己的学习方法和思路。     (2)事物的发展总不可能是一蹴而就的。了解发展的历程,对深入理解问题有很大的好处。所以在2.4.x的内核的基础上学习2.6.x的内核,就能够体会到2.6.x的内核在哪些方面要出色,或者为什么要采取这种改进技术。相信理论清晰了,即时2.6.x的内核也会容易上手。       下面总结了第一个内核程序hello.c的学习过程。   (一)第一阶段:尽量简单   /*  * hello.c  */ # define MODULE # include < linux / module . h > int init_module ( void ) {         printk ( "Hello World!\n" ) ;          return 0 ; } void cleanup_module ( void ) {         printk ( "Goodbye!\n" ) ; } 执行,出现错误一: [ root@lqm drivers ] # gcc - c hello . c [ root@lqm drivers ] # insmod hello . o hello . o : kernel - module version mismatch         hello . o was compiled for kernel version 2 . 4 . 20          while

【转】bootloader如何固化?

文章说明:calmarrow(lqm)原创 文章引自: http://piaoxiang.cublog.cn         关于bootloader,先简要地总结一下。经过了第一个阶段的学习,对bootloader有了一个整体的认识,其实把它当作一个功能单元就可以了,职责就是完成从硬件加电到操作系统内核运行之前的所有工作,这些工作包括硬件检测、硬件初始化、加载kernel。这些工作怎么完成呢?按照功能分为两个部分比较合适,硬件检测和初始化功能实现作为stage1;加载kernel作为stage2。stage1完全依赖于硬件,这一部分用汇编语言实现;stage2与操作系统有关,一般用C语言来实现。在嵌入式系统的开发过程中,bootloader有两种选择,要么自行开发,要么移植。我还没有写过bootloader,只是移植过U-boot,使用过Redboot。       这里讨论一个问题,bootloader如何烧写(固化)到非易失性存储介质(比如Nor Flash,NAND Flash等)里呢?       讨论之前,先要理解编程器的概念。虽然学通信工程,应该对这些工具不陌生,但是本科下来,对这些概念确实没有深刻的印象。实际用到,才发现自己基础太差,只能努力的弥补。我写blog,很大程度上是对基础知识的巩固,相信基础扎实了,知识体系才可以慢慢的完善,才能最终胜任更高难度的工作。       编程器也叫device programmer,是对非易失性存储介质和其他电可编程设备进行编程的工具。传统的编程器,需要把Flash(举例)从电路板上取下来,插到编程器的接口上,以完成擦除和烧写。现在的编程器发展的方向是ISP(In-System Programming,在系统可编程),就是指电路板上的空白器件可以编程写入最终用户代码,而不需要从电路板上取下器件。已经编程的器件也可以用ISP方式擦除或再编程,如Nor Flash支持重复擦写10万次左右。可见,ISP,智能编程器是发展的方向。       利用编程器可以解决前面提高的问题,不仅可以烧写bootloader,还可以烧写kernel,fs等等。也就是都属于固化最终用户代码的过程。       下面考虑两种实际情况:     1、厂商已经提供固化的程序代码,不允许对其修改。那么这种

【转】《嵌入式系统》读书笔记(2):ARM体系结构(下)

文章说明:calmarrow(lqm)读毛德操的《嵌入式系统》所做笔记 文章引自: http://piaoxiang.cublog.cn ARM指令系统     系统的指令系统介绍这里就不罗列了,没有多大意义。这里只是总结一些小的知识点和经验,便于对ARM指令系统有更为深入的理解。 1、ARM处于用户态模式时,可见的通用寄存器是16个,即R0-R15。外加一个CPSR(Current Program Status Register,当前程序状态寄存器),总共是17个。其中3个有特殊用途:R15��程序计数器PC,R14��程序链接寄存器LR,R13��堆栈指针SP。 2、ARM有7中运行状态:usr、fiq、irq、sve、abt、und、sys。除用户状态外的6中均为系统状态(特权模式)。当CPU从用户状态进入系统状态时,或者发生系统状态间的切换时,都需要将CPSR的内容保存起来,以备将来恢复原来的运行状态,所以每个系统状态都有个"保存程序状态寄存器(Saved Program Status Register)"SPSR。CPSR和SPSR都是32位的,实际上只用了其中的一部分。 3、ARM体系结构中,每一条指令都可以条件执行。例如: cmp r0, #0 addeq r0, r2, r5 addne r0, r0, r0, lsl #1 等价于: if (r0 = = 0) {  r0 = r2 + r5; } else {  r0 = r0 * 3; }     可见,利用这种独特的条件执行可以得到很简洁的汇编代码,要不然就得在汇编代码中插入条件转移指令。不过,当if或else下面的条件执行部分较大时,插入条件转移指令更合适。有人做过分析,当一个条件执行部分的大小超过三条指令时,就还是以插入条件转移指令为好;反之则以条件执行指令为好。     在条件转移的设计中,同时要注意程序的可读性。虽然程序都能得到正确的结果,但是安排合理的程序更具有可读性,也更加易于维护。宁肯牺牲一部分时间来完善,也不要在事后代码维护的时候才意识到。在EDUKIT-III的汇编实验中,提供的程序就存在可读性差的问题,经过修改后的程序如下:   / *   * Filename   : asm_d   * Descri

【转】《嵌入式系统》读书笔记(1):ARM体系结构(上)

文章说明:calmarrow(lqm)读毛德操的《嵌入式系统》所做笔记 文章引自: http ://piaoxiang.cublog.cn       学习《嵌入式系统��采用公开源代码和StrongARM/XScale处理器》一书,对ARM核的体系结构有了一个比较全面而且深入的认识,纠正了以前不少错误的认识。现在以ARM核的体系结构为主线,按照理解的先后顺序,结合自己的实际应用经验,总结相关知识点,以获得更大的提高。 什么是体系结构?     所谓"体系结构",也可以称为"系统结构",是指程序员在为特定处理器编制程序时所"看到"从而可以在程序中使用的资源及其相互间的关系。       体系结构最为重要的就是处理器所提供的指令系统和寄存器组。指令系统分为CISC(Complex Instruction Set Computer,复杂指令集计算机)和RISC(Reduced Instruction Set Computer,精简指令集计算机)。其中,嵌入式系统中的CPU往往是RISC结构的,至于原因,在后面总结完CISC和RISC之后会给出。ARM核就是RISC结构,由于其在嵌入式系统占的比重比较大,所以ARM几乎成为RISC的代名词了。寄存器组与采用的指令系统是密切相关的,从这一点上考虑,体系结构中最为重要的应该就是指令系统了。       在体系结构中,还有存储器结构。现在有两种:冯・诺依曼结构和哈佛结构。传统的计算机采用冯・诺依曼结构,也称为普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。主要特点是:程序和数据共用一个存储空间;程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置;采用单一的地址及数据总线;程序指令和数据的宽度相同。这样,处理器在执行指令时,必须从存储器中取出指令解码,再取操作数执行运算,即使单条指令也要耗费几个甚至几十个周期,那么,在高速运算的时候,在传输通道上会出现瓶颈效应。目前使用冯・诺依曼结构的MPU和MCU有很多,如Intel 8086、ARM公司的ARM7、MIPS公司的MIPS处理器等。Harvard结构是一种将程序指令存储和数据存储分开的存储器结构,Harvard结构是一种并行体系结构,主要特点是:程序和数据存储

【转】vivi开发笔记(二十):vivi延时函数实现不合理性的探讨

文章说明:calmarrow(lqm)原创 文章引自: http://piaoxiang.cublog.cn       vivi实现了两个延时函数:udelay和mdelay。前者是微秒级,后者是毫秒级。对于一般应用已经可以了。但是在分析其实现过程中,发现其设计是不合理的。在探讨过程中,把中断的层次概念弄清晰了,算是额外的收获。下面展开具体分析。   # ifndef _VIVI_TIME_H_ # define _VIVI_TIME_H_ # include "config.h" # ifndef __ASSEMBLY__ void init_time ( void ) ; void mdelay ( unsigned int ) ; void udelay ( unsigned int ) ; # endif # endif /* _VIVI_TIME_H_ */       udelay和mdelay类似。现在以udelay为主线。首先,声明是在【include/time.h】中,如上所示。然后追踪其定义,利用source insight很容易找到。发现其核心的处理部分是在【arch/s3c2410/proc.c】中,如下:   static void time_wait ( unsigned int sec , int unit ) {      unsigned long ticks , clock_tick_rate ;      /* clear interupt bit */     SRCPND | = INT_TIMER4 ;     INTPND | = INT_TIMER4 ;     INTMSK & = ~ INT_TIMER4 ;              /* enable timer 4 interrupt */     clock_tick_rate = get_clock_tick_rate ( ) ;      if ( clock_tick_rate = = 0 ) {         printk ( "Can not get a clock tick rate\n&