Linux内核模块的添加
操作系统实验---内核模块实现

实验报告实验题目:内核模块实现姓名:学号:课程名称:操作系统所在学院:信息科学与工程学院专业班级:计算机任课教师:module_init(初始函数名);module_exit(退出函数名 );MODULE_LICENSE("GPL");//模块通用公共许可证5、makefile文件内容基本格式ifneq ($(KERNELRELEASE),)obj-m:=xxx.oelseKDIR:=/lib/modules/$(shell uname -r)/buildPWD:=$(shell pwd)all:make -C $(KDIR) M=$(PWD) modulesclean:rm -rf *.o *.ko *.mod.c *.cmd *.markers *.order *.symvers .tmp_versions endif说明:1) KERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量。
ifneq($(KERNELRELEASE),) 判断该变量是否为空。
2) KDIR := /lib/modules/$(shell uname -r)/build 是给KDIR这个变量赋值,值为当前linux运行的内核源码。
3) 当make的目标为all时,-C $(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD)表明然后返回到当前目录继续读入、执行当前的Makefile。
当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。
4) 我们可以把上述的Makefile文件作为一个模板,只需要改动obj-m := hello.o这条语句就可以了:obj-m=XXX.o。
4、进入管理员权限,cd到目录下。
输入如下命令:5、输入make命令以编译:6、编译成功后,输入insmod命令安装自己的内核模块:7、查看内核模块:可以看到自己的time模块安装成功。
操作系统实验一向LINUX内核增加一个系统调用

操作系统实验一向LINUX内核增加一个系统调用一、背景介绍操作系统是计算机硬件与应用程序之间的接口,负责管理和调度计算机系统的各种资源,并提供用户与计算机系统的交互界面。
内核是操作系统的核心部分,负责管理和分配计算机系统的资源,执行各种任务。
系统调用是操作系统提供给应用程序的一种接口,可以让应用程序访问内核提供的功能,例如文件操作、进程管理、网络通信等。
在一些情况下,我们可能需要在LINUX内核中增加新的系统调用,以满足特定的需求。
本文将介绍如何向LINUX内核增加一个系统调用的具体步骤。
二、增加系统调用的步骤1.编写系统调用的具体实现代码首先,我们需要编写一个具体的系统调用的实现代码。
在LINUX内核中,系统调用的实现代码通常位于内核的/syscalls目录下。
我们可以在该目录下新建一个.c文件,编写我们自己的系统调用代码。
2.修改内核源代码3.更新系统调用表每个系统调用都在内核中有一个唯一的标识符,存储在一个叫做系统调用表的地方。
我们需要更新系统调用表,将新增的系统调用添加到表中。
这样,用户程序才能够通过系统调用号来调用新增的系统调用。
4.重新编译内核在修改完内核源代码后,我们需要重新编译内核。
这通常涉及到一些繁琐的步骤,例如配置内核选项、编译内核、安装内核等。
在重新编译内核之后,我们需要重新启动计算机,使新的内核生效。
5.修改用户程序最后,我们需要修改用户程序,以便能够调用新增的系统调用。
用户程序通常是通过C语言编写的,我们可以在用户程序的代码中添加对新增系统调用的调用代码。
三、实验结果在完成上述步骤后,我们就成功地向LINUX内核增加了一个系统调用。
用户程序可以通过系统调用调用自己新增的系统调用,从而实现特定的功能。
总结:本文介绍了向LINUX内核增加一个系统调用的具体步骤,包括编写系统调用的具体实现代码、修改内核源代码、更新系统调用表、重新编译内核和修改用户程序。
在实施这些步骤之前,我们需要对操作系统和内核的相关概念有一定的了解,并具备一定的编程能力。
Linux加载内核模块月与灯依旧

Linux加载内核模块月与灯依旧Linux加载内核模块的过程,记录一下,主要命令有modprobe、insmod及depmod等,命令由module-init-tools的软件包提供,请先确认系统安装了此软件包。
本文方法已在CentOS 5 x86_64和CentOS6 x86_64系统上验证通过。
一,查看内核已加载的模块[root@os ~]# lsmod该命令通过读取/proc/modules文件中的内容列出已加载的模块。
系统中的所有模块位于/lib/modules/$(uname -r)/kernel/下的各种目录中。
二,手动加载模块手动加载模块的方法有两个,下面分别介绍。
2.1 执行insmod命令加载模块[root@os ~]# insmod mycdev.ko2.2 执行modprobe命令加载模块将模块拷入到相应目录下[root@os ~]# cp mycdev.ko /lib/modules/$(uname -r)/kernel/drivers/char/然后把模块的绝对地址写入到modules.dep文件中手动写入(注意写入的行末尾有一个冒号)[root@os ~]# echo /lib/modules/$(uname -r)/kernel/drivers/char/mycdev.ko: >> /lib/modules/$(uname -r)/modules.dep或者执行如下命令自动写入[root@os ~]# depmod -a然后,就可以加载模块了[root@os ~]# modprobe mycdev #加载模块[root@os ~]# lsmod | grep mycdev #检验加载是否成功mycdev 35840 0三,卸载模块[root@os ~]# rmmod sysdog四,开机自动加载模块鸟哥的linux私房菜一书中,介绍的Linux系统开机流程:(1) 载入BIOS的硬件信息,并取得第一个开机装置的代号(2) 读取第一个开机装置的MBR的boot Loader (grub)的开机信息(3) 载入OS Kernel信息,解压Kernel,尝试驱动硬件(4) Kernel执行init程序并获得run-lebel信息(如3或5)(5) init执行/etc/rc.d/rc.sysinit(6) 启动内核外挂模块(/etc/modprobe.conf)(7) init执行run-level的各种Scripts,启动服务(8) init执行/etc/rc.d/rc.local(9) 执行/bin/login,等待用户Login(10)Login后进入Shell打开/etc/rc.sysinit(是一个软链接,指向/etc/rc.d/rc.sysinit),会发现有如下内容……# Load other user-defined modulesfor file in /etc/sysconfig/modules/*.modules ; do[ -x $file ] && $filedone# Load modules (for backward compatibility with VARs)if [ -f /etc/rc.modules ]; then/etc/rc.modulesfi……由此可见,如果想让一个模块开机自动加载,只要把模块加到这两个文件之中即可。
Linux设备驱动程序原理及框架-内核模块入门篇

Linux设备驱动程序原理及框架-内核模块入门篇内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块内核模块介绍Linux采用的是整体式的内核结构,这种结构采用的是整体式的内核结构,采用的是整体式的内核结构的内核一般不能动态的增加新的功能。
为此,的内核一般不能动态的增加新的功能。
为此,Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制,可安装) 提供了一种全新的机制模块” )。
利用这个机制“模块”(module)。
利用这个机制,可以)。
利用这个机制,根据需要,根据需要,在不必对内核重新编译链接的条件将可安装模块动态的插入运行中的内核,下,将可安装模块动态的插入运行中的内核,成为内核的一个有机组成部分;成为内核的一个有机组成部分;或者从内核移走已经安装的模块。
正是这种机制,走已经安装的模块。
正是这种机制,使得内核的内存映像保持最小,的内存映像保持最小,但却具有很大的灵活性和可扩充性。
和可扩充性。
内核模块内核模块介绍可安装模块是可以在系统运行时动态地安装和卸载的内核软件。
严格来说,卸载的内核软件。
严格来说,这种软件的作用并不限于设备驱动,并不限于设备驱动,例如有些文件系统就是以可安装模块的形式实现的。
但是,另一方面,可安装模块的形式实现的。
但是,另一方面,它主要用来实现设备驱动程序或者与设备驱动密切相关的部分(如文件系统等)。
密切相关的部分(如文件系统等)。
课程内容内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块应用层加载模块操作过程内核引导的过程中,会识别出所有已经安装的硬件设备,内核引导的过程中,会识别出所有已经安装的硬件设备,并且创建好该系统中的硬件设备的列表树:文件系统。
且创建好该系统中的硬件设备的列表树:/sys 文件系统。
(udev 服务就是通过读取该文件系统内容来创建必要的设备文件的。
)。
linux module的用法

linux module的用法
Linux模块是一种可以动态加载到Linux内核中以扩展其功能的软件组件。
它们通常用于添加新的驱动程序、文件系统或其他内核功能。
下面我将从多个角度来介绍Linux模块的用法。
首先,要编写一个Linux模块,你需要具备一定的C语言编程知识。
一个基本的Linux模块包括初始化函数和清理函数。
初始化函数在模块加载时被调用,而清理函数在模块被卸载时被调用。
你需要使用特定的宏和数据结构来定义模块的初始化和清理函数,以及模块的许可证和作者信息。
其次,编译模块需要使用Linux内核源代码中的构建系统。
你需要确保已经安装了正确版本的内核头文件和构建工具。
然后,你可以编写一个Makefile来编译你的模块。
在Makefile中,你需要指定内核源代码的路径,并使用特定的命令来编译模块。
一旦你编译好了你的模块,你可以使用insmod命令将其加载到内核中。
加载模块后,你可以使用lsmod命令来查看已加载的模块列表。
你还可以使用modinfo命令来查看模块的信息,包括作者、描述和许可证等。
当你不再需要模块时,你可以使用rmmod命令将其从内核中卸载。
卸载模块后,你可以使用dmesg命令来查看内核日志,以确保
模块已经成功卸载。
总的来说,Linux模块的用法涉及到编写模块代码、编译模块、加载模块以及卸载模块等步骤。
掌握了这些基本的用法,你就可以
开始开发自己的Linux内核模块了。
希望这些信息能够帮助你更好
地理解Linux模块的用法。
linux内核配置make_menuconfig菜单详解

linux内核配置make menuconfig菜单详解前言一、配置系统的基本结构Linux内核的配置系统由三个部分组成,分别是:1、Makefile:分布在 Linux 内核源代码根目录及各层目录中,定义Linux 内核的编译规则;2、配置文件(config.in(2.4内核,2.6内核)):给用户提供配置选择的功能;3、配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于 Make config、Make menuconfig 和 make xconfig)。
这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。
本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。
所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。
二、makefile menuconfig过程讲解当我们在执行make menuconfig这个命令时,系统到底帮我们做了哪些工作呢?这里面一共涉及到了一下几个文件我们来一一讲解Linux内核根目录下的scripts文件夹arch/$ARCH/Kconfig文件、各层目录下的Kconfig文件Linux内核根目录下的makefile文件、各层目录下的makefile文件Linux内核根目录下的的.config文件、arm/$ARCH/下的config文件Linux内核根目录下的 include/generated/autoconf.h文件1)scripts文件夹存放的是跟make menuconfig配置界面的图形绘制相关的文件,我们作为使用者无需关心这个文件夹的内容2)当我们执行make menuconfig命令出现上述蓝色配置界面以前,系统帮我们做了以下工作:首先系统会读取arch/$ARCH/目录下的Kconfig文件生成整个配置界面选项(Kconfig是整个linux配置机制的核心),那么ARCH环境变量的值等于多少呢?它是由linux内核根目录下的makefile文件决定的,在makefile下有此环境变量的定义:或者通过 make ARCH=arm menuconfig命令来生成配置界面,默认生成的界面是所有参数都是没有值的比如教务处进行考试,考试科数可能有外语、语文、数学等科,这里相当于我们选择了arm科可进行考试,系统就会读取arm/arm/kconfig文件生成配置选项(选择了arm科的卷子),系统还提供了x86科、milps科等10几门功课的考试题3)假设教务处比较“仁慈”,为了怕某些同学做不错试题,还给我们准备了一份参考答案(默认配置选项),存放在arch/$ARCH/configs下,对于arm科来说就是arch/arm/configs 文件夹:此文件夹中有许多选项,系统会读取哪个呢?内核默认会读取linux内核根目录下.config文件作为内核的默认选项(试题的参考答案),我们一般会根据开发板的类型从中选取一个与我们开发板最接近的系列到Linux内核根目录下(选择一个最接近的参考答案)#cp arch/arm/configs/s3c2410_defconfig .config4).config假设教务处留了一个心眼,他提供的参考答案并不完全正确(.config 文件与我们的板子并不是完全匹配),这时我们可以选择直接修改.config文件然后执行make menuconfig命令读取新的选项但是一般我们不采取这个方案,我们选择在配置界面中通过空格、esc、回车选择某些选项选中或者不选中,最后保存退出的时候,Linux内核会把新的选项(正确的参考答案)更新到.config中,此时我们可以把.config重命名为其它文件保存起来(当你执行make distclean时系统会把.config文件删除),以后我们再配置内核时就不需要再去arch/arm/configs下考取相应的文件了,省去了重新配置的麻烦,直接将保存的.config文件复制为.config即可.5)经过以上两步,我们可以正确的读取、配置我们需要的界面了那么他们如何跟makefile文件建立编译关系呢?当你保存make menuconfig选项时,系统会除了会自动更新.config外,还会将所有的选项以宏的形式保存在Linux内核根目录下的include/generated/autoconf.h文件下内核中的源代码就都会包含以上.h文件,跟宏的定义情况进行条件编译。
linux内核initrd文件自定义方法

linux内核initrd文件自定义方法重新编译内核后,可能加入了自定义的模块,就有可能需要修改init文件,而init文件就在initrd中,这里记录下操作步骤,以防遗忘。
1. cp /boot/initrd-3.2.img /tmp/mylinux/initrd-3.2.img.gz这里之所以进行改名,是因为initrd-3.2.img是经过gzip压缩过的,所以需要对其解压,但是gzip对解压的文件的文件后缀名又有要求,所以就先进行改名。
2. gunzip initrd-3.2.9.img.gz3. cpio -id < initrd-3.2.9.img经过以上三步,就在当前目录下解压了initrd文件,从而得到了init文件。
根据自己的需求修改init文件后,通过下面命令重新生成initrd文件。
4. find . | cpio -H newc -o | gzip -9 > /boot/initrd-3.2.9.img注意一下内容摘自网上资料,留作参考:en_init_cpio获取gen_init_cpio,工具,gen_init_cpio是编译内核时得到的,在内核源代码的usr 目录下,我们可以通过以下步骤获取它,进入内核源代码执行:# make menuconfig# make usr/这样即编译好gen_init_cpio,gen_initramfs_list.sh 在内核源代码的 script 目录下,将这两个文件 copy 到 /tmp 目录下,/tmp/initrd 为解压好的initrd 目录,执行以下命令制作initrd :#制作initrd :# gen_initramfs_list.sh initrd/ > filelist# gen_init_cpio filelist >initrd.img# gzip initrd.img# mv initrd.img initrd-'uname –r’.img只有用这个方式压缩的initrd ,在Linux系统重启的时候才能一正确的文件格式 boot 起来,也可以用这种方式修改安装光盘的initrd文件然后进行系统安装。
Linux内核模块开发(简单)

Linux内核模块开发(简单)Linux系统为应⽤程序提供了功能强⼤且容易扩展的API,但在某些情况下,这还远远不够。
与硬件交互或进⾏需要访问系统中特权信息的操作时,就需要⼀个内核模块。
Linux内核模块是⼀段编译后的⼆进制代码,直接插⼊Linux内核中,在 Ring 0(x86–64处理器中执⾏最低和受保护程度最低的执⾏环)上运⾏。
这⾥的代码完全不受检查,但是运⾏速度很快,可以访问系统中的所有内容。
Intel x86架构使⽤了4个级别来标明不同的特权级。
Ring 0实际就是内核态,拥有最⾼权限。
⽽⼀般应⽤程序处于Ring 3状态--⽤户态。
在Linux中,还存在Ring 1和Ring 2两个级别,⼀般归属驱动程序的级别。
在Windows平台没有Ring 1和Ring 2两个级别,只⽤Ring 0内核态和Ring 3⽤户态。
在权限约束上,⾼特权等级状态可以阅读低特权等级状态的数据,例如进程上下⽂、代码、数据等等,但反之则不可。
Ring 0最⾼可以读取Ring 0-3所有的内容,Ring 1可以读Ring 1-3的,Ring 2以此类推,Ring 3只能读⾃⼰的数据。
1. 为什么要开发内核模块编写Linux内核模块并不是因为内核太庞⼤⽽不敢修改。
直接修改内核源码会导致很多问题,例如:通过更改内核,你将⾯临数据丢失和系统损坏的风险。
内核代码没有常规Linux应⽤程序所拥有的安全防护机制,如果内核发⽣故障,将锁死整个系统。
更糟糕的是,当你修改内核并导致错误后,可能不会⽴即表现出来。
如果模块发⽣错误,在其加载时就锁定系统是最好的选择,如果不锁定,当你向模块中添加更多代码时,你将会⾯临失控循环和内存泄漏的风险,如果不⼩⼼,它们会随着计算机继续运⾏⽽持续增长,最终,关键的存储器结构甚⾄缓冲区都可能被覆盖。
编写内核模块时,基本是可以丢弃传统的应⽤程序开发范例。
除了加载和卸载模块之外,你还需要编写响应系统事件的代码(⽽不是按顺序模式执⾏的代码)。
Linux内核模块

⼯作模式⼯作性质层次权限影响竞态运⾏⽅式应⽤程序USR 模式策略性⽤户层低局部局部主动内核模块SVC 模式功能性内核层⾼全局全局被挡Linux 内核模块1、什么是内核模块?内核模块是Linux 提供的⼀种机制,允许在内核运⾏时动态加载进内核中,具有两个特点: 1)内核模块本⾝不编译⼊内核映像,有效控制缩减内核镜像⼤⼩ 2)内核模块⼀旦被加载,他就和内核中的其他部分完全⼀样2、为什么需要内核模块?如果在内核编译时把所有的功能都编译进去,就会导致内核很⼤,⽽且要往内核中添加或删除功能时必须重新编译内核⽐如在Ubuntu 在通⽤PC 平台上,预先⽆法知道需要什么设备,就不知道预先编译什么驱动。
3、内核模块和应⽤程序的区别4、内核模块的基本构成|——两个函数(⼀般需要)| |——模块初始化(加载)函数:当内核模块加载进内核的时候,做⼀些准备⼯作| |——模块卸载函数:回收、清理资源||——授权(许可证声明)(必须):Linux 内核受GPL (General Public License )授权约束|——模块参数(可选):模块被加载时可以被传递给它的值,本⾝对应模块内的全局变量|——模块导出符号(可选)|——模块信息说明(可选)5、模块加载(初始化)函数⼀般以 __init 标识声明函数命名规则 xxx_init xxx 设备名 init 功能名(初始化)函数形式:static ini __init xxx_init(void ){/* 初始化代码* 返回值: 成功:0 失败:负数,绝对值是错误码* 应⽤层得到的返回值是-1,错误码保存到errno (每个进程有⼀个); 标准化errno.h 已经明确定义linux/errno.h */}注册⽅式: module_init(x); x 为模块初始化函数的⾸地址 6、模块卸载函数⼀般以 __exit 标识声明函数命名规则 xxx_exit xxx 设备名 exit 功能名(卸载)static ini __exit xxx_exit(void ){/* 释放代码 */}注册⽅式: module_exit(x); x为模块卸载函数的⾸地址7、模块许可证声明MODULE_LICENSE(_license) //_license就是授权名称的字符串//"GPL" [GNU Public License v2 or later]//"GPL v2" [GNU Public License v2]//"GPL and additional rights" [GNU Public License v2 rights and more]//"Dual BSD/GPL" [GNU Public License v2 or BSD license choice]//"Dual MIT/GPL" [GNU Public License v2 or MIT license choice]//"Dual MPL/GPL" [GNU Public License v2 or Mozilla license choice]8、模块声明与描述在Linux内核模块中,我们可以⽤MODULE_AUTHOR、MODULE_DESCRIPTION、MODULE_VERSION、MODULE_DEVICE_TABLE、MODULE_ALIAS分别来声明模块的作者、描述、版本、设备表和别名,例如:MODULE_AUTHOR(author);MODULE_DESCRIPTION(description);MODULE_VERSION(version_string);MODULE_DEVICE_TABLE(table_info);MODULE_ALIAS(alternate_name);对于USB、PCI等设备驱动,通常会创建⼀个MODULE_DEVICE_TABLE,表明该驱动模块⽀持的设备,如:/* 对应此驱动的设备列表 */static struct usb_device_id skel_table [ ] = {{USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* 表结束 */}};MODULE_DEVICE_TABLE (usb, skel_table);9、模块参数:在加载模块时,可以给模块传参头⽂件 linux/moduleparam.hA、传递普通变量module_param(name, type, perm);声明内核模块参数/*name - 接收参数的变量名type - 变量类型 Standard types are: byte, short, ushort, int, uint, long, ulong charp: a character pointer bool: a bool, values 0/1, y/n, Y/N. invbool: the above, only sense-reversed (N = true)perm - 权限 头⽂件 linux/stat.h #define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) #define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) #define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) #define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) #define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)*/范例:int i = 0;module_param(i, int, 0644);运⾏:# insmod xxx.ko i=10B、传递数组参数module_param_array(name, type, nump, perm)/*声明内核模块数组参数name - 数组名type - 数组成员类型nump – ⼀个指向保存数组长度的整型变量的指针perm - 权限*/范例:int arr[] = {1,2,3,4,5,6};int len=0;module_param(arr, int, &len, 0644);运⾏:# insmod xxx.ko arr=1,2,3,4,5C、传递字符串参数module_param_string(name, string, len, perm)/*声明内核模块字符串参数name - 字符串缓存的外部名(传⼊变量名)string - 字符串缓存的内部名nump - 数组的数量perm - 权限*/范例:char insidestr[] = "hello world";module_param(extstr, insidestr, szieof(insidestr), 0644);运⾏:# insmod xxx.ko extstr="hello"10、编译内核模块如果⼀个内核模块要加载到某个内核中运⾏,则这个模块必须使⽤编译该内核镜像的源码进⾏编译,否则运⾏时会出错A、头⽂件(语法问题)B、编译结果(最主要影响)编译时符号表(只在编译时使⽤)运⾏时内核符号表# cat /proc/kallsyms 运⾏时内核符号表C、编译系统⽰例Makefile:# 内核模块的Makefile(模块源码在内核源码外,且内核先编译)# 1、找内核的Makefile# 2、内核的Makefile找内核模块的Makeifle内核模块的Makeifle定义要编译对象ifneq ($(KERNELRELEASE),)#要编译对象表⽰把demo.c编译成demo.ko obj-m = demo.oelse#内核源码⽬录KERNELDIR := /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendifclean: rm -rf .tmp_versions Module.symvers modules.order .tmp_versions .*.cmd *.o *.ko *.mod.cKERNELRELEASE 是在内核源码的顶层Makefile中定义的⼀个变量,在第⼀次读取执⾏此Makefile时,KERNELRELEASE没有被定义,所以make将读取执⾏else之后的内容。
openwrt增加软件包及内核模块总结

openwrt增加软件包及内核模块总结OpenWrt是一个非常强大的嵌入式Linux发行版,可用于路由器、嵌入式设备和其他网络设备。
在OpenWrt上增加软件包及内核模块可以为设备添加更多的功能和特性,本文将详细介绍如何在OpenWrt中增加软件包及内核模块。
要在OpenWrt中增加软件包,我们需要先连接到设备的Shell。
可以通过SSH或串口连接到路由器或嵌入式设备的Shell。
在Shell中,我们可以使用opkg命令来、安装和卸载软件包。
要软件包,可以使用以下命令:```plaintextopkg update # 更新软件仓库opkg list # 列出所有可用的软件包opkg list , grep package_name # 软件包```要安装软件包,可以使用以下命令:```plaintextopkg install package_name # 安装软件包```要卸载软件包,可以使用以下命令:```plaintextopkg remove package_name # 卸载软件包```除了使用opkg命令,还可以通过LuCI界面来管理OpenWrt的软件包。
LuCI是OpenWrt的Web管理界面,可以通过浏览器访问。
在LuCI界面中,可以直观地、安装和卸载软件包,而无需使用命令行。
```plaintext```然后,进入OpenWrt源代码的目录,并运行以下命令来配置编译环境:```plaintextcd openwrt./scripts/feeds update -a./scripts/feeds install -amake defconfig # 使用默认配置make menuconfig # 进入配置界面```在配置界面中,可以选择要编译的软件包和内核模块。
通过功能,可以找到特定的软件包和内核模块。
选中后,保存配置并退出配置界面。
接下来,运行以下命令来开始编译:```plaintextmake```编译过程可能需要一段时间,取决于机器的性能和网络速度。
打印Linux内核task_struct(PCB)的信息的可加模块编写

打印Linux 内核task_struct (PCB )的信息的可加模块编写废话不多说,直接上源代码:这个程序是加载进内核的模块,作⽤是:打印系统中所有进程的⼀些信息,注意:这是ubuntu系统下的操作部分函数原型:#include <linux/kernel.h>#include <linux/sched.h> //这个⽂件定义了linux 下的task_struct 数据结构#include <linux/init.h>#include <linux/module.h>#include <linux/fdtable.h>#include <linux/init_task.h> //⾥⾯定义了 init_task (0号进程)//内核模块初始化函数static int __init print_pid(void ){ struct task_struct *task,*p; //指向PCB 的指针 struct list_head *pos;//list_head 是⼀个双向链表,⽤来链接os 中的所有进程,我们可以⽤它访问系统中的所有进程, \ //每个pcb 内部都维护⼀个list_head 类型的tasks 链表,这样就可以通过>每个进程的pcb 访问所有进程了int count=0;//记录当前系统中的进程数⽬ printk("Hello World enter begin:\n"); task =&init_task; //0号进程,所有进程的⽗进程,遍历进程链表list_head 从0号进程开始 //list_for_each ⽤来遍历进程链表,让pos 从头指向task 双向链表中的每⼀个结点(task_struct),list_for_each 是⼀个宏 //list.h 头⽂件中list_for_each(pos,&task->tasks) { //list_entry 是⼀个容器宏 ,作⽤是:让pos 从指向结构体task_struct 的成员tasks,变为指向结构提task_struct 本⾝,\ //由内部成员地址指向拥有该成员的结构体地址p=list_entry(pos,struct task_struct,tasks); count ++; //++ printk("\n\n"); //现在pos 指向了每⼀个进程的pcb,那么就可以输出pcb 中的信息了 printk("pid:%d; state:%lx; prio:%d; static_prio:%d; parent'pid:%d;", p->pid,p->state,p->prio,p->static_prio,(p->parent)->pid);}printk("进程的个数:%d\n",count);return 0;}//内核退出函数static void __exit pid_exit(void ){ printk("exiting...\n");}module_init(print_pid);module_exit(pid_exit);MODULE_LICENSE("GPL");/** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */宏,⽤来遍历head 链表,并且让pos 指向每⼀个结点#define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)/** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_head within the struct. */2.task_struct数据结构简单介绍,信息太多了,这⾥仅仅介绍⽬前⽤的task_struc位于<linux/sched.h>头⽂件中//linux中进程的状态/* Used in tsk->state:进程的状态都是2的次幂,保证"与"操作可以得到所有状态 */#define TASK_RUNNING 0x0000#define TASK_INTERRUPTIBLE 0x0001#define TASK_UNINTERRUPTIBLE 0x0002#define __TASK_STOPPED 0x0004#define __TASK_TRACED 0x0008插⼊⼀张图⽚说明进程之间的关系,养⽗是因为⽗亲可能被杀死,或者断了,那么系统要为当前进程找⼀个养⽗进程,否则当前进程及兄弟,孩⼦进程资源⽆法释放,导致内存⽤不了了(因为指针丢了,招不到这块内存的地址了)系统中进程的组织⽅式:3.Makefile⽂件编写.c 内核正⽂⽂件ptr 表⽰member 的地址,type 表⽰结构体的类型.member 结构体中的成员#define list_entry(ptr, type, member) \ container_of(ptr, type, member)struct task_struct {#ifdef CONFIG_THREAD_INFO_IN_TASKstruct thread_info thread_info;#endif /* -1 unrunnable, 0 runnable, >0 stopped: 进程状态*/ volatile long state; /* ⽗亲进程*/ struct task_struct __rcu *real_parent;/* 养⽗进程 采⽤链表*/ struct task_struct __rcu *parent;/* * ⼦孙,兄弟,和组领导者进程,双向链表链接 */ struct list_head children; struct list_head sibling; struct task_struct *group_leader; //每个进程task_struct 内都有⼀个list_head 双向链表,⽤来链接系统中所有的进程pcb //我们可以通过它来获得系统中所有的进程信息 struct list_head tasks; //线程对应的pidpid_t pid; //线程组的pid pid_t tgid; .... //优先级 int prio; int static_prio; int normal_prio; unsigned int rt_priority; ...Makefile ⽂件⽤来编译产⽣内核.ko 模块的⽂件架构:4.编译5.插⼊内核,并显⽰结果显⽰消息:使⽤命令dmesg,这⾥只截取了部分太多了,发现我的系统⽬前有364个进程附录:完整的task_struct定义和sched.h头⽂件obj-m:=task_struct.o #产⽣task_struct 模块的⽬标⽂件#⽬标⽂件 ⽂件 要与模块⽂件名字相同CURRENT_PATH:=$(shell pwd)LINUX_KERNEL:=$(shell uname -r)LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模块#[Tab] 内核的路径 当前⽬录编译完放在哪⾥ 表明编译的是内核>⽂件clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean/* SPDX-License-Identifier: GPL-2.0 */#ifndef _LINUX_SCHED_H#define _LINUX_SCHED_H/** Define 'struct task_struct' and provide the main scheduler* APIs (schedule(), wakeup variants, etc.)*/#include <uapi/linux/sched.h>#include <asm/current.h>#include <linux/pid.h>#include <linux/sem.h>#include <linux/shm.h>#include <linux/kcov.h>#include <linux/mutex.h>#include <linux/plist.h>#include <linux/hrtimer.h>#include <linux/seccomp.h>#include <linux/nodemask.h>#include <linux/rcupdate.h>#include <linux/refcount.h>#include <linux/resource.h>#include <linux/latencytop.h>#include <linux/sched/prio.h>#include <linux/sched/types.h>#include <linux/signal_types.h>#include <linux/mm_types_task.h>#include <linux/task_io_accounting.h>#include <linux/posix-timers.h>#include <linux/rseq.h>/* task_struct member predeclarations (sorted alphabetically): */struct audit_context;struct backing_dev_info;struct bio_list;struct blk_plug;struct capture_control;struct cfs_rq;struct fs_struct;struct futex_pi_state;struct io_context;struct mempolicy;struct nameidata;struct nsproxy;struct perf_event_context;struct pid_namespace;struct pipe_inode_info;struct rcu_node;struct reclaim_state;struct robust_list_head;struct root_domain;struct rq;struct sched_attr;struct sched_param;struct seq_file;struct sighand_struct;struct signal_struct;struct task_delay_info;struct task_group;/** Task state bitmask. NOTE! These bits are also* encoded in fs/proc/array.c: get_task_state().** We have two separate sets of flags: task->state* is about runnability, while task->exit_state are* about the task exiting. Confusing, but this way* modifying one set can't modify the other one by* mistake.*//* Used in tsk->state:进程的状态都是2的次幂保证"与"操作可以得到所有状态 */#define TASK_RUNNING 0x0000#define TASK_INTERRUPTIBLE 0x0001#define TASK_UNINTERRUPTIBLE 0x0002#define __TASK_STOPPED 0x0004#define __TASK_TRACED 0x0008/* Used in tsk->exit_state: */#define EXIT_DEAD 0x0010#define EXIT_ZOMBIE 0x0020#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)/* Used in tsk->state again: */#define TASK_PARKED 0x0040#define TASK_DEAD 0x0080#define TASK_WAKEKILL 0x0100#define TASK_WAKING 0x0200#define TASK_NOLOAD 0x0400#define TASK_NEW 0x0800#define TASK_STATE_MAX 0x1000/* Convenience macros for the sake of set_current_state: */#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)/* Convenience macros for the sake of wake_up(): */#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)/* get_task_state(): */#define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \__TASK_TRACED | EXIT_DEAD | EXIT_ZOMBIE | \TASK_PARKED)#define task_is_traced(task) ((task->state & __TASK_TRACED) != 0)#define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0)#define task_is_stopped_or_traced(task) ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0) #define task_contributes_to_load(task) ((task->state & TASK_UNINTERRUPTIBLE) != 0 && \(task->flags & PF_FROZEN) == 0 && \(task->state & TASK_NOLOAD) == 0)#ifdef CONFIG_DEBUG_ATOMIC_SLEEP/** Special states are those that do not use the normal wait-loop pattern. See* the comment with set_special_state().*/#define is_special_task_state(state) \((state) & (__TASK_STOPPED | __TASK_TRACED | TASK_PARKED | TASK_DEAD))#define __set_current_state(state_value) \do { \WARN_ON_ONCE(is_special_task_state(state_value));\current->task_state_change = _THIS_IP_; \current->state = (state_value); \} while (0)#define set_current_state(state_value) \do { \WARN_ON_ONCE(is_special_task_state(state_value));\current->task_state_change = _THIS_IP_; \smp_store_mb(current->state, (state_value)); \} while (0)#define set_special_state(state_value) \do { \unsigned long flags; /* may shadow */ \WARN_ON_ONCE(!is_special_task_state(state_value)); \raw_spin_lock_irqsave(¤t->pi_lock, flags); \current->task_state_change = _THIS_IP_; \current->state = (state_value); \raw_spin_unlock_irqrestore(¤t->pi_lock, flags); \} while (0)#else/** set_current_state() includes a barrier so that the write of current->state* is correctly serialised wrt the caller's subsequent test of whether to* actually sleep:** for (;;) {* set_current_state(TASK_UNINTERRUPTIBLE);* if (!need_sleep)* break;** schedule();* }* __set_current_state(TASK_RUNNING);** If the caller does not need such serialisation (because, for instance, the* condition test and condition change and wakeup are under the same lock) then* use __set_current_state().** The above is typically ordered against the wakeup, which does:** need_sleep = false;* wake_up_state(p, TASK_UNINTERRUPTIBLE);** where wake_up_state() executes a full memory barrier before accessing the* task state.** Wakeup will do: if (@state & p->state) p->state = TASK_RUNNING, that is,* once it observes the TASK_UNINTERRUPTIBLE store the waking CPU can issue a * TASK_RUNNING store which can collide with __set_current_state(TASK_RUNNING). ** However, with slightly different timing the wakeup TASK_RUNNING store can* also collide with the TASK_UNINTERRUPTIBLE store. Losing that store is not* a problem either because that will result in one extra go around the loop* and our @cond test will save the day.** Also see the comments of try_to_wake_up().*/#define __set_current_state(state_value) \current->state = (state_value)#define set_current_state(state_value) \smp_store_mb(current->state, (state_value))/** set_special_state() should be used for those states when the blocking task* can not use the regular condition based wait-loop. In that case we must* serialize against wakeups such that any possible in-flight TASK_RUNNING stores* will not collide with our state change.*/#define set_special_state(state_value) \do { \unsigned long flags; /* may shadow */ \raw_spin_lock_irqsave(¤t->pi_lock, flags); \current->state = (state_value); \raw_spin_unlock_irqrestore(¤t->pi_lock, flags); \} while (0)#endif/* Task command name length: */#define TASK_COMM_LEN 16extern void scheduler_tick(void);#define MAX_SCHEDULE_TIMEOUT LONG_MAXextern long schedule_timeout(long timeout);extern long schedule_timeout_interruptible(long timeout);extern long schedule_timeout_killable(long timeout);extern long schedule_timeout_uninterruptible(long timeout);extern long schedule_timeout_idle(long timeout);asmlinkage void schedule(void);extern void schedule_preempt_disabled(void);asmlinkage void preempt_schedule_irq(void);extern int __must_check io_schedule_prepare(void);extern void io_schedule_finish(int token);extern long io_schedule_timeout(long timeout);extern void io_schedule(void);/*** struct prev_cputime - snapshot of system and user cputime* @utime: time spent in user mode* @stime: time spent in system mode* @lock: protects the above two fields** Stores previous user/system time values such that we can guarantee* monotonicity.*/struct prev_cputime {#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVEu64 utime;u64 stime;raw_spinlock_t lock;#endif};enum vtime_state {/* Task is sleeping or running in a CPU with VTIME inactive: */VTIME_INACTIVE = 0,/* Task runs in userspace in a CPU with VTIME active: */VTIME_USER,/* Task runs in kernelspace in a CPU with VTIME active: */VTIME_SYS,};struct vtime {seqcount_t seqcount;unsigned long long starttime;enum vtime_state state;u64 utime;u64 stime;u64 gtime;};/** Utilization clamp constraints.* @UCLAMP_MIN: Minimum utilization* @UCLAMP_MAX: Maximum utilization* @UCLAMP_CNT: Utilization clamp constraints count*/enum uclamp_id {UCLAMP_MIN = 0,UCLAMP_MAX,UCLAMP_CNT};#ifdef CONFIG_SMPextern struct root_domain def_root_domain;extern struct mutex sched_domains_mutex;#endifstruct sched_info {#ifdef CONFIG_SCHED_INFO/* Cumulative counters: *//* # of times we have run on this CPU: */unsigned long pcount;/* Time spent waiting on a runqueue: */unsigned long long run_delay;/* Timestamps: *//* When did we last run on a CPU? */unsigned long long last_arrival;/* When were we last queued to run? */unsigned long long last_queued;#endif /* CONFIG_SCHED_INFO */};/** Integer metrics need fixed point arithmetic, e.g., sched/fair* has a few: load, load_avg, util_avg, freq, and capacity.** We define a basic fixed point arithmetic range, and then formalize* all these metrics based on that basic range.*/# define SCHED_FIXEDPOINT_SHIFT 10# define SCHED_FIXEDPOINT_SCALE (1L << SCHED_FIXEDPOINT_SHIFT) /* Increase resolution of cpu_capacity calculations */# define SCHED_CAPACITY_SHIFT SCHED_FIXEDPOINT_SHIFT# define SCHED_CAPACITY_SCALE (1L << SCHED_CAPACITY_SHIFT) struct load_weight {unsigned long weight;u32 inv_weight;};/*** struct util_est - Estimation utilization of FAIR tasks* @enqueued: instantaneous estimated utilization of a task/cpu* @ewma: the Exponential Weighted Moving Average (EWMA)* utilization of a task** Support data structure to track an Exponential Weighted Moving Average* (EWMA) of a FAIR task's utilization. New samples are added to the moving * average each time a task completes an activation. Sample's weight is chosen * so that the EWMA will be relatively insensitive to transient changes to the* task's workload.** The enqueued attribute has a slightly different meaning for tasks and cpus: * - task: the task's util_avg at last task dequeue time* - cfs_rq: the sum of util_est.enqueued for each RUNNABLE task on that CPU * Thus, the util_est.enqueued of a task represents the contribution on the* estimated utilization of the CPU where that task is currently enqueued.** Only for tasks we track a moving average of the past instantaneous* estimated utilization. This allows to absorb sporadic drops in utilization* of an otherwise almost periodic task.*/struct util_est {unsigned int enqueued;unsigned int ewma;#define UTIL_EST_WEIGHT_SHIFT 2} __attribute__((__aligned__(sizeof(u64))));/** The load_avg/util_avg accumulates an infinite geometric series* (see __update_load_avg() in kernel/sched/fair.c).** [load_avg definition]** load_avg = runnable% * scale_load_down(load)** where runnable% is the time ratio that a sched_entity is runnable.* For cfs_rq, it is the aggregated load_avg of all runnable and* blocked sched_entities.** [util_avg definition]** util_avg = running% * SCHED_CAPACITY_SCALE** where running% is the time ratio that a sched_entity is running on* a CPU. For cfs_rq, it is the aggregated util_avg of all runnable* and blocked sched_entities.** load_avg and util_avg don't direcly factor frequency scaling and CPU* capacity scaling. The scaling is done through the rq_clock_pelt that* is used for computing those signals (see update_rq_clock_pelt())** N.B., the above ratios (runnable% and running%) themselves are in the* range of [0, 1]. To do fixed point arithmetics, we therefore scale them* to as large a range as necessary. This is for example reflected by* util_avg's SCHED_CAPACITY_SCALE.** [Overflow issue]** The 64-bit load_sum can have 4353082796 (=2^64/47742/88761) entities* with the highest load (=88761), always runnable on a single cfs_rq,* and should not overflow as the number already hits PID_MAX_LIMIT.** For all other cases (including 32-bit kernels), struct load_weight's * weight will overflow first before we do, because:** Max(load_avg) <= Max(load.weight)** Then it is the load_weight's responsibility to consider overflow* issues.*/struct sched_avg {u64 last_update_time;u64 load_sum;u64 runnable_load_sum;u32 util_sum;u32 period_contrib;unsigned long load_avg;unsigned long runnable_load_avg;unsigned long util_avg;struct util_est util_est;} ____cacheline_aligned;struct sched_statistics {#ifdef CONFIG_SCHEDSTATSu64 wait_start;u64 wait_max;u64 wait_count;u64 wait_sum;u64 iowait_count;u64 iowait_sum;u64 sleep_start;u64 sleep_max;s64 sum_sleep_runtime;u64 block_start;u64 block_max;u64 exec_max;u64 slice_max;u64 nr_migrations_cold;u64 nr_failed_migrations_affine;u64 nr_failed_migrations_running;u64 nr_failed_migrations_hot;u64 nr_forced_migrations;u64 nr_wakeups;u64 nr_wakeups_sync;u64 nr_wakeups_migrate;u64 nr_wakeups_local;u64 nr_wakeups_remote;u64 nr_wakeups_affine;u64 nr_wakeups_affine_attempts;u64 nr_wakeups_passive;u64 nr_wakeups_idle;#endif};struct sched_entity {/* For load-balancing: */struct load_weight load;unsigned long runnable_weight;struct rb_node run_node;struct list_head group_node;unsigned int on_rq;u64 exec_start;u64 sum_exec_runtime;u64 vruntime;u64 prev_sum_exec_runtime;u64 nr_migrations;struct sched_statistics statistics;#ifdef CONFIG_FAIR_GROUP_SCHEDint depth;struct sched_entity *parent;/* rq on which this entity is (to be) queued: */struct cfs_rq *cfs_rq;/* rq "owned" by this entity/group: */struct cfs_rq *my_q;#endif#ifdef CONFIG_SMP/** Per entity load average tracking.** Put into separate cache line so it does not* collide with read-mostly values above.*/struct sched_avg avg;#endif};struct sched_rt_entity {struct list_head run_list;unsigned long timeout;unsigned long watchdog_stamp;unsigned int time_slice;unsigned short on_rq;unsigned short on_list;struct sched_rt_entity *back;#ifdef CONFIG_RT_GROUP_SCHEDstruct sched_rt_entity *parent;/* rq on which this entity is (to be) queued: */struct rt_rq *rt_rq;/* rq "owned" by this entity/group: */struct rt_rq *my_q;#endif} __randomize_layout;struct sched_dl_entity {struct rb_node rb_node;/** Original scheduling parameters. Copied here from sched_attr* during sched_setattr(), they will remain the same until* the next sched_setattr().*/u64 dl_runtime; /* Maximum runtime for each instance */ u64 dl_deadline; /* Relative deadline of each instance */ u64 dl_period; /* Separation of two instances (period) */u64 dl_bw; /* dl_runtime / dl_period */u64 dl_density; /* dl_runtime / dl_deadline *//** Actual scheduling parameters. Initialized with the values above,* they are continuously updated during task execution. Note that* the remaining runtime could be < 0 in case we are in overrun.*/s64 runtime; /* Remaining runtime for this instance */u64 deadline; /* Absolute deadline for this instance */unsigned int flags; /* Specifying the scheduler behaviour */ /** Some bool flags:** @dl_throttled tells if we exhausted the runtime. If so, the* task has to wait for a replenishment to be performed at the* next firing of dl_timer.** @dl_boosted tells if we are boosted due to DI. If so we are* outside bandwidth enforcement mechanism (but only until we* exit the critical section);** @dl_yielded tells if task gave up the CPU before consuming* all its available runtime during the last job.** @dl_non_contending tells if the task is inactive while still* contributing to the active utilization. In other words, it* indicates if the inactive timer has been armed and its handler* has not been executed yet. This flag is useful to avoid race* conditions between the inactive timer handler and the wakeup* code.** @dl_overrun tells if the task asked to be informed about runtime* overruns.*/unsigned int dl_throttled : 1;unsigned int dl_boosted : 1;unsigned int dl_yielded : 1;unsigned int dl_non_contending : 1;unsigned int dl_overrun : 1;/** Bandwidth enforcement timer. Each -deadline task has its* own bandwidth to be enforced, thus we need one timer per task.*/struct hrtimer dl_timer;/** Inactive timer, responsible for decreasing the active utilization* at the "0-lag time". When a -deadline task blocks, it contributes* to GRUB's active utilization until the "0-lag time", hence a* timer is needed to decrease the active utilization at the correct* time.*/struct hrtimer inactive_timer;};#ifdef CONFIG_UCLAMP_TASK/* Number of utilization clamp buckets (shorter alias) */#define UCLAMP_BUCKETS CONFIG_UCLAMP_BUCKETS_COUNT/** Utilization clamp for a scheduling entity* @value: clamp value "assigned" to a se* @bucket_id: bucket index corresponding to the "assigned" value* @active: the se is currently refcounted in a rq's bucket* @user_defined: the requested clamp value comes from user-space** The bucket_id is the index of the clamp bucket matching the clamp value * which is pre-computed and stored to avoid expensive integer divisions from * the fast path.** The active bit is set whenever a task has got an "effective" value assigned, * which can be different from the clamp value "requested" from user-space. * This allows to know a task is refcounted in the rq's bucket corresponding * to the "effective" bucket_id.** The user_defined bit is set whenever a task has got a task-specific clamp * value requested from userspace, i.e. the system defaults apply to this task * just as a restriction. This allows to relax default clamps when a less* restrictive task-specific value has been requested, thus allowing to* implement a "nice" semantic. For example, a task running with a 20%* default boost can still drop its own boosting to 0%.*/struct uclamp_se {unsigned int value : bits_per(SCHED_CAPACITY_SCALE);unsigned int bucket_id : bits_per(UCLAMP_BUCKETS);unsigned int active : 1;#endif /* CONFIG_UCLAMP_TASK */union rcu_special {struct {u8 blocked;u8 need_qs;u8 exp_hint; /* Hint for performance. */u8 deferred_qs;} b; /* Bits. */u32 s; /* Set of bits. */};enum perf_event_task_context {perf_invalid_context = -1,perf_hw_context = 0,perf_sw_context,perf_nr_task_contexts,};struct wake_q_node {struct wake_q_node *next;};struct task_struct {#ifdef CONFIG_THREAD_INFO_IN_TASK/** For reasons of header soup (see current_thread_info()), this* must be the first element of task_struct.*/struct thread_info thread_info;#endif/* -1 unrunnable, 0 runnable, >0 stopped: */volatile long state;/** This begins the randomizable portion of task_struct. Only* scheduling-critical items should be added above here.*/randomized_struct_fields_startvoid *stack;refcount_t usage;/* Per task flags (PF_*), defined further below: */unsigned int flags;unsigned int ptrace;#ifdef CONFIG_SMPstruct llist_node wake_entry;int on_cpu;#ifdef CONFIG_THREAD_INFO_IN_TASK/* Current CPU: */unsigned int cpu;#endifunsigned int wakee_flips;unsigned long wakee_flip_decay_ts;struct task_struct *last_wakee;/** recent_used_cpu is initially set as the last CPU used by a task* that wakes affine another task. Waker/wakee relationships can* push tasks around a CPU where each wakeup moves to the next one. * Tracking a recently used CPU allows a quick search for a recently* used CPU that may be idle.*/int recent_used_cpu;int wake_cpu;#endifint on_rq;int normal_prio;unsigned int rt_priority;const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt;#ifdef CONFIG_CGROUP_SCHEDstruct task_group *sched_task_group;#endifstruct sched_dl_entity dl;#ifdef CONFIG_UCLAMP_TASK/* Clamp values requested for a scheduling entity */ struct uclamp_se uclamp_req[UCLAMP_CNT];/* Effective clamp values used for a scheduling entity */ struct uclamp_se uclamp[UCLAMP_CNT];#endif#ifdef CONFIG_PREEMPT_NOTIFIERS/* List of struct preempt_notifier: */struct hlist_head preempt_notifiers;#endif#ifdef CONFIG_BLK_DEV_IO_TRACEunsigned int btrace_seq;#endifunsigned int policy;int nr_cpus_allowed;const cpumask_t *cpus_ptr;cpumask_t cpus_mask;#ifdef CONFIG_PREEMPT_RCUint rcu_read_lock_nesting;union rcu_special rcu_read_unlock_special; struct list_head rcu_node_entry;struct rcu_node *rcu_blocked_node;#endif /* #ifdef CONFIG_PREEMPT_RCU */#ifdef CONFIG_TASKS_RCUunsigned long rcu_tasks_nvcsw;u8 rcu_tasks_holdout;u8 rcu_tasks_idx;int rcu_tasks_idle_cpu;struct list_head rcu_tasks_holdout_list;#endif /* #ifdef CONFIG_TASKS_RCU */struct sched_info sched_info;struct list_head tasks;#ifdef CONFIG_SMPstruct plist_node pushable_tasks;struct rb_node pushable_dl_tasks;#endifstruct mm_struct *mm;struct mm_struct *active_mm;/* Per-thread vma caching: */struct vmacache vmacache;#ifdef SPLIT_RSS_COUNTINGstruct task_rss_stat rss_stat;#endifint exit_state;int exit_code;int exit_signal;/* The signal sent when the parent dies: */int pdeath_signal;/* Used for emulating ABI behavior of previous Linux versions: */unsigned int personality;/* Scheduler bits, serialized by scheduler locks: */unsigned sched_reset_on_fork:1;unsigned sched_contributes_to_load:1;unsigned sched_migrated:1;unsigned sched_remote_wakeup:1;#ifdef CONFIG_PSIunsigned sched_psi_wake_requeue:1;#endif/* Force alignment to the next boundary: */unsigned :0;/* Unserialized, strictly 'current' *//* Bit to tell LSMs we're in execve(): */unsigned in_execve:1;unsigned in_iowait:1;#ifndef TIF_RESTORE_SIGMASKunsigned restore_sigmask:1;#endif#ifdef CONFIG_MEMCGunsigned in_user_fault:1;#endif#ifdef CONFIG_COMPAT_BRKunsigned brk_randomized:1;#endif#ifdef CONFIG_CGROUPS/* disallow userland-initiated cgroup migration */unsigned no_cgroup_migration:1;/* task is frozen/stopped (used by the cgroup freezer) */unsigned frozen:1;#endif#ifdef CONFIG_BLK_CGROUP/* to be used once the psi infrastructure lands upstream. */unsigned use_memdelay:1;#endifunsigned long atomic_flags; /* Flags requiring atomic access. */ struct restart_block restart_block;pid_t pid;pid_t tgid;#ifdef CONFIG_STACKPROTECTOR/* Canary value for the -fstack-protector GCC feature: */unsigned long stack_canary;#endif/** Pointers to the (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with* p->real_parent->pid)*//* Real parent process: */struct task_struct __rcu *real_parent;/* Recipient of SIGCHLD, wait4() reports: */struct task_struct __rcu *parent;/** Children/sibling form the list of natural children:*/struct list_head children;struct list_head sibling;。
[精华版]linux内核配置选项
![[精华版]linux内核配置选项](https://img.taocdn.com/s3/m/a206201cba68a98271fe910ef12d2af90342a840.png)
Code maturity level options代码成熟度选项Prompt for developm ent and/or incomplete code/drivers显示尚在开发中或尚未完成的代码与驱动.除非你是测试人员或者开发者,否则请勿选择General setup常规设置Local version - append to kernel release在内核版本后面加上自定义的版本字符串(小于64字符),可以用"unam e -a"命令看到Automatically append version information to the version string自动在版本字符串后面添加版本信息,编译时需要有perl以及git仓库支持Support for paging of anonymous memory (swap)使用交换分区或者交换文件来做为虚拟内存System V IPCSystem V进程间通信(IPC)支持,许多程序需要这个功能.必选,除非你知道自己在做什么IPC NamespacesIPC命名空间支持,不确定可以不选POSIX Message QueuesPOSIX消息队列,这是POSIX IPC中的一部分BSD Process Accounting将进程的统计信息写入文件的用户级系统调用,主要包括进程的创建时间/创建者/内存占用等信息BSD Process Accounting version 3 file format使用新的第三版文件格式,可以包含每个进程的PID和其父进程的PID,但是不兼容老版本的文件格式Export task/process statistics through netlink通过netlink接口向用户空间导出任务/进程的统计信息,与BSD Process Accounting的不同之处在于这些统计信息在整个任务/进程生存期都是可用的Enable per-task delay accounting在统计信息中包含进程等候系统资源(cpu,IO同步,内存交换等)所花费的时间UTS NamespacesUTS名字空间支持,不确定可以不选Auditing support审计支持,某些内核模块(例如SELinux)需要它,只有同时选择其子项才能对系统调用进行审计Enable system-call auditing support支持对系统调用的审计Kernel .config support把内核的配置信息编译进内核中,以后可以通过scripts/extract-ikconfig脚本来提取这些信息Enable access to .config through /proc/config.gz允许通过/proc/config.gz访问内核的配置信息Cpuset support只有含有大量CPU(大于16个)的SMP系统或NUMA(非一致内存访问)系统才需要它Kernel->user space relay support (formerly relayfs)在某些文件系统上(比如debugfs)提供从内核空间向用户空间传递大量数据的接口Initramfs source file(s)initrd已经被initramfs取代,如果你不明白这是什么意思,请保持空白Optimize for size (Look out for broken compilers!)编译时优化内核尺寸(使用"-Os"而不是"-O2"参数编译),有时会产生错误的二进制代码Enable extended accounting over taskstats收集额外的进程统计信息并通过taskstats接口发送到用户空间Configure standard kernel features (for sm all systems)配置标准的内核特性(为小型系统)Enable 16-bit UID system calls允许对UID系统调用进行过时的16-bit包装Sysctl syscall support不需要重启就能修改内核的某些参数和变量,如果你也选择了支持/proc,将能从/proc/sys存取可以影响内核行为的参数或变量Load all symbols for debugging/kksymoops装载所有的调试符号表信息,仅供调试时选择Include all symbols in kallsyms在kallsyms中包含内核知道的所有符号,内核将会增大300KDo an extra kallsyms pass除非你在kallsyms中发现了bug并需要报告这个bug才打开该选项Support for hot-pluggable devices支持热插拔设备,如usb与pc卡等,Udev也需要它Enable support for printk允许内核向终端打印字符信息,在需要诊断内核为什么不能运行时选择BUG() support显示故障和失败条件(BUG和WARN),禁用它将可能导致隐含的错误被忽略Enable ELF core dumps内存转储支持,可以帮助调试ELF格式的程序Enable full-sized data structures for core在内核中使用全尺寸的数据结构.禁用它将使得某些内核的数据结构减小以节约内存,但是将会降低性能Enable futex support快速用户空间互斥体可以使线程串行化以避免竞态条件,也提高了响应速度.禁用它将导致内核不能正确的运行基于glibc的程序Enable eventpoll support支持事件轮循的系统调用Use full shmem filesystem启用shmem支持.shmem是基于共享内存的文件系统(可能用到swap),在启用TMPFS后可以挂载为tmpfs供用户空间使用,它比简单的ramfs先进许多Use full SLAB allocator使用SLAB完全取代SLOB进行内存分配,SLAB是一种优秀的内存分配管理器,推荐使用Enable VM event counters for /proc/vmstat允许在/proc/vmstat中包含虚拟内存事件记数器Loadable module support可加载模块支持Enable loadable module support打开可加载模块支持,如果打开它则必须通过"make modules_install"把内核模块安装在/lib/modules/中Module unloading允许卸载已经加载的模块Forced module unloading允许强制卸载正在使用中的模块(比较危险)Module versioning support允许使用其他内核版本的模块(可能会出问题)Source checksum for all modules为所有的模块校验源码,如果你不是自己编写内核模块就不需要它Automatic kernel module loading让内核通过运行modprobe来自动加载所需要的模块,比如可以自动解决模块的依赖关系Block layer块设备层Enable the block layer块设备支持,使用硬盘/USB/SCSI设备者必选Support for Large Block Devices仅在使用大于2TB的块设备时需要Support for tracing block io actions块队列IO跟踪支持,它允许用户查看在一个块设备队列上发生的所有事件,可以通过blktrace程序获得磁盘当前的详细统计数据Support for Large Single Files仅在可能使用大于2TB的文件时需要IO SchedulersIO调度器Anticipatory I/O scheduler适用于大多数环境,但不太合适数据库应用Deadline I/O scheduler通常与Anticipatory相当,但更简洁小巧,更适合于数据库应用CFQ I/O scheduler为所有进程分配等量的带宽,适合于桌面多任务及多媒体应用Default I/O scheduler默认IO调度器Processor type and features中央处理器(CPU)类型及特性Symmetric multi-processing support对称多处理器支持,如果你有多个CPU或者使用的是多核CPU就选上.此时"Enhanced Real Time Clock Support"选项必须开启,"Advanced Power Managem ent"选项必须关闭Subarchitecture Type处理器的子架构,大多数人都应当选择"PC-compatible"Processor family处理器系列,请按照你实际使用的CPU选择Generic x86 support通用x86支持,如果你的CPU能够在上述"Processor family"中找到就别选HPET Timer SupportHPET是替代8254芯片的新一代定时器,i686及以上级别的主板都支持,可以安全的选上Maximum number of CPUs支持的最大CPU数,每增加一个内核将增加8K体积SMT (Hyperthreading) scheduler support支持Intel的超线程(HT)技术Multi-core scheduler support针对多核CPU进行调度策略优化Preemption Model内核抢占模式No Forced Preemption (Server)适合服务器环境的禁止内核抢占Voluntary Kernel Preemption (Desktop)适合普通桌面环境的自愿内核抢占Preemptible Kernel (Low-Latency Desktop)适合运行实时程序的主动内核抢占Preempt The Big Kernel Lock可以抢占大内核锁,应用于实时要求高的场合,不适合服务器环境Machine Check Exception让CPU检测到系统故障时通知内核,以便内核采取相应的措施(如过热关机等)Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4每5秒检测一次这些cpu的非致命错误并纠正它们,同时记入日志check for P4 thermal throttling interrupt当P4的cpu过热时显示一条警告消息Enable VM86 support虚拟X86支持,在DOSEMU下运行16-bit程序或XFree86通过BIOS初始化某些显卡的时候才需要Toshiba Laptop supportToshiba笔记本模块支持Dell laptop supportDell笔记本模块支持Enable X86 board specific fixups for reboot修正某些旧x86主板的重起bug,这种主板基本绝种了/dev/cpu/microcode - Intel IA32 CPU microcode support使用不随Linux内核发行的IA32微代码,你必需有IA32微代码二进制文件,仅对Intel的CPU有效/dev/cpu/*/msr - Model-specific register support在多cpu系统中让特权CPU访问x86的MSR寄存器/dev/cpu/*/cpuid - CPU information support能从/dev/cpu/x/cpuid获得CPU的唯一标识符(CPUID)Firmware Drivers固件驱动程序BIOS Enhanced Disk Drive calls determine boot disk有些BIOS支持从某块特定的硬盘启动(如果BIOS不支持则可能无法启动),目前大多数BIOS还不支持BIOS update support for DELL systems via sysfs仅适用于DELL机器Dell Systems Managem ent Base Driver仅适用于DELL机器High Memory Support最高内存支持,总内存小于等于1G的选"off",大于4G的选"64G"Memory split如果你不是绝对清楚自己在做什么,不要改动这个选项Memory model一般选"Flat Memory",其他选项涉及内存热插拔64 bit Memory and IO resources使用64位的内存和IO资源Allocate 3rd-level pagetables from highmem在内存很多(大于4G)的机器上将用户空间的页表放到高位内存区,以节约宝贵的低端内存Math emulation数学协处理器仿真,486DX以上的cpu就不要选它了MTRR (Memory Type Range Register) support打开它可以提升PCI/AGP总线上的显卡2倍以上的速度,并且可以修正某些BIOS错误Boot from EFI supportEFI是一种可代替传统BIOS的技术(目前的Grub/LILO尚不能识别它),但是现在远未普及Enable kernel irq balancing让内核将irq中断平均分配给多个CPU以进行负载均衡,但是要配合irqbanlance守护进程才行Use register arguments使用"-mregparm=3"参数编译内核,将前3个参数以寄存器方式进行参数调用,可以生成更紧凑和高效的代码Enable seccomp to safely compute untrusted bytecode只有嵌入式系统可以不选Timer frequency内核时钟频率,桌面推荐"1000 HZ",服务器推荐"100 HZ"或"250 HZ"kexec system call提供kexec系统调用,可以不必重启而切换到另一个内核kernel crash dumps被kexec启动后产生内核崩溃转储Physical address where the kernel is loaded内核加载的物理地址,除非你知道自己在做什么,否则不要修改.在提供kexec系统调用的情况下可能要修改它Support for hot-pluggable CPUs对热插拔CPU提供支持Compat VDSO support如果Glibc版本大于等于2.3.3就不选,否则就选上Power management options电源管理选项Power Managem ent support电源管理有APM和ACPI两种标准且不能同时使用.即使关闭该选项,X86上运行的Linux也会在空闲时发出HLT指令将CPU进入睡眠状态Legacy Power Management API传统的电源管理API,比如软关机和系统休眠等接口Power Managem ent Debug Support仅供调试使用Driver model /sys/devices/.../power/state files内核帮助文档反对使用该选项,即将被废除ACPI (Advanced Configuration and Power Interface) Support必须运行acpid守护程序ACPI才能起作用.ACPI是为了取代APM而设计的,因此应该尽量使用ACPI而不是APMAC Adapter如果你的系统可以在AC和电池之间转换就可以选Battery通过/proc/acpi/battery向用户提供电池状态信息,用电池的笔记本可以选Button守护程序捕获Power,Sleep,Lid按钮事件,并根据/proc/acpi/event做相应的动作,软件控制的poweroff 需要它Video仅对集成在主板上的显卡提供ACPI2.0支持,且不是所有集成显卡都支持Generic Hotkey统一的热键驱动,建议不选Fan允许通过用户层的程序来对系统风扇进行控制(开,关,查询状态),支持它的硬件并不多Dock支持由ACPI控制的集线器(docking stations)Processor让ACPI处理空闲状态,并使用ACPI C2和C3处理器状态在空闲时节省电能,同时它还被cpufreq的"Performance-state drivers"选项所依赖Thermal Zone系统温度过高时可以利用ACPI thermal zone及时调整工作状态以避免你的CPU被烧毁ASUS/Medion Laptop ExtrasASUS笔记本专用,以提供额外按钮的支持,用户可以通过/proc/acpi/asus来打开或者关闭LCD的背光/调整亮度/定制LED的闪烁指示等功能IBM ThinkPad Laptop ExtrasIBM ThinkPad专用Toshiba Laptop ExtrasToshiba笔记本专用Disable ACPI for systems before Jan 1st this year输入四位数的年份,在该年的1月1日前不使用ACPI的功能("0"表示一直使用)Debug Statements详细的ACPI调试信息,不搞开发就别选Power Managem ent Timer Support这个Timer在所有ACPI兼容的平台上都可用,且不会受PM功能的影响,建议总是启用它.如果你在kernel log中看到了'many lost ticks'那就必须启用它ACPI0004,PNP0A05 and PNP0A06 Container Driver支持内存和CPU的热插拔Smart Battery System支持依赖于I2C的"智能电池".这种电池非常老旧且罕见,还与当前的ACPI标准兼容性差APM (Advanced Power Managem ent) BIOS SupportAPM在SMP机器上必须关闭,一般来说当前的笔记本都支持ACPI,所以应尽量关闭该该选项Ignore USER SUSPEND只有NEC Versa M系列的笔记本才需要选择这一项Enable PM at boot time系统启动时即启用APM,选上这个选项能让系统自动的进行电源管理,但常常导致启动时死机Make CPU Idle calls when idle系统空闲时调用空闲指令(halt),只有老式的CPU才需要选它,且对于SMP系统必须关闭Enable console blanking using APM在屏幕空白时关闭LCD背光,事实上对所有的笔记本都无效RTC stores time in GMT将硬件时钟应该设为格林威治时间,否则视为本地时间.建议你使用GMT,这样你无须为时区的改变而担心Allow interrupts during APM BIOS calls允许APM的BIOS调用时中断,IBM Thinkpad的一些新机器需要这项.如果休眠时挂机(包括睡下去就醒不来),可以试试它Use real mode APM BIOS call to power off此驱动为某些有Bug的BIOS准备,如果你的系统不能正常关机或关机时崩溃,可以试试它CPU Frequency scaling允许动态改变CPU主频,达到省电和降温的目的,必须同时启用下面的一种governor才行Enable CPUfreq debugging允许对CPUfreq进行调试CPU frequency translation statistics通过sysfs文件系统输出CPU频率变换的统计信息CPU frequency translation statistics details输出详细的CPU频率变换统计信息Default CPUFreq governor默认的CPU频率调节器'performance' governor'性能'优先,静态的将频率设置为cpu支持的最高频率'powersave' governor'节能'优先,静态的将频率设置为cpu支持的最低频率'userspace' governor for userspace frequency scaling既允许手动调整cpu频率,也允许用户空间的程序动态的调整cpu频率(需要额外的调频软件,比如cpufreqd)'ondemand' cpufreq policy governor'立即响应',周期性的考察CPU负载并自动的动态调整cpu频率(不需要额外的调频软件),适合台式机'conservative' cpufreq governor'保守',和'ondemand'相似,但是频率的升降是渐变式的(幅度不会很大),更适合用于笔记本/PDA/AMD64环境ACPI Processor P-States driver将ACPI2.0的处理器性能状态报告给CPUFreq processor drivers以决定如何调整频率,该选项依赖于ACPI->Processor{省略的部分请按照自己实际使用的CPU选择}/proc/acpi/processor/../performance interface内核帮助文档反对使用该选项,即将被废除Relaxed speedstep capability checks放松对系统的speedstep兼容性检查,仅在某些老旧的Intel系统上需要打开Bus options (PCI, PCMCIA, EISA, MCA, ISA)总线选项PCI supportPCI支持,如果使用了PCI或PCI Express设备就必选PCI access modePCI访问模式,强列建议选"Any"(系统将优先使用"MMConfig",然后使用"BIOS",最后使用"Direct"检测PCI设备)PCI Express supportPCI Express支持(目前主要用于显卡和千兆网卡)PCI Express Hotplug driver如果你的主板和设备都支持PCI Express热插拔就可以选上Use polling mechanism for hot-plug events对热插拔事件采用轮询机制,仅用于测试目的Root Port Advanced Error Reporting support由PCI Express AER驱动程序处理发送到Root Port的错误信息Message Signaled Interrupts (MSI and MSI-X)充许设备通过PCI总线写入内存堆栈产生一个中断而不是使用默认的IRQ中断,建议不选PCI Debugging将PCI调试信息输出到系统日志里Interrupts on hypertransport devices允许本地的hypertransport设备使用中断ISA support现在基本上没有ISA的设备了,如果你有就选吧MCA support微通道总线,老旧的IBM的台式机和笔记本上可能会有这种总线NatSemi SCx200 support在使用AMD Geode处理器的机器上才可能有PCCARD (PCMCIA/CardBus) supportPCMCIA卡(主要用于笔记本)支持Enable PCCARD debugging仅供调试16-bit PCMCIA support一些老的PCMCIA卡使用16位的CardBus32-bit CardBus support当前的PCMCIA卡基本上都是32位的CardBusCardBus yenta-compatible bridge support使用PCMCIA卡的基本上都需要选择这一项,子项请按照自己实际使用的PCMCIA卡选择{省略的部分请按照自己实际使用的PCMCIA卡选择}PCI Hotplug SupportPCI热插拔支持,如果你有这样的设备就到子项中去选吧Executable file formats可执行文件格式Kernel support for ELF binariesELF是开放平台下最常用的二进制文件格式,支持动态连接,支持不同的硬件平台.除非你知道自己在做什么,否则必选Kernel support for a.out and ECOFF binaries早期UNIX系统的可执行文件格式,目前已经被ELF格式取代Kernel support for MISC binaries允许插入二进制的封装层到内核中,使用Java,.NET,Python,Lisp等语言编写的程序时需要它Networking网络Networking options网络选项Network packet debugging在调试不合格的包时加上额外的附加信息,但在遇到Dos攻击时你可能会被日志淹没Packet socket这种Socket可以让应用程序(比如tcpdump,iptables)直接与网络设备通讯,而不通过内核中的其它中介协议Packet socket: mmapped IO让Packet socket驱动程序使用IO映射机制以使连接速度更快Unix domain sockets一种仅运行于本机上的效率高于TCP/IP的Socket,简称Unix socket.许多程序都使用它在操作系统内部进行进程间通信(IPC),比如X Window和syslogTransformation user configuration interface为IPsec(可在ip层加密)之类的工具提供XFRM用户配置接口支持Transformation sub policy supportXFRM子策略支持,仅供开发者使用PF_KEY sockets用于可信任的密钥管理程序和操作系统内核内部的密钥管理进行通信,IPsec依赖于它TCP/IP networkingTCP/IP协议当然要选IP: multicasting群组广播,似乎与网格计算有关,仅在使用MBONE的时候才需要IP: advanced router高级路由,如果想做一个路由器就选吧IP: policy routing策略路由IP: equal cost multipath用于路由的基于目的地址的负载均衡IP: verbose route monitoring显示冗余的路由监控信息IP: kernel level autoconfiguration在内核启动时自动配置ip地址/路由表等,需要从网络启动的无盘工作站才需要这个东西IP: tunnelingIP隧道,将一个IP报文封装在另一个IP报文内的技术IP: GRE tunnels over IP基于IP的GRE(通用路由封装)隧道IP: multicast routing多重传播路由IP: ARP daemon support这东西尚处于试验阶段就已经被废弃了IP: TCP syncookie support抵抗SYN flood攻击的好东西,要启用它必须同时启用/proc文件系统和"Sysctl support",然后在系统启动并挂载了/proc之后执行"echo 1 >/proc/sys/net/ipv4/tcp_syncookies"命令IP: AH transformationIPsec验证头(AH)实现了数据发送方的验证处理,可确保数据既对于未经验证的站点不可用也不能在路由过程中更改IP: ESP transformationIPsec封闭安全负载(ESP)实现了发送方的验证处理和数据加密处理,用以确保数据不会被拦截/查看或复制IP: IPComp transformationIPComp(IP静荷载压缩协议),用于支持IPsecIP: IPsec transport modeIPsec传输模式,常用于对等通信,用以提供内网安全.数据包经过了加密但IP头没有加密,因此任何标准设备或软件都**看和使用IP头IP: IPsec tunnel modeIPsec隧道模式,用于提供外网安全(包括虚拟专用网络).整个数据包(数据头和负载)都已经过加密处理且分配有新的ESP头/IP头和验证尾,从而能够隐藏受保护站点的拓扑结构IP: IPsec BEET modeIPsec BEET模式INET: socket monitoring interfacesocket监视接口,一些Linux本地工具(如:包含ss的iproute2)需要使用它TCP: advanced congestion control高级拥塞控制,如果没有特殊需求(比如无线网络)就别选了,内核会自动将默认的拥塞控制设为"Cubic"并将"Reno"作为候补IP: Virtual Server ConfigurationIP虚拟服务器允许你基于多台物理机器构建一台高性能的虚拟服务器,不玩集群就别选了The IPv6 protocol你要是需要IPv6就选吧NetLabel subsystem supportNetLabel子系统为诸如CIPSO与RIPSO之类能够在分组信息上添加标签的协议提供支持,如果你看不懂就别选了Security Marking对网络包进行安全标记,类似于nfmark,但主要是为安全目的而设计,如果你不明白的话就别选Network packet filtering (replaces ipchains)Netfilter可以对数据包进行过滤和修改,可以作为防火墙("packet filter"或"proxy-based")或网关(NAT)或**(proxy)或网桥使用.选中此选项后必须将"Fast switching"关闭,否则将前功尽弃Network packet filtering debugging仅供开发者调试Netfilter使用Bridged IP/ARP packets filtering如果你希望使用一个针对桥接的防火墙就打开它Core Netfilter Configuration核心Netfilter配置(当包流过Chain时如果match某个规则那么将由该规则的target来处理,否则将由同一个Chain中的下一个规则进行匹配,若不match所有规则那么最终将由该Chain的policy进行处理)Netfilter netlink interface允许Netfilter在与用户空间通信时使用新的netlink接口.netlink Socket是Linux用户态与内核态交流的主要方法之一,且越来越被重视Netfilter NFQUEUE over NFNETLINK interface通过NFNETLINK接口对包进行排队Netfilter LOG over NFNETLINK interface通过NFNETLINK接口对包记录.该选项废弃了ipt_ULOG和ebg_ulog机制,并打算在将来废弃基于syslog的ipt_LOG和ip6t_LOG模块Layer 3 Independent Connection tracking独立于第三层的链接跟踪,通过广义化的ip_conntrack支持其它非IP协议的第三层协议Netfilter Xtables support如果你打算使用ip_tables,ip6_tables,arp_tables之一就必须选上"CLASSIFY" target support允许为包设置优先级,一些排队规则(atm,cbq,dsmark,pfifo_fast,htb,prio)需要使用它"CONNMARK" target support类似于"MARK",但影响的是连接标记的值"DSCP" target support允许对ip包头部的DSCP(Differentiated Services Codepoint)字段进行修改,该字段常用于Qos "MARK" target support允许对包进行标记(通常配合ip命令使用),这样就可以改变路由策略或者被其它子系统用来改变其行为"NFQUEUE" target Support用于替代老旧的QUEUE(iptables内建的target之一),因为NFQUEUE能支持最多65535个队列,而QUEUE只能支持一个"NOTRACK" target support允许规则指定哪些包不进入链接跟踪/NAT子系统"SECMARK" target support允许对包进行安全标记,用于安全子系统"CONNSECMARK" target support针对链接进行安全标记,同时还会将连接上的标记还原到包上(如果链接中的包尚未进行安全标记),通常与SECMARK target联合使用"comment" match support允许你在iptables规则集中加入注释"connbytes" per-connection counter match support允许针对单个连接内部每个方向(进/出)匹配已经传送的字节数/包数"connmark" connection mark match support允许针对每个会话匹配先前由"CONNMARK"设置的标记值"conntrack" connection tracking match support连接跟踪匹配,是"state"的超集,它允许额外的链接跟踪信息,在需要设置一些复杂的规则(比如网关)时很有用"DCCP" protocol match supportDCCP是打算取代UDP的新传输协议,它在UDP的基础上增加了流控和拥塞控制机制,面向实时业务"DSCP" match support允许对IP包头的DSCP字段进行匹配"ESP" match support允许对IPSec包中的ESP头进行匹配,使用IPsec的话就选上吧"helper" match support加载特定协议的连接跟踪辅助模块,由该模块过滤所跟踪的连接类型的包,比如ip_conntrack_ftp模块"length" match support允许对包的长度进行匹配"limit" match support允许根据包的进出速率进行规则匹配,常和"LOG target"配合使用以抵抗某些Dos攻击"mac" address match support允许根据以太网的MAC进行匹配,常用于无线网络环境"mark" match support允许对先前由"MARK"标记的特定标记值进行匹配IPsec "policy" match support使用IPsec就选上吧Multiple port match support允许对TCP或UDP包同时匹配多个端口(通常情况下只能匹配一个端口)"physdev" match support允许对到达的或将要离开的物理桥端口进行匹配"pkttype" packet type match support允许对封包目的地址类别(广播/群播/直播)进行匹配"quota" match support允许对总字节数的限额值进行匹配"realm" match support允许对iptables中的路由子系统中的realm值进行匹配"sctp" protocol match support流控制传输协议(SCTP),十年以后也许能够普及的东西"state" match support这是对包进行分类的有力工具,它允许利用连接跟踪信息对连接中处于特定状态的包进行匹配"statistic" match support允许根据一个给定的百分率对包进行周期性的或随机性的匹配"string" match support允许根据包所承载的数据中包含的特定字符串进行匹配"tcpmss" match support允许根据TCP SYN包头中的MSS(最大分段长度)选项的值进行匹配IP: Netfilter Configuration针对IPv4的Netfilter配置Connection tracking (required for masq/NAT)链接跟踪.可用于报文伪装或地址转换,也可用于增强包过滤能力Connection tracking flow accounting允许针对每个连接记录已经传送的字节/包数,常用于connbytes matchConnection mark tracking support允许对连接进行标记,与针对单独的包进行标记的不同之处在于它是针对连接流的.CONNMARK target和connmark match需要它的支持Connection tracking security mark support允许对连接进行安全标记,通常这些标记包(SECMARK)复制到其所属连接(CONNSECMARK),再从连接复制到其关联的包(SECMARK)Connection tracking events连接跟踪事件支持.如果启用这个选项,连接跟踪代码将提供一个notifier链,它可以被其它内核代码用来获知连接跟踪状态的改变Connection tracking netlink interface支持基于netlink的用户空间接口SCTP protocol connection tracking supportSCTP是IP网面向多媒体通信的新一代的流控制传输协议FTP protocol supportFTP协议IRC protocol supportIRC协议是一种用来实时聊天协议,用过mIRC的人应当不陌生NetBIOS name service protocol supportNetBIOS名字服务协议TFTP protocol supportTFTP是基于UDP的比FTP简单的文件传输协议Amanda backup protocol supportAmanda备份协议PPTP protocol support点对点隧道协议(PPTP)是一种支持多协议虚拟专用网络的网络技术,ADSL用户对它应该很熟悉H.323 protocol supportITU-T提出的用于IP电话的协议SIP protocol supportIETE提出的用于IP电话的协议IP Userspace queueing via NETLINK已废弃IP tables support (required for filtering/masq/NAT)要用iptables就肯定要选上IP range match support允许对ip地址的范围进行匹配TOS match support允许对ip包头的TOS(Type Of Service)字段进行匹配recent match support可以创建一个或多个刚刚使用过的ip地址列表,然后根据这些列表进行匹配ECN match support允许对TCP/IP包头的ECN(Explicit Congestion Notification)字段进行匹配.ECN是一种显式拥塞通知技术,它不但要求路由器支持而且要求端到端主机的支持,其基本思想是当路由器发生早期拥塞时不是丢弃包而是尽量对包进行标记,接收方接到带有ECN提示的包时,通知发送方网络即将发生拥塞,也就是它通过对包的标记提示TCP源即将发生拥塞,从而引发拥塞避免算法AH match support允许对IPSec包头的AH字段进行匹配TTL match support允许对ip包头的TTL(生存期)字段进行匹配Owner match support允许对本地生成的包按照其宿主(user,group,process,session)进行匹配address type match support允许对地址类型(单播,本地,广播)进行匹配hashlimit match support是limit的升级,它基于你选择的ip地址与/或端口动态的创建以limit为桶(bucket)的哈希表.它可以创建诸如"为每个特定的目标IP分配10kpps"或"允许每个特定的源IP分配500pps"之类的规则Packet filtering定义filter表以允许对包进行过滤REJECT target support允许返回一个ICMP错误而不是简单的丢弃包LOG target support允许将符合条件的包头信息通过syslog进行记录ULOG target support透过netlink socket将符合条件的封包交给用户空间的ulogd守护进程.反对使用该选项,因为它已经被NETFILTER_NETLINK_LOG代替TCPMSS target support允许修改TCP包头中的MSS(最大分段长度)选项值Full NAT允许进行伪装/端口转发以及其它的NAT功能,仅在你需要使用iptables中的nat表时才需要选择Packet mangling在iptables中启用mangle表以便对包进行各种修改,常用于改变包的路由raw table support (required for NOTRACK/TRACE)在iptables中添加一个'raw'表,该表在netfilter框架中非常靠前,并在PREROUTING和OUTPUT链上有钩子,从而可以对收到的数据包在连接跟踪前进行处理ARP tables supportARP表支持.只有在局域网中才有ARP欺骗问题,另外路由器也会遭到ARP欺骗ARP packet filteringARP包过滤.对于进入和离开本地的ARP包定义一个filter表,在桥接的情况下还可以应用于被转发ARP 包ARP payload mangling允许对ARP包的荷载部分进行修改,比如修改源和目标物理地址IPv6: Netfilter Configuration针对IPv6的Netfilter配置,需要的话可以参考前面IPv4的Netfilter配置进行选择DECnet: Netfilter Configuration针对DECnet的Netfilter配置Bridge: Netfilter Configuration针对桥接的Netfilter配置DCCP Configuration数据报拥塞控制协议在UDP的基础上增加了流控和拥塞控制机制,使数据报协议能够更好地用于流媒体业务的传输SCTP Configuration。
Linux操作系统修改内核参数的三种方法详细说明

Linux操作系统修改内核参数的三种方法详细说明linux内核的参数设置怎么弄呢,Linux 操作系统修改内核参数有以下三种方式:修改 /etc/sysctl.conf 文件;在文件中加入配置项,格式为 key = value,保存修改后的文件,执行命令 sysctl -p 加载新配置。
使用 sysctl 命令临时修改;如:sysctl -w net.ipv4.tcp_mem = “379008 505344 758016”直接修改/proc/sys/ 目录中的文件。
如:echo “379008 505344 758016” 》 /proc/sys/net/ipv4/tcp_mem 注意:第一种方式在重启操作系统后自动永久生效;第二种和第三种方式在重启后失效。
内核参数kernel.core_uses_pi d = 1core_uses_pid 可以控制 core 文件的文件名中是否添加 pid 作为扩展名。
设置为1,表示添加 pid 作为扩展名,生成的 core 文件格式为core.xxx;设置为0(默认),表示生成的 core 文件统一命名为 core。
kernel.core_pat te rn = corecore_pattern 可以控制 core 文件的保存位置和文件格式。
如:kernel.core_pattern = “/corefile/core-%e-%p-%t”,表示将core 文件统一生成到 /corefile 目录下,产生的文件名为 core-命令名-pid-时间戳。
以下是参数列表:%p - insert pid into filename 添加 pid%u - insert current uid into filename 添加当前 uid%g - insert current gid into filename 添加当前 gid%s - insert signal that caused the coredump into the filename 添加导致产生 core 的信号%t - insert UNIX ti me that the coredump occurred into filename 添加 core 文件生成时的 unix 时间%h - insert hostname where the coredump happened into filename 添加主机名%e - insert coredumping executable name into filename 添加命令名kernel.msgmax = 8192进程间的消息传递是在内核的内存中进行的。
linux module用法

linux module用法Linux模块用法:详解如何使用Linux模块开发引言:Linux模块是一种动态扩展内核功能的方法,它允许用户在不修改内核的情况下增加或改变内核的功能。
本文将详细介绍Linux模块的基本概念、用法以及一步一步回答关于Linux模块的问题。
第一部分:了解Linux模块1. 什么是Linux模块?- Linux模块是一种可加载的代码,它与内核紧密关联并具有与内核无缝交互的能力。
它允许用户在运行时向内核中添加新功能。
2. Linux模块的作用是什么?- Linux模块的作用在于允许用户扩展或修改内核的功能,而无需重新编译和重新启动整个内核。
3. Linux模块与内核的关系是什么?- Linux模块是内核的一部分,它以插件的形式加载到内核中,并与内核及其功能进行交互。
4. Linux模块的分类有哪些?- 根据功能的不同,Linux模块可以分为驱动程序、文件系统、网络协议等各种类型。
第二部分:Linux模块的基本用法1. 如何编写Linux模块?- 使用C语言编写Linux模块,源文件通常以`.c`为扩展名。
2. 如何编译Linux模块?- Linux模块的编译需要使用内核提供的`Makefile`文件,并通过`make`命令进行编译。
3. 如何加载Linux模块?- 使用`insmod`命令可以加载一个Linux模块到内核中。
4. 如何卸载Linux模块?- 使用`rmmod`命令可以将一个已加载的Linux模块从内核中卸载。
5. 如何查看已加载的Linux模块?- 使用`lsmod`命令可以列出当前已加载的Linux模块。
第三部分:Linux模块的开发步骤1. 步骤一:准备开发环境- 安装Linux内核源代码以及编译工具链。
2. 步骤二:编写Linux模块代码- 创建一个新的源文件,并实现相关的功能。
3. 步骤三:编译生成Linux模块- 使用Makefile文件进行编译,并生成`.ko`的模块文件。
Linux内核模块的加载过程

Linux 内核模块的加载过程前 段时间为了解决内核模块无法卸载的问题,对模块的加载过程详细地学习了一番。
加载模块时常用的命令是insmod 和modprobe ,这两个命令主要是通 过系统调用sys_init_module ()来完成主要的工作,,用户层做的更多的是对参数的处理,,以及将插入的模块加入到内存中。
系统调用 sys_init_module ()将大部分工作委托给load_module ()函数来完成,,load_module ()中的操作,,大部分是围绕着 ELF 文件的格式来完成的,,所以如果对ELF 文件了解的话,看load_module ()的过程很容易。
下面将我对load_module ()的一些理解贴出来和大家分享一下,,注释比较详细,就不多说了:/* Allocate and load the module : note that size of section 0 is alwayszero , and we rely on this for optional sections. *//** load_module ()负责最艰苦的模块加载全过程。
sys_init_module ()调用load_module (), * 后者将在内核空间利用vmalloc 分配一块大小同样为len 的地址空间。
然后通过* copy_from_user 函数的调用将用户空间的文件数据复制到内核空间中,,从而在内核空间 * 构造出内核模块的一个ELF 静态的内存视图。
接下来的操作都将以此视图为基础,为使 * 叙述简单起见,我们称该视图为HDR 视图。
HDR 视图所占用的内存空间在load_module 结束时* 通过vfree 予以释放。
*/static noinline struct module *load_module (void __user *umod ,unsigned long len ,const char __user *uargs){/** ELF 文件头地址。
Linux的内核编译和内核模块的管理

Linux的内核编译和内核模块的管理一、内核的介绍内核室操作系统的最重要的组件,用来管理计算机的所有软硬件资源,以及提供操作系统的基本能力,RED hatenterpriselinux的许多功能,比如软磁盘整列,lvm,磁盘配额等都是由内核来提供。
1.1内核的版本与软件一样内核也会定义版本的信息,以便让用户可以清楚的辨认你用得是哪个内核的一个版本,linux内核以以下的的语法定义版本的信息MAJOR.MINOR.RELEASE[-CUSTOME]MAJOR:主要的版本号MINOR:内核的次版本号,如果是奇数,表示正在开发中的版本,如果是偶数,表示稳定的版本RELEASE:修正号,代表这个事第几次修正的内核CUSTOME 这个是由linux产品商做定义的版本编号。
如果想要查看内核的版本使用uname 来查看语法#uname [选项]-r --kernel-release 只查看目前的内核版本号码-s --kernel-name 支持看内核名称、-n --nodename 查看当前主机名字-v --kernel-version 查看当前内核的版本编译时间-m --machine 查看内核机器平台名称-p --processor 查看处理器信息-I --hard-platform 查看硬件平台信息-o --operating-system 查看操作系统的名称-a 查看所有1.2内核的组件内核通常会以镜像文件的类型来存储在REDHAT ENTERPRISE LINUX 中,当你启动装有REDHAT ENTERPRISE linux的系统的计算机时,启动加载器bootloader 程序会将内核镜像文件直接加载到程序当中,已启动内核与整个操作系统一般来说,REDHAT ENTERPRISE LINUX 会把内核镜像文件存储在/boot/目录中,文件名称vmlinuz-version或者vmlinux-version 其中version就是内的版本号内核模块组成linux内核的第二部分是内核模块,或者单独成为内核模块。
Linux内核配置

Linux内核配置系统1.配置系统的基本结构Linux内核的配置系统由三个部分组成,分别是:1.Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则;2.配置文件(config.in):给用户提供配置选择的功能;3.配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于Xwindows 图形界面的用户配置界面,各自对应于 Make config、Makemenuconfig 和 make xconfig)。
这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。
本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。
所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。
所以,在本文中,我们只对Makefile 和配置文件进行讨论。
另外,凡是涉及到与具体 CPU 体系结构相关的内容,我们都以 ARM 为例,这样不仅可以将讨论的问题明确化,而且对内容本身不产生影响。
2. Makefile2.1 Makefile 概述Makefile 的作用是根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成 Linux 内核二进制文件。
由于 Linux 内核源代码是按照树形结构组织的,所以 Makefile 也被分布在目录树中。
Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:1.Makefile:顶层 Makefile,是整个内核配置、编译的总体控制文件。
2..config:内核配置文件,包含由用户选择的配置选项,用来存放内核配置后的结果(如 make config)。
3.arch/*/Makefile:位于各种 CPU 体系目录下的 Makefile,如arch/arm/Makefile,是针对特定平台的 Makefile。
嵌入式Linux内核模块的配置与编译

嵌入式Linux内核模块的配置与编译一、简介随着 Linux操作系统在嵌入式领域的快速发展,越来越多的人开始投身到这方面的开发中来。
但是,面对庞大的Linux内核源代码,开发者如何开始自己的开发工作,在完成自己的代码后,该如何编译测试,以及如何将自己的代码编译进内核中,所有的这些问题都直接和Linux的驱动的编译以及Linux的内核配置系统相关。
内核模块是一些在操作系统内核需要时载入和执行的代码,它们扩展了操作系统内核的功能却不需要重新启动系统,在不需要时可以被操作系统卸载,又节约了系统的资源占用。
设备驱动程序模块就是一种内核模块,它们可以用来让操作系统正确识别和使用使用安装在系统上的硬件设备。
Linux内核是由分布在全球的Linux爱好者共同开发的,为了方便开发者修改内核,Linux的内核采用了模块化的内核配置系统,从而保证内核扩展的简单与方便。
本文通过一个简单的示例,首先介绍了如何在Linux下编译出一个内核模块,然后介绍了Linux内核中的配置系统,讲述了如何将一个自定义的模块作为系统源码的一部分编译出新的操作系统,注意,在这里我们介绍的内容均在内核2.6.13.2(也是笔者的开发平台的版本)上编译运行通过,在2.6.*的版本上基本上是可以通用的。
二、单独编译内核模块首先,我们先来写一个最简单的内核模块:#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#define DRIVER_VERSION "v1.0"#define DRIVER_AUTHOR "RF"#define DRIVER_DESC "just for test"MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");staticintrfmodule_init(void){printk("hello,world:modele_init");return 0;}static void rfmodule_exit(void){printk("hello,world:modele_exit");}module_init (rfmodule_init);module_exit (rfmodule_exit);这个内核模块除了在载入和卸载的时候打印2条信息之外,没有任何其他功能,不过,对于我们这个编译的例子来讲,已经足够了。
linux实验_添加内核模块-完整版本

添加内核模块1.编写helloworld模块,了解模块的编程方法。
首先编写一个helloworld程序,如下图:图1 HelloWorld模块测试c程序两个头文件linux/module.h和linux/init.h是编写模块所必需的;程序里面有两个函数,第一个函数moduletest_init实现模块加载时的动作,第二个函数moduletest_exit实现模块卸载是的动作。
两个函数的函数名可以任意指定。
module_init和module_exit是两个宏,括号里的函数名才是真正的模块加载和卸载时要执行的函数,即不管上面的两个函数的函数名是什么,只要经过这两个宏的指定,就会称为模块加载和卸载时运行的函数。
最后一句表示模块遵循公共许可证,一般来说都要加上,不加会出现警告。
然后编译内核模块。
⑴编写Makefile文件;在与源文件同目录下,新建文件名为Makefile,注意M要大写。
编辑Makefile文件,添加以下内容并保存,如图:图2 helloworld模块的Makefile文件⑵编译内核模块;打开终端,进入当前所在的目录。
执行命令 make命令成功执行后,会在当前目录下生成许多文件,HelloWorld.o HelloWorld.ko HelloWorld.mod.o HelloWorld.mod.c Modules.symvers 其中,HelloWorld.ko是我们要加载的模块。
最后加载和卸载模块:终端在当前目录下,输入命令 insmod ./HelloWorld.ko;输入命令lsmod,能找到名为HelloWorld的模块,说明模块已经加载;输入命令dmesg,查看最后一行,会有模块加载时调用的函数输出;输入命令rmmod HelloWorld ,卸载模块(注意与加载时不同),然后输入lsmod,已经找不到HelloWorld模块,说明模块已经卸载;输入命令dmesg,查看模块卸载是调用的函数输出。
linux内核模块原理

linux内核模块原理嘿,朋友们!你们知道吗,Linux 内核模块那可真是个超级有趣的东西啊!就好像是一个庞大机器中的各种精巧零件,可以随时插拔更换,让这个大机器变得更强大、更灵活!Linux 内核模块原理呢,简单来说,就是允许在运行中的内核中动态地添加或移除功能。
这就好比你在玩一个超级复杂的积木游戏,你可以根据自己的需求和想法,随时添加或拿走一些积木块,来搭建出你想要的结构。
比如说,假设你的系统原本不支持某种特定的硬件设备,但是通过加载一个专门的内核模块,嘿,马上就可以让这个硬件正常工作啦!这多神奇啊!再比如,你可能需要在特定情况下启用一些特殊的安全机制,没问题,加载相应的模块就行啦。
这就好像是一个武林高手,平时可能隐藏着自己的某些绝技,但是在关键时刻,就能把这些绝技使出来,大显神威!而且哦,内核模块的好处还在于它的灵活性。
它不需要你重新编译整个内核,就能实现功能的扩展或修改。
这可省了不少事儿呢!我给你们讲个实际例子吧。
有一次,一个公司的服务器需要支持一种新的网络协议,要是按照传统方法,那得大动干戈地重新编译内核。
但是呢,他们用了内核模块,短短几个小时就搞定了,服务器马上就能支持新协议了,这效率,简直了!Linux 内核模块的实现其实也很有意思。
它就像是一个智能的插件系统,内核会提供一系列的接口和机制,让模块能够与内核进行交互。
模块可以注册自己的函数、变量等等,这样内核就能在需要的时候调用它们。
这就好像是你加入了一个团队,你要向团队展示你的能力和特长,让团队在需要的时候能想起你,找你帮忙。
总之啊,Linux 内核模块原理真的是非常重要且超级有趣的一部分。
它让 Linux 系统变得无比强大和灵活,就像是给系统注入了无限的可能性!你们难道不觉得这太酷了吗?还不快去深入了解一下!。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验一:Linux内核模块的添加(一)静态加载:把组件都添加进内核文件中,在目录kongfig文件中增加新代码对应的编译选项,在Makefile文件中添加编译条目。
(二)动态加载:下载并安装Linux内核模板:
make modules _install ARCH = arm CROSS _COMPILE
=arm-linux,编写Makefile。
以hello word为例来实现这两种方法:
静态加载:
(1)hello word.c源代码
#include <linux/init.h>
#include <linux/module.h>
static int hello_init(void)
{
printk(KERN_INFO " Hello World enter\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_INFO " Hello World exit\n ");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("Barry Song <21cnbao@>"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("A simple Hello World Module"); MODULE_ALIAS("a simplest module");
把所有的组件都翻译进内核文件,即生成zImage或bzImage
(1)进入linux-2.6.32.2-mini2440内核
(2)进入/drivers建立Hello文件夹,在Hello文件夹里面建立hello.c,Makef ile,Kconfig
Makefiel:obj-y(CONFIG_HELLO_WORD) +=hello.o Kconfig:config hello_word
tristate "TEST hello word"
help
usually you have to make
(3)在drivers里面的Makefile添加:obj-y(CONFIG_HELLO_WORD)
Hello/
(4)在drivers里面的Kconfig添加source "drivers/Hello/Kconfig" (5)输入make menuconfig进入内核配置界面
(6)然后输入y退出并保存
(7)生成了.config文件为配置的记录
(8)在make bzImage进行编译内核
(9)然后在arch/arm/boot/下生成bzImage
动态加载:直接编译成PC机X86的内核模块
(1)模块加载函数:insmod ;模块卸载函数:rmmod;
查看模块函数:lsmod
(2)模块可选信息:模块参数、模块导出符号、模块作者等信息声明(3)在/work里面加入hello.c文件和Makefile文件
Makefile 的内容为:ifneq ($(KERNELRELEASE),)
obj-m :=hello.o 和要编译的模块的名字一致
else
KDIR:= /lib/modules/3.5.0-17-generic/build
以便寻找内核源码目录下的Mmakefile
all:
make -C $(KDIR) M=$(PWD) modules 用KDIR目录下的Makefile来编译当前目录下的模块
clean:
rm -f *.ko *.o *.mod.o *.mod.c .symvers endif
(4)、执行make 命令
(5)、然后查看hello文件夹生成hello.ko文件
(6)执行insmod
hello.ko进行加载模块:(7)lsmod查看模块查看加载模块输出信息
(8)删除rmmod模块
(9)查看删除模块输出信息
(10)这样,就完成了对模块的添加和删除。
总结:通过对Linux内核模块的添加和删除实验,我学会了关于内核添加和删除的很多相关知识,首先,把组件编译进内核中,如果建立的一个文件夹,需要使建立的文件夹里的Kconfig和Makefile生效,需要在上一级目录里修改Kconfig和Makefile,这样才能使新建立的Kconfig和Makefile 生效。
其次,在模块动态加载到内核过程中,常常会出现不成功的时候,通过问老师,知道了是版本的问题,使得模块加载不成功。
我会在以后的学习过程中,加强这方面的学习,提高这方面的技能,让自己所学得到运用。