ImageVerifierCode 换一换
格式:DOCX , 页数:28 ,大小:584.82KB ,
资源ID:7231654      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-7231654.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(内核复习.docx)为本站会员(b****6)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

内核复习.docx

1、内核复习一、1、操作系统:指在整个系统中负责完成最基本功能和系统管理的那些部分。这些部分应该包括内核、设备驱动程序、启动引导程序、命令行shell或者其他种类的用户界面、基本的文件管理工具和系统工具。2、内核:内核是操作系统的内在核心。系统其他部分必须依靠内核这部分软件提供的服务。像管理硬件设备,分配系统资源等等。内核有时候被称作是超级管理者或者是操作系统核心。通常一个内核由负责响应中断的中断服务程序,负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间的内存管理程序和网络、进程间通信等系统服务程序共同组成。3内核空间:对于提供保护机制的现代系统来说,内核独立于普通应用程序,它一

2、般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限。这种系统态和被保护起来的内存空间,统称为内核空间。用户空间:相对的,应用程序在用户空间执行。它们只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,还有其他一些使用限制。当内核运行的时候,系统以内核态进入内核空间,相反,普通用户程序以用户态进入用户空间。4、进程上下文:当一个应用程序请求执行一条系统调用,我们说内核正在代其执行。进一步解释,应用程序被称为通过系统调用在内核空间运行,而内核被称为运行于进程上下文中。中断上下文:硬件设备想和系统通信的时候,它首先要发出一个异步的中断信号去打断内核正在执行的

3、工作。中断通常对应着一个中断号,内核通过这个中断号查找相应的中断服务程序,并调用这个程序响应和处理中断。许多操作系统的中断服务程序都不在进程上下文中执行。它们在一个与所有进程都无关的、专门的中断上下文中运行。5、上下文代表着内核活动的范围。实际上我们可以将处理器在任何指定时间点上的活动范围概括为下列三者之一:运行于内核空间,处于进程上下文,代表某个特定的进程执行。运行干内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断。运行于用户空间,执行用户进程。6、单内核与微内核设计之比较:单内核(Linux、Unix):所谓单内核就是把它从整体上作为一个单独的大过程来实现,并同时运行在一个单独

4、的地址空间。因此,这样的内核通常以单个静态二进制文件的形式存放于磁盘。所有内核服务都在这样的一个大内核空间中运行。内核各个模块可以直接调用函数来进行通信。微内核(Window NT):微内核的功能被划分为独立的过程,每个过程叫做一个服务器。所有的服务器都保持独立并运行在各自的地址空间。服务器的各自独立有效地避免了一个服务器的失效祸及另一个。服务器间的通信需要通过消息传递来实现。二、1、相对于用户空间内应用程序的开发,内核开发有很大的不同。最重要的差异包括以下几种:内核编程时不能访问C库。内核编程时必须使用GNU C。内核编程时缺乏像用户空间那样的内存保护机制。内核编程时浮点数很难使用。内核只有

5、一个很小的定长堆栈。由于内核支持异步中断、抢占和SMP,因此必须时刻注意同步和并发。要考虑可移植性的重要性。2、与用户空间的应用程序不同,内核不能链接使用标准C函数库,对内核来说,完整的c库太大了,但是,大部分常用的C库函数在内核中都已经得到了实现。在内核编程中,只能使用内核源代码树中的头文件。内核代码虽然无法调用printf(),但它可以调用printk()函数。3、内联(inline)函数:定义一个内联函数的时候,需要使用static作为关键字,并且用inline限定它。 比如:static inline void dog(unigned long tail_size)定义:内联函数必须在

6、使用之前就定义好,否则编译器就没法把这个函数展开。实践中一般在头文件中定义内联函数。由于使用了static作为关键字进行限制,所以编译时不会为内联函数单独建立一个函数体。如果一个内联函数仅仅在某个源文件中使用,那么也可以把它定义在该文件开始的地方。4、没有内存保护机制:如果一个用户程序试图进行一次非法的内存访问,内核会发现这个错误,发送SIGSEGV,并结束整个进程。然而,如果是内核自己非法访问了内存,那后果就很难控制了。内核中发生的内存错误会导致oops,这是内核中出现的最常见的一类错误。在内核中,不应该去做访问非法的内存地址,引用空指针之类的事情,否则它可能会死掉,却根本不知会你一声在内核

7、里,风险常常会比外面大一些。此外,内核中的内存都不分页。也就是说,每用掉一个字节,物理内存就减少一个字节。所以,在你想往内核里加入什么新功能的时候,要记住这一点。5、不要轻易在内核中使用浮点数:在用户空间的进程内进行浮点操作的时候,内核会完成从整数操作到浮点数操作的模式转换。在执行浮点指令时到底会做些什么,因体系结构不同,内核的选择也不同,但是,内核通常捕获陷阱并做相应处理。和用户空间进程不同,内核并不能完美地支持浮点操作,因为它本身不能陷入。在内核中使用浮点数时,除了要人工保存和恢复浮点寄存器,还有其他一些琐碎的事情要做。如果要直截了当的回答,那就是,别这么做了,不要在内核中使用浮点数。6、

8、容积小而固定的栈:用户空间的程序可以从栈上分配大量的空间来存放变量,甚至巨大的结构体或者是包含许多数据项的数组都没有问题。之所以可以这么做,是因为用户空间的栈本身比较大,而且还能动态的增长。内核栈的准确大小随体系结构而变。在x86上,栈的大小在编译时配置,可以是4KB也可以是8KB。从历史上说,内核栈的大小是两页,这就意味着,32位机的内核栈是8KB,而64位机是16KB,这是固定不变的。每个处理器都有自己的栈。7、同步和并发:内核很容易产生竞争条件。Linux是抢占多任务操作系统。Linux内核支持多处理器系统。中断是异步到来的,完全不顾及当前正在执行的代码。Linux内核可以抢占。常用的解

9、决竞争的办法是自旋锁和信号量。8、可移植性的重要性:Linux是一个可移植的操作系统,并且一直保持这种特点。也就是说,大部分C代码应该与体系结构无关,在许多不同体系结构的计算机上都能够编译和执行,因此,必须把体系结构相关的代码从内核代码树的特定目录中适当地分离出来。三、1、嵌入式linux系统的组成包括三部分:bootloader程序,linux内核,根文件系统。Bootloader程序:系统上电时第一个要执行的程序,主要功能是为启动linux内核准备环境;Linux内核:操作系统的核心部分,是一个单一的文件(uImage);根文件系统:根文件系统包括操作系统的一些系统工具,C函数库等的东西。

10、2、嵌入式linux软件开发的特点:需要交叉编译:1、硬件平台处理器较慢,内存和外存容量小等等;2、把软件开发放在高性能的PC机上进行;3、PC机上CPU指令集与嵌入式CPU的指令集是不同的,因此,在PC机上开发嵌入式软件需要交叉编译。需要移植:1、由于嵌入式系统是一个软硬件定制的系统,硬件平台各不相同,软件设计需要根据不同的硬件设备来添加或修改相应的代码,这就是移植。3、交叉开发环境是指编译、链接和调试嵌入式应用软件的环境,它与运行嵌入式应用软件的环境有所不同,通常采用宿主机目标机模式。4、5、嵌入式软件开发过程中的交叉调试与本地软件开发过程中的调试方式有所差别:本地软件开发:调试器与被调试

11、的程序往往运行在同一台计算机上。调试器是一个单独运行着的进程,它通过操作系统提供的调试接口来控制被调试的进程。 嵌入式软件开发:调试时采用的是在宿主机和目标机之间进行的交叉调试。调试器运行在宿主机,但被调试的进程却是运行在目标板。调试器和被调试进程通过串口或者网络进行通信,调试器可以控制、访问被调试进程,读取被调试进程的当前状态,并能够改变被调试进程的运行状态。六、1、一个API定义了一组应用程序使用的编程接口,应用编程接口(API)与系统调用的关系:应用程序编程接口实际上并不需要和内核提供的系统调用对应。一个API可以实现成一个系统调用;一个API也可以通过调用多个系统调用来实现一个API也

12、可以完全不使用任何系统调用。实际上,API可以在各种不同的操作系统上实现,给应用程序提供完全相同的接口。2、系统调用(在Linux中常称作syscalls):通常通过函数进行调用。它们通常都需要定义一个或几个参数。系统调用还会通过一个long类型的返回值来表示成功或者错误。通常,但也不绝对,用一个负的返回值来表明错误。返回一个0值通常(当然仍不是绝对的)表明成功。Unix系统调用在出现错误的时候会把错误码写入errno全局变量。通过调用perror()库函数,可以把该变量翻译成用户可以理解的错误字符串。3、系统调用号:每个系统调用被赋予一个系统调用号。系统调用号关联系统调用。当用户空间的进程执

13、行一个系统调用的时候,这个系统调用号就被用来指明到底是要执行哪个系统调用;进程不会提及系统调用的名称。系统调用号相当关键,一旦分配就不能再有任何变更,否则编译好的应用程序就会崩溃。此外,如果一个系统调用被删除,它所占用的系统调用号也不允许被回收利用,否则,以前编译过的代码会调用这个系统调用。4、系统调用表(sys_call_table):表中存放每个的系统调用的入口地址(函数指针);每一个体系结构都有对应的一个系统调用表;5、系统调用的处理过程:用户空间的程序无法直接执行内核代码。所以,应用程序应该以某种方式通知系统,告诉内核自己需要执行一个系统调用,希望系统切换到内核态,这样内核就可以代表应

14、用程序来执行该系统调用了。通知内核的机制是靠软中断实现的:通过引发一个异常来促使系统切换到内核态去执行异常处理程序。6、系统调用的实现:1)参数验证:系统调用必须仔细检查它们所有的参数是否合法有效。 系统调用在内核空间执行,如果任由用户将不合法的输入传递给内核,那么系 统的安全和稳定将面临极大的考验。 举例来说,与文件I/O相关的系统调用必须检查文件描述符是否有效。与进程 相关的函数必须检查提供的PID是否有效。必须检查每个参数,保证它们不但 合法有效,而且正确。2)检查用户提供的指针是否有效。在接收一个用户空间的指针之前,内核必须保证:指针指向的内存区域属于用户空间。进程决不能哄骗内核去读内

15、核空间的数据。指针指向的内存区域在进程的地址空间里。进程决不能哄骗内核去读其他进程的数据。如果是读,该内存应被标记为可读。如果是写,该内存应被标记为可写。进程决不能绕过 内存访问限制。3)最后一项检查针对是否有合法权限:新的系统允许检查针对特定资源的特殊权限。调用者可以使用capable()函数来检查是否有权能对指定的资源进行操作,如果它返回非零值,调用者就有权进行操作,返回零则无权操作。举个例子,capable(CAP_SYS_NICE)可以检查调用者是否有权改变其他进程的nice值。默认情况下,属于超级用户的进程拥有所有权利而非超级用户没有任何权利。7、为什么不通过系统调用的方式实现:建立

16、一个新的系统调用的好处:系统调用创建容易且使用方便。 Linux系统调用的高性能显而易见。问题:你需要一个系统调用号,而这需要在一个内核在处于开发版本的时候由官方分配给 你。 系统调用被加入稳定内核后就被固化了,为了避免应用程序的崩溃,它的界面不允 许做改动。 需要将系统调用分别注册到每个需要支持的体系结构中去。 在脚本中不容易调用系统调用,也不能从文件系统直接访问系统调用。 如果仅仅进行简单的信息交换,系统调用就大材小用了。替代方法:创建一个设备节点,通过read()和、write()访问它。用ioctl()进行特别的设置操 作和获取特别信息。 一些接口如信号量,可以用文件描述符表示以进行操

17、作。像信号量这样的某 些接口,可以用文件描述符来表示,因此也就可以按上述方式对其进行操作。 把增加的信息作为一个文件放在sysfs的合适位置。七、1、什么是内核模块?定义:内核模块是一种没有经过链接,不能独立运行的目标文件,是在内核空间中运行的程序。经过链接装载到内核里面成为内核的一部分,可以访问内核的公用符号(函数和变量)。内核模块可以让操作系统内核在需要时载入和执 行,在不需要时由操作系统卸载。它们扩展了操作系统内核的功能却不需要重新启动系统。如果没有内核模块,我们不得不一次又一次重新编译生成单内核操作系统的内核镜 像来加入新的功能。这还意味着一个臃肿的内核。2、模块机制的优点:减小内核映

18、像尺寸,增加系统灵活性; 节省开发时间;修改内核,不必重新编译整个内核。 模块的目标代码一旦被链入内核,作用和静态链接的内核目标代码完全 等价。模块机制的缺点:对系统性能有一定损失; 使用不当时会导致系统崩溃;3、一个内核模块至少包含两个函数:初始化函数,在模块加载到内核时被调用。卸载函数,在内核模块被卸载时被调用。 现在的模块“初始化”和“卸载”函数可以起任意的名字。通过宏 module_init()声明初始化函数,通过module_exit()声明卸载函数 。任一个内核模块需要包含linux/module.h4、关于_init和_exit宏:如果该模块被编译进内核,而不是动态加载,则宏 _

19、init的使用会在初始化完成后丢弃该函数并收回所占内存。 如果该模块被编译进内核,宏_exit将忽略“清理收尾”的函数。这些宏在头文件linux/init.h定义。5、内核模块证书和内核模块文档说明:2.4内核后,引入识别代码是否在GPL许可下发布的机制 。在使用非公开的源代码产品时会得到警告。通过宏MODULE_LICENSE(“GPL”),设置模块遵守GPL证书,取消警告信息。宏MODULE_DESCRIPTION()用来描述模块的用途。宏MODULE_AUTHOR()用来声明模块的作者。 这些宏都在头文件linux/module.h定义。使用这些宏只是用来提供识别信息。6、编译模块过程中

20、的第一步是决定在那里管理模块源码:你可以把模块源码加入到内核源代码树中;也可以在内核源代码树之外维护和构建你的模块源码。八、1、Linux设备驱动概述:1)操作系统内核是通过各种驱动程序来驾驭硬件设备,它为用户屏蔽了各种各样的设备。2)设备驱动程序是操作系统内核和机器硬件之间的接口,系统调用是操作系统内核和应用程序之间的接口。3)在应用程序看来,硬件设备只是一个设备文件, 应用程序可以象操作普通文件一样对硬件设备进行操作. 2、驱动完成的功能:1)对设备初始化和释放. 2)把数据从内核传送到硬件和从硬件读取数据. 3)读取应用程序传送给设备文件的数据和回送应用程序请求的数据. 4)检测和处理设

21、备出现的错误. 3、Linux下设备的属性:1)设备的类型:字符设备、块设备、网络设备;2)主设备号:标识设备对应的驱动程序。一般“一个主设备号对应一个驱动程序”3)次设备号:每个驱动程序负责管理它所驱动的几个硬件实例,这些硬件实例则由次设备 号来表示。同一驱动下的实例编号,用于确定设备文件所指的设备。4)文件名:设备结点的名字。4、设备号:在内核驱动程序中,使用dev_t类型用于保存设备号。dev_t是无符号32位整型;高12位表示主设备号;低20位是次设备号;在驱动程序中,常常要通过设备号获取主、次设备号:MAJOR(dev_t dev); /获取主设备号MINOR(dev_t dev);

22、 /获取次设备号通过主、次设备号合成设备号:MKDEV(int major, int minor);dev_t类型以后可能会发生变化,但只要使用这些宏,就可保证设备驱动程序的正确性。5、编写驱动程序要做的第一件事,为字符设备获取一个设备号。1)如果事先知道所需要的设备号(主设备号)的情况,可以使用以下函数,向内核申请已知的设备号:int register_chrdev_region(dev_t first, unsigned count,const char *name);first是要分配的起始设备号值。 count 所请求的连续设备编号的个数。name设备名称,指和该编号范围建立关系的设备

23、。分配成功返回0,失败返回负数。2)可以让内核动态分配设备号(主要是主设备号);使用下面的函数来动态申请设备号;int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name);dev 是一个仅用于输出的参数, 它在函数成功完成时保存已分配范围的第一个编号。baseminor 应当是请求的第一个要用的次设备号,它常常是 0. count 和 name 参数跟request_chrdev_region 的一样.3)不再使用时,释放这些设备编号。使用以下函数: void unregist

24、er_chrdev_region(dev_t from, unsigned count);在模块的卸载函数中调用该函数。编写设备驱动的第二步就是注册该设备为struct cdev 分配空间:struct cdev *my_cdev = cdev_alloc();初始化struct cdev :void cdev_init(struct cdev *cdev, const struct file_operations *fops) cdev设置完成,通知内核struct cdev的信息(在执行这步之前必须确定你对struct cdev的以上设置已经完成!): int cdev_add(struc

25、t cdev *p, dev_t dev, unsigned count);dev 是要添加的设备的 cdev 结构, num 是这个设备对应的第一个设备号,count 是应当关联到设备的设备号的数目. 卸载字符设备:void cdev_del(struct cdev *dev);早期方法:注册一个字符设备的早期方法: int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);major 是给定的主设备号。为0代表什么?name 是驱动的名字(将出现在 /proc/device

26、s), fops 是设备驱动的file_operations 结构。register_chrdev 将给设备分配 0 - 255 的次设备号, 并且为每一个建立一个缺省的 cdev 结构。从系统中卸载字符设备的函数: int unregister_chrdev(unsigned int major, const char *name);6、大部分驱动程序涉及三个重要的内核数据结构:文件操作file_operations结构体文件对象file结构体索引节点inode结构体1)file_operations重要的成员owner : 指向拥有该结构体的模块的指针,内核使用该指针维护模块使用计数。ll

27、seek : 用来修改文件的当前读写位置,把新位置作为返回值返回,loff_t是在LINUX中定 义的长偏移量 .read : 用来从设备中读取数据。非负返回值表示成功读取的直接数。write : 向设备发送数据。ioctl : 提供一种执行设备特定命令的方法。2)索引节点inode结构文件打开,在内存建立副本后,由唯一的索引节点inode描述。与file结构不同。file结构是进程使用的结构,进程每打开一个文件,就建立一个file结构。不同的进程打开同一个文件,建立不同的file结构。inode结构是内核使用的结构,文件在内存建立副本,就建立一个inode结构来描述。一个文件在内存里面只有一

28、个inode结构对应。3)struct inode 结构代表一个实实在在文件,每个文件只对应一个inode;struct file 结构代表一个打开的文件,同一个文件可以对应多个file结构;struct file_operations结构代表底层操作硬件函数的集合;九、1、应用层与驱动层层次结构框图:2、注册cdev分析:cdev结构的注册分两步,第一步是初始化cdev结构;第二步是注册。cdev_add()函数分析如下:3、字符设备注册过程如下图:内核里面,通过一个宏来建立实地址到虚地址的映射,这个宏是:ioremap( paddr,size);宏的第一个参数是要映射的实地址;第二个参数是

29、要映射的大小;宏返回映射后的虚拟地址;例如,GPM4CON控制寄存的地址映射如下:unsigned long viraddr;viraddr = ioremap(0x110002e0,8 );通过 *(volatile unsigned long *)viraddr 就可以在内核中访问GPM4CON寄存器。 取消映射的宏是:iounmap(viraddr);十、并发执行的原因:在一段内核代码操作某资源的时候系统产生了一个中断,而且该中断的处理程序还要访问这一资源,这就是一个bug;一段内核代码在访问一个共享资源期间可以被抢占;内核代码在临界区里睡眠;最后还要注意,两个处理器绝对不能同时访问同一

30、共享数据.这里的基本原则是:在编写代码的开始阶段就要设计恰当的锁。十一、1、原子整数操作:1)原子整数方法使用一种特殊的类型: atomic_t2)引入了一个特殊数据类型主要是出于一下原因:首先,让原子函数只接受atomic_t类型的操作数,可以确保原子操作函数只与这种特殊类型数据一起使用。同时,这也保证了该类型的数据不会被传递给其他任何非原子函数。最后,在不同体系结构上实现原子操作的时候,使用atomic_t可以屏蔽其间的差异。2、原子整数操作最常见的用途就是实现计数器:atomic_inc(atomic_t *v) 自加1atomic_dec(atomic_t *v) 自减1还可以用原子整数操作原子地执行一个操作并检查结果。一个常见的例子就是原子的减操作和检查。int atomic_dec_and_test(atomic_t *v);这个函数将给定的原子变量减1,如果结果为0,就返回真;否则返回假。十二、1、自旋锁:1)任何时候只能有一个线程持有的锁2)注意:自旋锁被一个线程持有时,其他线程不能获得这个锁,只能忙等这个锁,3)长时间占有自旋锁并不是一个明智的方法4)接口定义在文件中5)自旋锁的使用: DEFINE_SPINLO

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2