字符设备研究_2

  昨天留下了几个问题:

  1. .KOBJECT是什么?
  2. THIS_MODULE是什么宏?
  3. file操作是什么?
  4. 等待队列是什么?
  5. count是什么?

THIS_MODULE:  

   先从简单的开始求解,THIS_MODULE,其定义为struct module的指针,指向__this_module,而__this_module在编译生成的.mod.c中定义,.看名字就可知这是指向本 module的指针,而且其应该有的地址在insmod之前应该都是不知道的.至于什么时候又是怎么赋值给它的,还有这个模块又是怎么从用户空间插入内核 空间的,只能Google之了.大概过程为:insmod(用户空间)调用sys_init_module(系统调用@kernel/module.c) 调用load_module(内核空间).在load_module中就会把内核模块文件创建为模块插入并生成一个struct module表示该模块.

  其作用在于防止加载模块前对模块与模块对应的file进行操作.

struct module
    {
        enum module_state state;
        struct list_head list;
        char name[MODULE_NAME_LEN];

        struct module_kobject mkobj;
        struct module_param_attrs *param_attrs;
        const char *version;
        const char *srcversion;

        const struct kernel_symbol *syms;
        unsigned int num_syms;
        const unsigned long *crcs;

        const struct kernel_symbol *gpl_syms;
        unsigned int num_gpl_syms;
        const unsigned long *gpl_crcs;

        unsigned int num_exentries;
        const struct exception_table_entry *extable;

        int (*init)(void);
        void *module_init;
        void *module_core;
        unsigned long init_size, core_size;
        unsigned long init_text_size, core_text_size;
        struct mod_arch_specific arch;
        int unsafe;
        int license_gplok;

#ifdef CONFIG_MODULE_UNLOAD
        struct module_ref ref[NR_CPUS];
        struct list_head modules_which_use_me;
        struct task_struct *waiter;
        void (*exit)(void);
#endif

#ifdef CONFIG_KALLSYMS
        Elf_Sym *symtab;
        unsigned long num_symtab;
        char *strtab;
        struct module_sect_attrs *sect_attrs;
#endif
        void *percpu;
        char *args;
    };

  嗯..解决了THIS_MODULE,又多了俩问题:1.insmod的具体过程. 2.struct module的详细分析.解决优先级比较低,放在后面.

file_operations:

  linux中,一切皆为文件,而struct file则代表了一个被打开的文件,其结构提中存放动态的信息和供调用的ops方法,相对地,静态信息(例如设备号)则储存在inode结构提中.

  

  file_operation则是由驱动填充,供用户使用的方法.注意到一个参数(*ppos),一个指向偏移的指针.这个参数不可能由用户空间传来,那是在哪儿传的呢?跟踪一下,也藉此了解一下从用户空间调用驱动方法的过程.

  static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos);

  在捋思路的时候发现系统调用过程细节还是比较复杂的,留个坑,这里讲个简要过程,编写测试程序

  int fd = open("/dev/globalmem", O_RDWR);
  read(fd, buf, 200);
  close(fd);

  编译,反汇编,可知启动int$0x80终端进入内核执行syscall()

  438b1e:    e8 1d ba ff ff           callq  434540 <__libc_read>

  434549:    b8 00 00 00 00           mov    $0x0,%eax
  43454e:    0f 05                    syscall 

  而syscall会在/usr/include/asm/unistd_64.h中比较%eax寄存器的值.

#define __NR_read 0

  进入/usr/src/linux-source-3.13.0/fs/read_write.c

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct fd f = fdget(fd);
    ssize_t ret = -EBADF;

    if (f.file) {
        loff_t pos = file_pos_read(f.file);
        ret = vfs_read(f.file, buf, count, &pos);
        if (ret >= 0)
            file_pos_write(f.file, pos);
        fdput(f);
    }
    return ret;
}

static inline loff_t file_pos_read(struct file *file)
{
    return file->f_pos;
}

ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
    ssize_t ret;

    if (!(file->f_mode & FMODE_READ))
        return -EBADF;
    if (!file->f_op->read && !file->f_op->aio_read)
        return -EINVAL;
    if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
        return -EFAULT;

    ret = rw_verify_area(READ, file, pos, count);
    if (ret >= 0) {
        count = ret;
        if (file->f_op->read)
            ret = file->f_op->read(file, buf, count, pos);
        else
            ret = do_sync_read(file, buf, count, pos);
        if (ret > 0) {
            fsnotify_access(file);
            add_rchar(current, ret);
        }
        inc_syscr(current);
    }

    return ret;
}

  可见*ppos在内核调用file->f_op->read时用file->f_pos复制,结束后更新file->f_pos,用户空空间要想读取特定位置的数据只能先通过llseek来更改f_pos.

  嗯,问题更多了,明天继续解决.

  1. 等待队列是什么?
  2. count是什么?
  3. KOBJECT是什么?
  4. 系统调用具体过程.
  5. insmod的具体过程.
  6. struct module的详细分析

 

 

  

  

  

  

posted @ 2016-11-10 20:49  胡星宇  阅读(165)  评论(0编辑  收藏  举报