找回密码
 注册
关于网站域名变更的通知
查看: 465|回复: 3
打印 上一主题 下一主题

Linux内核模块简介

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-10-28 10:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
Linux系统内核按体积和功能的不同,可以分为两种:微内核与单内核。
      
    微内核,体积小,包含的功能也少,只负责进行进程调度、进程通信、底层中断等工作,而把传统操作系统内核的其他功能 模块,如设备驱动、内存管理、文件系统、网络协议等作为服务器运行于内核之上。每个功能模块都一个单独的进程,它们通过内核转发消息,进行联系,因此微内核更像是一个消息转发站。这种内核结构有利于降低内核各功能模块之时的合性,使得在不影响系统其他部分工作的前提下,用更高效的实现代替现有的功能模块的工作更加容易,同时,具有更好的可扩展性。但是,不同功能模块之间的消息传递需要一定的开销,这势必会影响到系统运行的效率。
      
    单内核操作系统采用了内核单一化设计,内核是一个单独的二进制映像,包含操作系统内核的各个组成部分,其模块间的通信是通过直接调用其他模块中的函数实现的,而不是消息传递。单内核又被称做单一内核、大内核、宏内核等。单内核运行时避免了频繁的消息传递,因此执行效率较高,但是从软件工程的角度来说,所有功能模块结合在一起作为一个进行运行,导致内核难以维护和增加新的功能。典型的单内核操作系统有UNIX、Linux、OS/360等。
      
    微内核和单内核各有优缺点,在Linux诞生之初,由于内核结构还曾经引起论战。但如今,Linux已被移植到各平台,早已证明其蓬勃的生命力。
      
        Linux采用单内核结构,同时支持模块特性。模块的全称为动态可加载内核模块,是一种目标对象文件,一般由一组函数或数据结构组成,运行于内核空间,不能被交换出内存。模块没有经过链接,不能独立运行,但是其代码可以在运行时链接到系统中作为内核的一部分运行,动态扩充内核的功能,也可以从内核中卸载。模块一旦被插入到内核,就获得和内核同等的地位,代码与内核代码完全等价。采用模块机制之后,更改内核特性时不再需要重新编译内核,可以把内核编译的很小,只包括一些最常用的功能,而把大部分功能作为模块编译,需要时再动态插入内核,利用模块来实现系统的可扩展性,使得内核结构更加紧凑灵活,这是Linux内核模块的重要作用。
      
    但,操作系统采用内核模块也有不足之处,模块装入内核之后即作为内核一部分运行,获得和内核完全等同的权限,可以访问内核的任意部分,如果模块出了问题,可能会影响到整个操作系统的稳定性,严重时甚至导致内核崩溃。内核中维护了一张符号表,包含了内核中所有全局变量和函数地址,当模块插入到内核时,会所自身的全局变量和函数插入到内核符号表中,当模块卸载时,需要把相应的标识符从内核符号表中删去,这些都产生了系统运行的开销。某些需要插入到内核中的模块,其运行可能依赖于早先插入的模块,因此内核还需要维护模块之间的依赖关系,这些也会造成一定开销。可以用模块机制来实现文件系统、驱动程序等功能,但是操作系统最基础最核心的部分不能使用模块机制,如进程调试、内存管理等功能。
      
        Linux系统包含对内核操作的实用工具软件,如modutils,其包含以下几个程序:
      
1.     insmod:将编译好的模块插入到内核当中。insmod运行时会自动调用模块中的Init_module()。只有超级用户才有使用insmod的权限。
      
2.     rmmod:用来把插入到内核中的模块卸载掉。rmmod运行时会自动调用模块中的cleanup_module()。只有超级用户才有使用rmmod的权限。
      
3.     lsmod:用来显示当前系统中所有正在运行的模块信息。
      
4.     ksyms:用来显示内核符号和模块符号表信息。
      
5.     depmod:处理可加载内核模块的依赖关系。
      
6.     modprobe:根据模块之间的依赖关系自动插入所需模块。
      % b' x1 f# Q# m' }1 ^- g
      
        Linux内核模块简单示例:
      
        #define MODULE
      
        #include <linux/module.h>
      
        int init_module(void)
      
        {
      
                printk(“<1>”hello!\n);
      
                return 0;
      
}
      
1 |) h/ P! X) `* ~4 r+ n      
void cleanup_module(void)
      
{
      
        printk(“<1>”goodbye!\n);
      
}
      
上例中定义了宏MODULE,它在程序中并未显示使用,但相当于一个开关,在头文件linux/module.h中,会根据这个宏是否定义过来执行一些操作,因此宏MODULE必须置于头文件语句#include <linux/module.h>之间。
      
init_module()是模块的必要组成部分,负责向内核注册模块提供新功能,当使用Insmod命令插入模块时,init_module()会被调用。同理,cleanup_module()也必不可少,每当卸载模块时,该函数会被调用,负责通知内核当前模块已经被卸载。
      
printk()是内核输出函数,功能与常用的printf()类似,但是不支持浮点数显示。printk()是一个内核函数,实现代码包含在内核中,工作在内核空间,而printf()实现代码在libc中,工作在用户空间。内核代码不能使用用户空间的资源,因此模块只能使用printk()。printk()可以对显示信息的优先级进行分类,这通过在消息前加一个代表消息优先级的数字或者宏来实现。<linux/kernel.h>中定义了8种消息优先级。
      
1.     KERN_EMERG:优先级别最高,表示最紧急的情况,一般代表系统即将崩溃;
      
2.     KERN_ALERT:优先级别次高,表示非常紧急的情况,需要立刻采取行动;
      
3.     KENR_CRIT:很紧急,常用于发生了严重的软硬件操作失败的情况;
      
4.     KERN_ERR:用于提示发生了错误,常用在驱动程序中,报告来自于硬件的错误;
      
5.     KERN_WARNING:警告级别,表示可能发生错误,但是这类错误通常不会有很严重的后果;
      
6.     KERN_NOTICE:告知级别,表示目前系统出现了一些情况,但属于正常情况。
      
7.     KERN_INFO:提示性信息;
      
8.     KERN_debug:调试信息,级别最低。
      
每个宏将来被展开后都表现为一个尖括号中的整数值,范围为0~7,数字越小代表优先级越高。

1 z2 W* i! j/ R& V

该用户从未签到

2#
发表于 2020-10-28 13:48 | 只看该作者
Linux现在用的很多。

点评

linux太难学了  详情 回复 发表于 2020-10-28 13:49
  • TA的每日心情
    开心
    2023-5-15 15:14
  • 签到天数: 1 天

    [LV.1]初来乍到

    3#
    发表于 2020-10-28 13:49 | 只看该作者
    行者~ABC 发表于 2020-10-28 13:48
    : f$ b/ y+ U! k& d- j, D$ RLinux现在用的很多。

      V- @; m) T8 V0 |8 _' X+ Clinux太难学了, g, J4 e& X( l

    点评

    资料很多,多下功夫肯定就会了  详情 回复 发表于 2020-10-28 15:24

    该用户从未签到

    4#
    发表于 2020-10-28 15:24 | 只看该作者
    Heaven_1 发表于 2020-10-28 13:49
      S, M3 I. V1 w- Y! T- V* O5 Slinux太难学了
    ; ]5 r5 p6 t1 x. h: Y/ M  C
    资料很多,多下功夫肯定就会了8 Q& p, c# i+ g1 Q- r
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-8-20 17:55 , Processed in 0.125000 second(s), 28 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表