基于Linux内核的键盘模拟实现

基于Linux内核的键盘模拟实现
基于Linux内核的键盘模拟实现

基于Linux内核的键盘模拟实现

摘摘要:当前,由于Linux资源完全公开,使得Linux 的发展日益广泛快速。基于Linux的各种应用已逐渐深入日常生活的方方面面,尤其是在嵌入式领域,由于内核可裁减定制,因此可随意地根据用户需求进行整个系统的定制与重构。其中,我们可以通过对各种标准外部设备的驱动进行改造,从而实现用户对标准设备的特定需求,例如可以通过对键盘的模拟来实现操作的自动化,从而可以避免重复的键盘操作。

关键词:系统调用勾子函数键盘模拟

1Linux内核支持的外部调用接口

由于Linux内核作为系统最深层次的核心,因此外部的开发人员并不能直接对内核进行操作。然而在一些应用程序的开发过程中,又不得不使用内核的某些功能,因此就提供了一些外部接口供开发人员直接与底层内核打交道。

1.1中断

在Linux 下,硬件中断叫做IRQ(Interrupt Requests)。有两种IRQ,短类型和长类型。短IRQ需要很短的时间,在此

期间机器的其他部分被锁定,而且没有其他中断被处理。一个长IRQ需要较长的时间,在此期间可能发生其他中断(但不是发自同一个设备)。如果可能的话,最好把一个中段声明为长类型。如果CPU接到一个中断,它就会停止一切工作(除非它正在处理一个更重要的中断,在这种情况下要等到更重要的中断处理结束后才会处理这个中断),把相关的参数存储到栈里,然后调用中断处理程序。这意味着在中断处理程序本身中有些事情是不允许的,因为这时系统处在一个未知状态。解决这个问题的方法是让中断处理程序做需要马上做的事,通常是从硬件读取信息或给硬件发送信息,然后把对新信息的处理调度到以后去做。

实现的方法是在接到相关的IRQ(在Intel平台上有16个IRQ)时调用中断处理程序。这个函数接到IRQ号码、函数名、标志、一个/proc/interrupts的名字和传给中断处理程序的一个参数。标志中可以包括SA_SHIRQ来表明你希望和其他处理程序共享此IRQ(通常很多设备公用一个IRQ),或者一个SA_INTERRUPT表明这是一个紧急中断。这个函数仅在此IRQ 没有其他处理程序或需要共享所有处理程序时才会成功运行。

1.2系统调用

系统调用发生在用户进程,通过一些特殊的函数来请求

内核提供服务。这时,用户进程被挂起,内核验证用户请求,尝试执行并把结果反馈给用户进程,接着用户进程重新启动。一般当前系统的系统调用作为一张表sys_call_table进行定义的,是由指向实现各种系统调用的内核函数的函数指针组成的表。具体参数参见Linux内核源代码

arch/i386/kernel/entry.S文件中。

1.3钩子函数

钩子(HOOK)是Linux系统中非常重要的系统接口,用它

可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。钩子可以监视系统或进程中的各种事件消息,截获发往目标的消息并进行处理。这样就可以在系统中安装自定义的钩子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。可见,利用钩子可以实现许多特殊而有用的功能。

2键盘工作机理

CPU对外部设备的管理是通过中断程序进行的,键盘也是一种外部设备,因此,CPU对键盘的管理也是通过中断进行的。当你击打键盘的时候,键盘控制器会向CPU提出中断申请,CPU响应此中断进行处理,这就完成了一次很简单与

人之间通过键盘进行的交互。

首先,当输入一个键盘值的时候,键盘将会发送相应的scancodes给键盘驱动。一个独立的击键可以产生一个六个scancodes的队列。键盘驱动中的handle_ scancode()函数解析scancodes流并通过kdb_translate()函数里的转换表(translation-table)将击键事件和键的释放事件(key release events)转换成连续的keycode。例如,'a'的keycode是30。击键'a'的时候便会产生keycode 30。释放a键的时候会产生keycode 158(128+30)。

然后,这些keycode通过对keymap的查询被转换成相应key符号。获得的字符被送入raw tty队列-tty_flip_buffer。receive_buf()函数周期性的从tty_flip_buffer中获得字符,然后把这些字符送入tty read队列。

当用户进程需要得到用户的输入的时候,它会在进程的标准输入(stdin)调用read()函数。sys_read()函数调用定义在相应的tty设备(如/dev/tty0)的file_operations结构中指向

tty_read的read()函数来读取字符并且返回给用户进程。

3键盘模拟的实现

通常情况下,对键盘模拟的实现一般是通过写一个自己的键盘中断句柄来实现,但这种方法容易导致系统崩溃。因此,在这种方法的基础上可以利用勾子函数来实现。

如附图所示,这里主要用到的勾子函数包括handle_ scancode(),put_queue(),receive_buf(),tty_read()和sys_read()等函数。

3.1handle_scancode函数

handle_scancode函数是键盘驱动程序中的一个入口函

数(参见文件/usr/src/linux/drives/char/keyboard.c):

void handle_scancode(unsigned char scancode, int down);

这里通过替换原始的handle_scancode()函数来实现纪录所有的scancode。即将原始的值保存,把新的值注册进去,从而实现所需要的功能,最后再调用回到原始值的情况下。当此新的功能函数完成后,我们就可以记录下键盘上的正确的击键行为了(其中可以包括一些特殊的key,如ctrl,alt,shift,print screen等等)。

3.2put_queue函数

handle_scancode()函数会调用put_queue函数,用来将字符放入tty_queue。

put_queue函数在内核中定义如下:void put_queue(int ch){wake_up(&keypress_wait);if (tty) {tty_insert_flip_char(tty, ch, 0);

con_schedule_flip(tty);}}

3.3receive_buf函数

底层tty驱动调用receive_buf()这个函数用来发送硬件设备接收处理的字符。参见

/usr/src/linux/drivers/char/n_tty.c:static void

n_tty_receive_buf(struct tty_struct *tty, const unsigned char

*cp, char *fp, int count)

参数cp是一个指向设备接收的输入字符的buffer的指针。参数fp是一个指向一个标记字节指针的指针。在具体的实现中,先保存原始的tty receive_buf()函数,然后重置

ldisc.receive_buf到自定义的new_receive_buf()函数来记录用户的输入。

3.4tty_read函数

当一个进程需要通过sys_read()函数来读取一个tty终端的输入字符时,tty_read函数就会被调用。参见文件

/usr/src/linux/drives/char/tty_io.c:static ssize_t tty_read(struct file * file, char * buf, size_t count, loff_t *ppos)

目前,利用勾子函数实现基于Linux内核的键盘模拟的这种方法使用非常灵活,同时也可以跨平台进行移植,可通过tty和pts来记录下本地和远程会话的所有击键动作,并且也支持一些特殊的按键。当然,要使键盘模拟更灵活,下一步还需要更多的改进,例如增加多种不同日志记录模式的支持等。□

关于Linux 内核中五个主要子系统的介绍

关于Linux 内核中五个主要子系统的介绍 发布时间:2008.01.02 06:23来源:赛迪网作者:sixth 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

linux驱动程序的编写

linux驱动程序的编写 一、实验目的 1.掌握linux驱动程序的编写方法 2.掌握驱动程序动态模块的调试方法 3.掌握驱动程序填加到内核的方法 二、实验内容 1. 学习linux驱动程序的编写流程 2. 学习驱动程序动态模块的调试方法 3. 学习驱动程序填加到内核的流程 三、实验设备 PentiumII以上的PC机,LINUX操作系统,EL-ARM860实验箱 四、linux的驱动程序的编写 嵌入式应用对成本和实时性比较敏感,而对linux的应用主要体现在对硬件的驱动程序的编写和上层应用程序的开发上。 嵌入式linux驱动程序的基本结构和标准Linux的结构基本一致,也支持模块化模式,所以,大部分驱动程序编成模块化形式,而且,要求可以在不同的体系结构上安装。linux是可以支持模块化模式的,但由于嵌入式应用是针对具体的应用,所以,一般不采用该模式,而是把驱动程序直接编译进内核之中。但是这种模式是调试驱动模块的极佳方法。 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。同时,设备驱动程序是内核的一部分,它完成以下的功能:对设备初始化和释放;把数据从内核传送到硬件和从硬件读取数据;读取应用程序传送给设备文件的数据和回送应用程序请求的数据;检测和处理设备出现的错误。在linux操作系统下有字符设备和块设备,网络设备三类主要的设备文件类型。 字符设备和块设备的主要区别是:在对字符设备发出读写请求时,实际的硬件I/O一般就紧接着发生了;块设备利用一块系统内存作为缓冲区,当用户进程对设备请求满足用户要求时,就返回请求的数据。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。 1 字符设备驱动结构 Linux字符设备驱动的关键数据结构是cdev和file_operations结构体。

探究linux内核,超详细解析子系统

探究linux内核,超详细解析子系统 Perface 前面已经写过一篇《嵌入式linux内核的五个子系统》,概括性比较强,也比较简略,现在对其进行补充说明。 仅留此笔记,待日后查看及补充!Linux内核的子系统 内核是操作系统的核心。Linux内核提供很多基本功能,如虚拟内存、多任务、共享库、需求加载、共享写时拷贝(Copy-On-Write)以及网络功能等。增加各种不同功能导致内核代码不断增加。 Linux内核把不同功能分成不同的子系统的方法,通过一种整体的结构把各种功能集合在一起,提高了工作效率。同时还提供动态加载模块的方式,为动态修改内核功能提供了灵活性。系统调用接口用户程序通过软件中断后,调用系统内核提供的功能,这个在用户空间和内核提供的服务之间的接口称为系统调用。系统调用是Linux内核提供的,用户空间无法直接使用系统调用。在用户进程使用系统调用必须跨越应用程序和内核的界限。Linux内核向用户提供了统一的系统调用接口,但是在不同处理器上系统调用的方法

各不相同。Linux内核提供了大量的系统调用,现在从系统 调用的基本原理出发探究Linux系统调用的方法。这是在一个用户进程中通过GNU C库进行的系统调用示意图,系 统调用通过同一个入口点传入内核。以i386体系结构为例,约定使用EAX寄存器标记系统调用。 当加载了系统C库调用的索引和参数时,就会调用0x80软件中断,它将执行system_call函数,这个函数按照EAX 寄存器内容的标示处理所有的系统调用。经过几个单元测试,会使用EAX寄存器的内容的索引查system_call_table表得到系统调用的入口,然后执行系统调用。从系统调用返回后,最终执行system_exit,并调用resume_userspace函数返回用户空间。 linux内核系统调用的核心是系统多路分解表。最终通过EAX寄存器的系统调用标识和索引值从对应的系统调用表 中查出对应系统调用的入口地址,然后执行系统调用。 linux系统调用并不单层的调用关系,有的系统调用会由

如何安装Linux内核源代码

如何获取Linux内核源代码 下载Linux内核当然要去官方网站了,网站提供了两种文件下载,一种是完整的Linux 内核,另一种是内核增量补丁,它们都是tar归档压缩包。除非你有特别的原因需要使用旧版本的Linux内核,否则你应该总是升级到最新版本。 使用Git 由Linus领头的内核开发队伍从几年前就开始使用Git版本控制系统管理Linux内核了(参考阅读:什么是Git?),而Git项目本身也是由Linus创建的,它和传统的CVS不一样,Git是分布式的,因此它的用法和工作流程很多开发人员可能会感到很陌生,但我强烈建议使用Git下载和管理Linux内核源代码。 你可以使用下面的Git命令获取Linus内核代码树的最新“推送”版本: $ git clone git://https://www.360docs.net/doc/9917992693.html,/pub/scm/linux/kernel/git/torvalds/linux-2.6.git 然后使用下面的命令将你的代码树与Linus的代码树最新状态同步: $ git pull 安装内核源代码 内核包有GNU zip(gzip)和bzip2格式。Bzip2是默认和首选格式,因为它的压缩比通常比gzip更好,bzip2格式的Linux内核包一般采用linux-x.y.z.tar.bz2形式的文件名,这里的x.y.z是内核源代码的具体版本号,下载到源代码包后,解压和抽取就很简单了,如果你下载的是bzip2包,运行: $ tar xvjf linux-x.y.z.tar.bz2 如果你下载的是gzip包,则运行: $ tar xvzf linux-x.y.z.tar.gz 无论执行上面哪一个命令,最后都会将源代码解压和抽取到linux-x.y.z目录下,如果你使用Git下载和管理内核源代码,你不需要下载tar包,只需要运行git clone命令,它就会自动下载和解压。 内核源代码通常都会安装到/usr/src/linux下,但在开发的时候最好不要使用这个源代码树,因为针对你的C库编译的内核版本通常也链接到这里的。 应用补丁

简析linux内核的内核执行流程图

简析linux核的执行流程 ----从bootsect.s到main.c(核版本0.11)Linux启动的第一阶段(从开机到main.c) 3个任务: A、启动BIOS,准备实模式下的中断向量表和中断服务程序。 B、从启动盘加载操作系统程序到存。 C、为执行32的main函数做过渡准备。 存变化如下: ①、0xFE000到0xFFFFF是BIOS启动块,其中上电后第一条指令在0xFFFF0。 ②、而后0x00000到0x003FF总共1KB存放中断向量表,而接下去的地址到0x004FF共256B存放BIOS数据,从0x0E05B 开始的约8KB的存中存放中断服务程序。 ③、利用BIOS中断0x19h把硬盘的第一扇区bootsect.s的代码加载到存中,即0x07c00处,后转到该处执行。 ④、将bootsect.s的代码复制到0x90000处。 ⑤、利用中断0x13h将setup.s程序加载到存0x90200处。 ⑥、再将剩余的约240个扇区的容加载到0x10000~0x2EFFF 处。 ⑦、开始转到setup.s处执行,第一件事就利用BIOS提供的中断服务程序从设备上获取核运行的所需系统数据并存在0x90000的地址处,这时将原来bootsect.s的代码覆盖得只剩2Byte的空间。

⑧、关中断并将系统代码复制到0x00000处,将原来放在这里的中断向量表与BIOS数据区覆盖掉,地址围是 0x00000~0x1EFFF。同时制作两表与两寄存器。 ⑨开地址线A20,寻址空间达到4GB,后对8259重新编程,改变中断号。 ⑩、转到head.s(大小是25K+184B)执行,执行该程序完后是这样的: 0x00000~0x04FFF:页目录与4个页表,每一项是4KB,共20KB;0x05000~0x05400:共1KB的空间是软盘缓冲区; 0x05401~0x054b8:共184B没用; 0x054b9~0x05cb8:共2KB的空间存中断描述符表; 0x05cb9~0x064b8:共2KB的空间存全局描述符表; 之后就是main函数的代码了! 第二阶段、从main.c函数到系统准备完毕阶段。 第一步:创建进程0,并让进程0具备在32位保护模式下载主机中的运算能力。流程是: 复制根设备和硬盘参数表(main.c中的102、110、111行) 物理存规划格局(main.c的112行~126行,其中有 rd_init函数定义在kernel/ramdisk.c中,此函数用于虚拟盘初始化;而mem_init函数是用于存管理结构初始化,定义在mem/memory.c中,该函数页面使用

LINUX字符设备驱动编写基本流程

---简介 Linux下的MISC简单字符设备驱动虽然使用简单,但却不灵活。 只能建立主设备号为10的设备文件。字符设备比较容易理解,同时也能够满足大多数简 单的硬件设备,字符设备通过文件系统中的名字来读取。这些名字就是文件系统中的特 殊文件或者称为设备文件、文件系统的简单结点,一般位于/dev/目录下使用ls进行查 看会显示以C开头证明这是字符设备文件crw--w---- 1 root tty 4, 0 4月 14 11:05 tty0。 第一个数字是主设备号,第二个数字是次设备号。 ---分配和释放设备编号 1)在建立字符设备驱动时首先要获取设备号,为此目的的必要的函数是 register_chrdev_region,在linux/fs.h中声明:int register_chrdev_region(dev_t first, unsigned int count, char *name);first是你想 要分配的起始设备编号,first的次编号通常是0,count是你请求的连续设备编号的 总数。count如果太大会溢出到下一个主设备号中。name是设备的名字,他会出现在 /proc/devices 和sysfs中。操作成功返回0,如果失败会返回一个负的错误码。 2)如果明确知道设备号可用那么上一个方法可行,否则我们可以使用内核动态分配的设 备号int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);dev是个只输出的参数,firstminor请求的第一个要用的次编号, count和name的作用如上1)对于新驱动,最好的方法是进行动态分配 3)释放设备号,void unregister_chrdev_region(dev_t first unsigned int count); ---文件操作file_operations结构体,内部连接了多个设备具体操作函数。该变量内部 的函数指针指向驱动程序中的具体操作,没有对应动作的指针设置为NULL。 1)fops的第一个成员是struct module *owner 通常都是设置成THIS_MODULE。 linux/module.h中定义的宏。用来在他的操作还在被使用时阻止模块被卸载。 2)loff_t (*llseek) (struct file *, loff_t, int);该方法用以改变文件中的当前读/ 写位置 返回新位置。 3)ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);该函数用 以从设备文件 中读取数据,读取成功返回读取的字节数。

史上最全linux内核配置详解

对于每一个配置选项,用户可以回答"y"、"m"或"n"。其中"y"表示将相应特性的支持或设备驱动程序编译进内核;"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去;"n"表示内核不提供相应特性或驱动程序的支持。只有<>才能选择M 1. General setup(通用选项) [*]Prompt for development and/or incomplete code/drivers,设置界面中显示还在开发或者还没有完成的代码与驱动,最好选上,许多设备都需要它才能配置。 [ ]Cross-compiler tool prefix,交叉编译工具前缀,如果你要使用交叉编译工具的话输入相关前缀。默认不使用。嵌入式linux更不需要。 [ ]Local version - append to kernel release,自定义版本,也就是uname -r可以看到的版本,可以自行修改,没多大意义。 [ ]Automatically append version information to the version string,自动生成版本信息。这个选项会自动探测你的内核并且生成相应的版本,使之不会和原先的重复。这需要Perl的支持。由于在编译的命令make-kpkg 中我们会加入- –append-to-version 选项来生成自定义版本,所以这里选N。 Kernel compression mode (LZMA),选择压缩方式。 [ ]Support for paging of anonymous memory (swap),交换分区支持,也就是虚拟内存支持,嵌入式不需要。 [*]System V IPC,为进程提供通信机制,这将使系统中各进程间有交换信息与保持同步的能力。有些程序只有在选Y的情况下才能运行,所以不用考虑,这里一定要选。 [*]POSIX Message Queues,这是POSIX的消息队列,它同样是一种IPC(进程间通讯)。建议你最好将它选上。 [*]BSD Process Accounting,允许进程访问内核,将账户信息写入文件中,主要包括进程的创建时间/创建者/内存占用等信息。可以选上,无所谓。 [*]BSD Process Accounting version 3 file format,选用的话统计信息将会以新的格式(V3)写入,注意这个格式和以前的v0/v1/v2 格式不兼容,选不选无所谓。 [ ]Export task/process statistics through netlink (EXPERIMENTAL),通过通用的网络输出工作/进程的相应数据,和BSD不同的是,这些数据在进程运行的时候就可以通过相关命令访问。和BSD类似,数据将在进程结束时送入用户空间。如果不清楚,选N(实验阶段功能,下同)。 [ ]Auditing support,审计功能,某些内核模块需要它(SELINUX),如果不知道,不用选。 [ ]RCU Subsystem,一个高性能的锁机制RCU 子系统,不懂不了解,按默认就行。 [ ]Kernel .config support,将.config配置信息保存在内核中,选上它及它的子项使得其它用户能从/proc/ config.gz中得到内核的配置,选上,重新配置内核时可以利用已有配置Enable access to .config through /proc/config.gz,上一项的子项,可以通过/proc/ config.gz访问.config配置,上一个选的话,建议选上。 (16)Kernel log buffer size (16 => 64KB, 17 => 128KB) ,内核日志缓存的大小,使用默认值即可。12 => 4 KB,13 => 8 KB,14 => 16 KB单处理器,15 => 32 KB多处理器,16 => 64 KB,17 => 128 KB。 [ ]Control Group support(有子项),使用默认即可,不清楚可以不选。 Example debug cgroup subsystem,cgroup子系统调试例子 Namespace cgroup subsystem,cgroup子系统命名空间 Device controller for cgroups,cgroups设备控制器

LINUX内核源文件介绍以及头文件介绍

LINUX 内核源文件介绍以及头文件介绍 LINUX 内核源文件介绍以及头文件介绍.txt两人之间的感情就像织毛衣,建立的时候一针一线,小心而漫长,拆除的时候只要轻轻一拉。。。。*******************LINUX 内核(0.11)源文件介绍****************** 1、内核源文件放置目录: | |————boot 系统引导汇编程序目录 | |————fs 文件系统目录 | |————include 头文件目录 | |————init 内核初始化程序目录 | |————kernel 内存进程调度、信号处理、系统调用等程序的目录 | |————lib 内核库函数目录 | |————mm 内存管理程序目录 | |————tools 生成内核Image文件的工具程序目录 | |————Makefile文件 | 2、引导启动程序目录boot 包含3个汇编语言文件,是内核源文件中最先被编译的程序。 功能:当计算机家电时引导内核启动,将内核代码加载到内存中,并完成系统初始化工作。 boot | |————bootsect.s 磁盘引导块程序,编译后会驻留在磁盘的第一个扇区中| |————setup.s 读取机器的硬件配置参数,并把内核模式system移动到适当的内存位置处 |

|————head.s 会被编译连接在system模块的最前部分,主要进行硬件设备的探测配置和内存管理页面的配置工作 | 3、文件系统目录fs 包含17个C语言程序 fs | |——buffer.c 管理高速缓冲区 | |——file_table.c 在0.11仅定义了一个文件句柄(描述符)结构数组 | |——ioctl.c 将引用kernel/chr_dev/tty.c中的函数,实现字符设备的IO 控制功能 | |——exec.c 主要包含一个执行程序函数do_execve() | |——fcntl.c 实现文件I/O控制的系统调用函数 | |——read_write.c 实现文件读/写和定位的三个系统调用函数 | |——stat.c 实现了两个获取文件状态的系统调用函数 | |——open.c 主要包含实现修改文件属性和创建与关闭文件的系统调用函数 | |——char_dev.c 主要包含字符设备读写函数rw_char() | |——pipe.c 包含管道读写函数和创建管道的系统调用函数 | |——file_dev.c 包含基于i节点和描述符结构的文件读写函数。 | |——namei.c 主要包括文件系统中目录名和文件名的操作函数和系统调用函数 | |——block_dev.c 包含块数据读和写函数 | |——inode.c 包含针对文件系统i节点操作的函数 | |——truncate.c 用于在删除文件时释放文件所占用的设备数据空间 | |——bitmap.c 用于处理文件系统中i节点和逻辑数据块的位图 |

Linux内核与跟文件系统的关系

Linux内核与根文件系统的关系 开篇题外话:对于Linux初学者来说,这是一个很纠结的问题,但这也是一个很关键的问题!一语破天机:“尽管内核是Linux 的核心,但文件却是用户与操作系统交互所采用的主要工具。这对Linux 来说尤其如此,这是因为在UNIX 传统中,它使用文件I/O 机制管理硬件 设备和数据文件。” 一.什么是文件系统 文件系统指文件存在的物理空间,linux系统中每个分区都是一个文件系统,都有自己的目 录层次结构。 Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其 中。这种机制有利于用户和操作系统的交互。 每个实际文件系统从操作系统和系统服务中分离出来,它们之间通过一个接口层:虚拟文件系统或VFS来通讯。VFS使得Linux可以支持多个不同的文件系统,每个表示一个VFS 的通用接口。由于软件将Linux 文件系统的所有细节进行了转换,所以Linux核心的其它部分及系统中运行的程序将看到统一的文件系统。Linux 的虚拟文件系统允许用户同时能透明地安装 许多不同的文件系统。 在Linux文件系统中,EXT2文件系统、虚拟文件系统、/proc文件系统是三个具有代表性的 文件系统。 二.什么是根文件系统 根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。 那么根文件系统在系统启动中到底是什么时候挂载的呢?先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后。切换根目录,再挂载具体的根文件系统.根文件系统执行完之后,也就是到了Start_kernel()函数的最后,执行init的进程,也就第一个用户进程。对系统进行各 种初始化的操作。 根文件系统之所以在前面加一个”根“,说明它是加载其它文件系统的”根“,既然是根的话,那么如果没有这个根,其它的文件系统也就没有办法进行加载的。它包含系统引导和使其他文件系统得以挂载(mount)所必要的文件。根文件系统包括Linux启动时所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在Linux挂载分区时Linux 一定会找/etc/fstab这个挂载文件等,根文件系统中还包括了许多的应用程序bin目录等,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。在Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt 目录上,/mnt目录下就有这个分区的各个目录,文件。

Linux kernel内核升级全过程,教你一次成功

序言 由于开发环境需要在linux-2.6内核上进行,于是准备对我的虚拟机上的Linux系统升级。没想到这一弄就花了两天时间( 反复装系统,辛苦啊~~),总算把Linux系统从2.4.20-8内核成功升级到了2.6.18内核。 网上虽然有很多介绍Linux内核升级的文章,不过要么过时,下载链接失效;要么表达不清,不知所云;更可气的是很多 文章在转载过程中命令行都有错误。刚开始我就是在这些“攻略”的指点下来升级的,以致于浪费了很多时间。 现在,费尽周折,升级成功,心情很爽,趁性也来写个“升级攻略”吧!于是特意又在虚拟机上重新安装一个Linux系统 ,再来一次完美的升级,边升级边记录这些步骤,写成一篇Linux内核升级记实录(可不是回忆录啊!),和大家一起分享 ~~! 一、准备工作 首先说明,下面带#号的行都是要输入的命令行,且本文提到的所有命令行都在终端里输入。 启动Linux系统,并用根用户登录,进入终端模式下。 1、查看Linux内核版本 # uname -a 如果屏幕显示的是2.6.x,说明你的已经是2.6的内核,也用不着看下文了,该干什么干什么去吧!~~~如果显示的是 2.4.x,那恭喜你,闯关通过,赶快进行下一步。 2、下载2.6内核源码 下载地址:https://www.360docs.net/doc/9917992693.html,/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2 3、下载内核升级工具 (1)下载module-init-tools-3.2.tar.bz2 https://www.360docs.net/doc/9917992693.html,/pub/linux/utils/kernel/module-init-tools/module-init-tools-3.2.tar.bz2 (2)下载mkinitrd-4.1.18-2.i386.rpm https://www.360docs.net/doc/9917992693.html,/fedora/linux/3/i386/RPMS.core/mkinitrd-4.1.18-2.i386.rpm (3)下载lvm2-2.00.25-1.01.i386.rpm https://www.360docs.net/doc/9917992693.html,/fedora/linux/3/i386/RPMS.core/lvm2-2.00.25-1.01.i386.rpm (4)下载device-mapper-1.00.19-2.i386.rpm https://www.360docs.net/doc/9917992693.html,/fedora/linux/3/i386/RPMS.core/device-mapper-1.00.19-2.i386.rpm (2.6.18内核和这4个升级工具我都有备份,如果以上下载地址失效,请到https://www.360docs.net/doc/9917992693.html,/guestbook留下你的邮箱,我给你发过去)

linux 驱动程序开发

1 什么是驱动 a)裸板驱动 b)有系统驱动linux 将驱动封装了一套框架(每个驱动) c)大量和硬件无关的代码已写好只需要编程实现和硬件相关的代码 d)难点:框架的理解代码的理解 e)需要三方面的知识: i.硬件相关的知识 1.电路原理图 2.芯片的数据手册 3.总线协议rs232 i2c等 ii.内核的知识 1.内核驱动属于内核的一部分,它运行在内核态需要对内核知识有了解 2.内存管理 3.解决竞争状态(如上锁) 4.。。。 iii.驱动框架的知识 1.内核中已经实现了大量硬件驱动完成了驱动的框架编程只需要根据硬 件进行添加 2 搭建linux驱动开发工具 a)安装交叉编译环境 i.arm-linux-gcc uboot PATH b)移植uboot c)移植内核 d)制作根文件系统然后通过nfs方式让开发板可以加载 3 内核驱动开发的基本知识 a)如何学驱动编程? i.最好的老师就是内核源码(没有man 功能) 1.要是用某个函数就去查看某个函数的定义注释 2.查看内核中其他模块儿时如何使用该函数的 3.专业书籍: a)内核开发:linux内核的设计与实现机械工程出版社 b)驱动开发:圣经级别的-LDD3:LINUX DEVICE c)操作性别叫强的:精通linux设备驱动程序开发

关于linux内核: 1)linux内核中所使用的函数都是自身实现的它肯定不会调用c库中的函数 2)linux中代码绝大多数代码时gun c语言完成的不是标准c语言可以理解为标c的扩展版和少部分汇编 需要注意的问题: 1)内核态不能做浮点数运算 2)用户空间的每个进程都有独立的0-3G的虚拟空间 多个进程共享同一个内核 内核使用的地址空间为3G-4G 3)每个线程有独立的栈空间 4 写一个最简单的内核模块儿(因为驱动时内核的一个模块套路都一样) a)几个宏 i.__FUNCTION__:展开为所在函数的名称 ii.__LINE__:展开为printk所在的行号 iii.__DATE__:展开为编译程序的日期 b)通用头文件 i.#include ii.#include c)没有main函数 然后写一个makefile 其中:obj -m +=helloworld.o -m表示生成模块儿 make -C 内核路径编译对象路径modules(固定表示模块儿) 例子:make -C /home/changjian/dirver/kernel M=$(PWD) modules 报错:如taints kernel(污染内核)因为写的驱动没有声明license 因为linux为开源所以写的驱动也必须声明为开源可以在程序里加入:MODULE_LICENSE(“GPL”);声明为开源 模块儿驱动开发 1、模块儿参数 a)内核中安装模块时也可以传递参数 i.insmod xx.ko var=123 b)模块参数的使用方法 i.首先在模块中定义全局变量 ii.然后使用module_param 或者module_param_array来修饰该变量 这样一个普通的全局变量就变成可以安装模块时传递参数的模块参数 module_param(name,type,perm) name:变量名称 type: name的类型(不包括数组) perm:权限类型rwxr-x 等类型内核做了相关的宏定义形如efine S_IRWXG 表示r w x g(同组) module_param_array(name,type,nump,perm)将某个数组声明为模块 参数

Linux内核十个版本性能对比

【IT168 评论】从2008年1月底至今,Linux Kernel系统内核已经先后升级了十次,版本号也从2.6.24上升到2.6.33,并且下个版本2.6.34也已进入开发阶段。今天我们就看看过去两年内这十个版本在性能上有何差异。 测试平台是一套工作站系统,硬件配置包括AMD Opteron 2384 2.7GHz四核心处理器(“上海”)、泰安Thunder n3600B S2927主板(NVIDIA nForce 3600PRO 芯片组)、4GB DDR2 ECC Reg内存、希捷ST3300622AS 300GB硬盘、ATI FirePro V8700显卡,软件上采用Ubuntu 8.04.4 LTS 64位操作系统,组件有GNOME 2.22.3、https://www.360docs.net/doc/9917992693.html, Server 1.4.0.90、GCC 4.2.4、EXT3。 Linux Kernel 2.6.24-2.6.33的每个版本都从Ubuntu PPA源上获取,而且均为64位版本。除了替换内核之外,系统其他设置均保持默认。 Apache Benchmark(静态网页服务):2.6.33成绩大幅提升,但事实最早的2.6.24版反而才是好的,之后八个版本都差得很多,最新版终于基本正常了。

PostgreSQL pgbench(每秒钟TPC-B交易数):2.6.30的成绩比上个版本骤然提升了多达770%,但之后2.6.32迅速下滑,最新的2.6.33却又完全不如2.6.30之前的六个版本了。

7-Zip Compression(文件压缩速度):不同版本有所波动,最新的2.6.33成了赢家,这才是我们最希望看到的。 LZMA Compression(256MB文件压缩):十个版本几乎没什么区别。

Linux内核目录文件简介

Linux V0.11目录文件简介 ●Makefile文件:该文件是编译辅助工具软件make的参数配置文件。 ●boot目录:功能是当计算机加电时引导内核启动,将内核代码加载到内存中,并做一些进入入32位保护运行方式前的系统初始化工作。 ①Bootsect.s:磁盘引导块程序,驻留磁盘第一个扇区。0x7C00 ②Setup.s:读取机器的硬件配置参数,并把内核模块system移动到适当的内存位置处。 ③Head.s:被编译连接在system模块的最前部分,主要进行硬件设备的探测设置和内存管理页面的初始设置工作。 ●fs目录:文件系统实现程序的目录。 1、file_table.c文件中,目前仅定义了一个文件句柄(描述符)结构数组。 2、ioctl.c文件将引用kernel/chr_dev/tty.c中的函数,实现字符设备的io控制功能。 3、exec.c程序主要包含一个执行程序函数do_execve(),它是所有exec()函数簇中的主要函数。 4、fcntl.c程序用于实现文件i/o控制的系统调用函数。 5、read_write.c程序用于实现文件读/写和定位三个系统调用函数。 6、stat.c程序中实现了两个获取文件状态的系统调用函数。 7、open.c程序主要包含实现修改文件属性和创建与关闭文件的系统调用函数。 8、char_dev.c主要包含字符设备读写函数rw_char()。 9、pipe.c程序中包含管道读写函数和创建管道的系统调用。 10、file_dev.c程序中包含基于i节点和描述符结构的文件读写函数。 11、namei.c程序主要包括文件系统中目录名和文件名的操作函数和系统调用函数。 12、block_dev.c程序包含块数据读和写函数。 13、inode.c程序中包含针对文件系统i节点操作的函数。 14、truncate.c程序用于在删除文件时释放文件所占用的设备数据空间。 15、bitmap.c程序用于处理文件系统中i节点和逻辑数据块的位图。 16、super.c程序中包含对文件系统超级块的处理函数。 17、buffer.c程序主要用于对内存高速缓冲区进行处理。 ·虚框中的ll_rw_block是块设备的底层读函数,它并不在fs目录中,而是 kernel/blk_dev/ll_rw_block.c中的块设备读写驱动函数。放在这里只是让我们清楚的看到,文件系统对于块设备中数据的读写,都需要通过高速缓冲区与块设备的驱动程序 (ll_rw_block())来操作来进行,文件系统程序集本身并不直接与块设备的驱动程序打交道。

Linux内核与驱动开发实验教材

内核与驱动开发实验教材 中程在线 实验一嵌入式开发环境的建立 实验目的 掌握嵌入式开发环境的构建,熟悉课程实验的开发板 掌握安装交叉编译工具的安装方法 掌握的烧写方法 掌握的编译方法 实验内容 安装交叉编译工具 编译 烧写 生成映像 基础知识 交叉编译工具 嵌入式系统的开发中,开发环境被称为主机。因为嵌入式目标系统的资源局限性,不可能完成构建系统的任务,所以需要主机使用交叉编译工具来构建目标系统。 实验使用交叉编译器,与桌面系统采用的编译器是不同,因为实验开发板采用的是处理器。 编译器将使用下列工具 , 与通常在平台上使用的工具不同,交叉编译工具编译处理的执行文件只能够在平台上运行。 嵌入式系统构建 一个嵌入式系统从软件的角度看通常可以分为四个层次: .引导加载程序()。引导加载程序是系统加电后运行的第一段软件代码。 . 内核。特定于嵌入式板子的定制内核以及内核的启动参数。 . 文件系统。包括根文件系统和建立于内存设备之上文件系统。通常用来作为。 .用户应用程序。特定于用户的应用程序。

主要的功能有: 初始化硬件,初始化, , , , 。 启动,这是最重要的功能,保存内核映像到中,并跳转到内核起始地址。 映像下载,下载内核映像和文件系统到,下载只能通过以太网进行。如命令完成文件下载。 内存控制,如命令可以烧写。 机中的引导加载程序由(其本质就是一段固件程序)和位于硬盘中的(比如,和等)一起组成。在完成硬件检测和资源分配后,将硬盘中的读到系统的中,然后将控制权交给。的主要运行任务就是将内核映象从硬盘上读到中,然后跳转到内核的入口点去运行,也即开始启动操作系统。 而在嵌入式系统中,通常并没有像那样的固件程序(注,有的嵌入式也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由来完成。在实验开发板(基于3C)的嵌入式系统中,系统在上电或复位时都从地址处开始执行,而在这个地址处安排的通常就是系统的程序。 简单地说,就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。 通常,是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的几乎是不可能的。尽管如此,我们仍然可以对归纳出一些通用的概念来,以指导用户特定的设计与实现。 内核是所有系统的中心软件组件。整个系统的能力完全受内核本身能力的限制。 由于内核支持多个架构,由于架构的差异性,每种架构都有不同的团队在维护,所以必须根据架构来选择供应内核的网站。见下表: 架构最合适的内核网站下载方式 等 内核源代码目录树结构说明如下: :包含和硬件体系结构相关的代码,每种平台占一个相应的目录。和位相关的代码存放在目录下,其中比较重要的包括(内核核心部分)、(内存管理)、(浮点单元仿真)、(硬件相关工具函数)、(引导程序)、(总线)和(相关状态)。 :常用加密和散列算法(如、等),还有一些压缩和校验算法。 :关于内核各部分的通用解释和注释。 :设备驱动程序,每个不同的驱动占用一个子目录。 :各种支持的文件系统,如、、等。 :头文件。其中,和系统相关的头文件被放置在子目录下。 :内核初始化代码(注意不是系统引导代码)。 :进程间通信的代码。 :内核的最核心部分,包括进程调度、定时器等,和平台相关的一部分代码放在*目录下。:库文件代码。 :内存管理代码,和平台相关的一部分代码放在*目录下。 :网络相关代码,实现了各种常见的网络协议。

Linux设备驱动程序说明介绍

Linux设备驱动程序简介 Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel 中的函数,有些常用的操作要自己来编写,而且调试也不方便。本人这几周来为实验室自行研制的一块多媒体卡编制了驱动程序,获得了一些经验,愿与Linux fans共享,有不当之处,请予指正。 以下的一些文字主要来源于khg,johnsonm的Write linux device driver,Brennan's Guide to Inline Assembly,The Linux A-Z,还有清华BBS上的有关device driver的一些资料. 这些资料有的已经过时,有的还有一些错误,我依据自己的试验结果进行了修正. 一、Linux device driver 的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作.设备驱动程序是内核的一部分,它完成以下的功能: 1.对设备初始化和释放. 2.把数据从内核传送到硬件和从硬件读取数据. 3.读取应用程序传送给设备文件的数据和回送应用程序请求的数据. 4.检测和处理设备出现的错误. 在Linux操作系统下有两类主要的设备文件类型,一种是字符设备,另一种是块设备.字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作.块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待. 已经提到,用户进程是通过设备文件来与实际的硬件打交道.每个设备文件都都有其文件属性(c/b),表示是字符设备还蔤强樯璞?另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们.设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序. 最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度.也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作.如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck. 读/写时,它首先察看缓冲区的内容,如果缓冲区的数据 如何编写Linux操作系统下的设备驱动程序 二、实例剖析 我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理.把下面的C代码输入机器,你就会获得一个真正的设备驱动程序.不过我的kernel是2.0.34,在低版本的kernel上可能会出现问题,我还没测试过. [code]#define __NO_VERSION__

Linux的版本与内核

Linux的版本与内核 Linux有两种版本,一个是核心(kernel)版,一个是发行(distribution)版。核心版的序号由三部分数字构成,其形式为:major.minor.patchlevel,其中,majoro为主版本号,minor为次版本号,二者共同构成了当前核心版本号。patchlevel表示对当前版本的修订次数。例如,2.2.11表示对核心作用2.2 版本的第11次修订。根据约定,次版本号为奇数时,表示该版本加入新内容,但不一定稳定,相当于测试版;次版本号为偶数时,表示这是一个可以使用的稳定版本。鉴于Linux内核开发工作的连续性,内核的稳定版本与在此基础上进一步开发的不稳定版本总是同时存在的。建议采用稳定的核心版本。 Linux的内核具有两种不同的版本号,实验版本和产品化版本。要确定LINUX版本的类型,只要查看一下版本号:每一个版本号由三位数字组成,第二位数字说明版本类型。如果第二位数字是偶数则说明这种版本是产品化版本,如果是奇数说明是实验版本。如2.6.20是产品化版本,2.6.16是实验版本。LINUX的两种版本是相互关联的。实验版本最初是产品化产品的拷贝,然后产品化版本只修改错误,实验版本继续增加新功能,到实验版本测试证明稳定后拷贝成新的产品化版本,不断循环,这样一方面可以方便广大软件人员加入到LINUX的开发和测试工作中来,另一方面又可以让一些用户使用上稳定的LINUX版本。真是做到开发和实用两不误。现在LINUX的内核的最新版本是2.6.20。 Linux内核 Linux是最受欢迎的自由电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统。Linux最早是由芬兰黑客 Linus Torvalds为尝试在英特尔x86架构上提供自由免费的类Unix操作系统而开发的。该计划开始于1991年,这里有一份Linus Torvalds 当时在Usenet新闻组comp.os.minix所登载的贴子,这份著名的贴子标志着Linux计划的正式开始。在计划的早期有一些Minix 黑客提供了协助,而今天全球无数程序员正在为该计划无偿提供帮助。技术上说Linux是一个内核。“内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。一套基于Linux内核的完整操作系统叫作Linux操作系统,或是GNU/Linux架构。今天Linux是一个一体化内核(monolithic kernel)系统。设备驱动程序可以完全访问硬件。Linux内的设备驱动程序可以方便地以模块化(modularize)的形式设置,并在系统运行期间可直接装载或卸载。Linux不是微内核(microkernel)架构的事实曾经引起了Linus Torvalds与Andy Tanenbaum之间一场著名的争论。 Linux内核简史 操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux 的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。

相关文档
最新文档