June 29, 2012 / Driver, Linux, PCI, Reading Note

简介 本章给出一个高层总线架构的综述 讨论重点是用于访问Peripheral Component Interconnect(PCI,外围设备互联)外设的内核函数 PCI总线是内核中得到最好支持的总线 本章主要介绍PCI驱动程序如果寻找其硬件和获得对它的访问 本章也会介绍ISA总线 PCI接口 PCI是一组完整的规范,定义了计算机的各个不同部分之间应该如何交互 PCI规范涵盖了与计算机接口相关的大部分问题 PCI架构被设计为ISA标准的替代品,有三个主要目标 获得在计算机和外设之间传输数据时更好的性能 通过使用比ISA更高的时钟频率,PCI总线获得了更好的性能,它的时钟频率一般是25或者33MHz(实际的频率是系统时钟的系数),最新的实现达到了66MHz甚至133MHz 配备了32位的数据总线,而且规范已经包括了64位的扩展 尽可能的平台无关性 简化往系统中添加和删除外设的工作 PCI设备是无跳线设备,可以引导阶段自动配置 * 每个PCI外设由一个总线编号、一个设备编号及一个功能编号来标识 * PCI规范允许单个系统拥有高达256个总线,但是256个总线对于许多大型系统而言是不够的,因此,Linux目前支持PCI域 * 每个PCI域可以拥有最多256个总线 * 每个总线上可支持32个设备,每个设备可以是多功能板,最多可有八种功能 * 每种功能都可以在硬件级由一个16位的地址来标识 * 为Linux编写的设备驱动程序可以使用一种特殊的数据结构(pci_dev)来访问设备 * 当前的工作站一般配置有至少两个PCI总线,在单个系统中插入多个总线,可通过桥(bridge)来完成,它是用来连接两个总线的特殊PCI外设 * PCI系统的整体布局组织为树型,其中每个总线连接到上一线总线,直到树根的0号总线 * lspci * proc/pci * /proc/bus/pci/ * 查看PCI设备清单和设备的配置寄存器 * /sys/bus/pci/devices * 每个外设板的硬件电路对如下三种地址空间的查询进行应答 * 内存位置 * I/O端口 * 配置寄存器 * 前两种地址空间由同一PCI总线上的所有设备共享 * 配置空间利用了地理寻址 * 配置查询每次只对一个槽寻址 *

read more »
June 27, 2012 / Data Types, Driver, Kernel, Linux, Reading Note

简介 由于Linux的多平台特性,任何一个重要的驱动程序都应该是可移植的 与内核代码相关的核心问题是应该能够同时访问已知长度的数据项,并充分利用不同处理器的能力 内核使用的数据类型主要被分成三类 类似int这样的标准C语言类型 类似u32这样的有确定大小的类型 像pid_t这样的用于特定内核对象的类型 本章将讨论在什么情况下使用这三种类型以及如何使用 使用标准C语言类型 当我们需要“两个字节的填充符”或者“用四个字节字符串表示的某个东西”时,我们不能使用标准类型,因为在不同的体系架构上,普通C语言的数据类型所占空间在大小并不相同 内核中的普通内存地址通常是unsigned long,在当前Linux支持的所有平台上,指针和long整形的大小总是相同的 C99标准定义了intptr_t和uintptr_t类型,它们是能够保存指针值的整形变量 为数据项分配确定的空间大小 <asm/types.h> <linux/types.h> u8, s8 u16, s16 u32, s32 u64, s64 如果一个用户空间程序需要使用这些类型,它可以在名字前加上两个下划线作为前缀 __u8 __u32 使用新编译器的系统将支持C99标准类型,如uint8_t和uint32_t 接口特定的类型 内核中最常用的数据类型由它们自己的typedef声明,这样可以防止出现任何移植性问题 “接口特定(interface-specific)”是指由某个库定义的一种数据类型,以便为某个特定的数据结构提供接口 完整的_t类型在<linux/types.h>中定义 _t数据项的主要问题是在我们需要打印它们的时候,不太容易选择正确的printk或者printf的输出格式 其他有关移植的问题 一个通用的原则是要避免使用显式的常量值 时间间隔 使用jiffies计算时间间隔的时候,应该用HZ来衡量 页大小 内存页的大小是PAGE_SIZE字节 PAGE_SHIFT <asm/page.h> getpagesize库函数 get_order函数 字节序 <asm/byteorder.h> __BIG_ENDIAN __LITTLE_ENDIAN u32 cpu_to_le32 (u32); u32 le32_to_cpu(u32); be64_to_cpu le16_to_cpus cpu_to_le32p 数据对齐 <asm/unaligned.h> get_unaligned(ptr); put_unaligned(val,

read more »
June 27, 2012 / Driver, Interrupt, Linux, Reading Note

简介 通常,很多设备的处理速度要比处理器慢得多,为了不让处理器一直等待外部事件,可以采用中断来让设备在产生事件时通知处理器 中断仅仅是一个信号,由硬件发出 准备并口 在没有节设定产生中断之前,并口是不会产生中断的 并口的标准规定设置端口2(px37a、0x27a或者其它端口)的第4位将启用中断报告,0x10 当处于启用中断状态,每当引脚10的电平发生从低到高改变时,并口就会产生一个中断 引脚9是并口数据字节中的最高位 安装中断处理例程 中断信号线是非常珍贵且有限的资源 内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表 模块在使用中断前要先请求一个中断通道,然后在使用后释放该通道 <linux/sched.h> int request_irq(unsigned int irq, irqreturn_t (handler) (int, void , struct pt_regs ), unsigned long flags, const char dev_name, void *dev_id); 返回0表示申请成功 flags SA_INTERRUPT 表明这是一个“快速”的中断处理例程 SA_SHIRQ 表示中断可以在设备之间共享 SA_SAMPLE_RANDOM 指出产生的中断能对/dev/random设备和/dev/urandom设备使用的熵池(entropy pool)有贡献 void free_irq(unsigned int irq, void *dev_id); int can_request_irq(unsigned int irq, unsigned long flags); 使用request_irq的正确位置应该是在设备第一次打开、硬件被告知产生中断之前 调用free_irq的位置是最后一次关闭设备、硬件被告知不用再中断处理器之后 /proc接口 /proc/interrupts 不依赖体系结构

read more »

简介 本章主要介绍对设备提供I/O访问的方法和函数,用于从设备读取数据或将数据写入到设备 主要的方法有I/O端口和I/O内存 I/O端口和I/O内存 每种外设都通过读写寄存器进行控制 在硬件层,内存区域和I/O区域没有概念上的区别:它们都通过向地址总线和控制总线发送电平信号进行访问,再通过数据总线读写数据 I/O寄存器和常规内存 I/O寄存器和RAM的最主要区别就是I/O操作具有边际效应,而内存操作则没有 内存写操作的唯一结果就是在指定位置存储一个数值 内存读操作则仅仅返回指定位置最后一次写入的数值 由硬件自身缓存引起的问题很好解决:只要把底层硬件配置成在访问I/O区域时禁止硬件缓存即可 由编译器优化和硬件重新排序引起的问题的解决办法是:对硬件必须以特定顺序执行的操作之间设置内存屏障 Linux提供了4个宏来解决所有可能的排序问题 <linux/kernel.h> void barrier(void); <asm/system.h> void rmb(void); void read_barrier_depends(void); void wmb(void); void mb(void); void smp_rmb(void); void smp_read_barrier_depends(void); void smp_wmb(void); void smp_mb(void); 因为内存屏障会影响系统性能,所以应该只用于真正需要的地方 使用I/O端口 I/O端口是驱动程序与许多设备之间的通信方式 I/O端口分配 <linux/ioport.h> struct resource request_region(unsigned long first, unsigned long n, const char name); void release_region(unsigned long start, unsigned long n); int check_region(unsigned long

read more »

kmalloc函数的内幕 不对所获取的内存空间清零 分配的区域在物理内存中也是连续的 flags参数 <linux/slab.h> <linux/gfp.h> GFP_KERNEL 在空闲内存较少时把当前进程转入休眠以等待一个页面 分配内存的函数必须是可重入的 GFP_ATOMIC 用于在中断处理例程或其他运行于进程上下文之外的代码中分配内存,不会休眠 GFP_USER 用于为用户空间页分配内存,可能会休眠 GFP_HIGHUSER 类似于GFP_USER,不过如果有高端内存的话就从那里分配 GFP_NOIO, GFP_NOFS 这两个标志的功能类似于GFP_KERNEL,但是为内核分配内存的工作方式添加了一些限制。具有GFP_NOFS标志的分配不允许执行任何文件系统调用,而GFP_NOIO禁止任何I/O的初始化。这两个标志主要在文件系统和虚拟内存代码中使用,这些代码中的内存分配可休眠,但不应该发生递归的文件系统调用 __GFP_DMA 该标志请求分配发生在可进行DMA的内存区段中 __GFP_HIGHHEM 这个标志表明要分配的内存可位于高端内存 __GFP_COLD 这个标志请求尚未使用的“冷”页面,对于DMA读取的页面分配,可使用这个标志 __GFP_NOWARN 很少使用,可以避免内核在无法满足分配请求时产生警告 __GFP_HIGH 标记了一个高优先级的请求,它允许为紧急善而消耗由内核保留的最后一些页面 __GFP_REPEAT, __GFP_NOFAIL, __GFP_NORETRY 告诉分配器在满足分配请求而遇到困难时应该采取何种行为 __GFP_REPEAT表示“努力再尝试一次”,它会重新尝试分配,但仍有可能失效 __GFP_NOFAIL标志告诉分配器始终不返回失败,它会努力满足分配请求,不鼓励使用这个标志 __GFP_NORETRY告诉分配器,如果所请求的内存不可获得,就立即返回 内存区段 __GFP_DMA和__GFP_HIGHHEM的使用与平台相关 Linux内核把内存分为三个区段:可用于DMA的内存、常规内存以及高端内存 可用于DMA的内存指存在于特别地址范围内的内存,外设可以利用这些内存执行DMA访问 高端内存是32位平台为了访问大量的内存而存在的一种机制 如果没有指定特定的标志,则kmalloc会在常规区段和DMA区段搜索 如果设置了__GFP_HIGHHEM标志,则所有三个区段都会被搜索 内存区段的背后机制在mm/page_alloc.c中实现 size参数 Linux处理内存分配的方法是,创建一系列的内存对象池,每个池中的内存块大小是固定一致的。处理分配请求时,就直接在包含有足够大的内存块的池中传递一个整块给请求者 kmalloc能处理的最小的内存块是32或者64 如果希望代码具有完整的可移植性,则不应该分配大于128KB的内存 后备高速缓存 Linux内核的调整缓存管理有时称为“slab分配器” slag分配器实现的高速缓存具有kmem_cache_t类型 kmem_cache_t kem_cache_create(const char name, size_t size, size_t offset, unsigned

read more »
June 23, 2012 / 学习, 工作, 生活, 研究生

转瞬间,时间又被吞噬了三个月,刚好这几天放假,回顾一下这三个月做了什么,看有没什么进步。 小记: 坚持记录每天的时间和金钱开销,让这两样东西变得可控,坚持把小事做好也是一件不容易的事情 将学习的内容和技术上遇到的问题发表到博客上,加强写作能力 学习HDFS源码,目前看完datanode源码,想看namenode和client源码,由于有别的事情要做,只能往后搁了 感冒一次,萎了将近一个月,上个月底又感冒了,萎到现在,觉得是自己把身子给搞垮了,从小不爱运动,体质比较虚,去年下半年为了学习,竟然是通过牺牲睡眠时间而不是提高效率来达到更好的学习效果,现在感觉好虚,跟高三时的感觉很相似,还是要注意休息和锻炼 学习普通话,普通话说不好主要原因有二:不管是潮汕话还是粤语,跟普通话的发音差得比较大,像翘舌、前鼻后鼻分不清;我从初中开始使用电脑时就学五笔,平时又少说话,一直记不住拼音。虽说三个月前整理了一些我容易混淆的拼音,但平时也看得少,似乎还没对我有什么帮助。普通话中带着家乡的味道是一特色,不懂得尊重他人文化的人爱取笑就取笑呗。 把网站和博客搬到香港的主机,访问速度变快,但现在香港没有Economy plan,明年还得找新的主机。博客的主题换了,做了SEO,多处地方也作了细微的调整,算是为找工作做准备吧 想练写字,事情太多,没坚持下去 习惯左手用鼠标 愚人节搞了一次恶作剧 学习自由泳,还没上道 新增jeoyg.in域名 做TopCoder,rating上下波动,不太稳定 实验室玉渡山春游 五一放假看车展 学习emacs,挺有意思的,有人说lisp和c是两个不同的极端 渐渐领会到慢的真谛 北大校赛 TCO,不过弱爆了,止于Round 2 Google Code Jam,不过弱爆了,止于Round 2 百度之星,不过弱爆了,止于复赛 学习使用git 练习朗读,中文和英文 英语感觉有进步,但不是很明显 发现英语能力有限不是词汇量或语法的问题,而是在语言方面的听说读写能力都成问题,中文英文都是,现在的记性已不如10年前,记不住那么多东西了 感觉我有强迫症,事情要么不做,要么就做到最好 慢慢地知道什么事情可以不做,什么事情我应该拒绝,时间和精力有限,不可能什么事情都做,不然只会把自己弄得很疲惫 目标日渐清晰,也慢慢地知道要怎么做,虽然晚了些年 看《设计模式》、《学会提问——批判性思维指南》、《Effective Java》等书 早睡早起 坚持运动 经过了这三月,我更加坚定以我现在的水平只能去找工作了,英语、表达、写作能力和眼界都达不到可以继续深造的程度,我还是先到社会中去锤炼,不断地调整自己的目标和步伐,最后能使自己的目标和能力相匹配。 据说8月就开始有内推,身边的很多人都已经为找工作做了挺长时间的准备,我也应该开始了吧,看书、coding、做面试题等等,暂定去互联网公司吧,不想太折腾,如果有给力的offer就不想再找了。如果要投外企,还要练口语,这是个很大的问题。 奋斗吧!

read more »
June 21, 2012 / Driver, Latency, Linux, Reading Note, time, Timer

度量时间差 内核通过定时器中断来跟踪时间流 时钟中断由系统定时硬件以周期性的间隔产生,这个间隔由内核根据HZ的值设定,在常见的x86 PC平台上,默认定义为1000 <linux/param.h> <linux/timex.h> jiffies_64 unsigned long jiffies 使用jiffies计数器 <linux/jiffies.h> int time_after(unsigned long a, unsigned long b); int time_before(unsigned long a, unsigned long b); int time_after_eq(unsigned long a, unsigned long b); int time_before_eq(unsigned long a, unsigned long b); 通常只需要包含<linux/sched.h> diff = (long)t2 -(long)t1 msec = diff * 1000 / HZ <linux/times.h unsigned long timespec_to_jiffies(struct timespec *value); void jiffies_to_timespec(unsigned

read more »

ioctl 支持的操作 简单数据传输 用户空间请求设备锁门 弹出介质 报告错误信息 改变波特率 执行自破坏 int ioctl(int fd, unsigned long cmd, …); 每个ioctl命令就是一个独立的系统调用,而且是非公开的 驱动程序的ioctl方法原型 int (ioctl) (struct inode inode, struct file *filp, unsigned int cmd, unsigned long arg); 选择ioctl命令 为方便程序员创建唯一的ioctl命令号,每一个命令号被分为多个位字段 Linux内核的约定方法为驱动程序选择ioctl编号 include/asm/ioctl.h 定义了要使用的位字段 类型(幻数) 序数 传送方向 参数大小 Documentation/ioctl-number.txt 罗列了内核所使用的幻数 <linux/ioctl.h> type 幻数,这个字段有8位宽(_IOC_TYPEBITS) number 序数,8位宽(_IOC_NRBITS) direction _IOC_NONE(没有数据传输) _IOC_READ _IOC_WRITE _IOC_READ | _IOC_WRITE(双向传输数据) size 所涉及的用户数据大小 通常是13位或14位 _IOC_SIZEBITS <asm/ioctl.h> _IO(type,

read more »
June 20, 2012 / extract, freemind, layer structure, xmind

自从接触了思维导图工具后,真心觉得这工具不错,做报告或是读书,用上它可以使思维更加清晰。对此类工具进行一番调研之后,选择了xmind,xmind是用java开发的,具有跨平台性,在Linux和Windows平台都能使用,其专业版是要收费的,不过免费版本的功能已足够使用了。 最近在看《Linux设备驱动》,主要使用xmind来做笔记,用来回顾已学过的知识很方便,但当我想把记录的内容发表到博客上时,就比较费力了,因为xmind导出的文本是没有层级结构的,这样的内容发表出来对读者来说是很困惑的。因为我的博客使用了“MediaWiki Markup for WordPress”这个插件,可以使用一部分wiki语法来写文章,相比用html标记简单高效,比如说我要使用符号列表,那么可以使用以下的语法: **二级 ***三级 ****四级 *又回到了一级 **二级 最后的显示效果就是: 一级 二级 三级 四级 又回到了一级 二级 那么如果我能知道xmind中内容的层级结构的话,只需要在每一条记录前加上相应数目的*号,就可以直接发表到博客上。 一开始,傻傻地手动地边看xmind边在每一条记录前加上相应数据的*号,最后发现这样很浪费时间,作为程序员,我们有责任让这种手工劳动变成自动化,于是开始想方设法来达到这一目标。 不断地进行,当发现用xmind导出成FreeMind格式的文件是个xml时,我顿时找到了希望,因为xml文件本身就是一种层级结构的格式。很快就想到dom4j,于是开始动手写代码,代码很简短,稍加调试就达成预期的目的。代码如下所示: * Copyright (c) 2012 by Institute of Computing Technology, * Chinese Academic of Sciences, Beijing, China. * ========================================================================== * file : Extracter.java * author: Jeoygin Wang * * last change: date: 6/20/12 6:56 PM * by: Jeoygin Wang *

read more »
June 20, 2012 / cedet, ecb, emacs, jdee

刚升级了一下我的arch,emacs由23升级到了24,升级后发现很多插件出问题了,包括cedet、ecb和jdee等,在Google搜了一小时,终于把问题给解决了。下面就把解决的方法分享出来,希望对大家有所帮助。 1. cedet 这个问题比较好解决,升级到1.1就能和emacs 24兼容。 2. ecb ecb已多年没更新了,最新的ecb-2.40只兼容cedet版本 1.0.6pre ~ 1.0.9,解决的方法是修改/path/to/ecb-2.40/ecb-upgrade.el,将1146行的 改为 这样就OK了。 3. jdee 问题之一也是jdee不兼容cedet 1.1,解决方法同ecb,修改支持的最大版本号,修改/path/to/jdee-2.4.0.1/lisp/jde.el文件,将43行的 修改为 然后删除/path/to/jdee-2.4.0.1/lisp/jde.elc,如果想编译jde.elc,可以打开emacs,输入M-x byte-compile-file,文件是/path/to/jdee-2.4.0.1/lisp/jde.el,如果编译成功就会生成jde.elc。 另外的问题是jdee使用了emacs 24不再支持的函数,解决方法是在~/.emacs文件中添加以下内容: (define-obsolete-function-alias 'make-local-hook 'ignore "21.1") 4. done 完成以上三步就大功告成,又可以使用emacs来写java程序了。 如果有问题,欢迎批评指正。 5. 参考资料

    Emacs24+cedet+ecb+jdee配置时出现的若干问题 installing JDEE and CEDET with Emacs 24

    read more »

« Newer Entries  
Older Entries »