zoukankan      html  css  js  c++  java
  • Linux内核源码分析 -- /dev/mem

    源码版本:Linux kernel 1.0

    分析字符设备 /dev/mem 的驱动程序

    既然是字符设备,万物皆文件,先找 file_operations 结构

    struct file_operations mem_fops

    static struct file_operations mem_fops = {
    	memory_lseek,
    	read_mem,
    	write_mem,
    	NULL,		/* mem_readdir */
    	NULL,		/* mem_select */
    	NULL,		/* mem_ioctl */
    	mmap_mem,
    	NULL,		/* no special open code */
    	NULL,		/* no special release code */
    	NULL		/* fsync */
    };
    

    支持 read write lseek mmap

    一个一个分析

    read_mem

    参数就是直接对 inode 进行操作

    static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
    {
    	unsigned long p = file->f_pos; // 获取 mem 文件的 pos 指针(其实就是我们指定的读取的地址)
    	int read; // 计数器,用来记录拷贝了多少数据
    
    	
    	if (count < 0) // 检查读取 size 的合法性,不能读取一个负数大小
    		return -EINVAL;
    
    	if (p >= high_memory) // 不能读取 high memory
    		return 0;
    	if (count > high_memory - p) // 如果读取的大小比可读内存区域还大的话
    		count = high_memory - p; // 只允许读除了 high memory 以外的内存
    	read = 0;
    
    	// 不能读取 0 号页,所以逐字节把 buf 前 4096 字节置 0(因为现在是在内核态,buf 位于用户态,需要用 put_fs_byte 来操作)
    	while (p < PAGE_SIZE && count > 0) {
    		put_fs_byte(0,buf); 
    		buf++;
    		p++;
    		count--;
    		read++;
    	}
    	// 把 p 为起始地址,大小为 count 的内存数据拷贝到用户态的 buf
    	memcpy_tofs(buf,(void *) p,count);
    	read += count; // 增加计数器的值
    	file->f_pos += read; // 移动文件 pos 指针
    	return read;
    }
    

    write_mem

    static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
    {
    	unsigned long p = file->f_pos; // 获取 mem 文件的 pos 指针(我们要写入数据的地址)
    	int written; // 计数器
    
    	if (count < 0) // 检查写入数据的大小的合法性
    		return -EINVAL;
    	if (p >= high_memory) // 不能写 high memory
    		return 0;
    	if (count > high_memory - p)
    		count = high_memory - p;
    	written = 0;
    	// 不能写 0 号页,直接跳过
    	while (p < PAGE_SIZE && count > 0) {
    		/* Hmm. Do something? */
    		buf++;
    		p++;
    		count--;
    		written++;
    	}
    	memcpy_fromfs((void *) p,buf,count); // 把数据从用户态 buf 拷贝到现在 p 指向的地址(数据块大小为 count)
    	written += count; // 增加计数器的值
    	file->f_pos += written; // 移动指针
    	return count;
    }
    

    memory_lseek

    /*
     * The memory devices use the full 32 bits of the offset, and so we cannot
     * check against negative addresses: they are ok. The return value is weird,
     * though, in that case (0).
     *
     * also note that seeking relative to the "end of file" isn't supported:
     * it has no meaning, so it returns -EINVAL.
     */
    static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
    {
    	switch (orig) {
    		case 0:
    			file->f_pos = offset;
    			return file->f_pos;
    		case 1:
    			file->f_pos += offset;
    			return file->f_pos;
    		default:
    			return -EINVAL;
    	}
    	if (file->f_pos < 0)
    		return 0;
    	return file->f_pos;
    }
    

    结语

    在对 /dev/mem 进行读写时,file->f_pos 其实就是我们读写的地址,buf 因为是位于用户态,在内核态不能直接读写用户态的数据,所以需要特定的函数去执行,就像高版本的 kernel 的 copy_from_user copy_to_user .......这类函数

  • 相关阅读:
    mwutil公用方法库——dateTool
    mwutil公用方法库文档——cookieTool
    mwutil 公用方法库文档 ——arrayTool
    localstorage封装!
    github commit 规范
    你好,C++(40)7.1 一切指针都是纸老虎:彻底理解指针
    你好,C++(39)6.4.4 依葫芦画瓢:用C++表达设计结果(下)
    你好,C++(38)从问题描述中发现对象的属性和行为 6.4 工资程序成长记:类与对象(上)
    你好,C++(37)上车的人请买票!6.3.3 用虚函数实现多态
    你好,C++(36)人参再好,也不能当饭吃!6.3 类是如何面向对象的
  • 原文地址:https://www.cnblogs.com/crybaby/p/14319075.html
Copyright © 2011-2022 走看看