资源预览内容
第1页 / 共45页
第2页 / 共45页
第3页 / 共45页
第4页 / 共45页
第5页 / 共45页
第6页 / 共45页
第7页 / 共45页
第8页 / 共45页
第9页 / 共45页
第10页 / 共45页
亲,该文档总共45页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
程序(chngx)的链接和内存装入第1页/共44页第一页,共45页。连续(linx)分配方式单一连续(linx)分配 这是最简单(jindn)的一种存储管理方式,但只能用于单用户、单任务的操作系统中。采用这种存储管理方式时,可把内存分为系统区和用户区两部分,系统区仅提供给OS使用,通常是放在内存的低址部分;用户区是指除系统区以外的全部内存空间, 提供给用户使用。 第2页/共44页第二页,共45页。固定分区(fn q)分配 1. 划分分区(fn q)的方法 分区大小(dxio)相等, 即使所有的内存分区大小(dxio)相等。 (2) 分区大小(dxio)不等。 第3页/共44页第三页,共45页。2. 内存(ni cn)分配 固定(gdng)分区使用表 第4页/共44页第四页,共45页。4.2.3 动态(dngti)分区分配 1. 分区(fn q)分配中的数据结构 空闲(kngxin)分区表。 (2) 空闲(kngxin)分区链。 空闲链结构 第5页/共44页第五页,共45页。5.4.1 请求分页机制1分页概念逻辑空间分页 内存(ni cn)空间分页页面和内存(ni cn)块的大小是由硬件确定的 逻辑地址表示 内存(ni cn)分配原则页表 第6页/共44页第六页,共45页。2请求分页的基本思想请求分页提供虚拟存储器 在每一个页表项中增加一个状态位表示一个页面是否已装入内存块如果地址(dzh)转换机构遇到一个具有N状态的页表项时,便产生一个缺页中断 第7页/共44页第七页,共45页。3Linux的多级页表Linux进程的虚存空间(kngjin) Linux系统采用三级页表的方式 第8页/共44页第八页,共45页。4内存页的分配与释放Linux系统采用两种方法(fngf)来管理内存页:位图和链表 页组中内存页的数量依次按2的倍数递增 第9页/共44页第九页,共45页。5.4.2 内存(ni cn)交换内核的交换守护进程kswapd :有自己的进程控制(kngzh)块task_struct结构,它与其他进程一样受内核的调度。但是,它没有自己独立的地址空间,只使用系统空间,所以也把它称为线程。它的任务就是保证系统中有足够的空闲内存页。当系统启动时,交换守护进程由内核的init(初始化)进程启动。被定时唤醒 。所做的工作主要分为两部分:将若干不常用的活跃内存页面变为不活跃状态;清理不活跃的“脏”页面,或者回收一些内存页,使之成为空闲的内存页。作为交换空间的交换文件实际就是普通文件,但它们所占的磁盘空间必须是连续的 第10页/共44页第十页,共45页。7.5 内 存 管 理 #include void *malloc(size_t size); #include void *calloc(size_t nmemb, size_t size); #include void *realloc(void *ptr, size_t size); #include void free(void *ptr);第11页/共44页第十一页,共45页。5.6 设 备 管 理5.6.1 设备管理(gunl)概述所有设备都作为特别文件,从而在管理上就具有下列共性:(1)每个设备都对应文件系统中的一个索引节点,都有一个文件名。(2)应用程序通常可以通过系统调用open( )打开设备文件,建立起与目标设备的连接。(3)对设备的使用类似于对文件的存取。(4)设备驱动程序是系统内核的一部分,它们必须为系统内核或者它们的子系统提供标准的接口。(5)设备驱动程序利用一些标准的内核服务,如内存(ni cn)分配等。另外,大多数Linux设备驱动程序都可以在需要时装入内核,不需要时卸载下来。 第12页/共44页第十二页,共45页。 设备(shbi)驱动的分层结构 第13页/共44页第十三页,共45页。5.6.2 设备(shbi)驱动程序和内核之间的接口1可安装模块可安装模块是可以在系统运行时动态地安装和拆卸的内核模块,即经过编译但尚未连接的目标文件(后缀为.o)。设备驱动程序或者与设备驱动紧密相关的部分(如文件系统)都是利用可安装模块实现(shxin)的。 在通常情况下,用户利用系统提供的插入模块工具和移走模块工具来装卸可安装模块。 第14页/共44页第十四页,共45页。2字符设备用户对字符设备的使用就和存取普通(ptng)文件一样。在应用程序中使用标准的系统调用来打开、关闭、读写字符设备。 第15页/共44页第十五页,共45页。3块设备对块设备的存取与对文件(wnjin)的存取方式一样,其实现机制也与字符设备使用的机制相同。 第16页/共44页第十六页,共45页。设备驱动(q dn)与文件系统的关系 设备(shbi)驱动是Linux内核的重要组成部分。驱动程序跟一般的用户应用程序不同,它工作在内核态,编程方法和使用的库函数都跟用户级的应用程序有所区别。在Linux内核中,设备(shbi)驱动跟文件系统联系紧密。每一个设备(shbi)都是作为一个设备(shbi)文件,交给文件系统去管理的。 设备(shbi)驱动程序内部是由一组函数组成的。函数由设备(shbi)驱动的上层文件系统来调用,每一个函数被称做一个入口点。入口点的集合被称为设备(shbi)驱动程序的上半部分,实现设备(shbi)驱动与文件系统的接口。常用的入口点有:open、close(或release)、read、write、ioctl等。 每一个函数的内部实现被称作驱动程序的下半部分,负责实现具体的设备(shbi)操作。函数的内部实现通常是靠系统调用提供的函数实现的,不能使用平常我们使用的用户级的C语言库函数。第17页/共44页第十七页,共45页。Linux通过设备号来区分不同的设备。设备号由两部分组成(z chn):主设备号MAJOR和次设备号MINOR。主设备号MAJOR指明对应哪些设备驱动。一般一个主设备号对应一个驱动程序。次设备号MINOR用来区分同一个驱动程序控制下的不同的独立的设备。例如:硬盘的主设备名称为hd。在/dev目录下hd即为硬盘。/dev/hda、/dev/hdb等是系统的第一个硬盘和第二个硬盘。而hda0和hda1分别是第一个硬盘上的第一个分区和第二个分区。/proc/devices列出所有现在正在使用的设备号。设备(shbi)号第18页/共44页第十八页,共45页。Linux操作系统将所有的设备全部看成(kn chn)文件,并通过文件的操作界面进行操作,用户程序可以像对其他文件一样对此设备文件进行操作。这意味着: 由于每一个设备至少由文件系统的一个文件代表,因而都有一个“文件名”。 应用程序通常可以通过系统调用open()打开设备文件,建立起与目标设备的连接。 打开了代表着目标设备的文件,即建立起与设备的连接后,可以通过read()、write()、ioctl()等常规的文件操作对目标设备进行操作。设备文件的属性由三部分信息组成:第一部分是文件的类型,第二部分是一个主设备号,第三部分是一个次设备号。其中类型和主设备号结合在一起惟一地确定了设备文件驱动程序及其界面,而次设备号则说明目标设备是同类设备中的第几个。设备(shbi)文件第19页/共44页第十九页,共45页。设备文件不能用普通的办法建立。要通过mknod命令。mknod命令的语法:mknod 路径 模式(msh) 主设备号 次设备号模式(msh)有两种:c为字符设备 b为块设备例如:mknod /dev/test c 254 0设备文件可以象普通文件一样直接使用,例如:/dev/lp0为一个打印机,使用cat doc.txt/dev/lp0就可以将文档交给打印机去进行打印/dev/ttyS0为主机上的串口COM1,使用读写文件的方法,也可以实现对串口的读写操作设备(shbi)文件第20页/共44页第二十页,共45页。一、设备驱动中的关键(gunjin)数据结构二、驱动程序框架三、实现各种功能的基本函数四、实例设备(shbi)驱动基础第21页/共44页第二十一页,共45页。要编写设备驱动程序,就要实现它跟高层文件系统和底层硬件之间的操作接口。这些接口一般要遵循DDI/DKI(Device-Driver Interface / Device-Kernel Interface)接口规范,所以要使用一些标准的数据结构来进行操作。底层硬件的操作主要(zhyo)由不同硬件的特性来决定。跟文件系统的接口主要(zhyo)使用三个数据结构:inode文件索引节点结构struct file文件结构file_operations文件操作结构,设备驱动程序要实现这个结构里的主要(zhyo)操作一、设备驱动中的关键(gunjin)数据结构第22页/共44页第二十二页,共45页。struct inode称做索引节点数据结构,定义如下:struct inode struct list_headi_hash;struct list_headi_list;struct list_headi_dentry;struct list_headi_dirty_buffers;struct list_headi_dirty_data_buffers;unsigned longi_ino;atomic_ti_count;kdev_ti_dev;umode_ti_mode;nlink_ti_nlink;uid_ti_uid;gid_ti_gid;kdev_ti_rdev;loff_ti_size;time_ti_atime;time_ti_mtime;time_ti_ctime;unsigned inti_blkbits;unsigned longi_blksize;unsigned longi_blocks;unsigned longi_version;struct semaphorei_sem;struct semaphorei_zombie;struct inode_operations*i_op;struct file_operations*i_fop;/文件(wnjin)操作指针struct super_block *i_sb;wait_queue_head_ti_wait;struct file_lock*i_flock;struct address_space*i_mapping;struct address_spacei_data;struct dquot*i_dquotMAXQUOTAS;struct list_headi_devices;struct pipe_inode_info*i_pipe;struct block_device*i_bdev;/块设备struct char_device *i_cdev;/字符设备unsigned longi_dnotify_mask; struct dnotify_struct*i_dnotify; unsigned longi_state;unsigned inti_flags;unsigned chari_sock;atomic_ti_writecount;unsigned inti_attr_flags;_u32i_generation;union struct minix_inode_infominix_i; struct ext2_inode_infoext2_i; struct ext3_inode_infoext3_i; struct hpfs_inode_infohpfs_i; struct ntfs_inode_infontfs_i; struct msdos_inode_infomsdos_i; struct umsdos_inode_infoumsdos_i; struct iso_inode_infoisofs_i; struct nfs_inode_infonfs_i; struct sysv_inode_infosysv_i; struct affs_inode_infoaffs_i; struct ufs_inode_infoufs_i; struct efs_inode_infoefs_i; struct romfs_inode_inforomfs_i; struct shmem_inode_infoshmem_i; struct coda_inode_infocoda_i; struct smb_inode_infosmbfs_i; struct hfs_inode_infohfs_i; struct adfs_inode_infoadfs_i; struct qnx4_inode_infoqnx4_i; struct reiserfs_inode_inforeiserfs_i; struct bfs_inode_infobfs_i; struct udf_inode_infoudf_i; struct ncp_inode_infoncpfs_i; struct proc_inode_infoproc_i; struct socketsocket_i; struct usbdev_inode_info usbdev_i; struct jffs2_inode_infojffs2_i; void*generic_ip; u; 第23页/共44页第二十三页,共45页。struct file主要用于与文件系统相关的设备驱动程序,可提供关于被打开(d ki)的文件的信息,定义如下:struct file struct list_headf_list;struct dentry*f_dentry;struct vfsmount *f_vfsmnt;struct file_operations*f_op;atomic_tf_count;unsigned int f_flags;mode_tf_mode;loff_tf_pos;unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;struct fown_structf_owner;unsigned intf_uid, f_gid;intf_error;unsigned longf_version;/* needed for tty driver, and maybe others */void*private_data;/* preallocated helper kiobuf to speedup O_DIRECT */struct kiobuf*f_iobuf;longf_iobuf_lock;第24页/共44页第二十四页,共45页。struct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char *, size_t, loff_t *);ssize_t (*write) (struct file *, const char *, size_t, loff_t *);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *,unsigned long, unsigned long, unsigned long, unsigned long);在用户自己的驱动程序中,首先要根据驱动程序的功能,完成file_operations结构(jigu)中函数的实现。不需要的函数接口可以直接在file_operations结构(jigu)中初始化为NULL。file_operations中的变量会在驱动程序初始化时,注册到系统内部。每个进程对设备的操作,都会根据主次设备号,转换成对file_operations结构(jigu)的访问。在设备驱动中,如果有需要的操作而本结构(jigu)中没有提供的,统统交给ioctl函数实现 第25页/共44页第二十五页,共45页。Linux的设备驱动程序与外部的接口可以分为三部分:驱动程序与内核的接口:通过file_operations来完成驱动程序与系统引导的接口:利用驱动程序对设备初始化驱动程序与设备的接口:描述了驱动程序如何与设备进行交互,这部分与具体设备密切相关驱动程序的代码可以分成以下(yxi)几个部分:驱动程序的注册和注销;设备的打开和释放;设备的读写;设备的控制;设备的中断和查询。二、设备(shbi)驱动程序框架第26页/共44页第二十六页,共45页。1. 驱动程序的注册和注销:驱动程序一般通过注册的方式将自己的函数操作集与具体的设备关联(gunlin)起来。所以,在设备初始化时,应向系统进行登记register。卸载设备的时候用unregister注销。字符设备和块设备的注册和注销并不相同。字符设备的注册函数是:int register_chrdev(unsigned int major,const char *name,struct file_operations *fops)卸载函数是:int unregister_chrdev(unsigned int major,const char *name)三、实现各部分需要(xyo)的基本函数第27页/共44页第二十七页,共45页。Linux对字符设备的管理是通过(tnggu)一个字符设备表chrdevs 来实现的。表里的每一项是一个device_struct结构。struct device_structconst char *name;struct file_operations *fops;chrdevs 的数组下标就是字符设备的主设备号major。要查看系统中这个表格的当前内容,看/proc/devices即可。字符(z f)设备表第28页/共44页第二十八页,共45页。字符设备的注册:向chrdevs 中增加一个新项。int register_chrdev(int major,char *name,struct file_operations *fops)major为申请的主设备号,为0时,自动寻找一个空闲号分配。name为设备的名字。fops为驱动程序中file_operations结构的指针。注册成功(chnggng)时,返回申请到的主设备号。出错时返回一个负值。字符设备的注销:void unregister_chrdev(int major,char *name)字符(z f)设备表第29页/共44页第二十九页,共45页。2. 设备读写:设备读写是实现用户空间和内核空间的数据交换,因此涉及内存操作(cozu)。设备驱动程序在申请和释放内存时,因为使用的是内核空间,不能调用用户空间的函数malloc和free,而代之以调用kmalloc和kfree,它们在中被定义为:void *kmalloc(unsigned int len, int priority);void kfree(void * obj);参数len为希望申请的字节数,obj为要释放的内存指针。priority为分配内存操作(cozu)的优先级,即在没有足够空闲内存时如何操作(cozu),一般由取值GFP_KERNEL解决即可。三、实现各部分(b fen)需要的基本函数第30页/共44页第三十页,共45页。2. 设备读写:设备读写是实现用户空间和内核空间的数据交换,因此涉及内存操作。内存间数据的传送:unsigned long copy_to_user(void *to,void *from,long count);unsigned long copy_from_user(void *to,void *from,long count);以上(yshng)两个函数的原型在三、实现各部分需要(xyo)的基本函数第31页/共44页第三十一页,共45页。3. 设备控制:对设备的控制是通过对I/O端口的读写来实现的。inline unsigned int inb(unsigned short port);inline unsigned int inb_p(unsigned short port); /读端口inline void outb(char value,unsigned short port);inline void outb_p(char value,unsigned short port);/写端口int _check_region(struct resource *parent, unsigned long start, unsigned long n);/检查一个区域的端口struct resource *_request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name);/申请(shnqng)一个区域的端口void _release_region(struct resource *parent, unsigned long start, unsigned long n);/释放一个区域的端口三、实现各部分需要的基本(jbn)函数第32页/共44页第三十二页,共45页。3. 设备控制:对设备的控制接口通过ioctl函数来实现。它就象个大杂物箱,把跟设备有关的各种操作都装在这里。例如:一个(y )LCD的驱动,要实现清屏LCD_Clear、显示矩形Disp_Rect、画线Draw_Line等功能。void LCD_Clear() void Disp_Rect() void Draw_Line static int *_ioctl(struct inode *inode, struct file *file, int cmd, long arg)switch(cmd)case:CLEARLCD_Clear();case:RECTDisp_Rect();case:LINEDraw_Line();三、实现(shxin)各部分需要的基本函数第33页/共44页第三十三页,共45页。编写一个,虽然它基本上什么也不干,但是(dnsh)它体现了一个字符设备驱动程序的基本框架:#define _NO_VERSION_#include #include #include #include #include #include #include #include #include #include unsigned int test_major = 0;/用一个静态变量存储设备号四、一个简单(jindn)的字符设备驱动程序第34页/共44页第三十四页,共45页。read和write的实现(shxin):static sszie_t read_test(struct file *file,char *buf,size_t count,loff_t *fops)copy_to_user(*buf,*file,count);static sszie_t write_test(struct file *file,char *buf,size_t count,loff_t *fops)copy_from_user(*file,*buf,count); 二、一个(y )简单的字符设备驱动程序第35页/共44页第三十五页,共45页。open和release的实现(shxin):static int open_test(struct inode *inode,struct file *file)MOD_INC_USE_COUNT;return 0;static int release_test(struct inode *inode,struct file *file)MOD_DEC_USE_COUNT;return 0;二、一个(y )简单的字符设备驱动程序第36页/共44页第三十六页,共45页。file_operations的实现:struct const struct file_operations test_fops=.read = read_test,.write = write_test,.open = open_test,.release = release_test;通过这个结构,将本程序的几个函数集成在这个结构里,注册到字符设备(shbi)表里去。如果有ioctl函数,则驱动程序里就可以写更丰富的函数了。二、一个(y )简单的字符设备驱动程序第37页/共44页第三十七页,共45页。注册(zhc)和注销:int init_module(void)int result;result = register_chrdev(0,”test”,&test_fops);if(test_major = 0)test_major = result;return 0;void cleanup_module(void)unregister_chrdev(0,”test”);二、一个简单(jindn)的字符设备驱动程序第38页/共44页第三十八页,共45页。编写完成后的工作(gngzu):编译用insmod安装,在/proc/devices里可看到安装的设备用mknod创建设备文件,设备号参见上条编写一个测试程序测试设备工作(gngzu)是否正常二、一个(y )简单的字符设备驱动程序第39页/共44页第三十九页,共45页。测试程序:#include #include #include #include main( )int testdev,i;char buf10;testdev = open(“/dev/test”,O_RDWR);read(testdev,buf,10);for(i=0;i10;i+)printf(“%dn”,bufi);close(testdev);二、一个简单(jindn)的字符设备驱动程序第40页/共44页第四十页,共45页。 5.7 中断、异常和系统(xtng)调用 5.7.1 中断处理1中断响应一般说来,中断响应顺序执行下述三步动作:(1)中止当前程序的执行;(2)保存(bocn)原程序的断点信息(主要是程序计数器PC和程序状态寄存器PS的内容);(3)从中断控制器取出中断向量,转到相应的处理程序。 第41页/共44页第四十一页,共45页。2中断处理核心对中断处理的顺序主要由以下动作完成: 保存正在运行进程的各寄存器的内容,把它们放入核 心栈的新帧面中。 确定(qudng)“中断源”或者核查中断发生,识别中断的类型(如时钟中断或者是盘中断)和中断的设备号(如哪个磁盘引起的中断)。系统接到中断后,就从机器那里得到一个中断号,它是检索中断向量表的位移。中断向量因机器而异,但通常都包括相应中断处理程序入口地址和中断处理时处理机的状态字。 核心调用中断处理程序,对中断进行处理。 中断处理完成并返回。中断处理程序执行完以后,核心便执行与机器相关的特定指令序列,恢复中断时寄存器内容和执行核心栈退栈,进程回到用户态。如果设置了重调度标志,则在本进程返回到用户态时做进程调度。第42页/共44页第四十二页,共45页。5.7.2 系统(xtng)调用系统调用象普通C函数调用那样出现在C程序中。只发生在用户空间。能把进程的状态从用户态变为核心态,Linux的系统调用是通过中断指令“INT 0x80”实现的。Linux内核在系统调用时是通过寄存器而不是堆栈传递(chund)参数。所有的系统调用都集中在系统调用入口表中统一管理。系统调用入口表是一个函数指针数组(大小为256),以系统调用号为下标在该数组中找到相应的函数指针,进而就能确定用户使用的是哪一个系统调用。当CPU执行到中断指令“INT 0x80”时,硬件就作出一系列响应,其动作与上述的中断响应相同第43页/共44页第四十三页,共45页。感谢您的观看(gunkn)!第44页/共44页第四十四页,共45页。内容(nirng)总结程序的链接和内存装入。当系统启动时,交换守护进程由内核的init(初始化)进程启动。在通常情况下,用户利用系统提供(tgng)的插入模块工具和移走模块工具来装卸可安装模块。在应用程序中使用标准的系统调用来打开、关闭、读写字符设备。设备读写是实现用户空间和内核空间的数据交换,因此涉及内存操作。#define _NO_VERSION_。unregister_chrdev(0,”test”)。感谢您的观看第四十五页,共45页。
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号