Snowdream

I'm awake but my world is half asleep
posts - 403, comments - 310, trackbacks - 0, articles - 7
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

读核笔记(1) - 内核模块

Posted on 2008-02-07 11:22 ZelluX 阅读(449) 评论(3)  编辑  收藏 所属分类: System
include/linux/module.h
struct module:
struct module
{
    
// 用于在用户空间传入module对象时判断传入的结构是否有效
    unsigned long size_of_struct;    /* == sizeof(module) */
    
struct module *next;
    
// 指向本module的名称,通常内核空间里申请的name内存位置都是紧跟在module{}结构后面的
    const char *name;
    
// 本module{}结构的空间 + 紧接着这段内存申请的归module{}结构使用的一部分空间
    
// size = sizeof(struct module) + sizeof(misc data)
    unsigned long size;

    
// 模块引用计数器,还没搞清楚这里的pad是干什么用的
    
// i386中atomic_t的定义: typedef struct { volatile int counter; } atomic_t;
    union
    
{
        atomic_t usecount;
        
long pad;
    }
 uc;                /* Needs to keep its size - so says rth */

    
// 模块当前状态,已初始化/运行中/被移除/被访问过等
    unsigned long flags;        /* AUTOCLEAN et al */

    
// 定义的内核模块符号数
    unsigned nsyms;
    
// 引用的模块链表节点数,遍历模块依赖性时使用
    unsigned ndeps;

    
// 符号表
    struct module_symbol *syms;
    
// 记录依赖的其他模块的数组
    struct module_ref *deps;
    
// 记录引用该模块的其他模块的数组
    struct module_ref *refs;
    
// 初始化和删除模块时调用的函数指针
    int (*init)(void);
    
void (*cleanup)(void);
    
// 中断向量表的入口和结束位置
    const struct exception_table_entry *ex_table_start;
    
const struct exception_table_entry *ex_table_end;
#ifdef __alpha__
    unsigned 
long gp;
#endif
    
/* Members past this point are extensions to the basic
       module support and are optional.  Use mod_member_present()
       to examine them.  
*/

    
// 这两个指针维持一些模块相关信息,方便卸载后再次装载模块时的配置
    const struct module_persist *persist_start;
    
const struct module_persist *persist_end;
    
int (*can_unload)(void);
    
int runsize;            /* In modutils, not currently used */
    
const char *kallsyms_start;    /* All symbols for kernel debugging */
    
const char *kallsyms_end;
    
const char *archdata_start;    /* arch specific data for module */
    
const char *archdata_end;
    
const char *kernel_data;    /* Reserved for kernel internal use */
}
;

struct module_symbol:
保存目标代码中的内核符号,读取文件装入模块时通过这个数据结构将里面包含的符号信息读入。
struct module_symbol
{
    unsigned 
long value; // 入口地址
     const char *name;    // 内核符号名称
}
;

struct module_ref:
注意这里dep和ref记录的不对称,应该可以看成是一个ref链表吧
module{} 中的deps数组分别指向了各个依赖的module_ref{}
struct module_ref
{
    
struct module *dep;    /* "parent" pointer */
    
struct module *ref;    /* "child" pointer */
    
struct module_ref *next_ref;
}
;

struct kernel_sym:
在sys_get_kernel_syms()中用到的结构,该函数将内核符号拷贝到用户空间的kernel_sym{}中,从而可以在用户态存放模块信息。
struct kernel_sym
{
    unsigned 
long value;    // 内核符号地址
    char name[60];        /* should have been 64-sizeof(long); oh well */
}
;

module.c中的一些函数先略去了,书上蛮详细的

模块的加载和卸载
insmod的任务:
从命令行中读入模块名,确定代码所在文件的位置
计算需要的内存
执行系统调用create_module(),传递新模块的名称和大小
用QM_MODULES获得所有已经链接模块的模块名
用QM_SYMBOL获得内核符号表和已经链接到内核的模块的符号表
使用这些信息重新定位该模块文件中的代码
在用户空间分配内存,拷贝相关信息
调用sys_init_module(),传递上面创建的用户态的内存区地址
释放用户态内存,结束

rmmod的任务:
用QM_MODULES和QM_REFS取得已经链接的模块列表和依赖关系
调用delete_module

评论

# re: 读核笔记(1) - 内核模块  回复  更多评论   

2008-02-07 14:27 by Lee.MaRS
// 模块引用计数器,还没搞清楚这里的pad是干什么用的
// i386中atomic_t的定义: typedef struct { volatile int counter; } atomic_t;
union
{
atomic_t usecount;
long pad;
} uc; /**//* Needs to keep its size - so says rth */

看它这里的注释,似乎是为了保证sizeof(uc)至少为sizeof(long)

# re: 读核笔记(1) - 内核模块  回复  更多评论   

2008-02-07 14:33 by ZelluX
@Lee.MaRS
哦,保证这个有什么用呢?对齐时方便吗?

# re: 读核笔记(1) - 内核模块  回复  更多评论   

2008-02-08 22:55 by Lee.MaRS
@ZelluX
除了对齐我也想不出还有什么别的用了

只有注册用户登录后才能发表评论。


网站导航: