字符设备研究_2
昨天留下了几个问题:
- .KOBJECT是什么?
- THIS_MODULE是什么宏?
- file操作是什么?
- 等待队列是什么?
- 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.
嗯,问题更多了,明天继续解决.
- 等待队列是什么?
- count是什么?
- KOBJECT是什么?
- 系统调用具体过程.
- insmod的具体过程.
- struct module的详细分析