Chinaunix首页 | 论坛 | 博客
  • 博客访问: 332344
  • 博文数量: 50
  • 博客积分: 961
  • 博客等级: 准尉
  • 技术积分: 495
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-07 08:30
文章分类

全部博文(50)

文章存档

2015年(2)

2014年(1)

2013年(4)

2012年(18)

2011年(25)

分类: LINUX

2011-09-28 09:25:30

   
    在Linux的驱动程序中,都会使用大量的outb、outw、inb、inw等等宏来访问硬件或寄存器。这些宏的定义都在相应处理器体系下的include\asm目录下的io.h中定义。追究下去,这些宏最终就是一个volatile变量的的赋值:
 
#define __arch_putb(v,a)      (*(volatile unsigned char *)(a) = (v))
#define __raw_writeb(v,a)     __arch_putb(v,a)
#define outb(v,p)             __raw_writeb(v,__io(p))
 
    在(*(volatile unsigned char *)(a) = (v))中,a是一个物理地址(实地址,多数是特殊功能寄存器地址)。(volatile unsigned char *)对a进行类型转换,成为一个指向该地址指针,最后*(volatile unsigned char *)(a)引用该指针对该地址赋值v。这样就可以达到访问底层硬件的目的了。
    应用程序中定义的变量都是经过优化的,即在运行的时候变量会暂存在CPU的Cache中。CPU修改该变量都是修改Cache中的值,而不会更新内存中的值。直到任务的切换或Cache失效,Cache中的值才会更新到内存中。这样访问硬件是没有时效性的,即有可能程序对硬件操作了多次后,实际才对硬件操作一次。而驱动程序必须要求每次操作都要对硬件起作用。所以,如果要访问硬件就必须避免编译器对其操作进行优化,使得CPU对硬件的操作不经过Cache而直接访问目标。用volatile声明一个变量就可以达到这个目的。     
    volatile关键字是一种类型修饰符,用它声明的变量表示可能被未知的因素(如:硬件等)更改。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。     
    (*(volatile unsigned char *)(a) = (v))访问的并不一定是实际的物理地址,可能是经过内存管理重新映射后的地址,也就是虚拟地址。只不过volatile是使变量访问不经过Cache优化。
 
阅读(830) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~