linux教程第08课内存与设备管理.ppt_第1页
linux教程第08课内存与设备管理.ppt_第2页
linux教程第08课内存与设备管理.ppt_第3页
linux教程第08课内存与设备管理.ppt_第4页
linux教程第08课内存与设备管理.ppt_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

5.4 内 存 管 理,操作系统常用的内存管理方式: 单一分配方式 分区式分配方式 页式分配方式 段式分配方式 Linux系统采用了虚拟内存管理机制,就是交换和请求分页存储管理技术,程序的链接和内存装入,连续分配方式,单一连续分配,这是最简单的一种存储管理方式,但只能用于单用户、单任务的操作系统中。采用这种存储管理方式时,可把内存分为系统区和用户区两部分,系统区仅提供给OS使用,通常是放在内存的低址部分;用户区是指除系统区以外的全部内存空间, 提供给用户使用。,固定分区分配,1. 划分分区的方法,分区大小相等, 即使所有的内存分区大小相等。 (2) 分区大小不等。,2. 内存分配,固定分区使用表,4.2.3 动态分区分配,1. 分区分配中的数据结构,空闲分区表。 (2) 空闲分区链。,空闲链结构,5.4.1 请求分页机制 1分页概念 逻辑空间分页 内存空间分页 页面和内存块的大小是由硬件确定的 逻辑地址表示 内存分配原则 页表,2请求分页的基本思想 请求分页提供虚拟存储器 在每一个页表项中增加一个状态位表示一个页面是否已装入内存块 如果地址转换机构遇到一个具有N状态的页表项时,便产生一个缺页中断,3Linux的多级页表 Linux进程的虚存空间 Linux系统采用三级页表的方式,4内存页的分配与释放 Linux系统采用两种方法来管理内存页:位图和链表 页组中内存页的数量依次按2的倍数递增,5.4.2 内存交换,内核的交换守护进程kswapd :有自己的进程控制块task_struct结构,它与其他进程一样受内核的调度。但是,它没有自己独立的地址空间,只使用系统空间,所以也把它称为线程。它的任务就是保证系统中有足够的空闲内存页。 当系统启动时,交换守护进程由内核的init(初始化)进程启动。被定时唤醒 。 所做的工作主要分为两部分:将若干不常用的活跃内存页面变为不活跃状态;清理不活跃的“脏”页面,或者回收一些内存页,使之成为空闲的内存页。 作为交换空间的交换文件实际就是普通文件,但它们所占的磁盘空间必须是连续的,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);,5.6 设 备 管 理 5.6.1 设备管理概述,所有设备都作为特别文件,从而在管理上就具有下列共性: (1)每个设备都对应文件系统中的一个索引节点,都有一个文件名。 (2)应用程序通常可以通过系统调用open( )打开设备文件,建立起与目标设备的连接。 (3)对设备的使用类似于对文件的存取。 (4)设备驱动程序是系统内核的一部分,它们必须为系统内核或者它们的子系统提供标准的接口。 (5)设备驱动程序利用一些标准的内核服务,如内存分配等。另外,大多数Linux设备驱动程序都可以在需要时装入内核,不需要时卸载下来。,设备驱动的分层结构,5.6.2 设备驱动程序和内核之间的接口,1可安装模块 可安装模块是可以在系统运行时动态地安装和拆卸的内核模块,即经过编译但尚未连接的目标文件(后缀为.o)。 设备驱动程序或者与设备驱动紧密相关的部分(如文件系统)都是利用可安装模块实现的。 在通常情况下,用户利用系统提供的插入模块工具和移走模块工具来装卸可安装模块。,2字符设备 用户对字符设备的使用就和存取普通文件一样。在应用程序中使用标准的系统调用来打开、关闭、读写字符设备。,3块设备 对块设备的存取与对文件的存取方式一样,其实现机制也与字符设备使用的机制相同。,设备驱动与文件系统的关系,设备驱动是Linux内核的重要组成部分。驱动程序跟一般的用户应用程序不同,它工作在内核态,编程方法和使用的库函数都跟用户级的应用程序有所区别。在Linux内核中,设备驱动跟文件系统联系紧密。每一个设备都是作为一个设备文件,交给文件系统去管理的。 设备驱动程序内部是由一组函数组成的。函数由设备驱动的上层文件系统来调用,每一个函数被称做一个入口点。入口点的集合被称为设备驱动程序的上半部分,实现设备驱动与文件系统的接口。常用的入口点有:open、close(或release)、read、write、ioctl等。 每一个函数的内部实现被称作驱动程序的下半部分,负责实现具体的设备操作。函数的内部实现通常是靠系统调用提供的函数实现的,不能使用平常我们使用的用户级的C语言库函数。,Linux通过设备号来区分不同的设备。设备号由两部分组成:主设备号MAJOR和次设备号MINOR。 主设备号MAJOR指明对应哪些设备驱动。一般一个主设备号对应一个驱动程序。 次设备号MINOR用来区分同一个驱动程序控制下的不同的独立的设备。 例如:硬盘的主设备名称为hd。在/dev目录下hd即为硬盘。/dev/hda、/dev/hdb等是系统的第一个硬盘和第二个硬盘。而hda0和hda1分别是第一个硬盘上的第一个分区和第二个分区。 /proc/devices列出所有现在正在使用的设备号。,设备号,Linux操作系统将所有的设备全部看成文件,并通过文件的操作界面进行操作,用户程序可以像对其他文件一样对此设备文件进行操作。这意味着: 由于每一个设备至少由文件系统的一个文件代表,因而都有一个“文件名”。 应用程序通常可以通过系统调用open()打开设备文件,建立起与目标设备的连接。 打开了代表着目标设备的文件,即建立起与设备的连接后,可以通过read()、write()、ioctl()等常规的文件操作对目标设备进行操作。 设备文件的属性由三部分信息组成:第一部分是文件的类型,第二部分是一个主设备号,第三部分是一个次设备号。其中类型和主设备号结合在一起惟一地确定了设备文件驱动程序及其界面,而次设备号则说明目标设备是同类设备中的第几个。,设备文件,设备文件不能用普通的办法建立。要通过mknod命令。 mknod命令的语法: mknod 路径 模式 主设备号 次设备号 模式有两种:c为字符设备 b为块设备 例如:mknod /dev/test c 254 0 设备文件可以象普通文件一样直接使用,例如: /dev/lp0为一个打印机,使用cat doc.txt/dev/lp0就可以将文档交给打印机去进行打印 /dev/ttyS0为主机上的串口COM1,使用读写文件的方法,也可以实现对串口的读写操作,设备文件,一、设备驱动中的关键数据结构 二、驱动程序框架 三、实现各种功能的基本函数 四、实例,设备驱动基础,要编写设备驱动程序,就要实现它跟高层文件系统和底层硬件之间的操作接口。这些接口一般要遵循DDI/DKI(Device-Driver Interface / Device-Kernel Interface)接口规范,所以要使用一些标准的数据结构来进行操作。 底层硬件的操作主要由不同硬件的特性来决定。跟文件系统的接口主要使用三个数据结构: inode文件索引节点结构 struct file文件结构 file_operations文件操作结构,设备驱动程序要实现这个结构里的主要操作,一、设备驱动中的关键数据结构,struct inode称做索引节点数据结构,定义如下: struct inode struct list_head i_hash; struct list_head i_list; struct list_head i_dentry; struct list_head i_dirty_buffers; struct list_head i_dirty_data_buffers; unsigned long i_ino; atomic_t i_count; kdev_t i_dev; umode_t i_mode; nlink_t i_nlink; uid_t i_uid; gid_t i_gid; kdev_t i_rdev; loff_t i_size; time_t i_atime; time_t i_mtime; time_t i_ctime; unsigned int i_blkbits; unsigned long i_blksize; unsigned long i_blocks; unsigned long i_version; struct semaphore i_sem; struct semaphore i_zombie; struct inode_operations *i_op; struct file_operations *i_fop; /文件操作指针 struct super_block *i_sb; wait_queue_head_t i_wait; struct file_lock *i_flock; struct address_space *i_mapping; struct address_space i_data; struct dquot *i_dquotMAXQUOTAS; struct list_head i_devices; struct pipe_inode_info *i_pipe; struct block_device *i_bdev; /块设备 struct char_device *i_cdev; /字符设备 unsigned long i_dnotify_mask; struct dnotify_struct *i_dnotify; unsigned long i_state; unsigned int i_flags; unsigned char i_sock; atomic_t i_writecount; unsigned int i_attr_flags;,_u32 i_generation; union struct minix_inode_info minix_i; struct ext2_inode_info ext2_i; struct ext3_inode_info ext3_i; struct hpfs_inode_info hpfs_i; struct ntfs_inode_info ntfs_i; struct msdos_inode_info msdos_i; struct umsdos_inode_info umsdos_i; struct iso_inode_info isofs_i; struct nfs_inode_info nfs_i; struct sysv_inode_info sysv_i; struct affs_inode_info affs_i; struct ufs_inode_info ufs_i; struct efs_inode_info efs_i; struct romfs_inode_info romfs_i; struct shmem_inode_info shmem_i; struct coda_inode_info coda_i; struct smb_inode_info smbfs_i; struct hfs_inode_info hfs_i; struct adfs_inode_info adfs_i; struct qnx4_inode_info qnx4_i; struct reiserfs_inode_info reiserfs_i; struct bfs_inode_info bfs_i; struct udf_inode_info udf_i; struct ncp_inode_info ncpfs_i; struct proc_inode_info proc_i; struct socket socket_i; struct usbdev_inode_info usbdev_i; struct jffs2_inode_info jffs2_i; void *generic_ip; u; ;,struct file主要用于与文件系统相关的设备驱动程序,可提供关于被打开的文件的信息,定义如下: struct file struct list_head f_list; struct dentry *f_dentry; struct vfsmount *f_vfsmnt; struct file_operations *f_op; atomic_t f_count; unsigned int f_flags; mode_t f_mode; loff_t f_pos; unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; struct fown_struct f_owner; unsigned int f_uid, f_gid; int f_error; unsigned long f_version; /* needed for tty driver, and maybe others */ void *private_data; /* preallocated helper kiobuf to speedup O_DIRECT */ struct kiobuf *f_iobuf; long f_iobuf_lock; ;,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结构中函数的实现。不需要的函数接口可以直接在file_operations结构中初始化为NULL。file_operations中的变量会在驱动程序初始化时,注册到系统内部。每个进程对设备的操作,都会根据主次设备号,转换成对file_operations结构的访问。 在设备驱动中,如果有需要的操作而本结构中没有提供的,统统交给ioctl函数实现,Linux的设备驱动程序与外部的接口可以分为三部分: 驱动程序与内核的接口:通过file_operations来完成 驱动程序与系统引导的接口:利用驱动程序对设备初始化 驱动程序与设备的接口:描述了驱动程序如何与设备进行交互,这部分与具体设备密切相关 驱动程序的代码可以分成以下几个部分: 驱动程序的注册和注销; 设备的打开和释放; 设备的读写; 设备的控制; 设备的中断和查询。,二、设备驱动程序框架,1. 驱动程序的注册和注销: 驱动程序一般通过注册的方式将自己的函数操作集与具体的设备关联起来。所以,在设备初始化时,应向系统进行登记register。卸载设备的时候用unregister注销。 字符设备和块设备的注册和注销并不相同。字符设备的注册函数是: int register_chrdev(unsigned int major,const char *name,struct file_operations *fops) 卸载函数是: int unregister_chrdev(unsigned int major,const char *name),三、实现各部分需要的基本函数,Linux对字符设备的管理是通过一个字符设备表chrdevs 来实现的。表里的每一项是一个device_struct结构。 struct device_struct const char *name; struct file_operations *fops; chrdevs 的数组下标就是字符设备的主设备号major。 要查看系统中这个表格的当前内容,看/proc/devices即可。,字符设备表,字符设备的注册:向chrdevs 中增加一个新项。 int register_chrdev(int major,char *name,struct file_operations *fops) major为申请的主设备号,为0时,自动寻找一个空闲号分配。name为设备的名字。fops为驱动程序中file_operations结构的指针。 注册成功时,返回申请到的主设备号。出错时返回一个负值。 字符设备的注销: void unregister_chrdev(int major,char *name),字符设备表,2. 设备读写: 设备读写是实现用户空间和内核空间的数据交换,因此涉及内存操作。 设备驱动程序在申请和释放内存时,因为使用的是内核空间,不能调用用户空间的函数malloc和free,而代之以调用kmalloc和kfree,它们在linux/kernel.h中被定义为: void *kmalloc(unsigned int len, int priority); void kfree(void * obj); 参数len为希望申请的字节数,obj为要释放的内存指针。priority为分配内存操作的优先级,即在没有足够空闲内存时如何操作,一般由取值GFP_KERNEL解决即可。,三、实现各部分需要的基本函数,2. 设备读写: 设备读写是实现用户空间和内核空间的数据交换,因此涉及内存操作。 内存间数据的传送: unsigned long copy_to_user(void *to,void *from,long count); unsigned long copy_from_user(void *to,void *from,long count); 以上两个函数的原型在,三、实现各部分需要的基本函数,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); /申请一个区域的端口 void _release_region(struct resource *parent, unsigned long start, unsigned long n); /释放一个区域的端口,三、实现各部分需要的基本函数,3. 设备控制: 对设备的控制接口通过ioctl函数来实现。它就象个大杂物箱,把跟设备有关的各种操作都装在这里。 例如:一个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:CLEAR LCD_Clear(); case:RECT Disp_Rect(); case:LINE Draw_Line(); ,三、实现各部分需要的基本函数,编写一个test.c,虽然它基本上什么也不干,但是它体现了一个字符设备驱动程序的基本框架: #define _NO_VERSION_ #include #include #include #include #include #include #include #include #include #include unsigned int test_major = 0; /用一个静态变量存储设备号,四、一个简单的字符设备驱动程序,read和write的实现: 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); ,二、一个简单的字符设备驱动程序,open和release的实现: 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; ,二、一个简单的字符设备驱动程序,file_operations的实现: struct const struct file_operations test_fops= .read = read_test, .write = write_test, .open = open_test, .release = release_test ; 通过这个结构,将本程序的几个函数集成在这个结构里,注册到字符设备表里去。如果有ioctl函数,则驱动程序里就可以写

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论