如何实现一个简单的含有输入参数的Hello内核模块,并在其中实现单链表
Linux内核模块编程
这篇文章的目的是使个人:
1.熟悉操作系统内核编程开发环境
2.初步掌握Linux环境下内核模块编写、编译、调试及运行的基本流程
3.熟悉内核编程的基本方法和步骤
编程环境
VMware Workstation Pro + Ubuntu 16.04 LTS
VMware+Ubuntu 16.04 LTS虚拟机安装教程参考:
2021安装Vmware和Ubuntu教程(特详细) - 知乎 (zhihu.com)
其中Ubuntu 16.04 LTS镜像下载参考:
(39条消息) ubuntu 16.04 镜像下载(国内开源镜像站)_ubtun16.04_dongjuexk的博客-CSDN博客
什么是内核模块?
内核模块的全称是动态可加载内核模块(Loadable Kernel Modul,KLM),可以动态载入内核,让它成为内核代码的一部分。一个模块一般由一组函数和数据结构组成。
模块要求
1.Ubuntu 16.04环境下实现含输入参数的Hello内核模块,可以按照输入的打印行数及姓名输出相应的信息。
2.在模块中实现单链表,完成insert、delete、lookup、print操作
如何编写带有输入参数的最简单的Hello World模块
打开终端,创建项目文件夹Linux-expr,命令如下:
1 2 3
| mkdir Linux-expr
cd Linux-expr
|
创建hello.c文件,文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/moduleparam.h>
MODULE_LICENSE("GPL");
static char*whom = "world";
static int num = 1;
module_param(whom,charp,S_IRUGO);
module_param(num,int,S_IRUGO);
static int hello_init(void)
{
int i; for (i=0;i<num;i++){ printk(KERN_ALERT "hello,%s\n",whom); } return 0;
}
static void hello_exit(void) { printk(KERN_ALERT "goodbye,kernel/n"); }
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("Maplemeo-silence");
MODULE_DESCRIPTION("This is a simple example!/n");
MODULE_VERSION("v1.0");
MODULE_ALIAS("A simplest example");
|
创建makefile文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11
| obj-m:=hello.o
CURRENT_PATH :=$(shell pwd) VERSION_NUM :=$(shell uname -r) LINUX_PATH :=/usr/src/linux-headers-$(VERSION_NUM)
all : make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules clean : make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean
|
通过make命令,编译文件:
可以看到目录下出现以下文件,其中hello.ko文件为我们所需要的内核模块文件:
使用insmod 命令加载模块(使用sudo权限)
使用lsmod查看模块是否加载进去,可以看到hello已经可以看到
使用demesg命令查看输出,可以看到有hello,world的输出
最后使用rmmod 命令卸载模块
如何编在模块中实现单链表
内核模块中实现单链表和在普通c程序中相差不多,值得注意的是,内存分配还是malloc被kmalloc所替换
listnode结构体如下所示,就是最简单的单链表结构:
1 2 3 4
| struct listnode{ int val_; struct listnode* next_; };
|
hello.c文件改写为如下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
| #include<linux/init.h> #include<linux/module.h> #include<linux/kernel.h> #include<linux/moduleparam.h> #include <linux/slab.h>
MODULE_LICENSE("GPL");
static char*whom = "world"; static int num = 1;
struct listnode{ int val_; struct listnode* next_; };
int insert(int val,struct listnode* head){ if(head == NULL){ printk(KERN_ALERT "the head is null, can not insert\n"); return -1; }else{ struct listnode* curr; curr = head; int num; num = 0; while(curr->next_!=NULL){ curr = curr->next_; num++; } struct listnode *new_node; new_node=kmalloc(sizeof(*new_node),GFP_KERNEL); new_node->val_ = val; new_node->next_ = NULL; curr->next_ = new_node; printk(KERN_ALERT "insert success!!! the new %d val = %d\n",num,new_node->val_); return 1; } }
void print(struct listnode* head){ if(head == NULL){ printk(KERN_ALERT "the head is null, can not printf\n"); return; } int num; num = 0; struct listnode* curr; curr = head; printk(KERN_ALERT "---------List Print--------\n"); while(curr->next_!=NULL){ curr = curr->next_; printk(KERN_ALERT "the %d val = %d\n",num,curr->val_); num++; } printk(KERN_ALERT "-------List Print end--------\n");
return; }
void delete(int val,struct listnode* head){ if(head == NULL){ printk(KERN_ALERT "the head is null, can not delete\n"); return; } struct listnode* curr; curr = head; int num; num = 0; while(curr->next_ != NULL){ struct listnode* prev; prev = curr; curr = curr->next_; if(curr->val_ == val){ prev->next_ = curr->next_; kfree(curr); printk(KERN_ALERT "delete success!!! the delete %d val = %d\n",num,val); return 1; } num++; }
printk(KERN_ALERT "delete fail!!! can not find val = %d\n",val); return -1; }
void lookup(int val,struct listnode* head){ if(head == NULL){ printk(KERN_ALERT "the head is null, can not delete\n"); return; } struct listnode* curr; curr = head; int num; num = 0; while(curr->next_ != NULL){ curr = curr->next_; if(curr->val_ == val){ printk(KERN_ALERT "lookup success!!! the lookup %d val = %d\n",num,curr->val_ ); return 1; } num++; }
printk(KERN_ALERT "lookup fail!!! can not lookup val = %d\n",curr->val_); return -1; }
module_param(whom,charp,S_IRUGO); module_param(num,int,S_IRUGO);
static int hello_init(void) { int i; for (i=0;i<num;i++){ printk(KERN_ALERT "hello,%s\n",whom); } struct listnode *head; head=kmalloc(sizeof(*head),GFP_KERNEL); if(head != NULL){ head->val_ = 0; head->next_ = NULL; printk(KERN_ALERT "the head val: %d\n",head->val_); } print(head); insert(7,head); print(head); delete(2,head); print(head); insert(1,head); insert(5,head); print(head); delete(1,head); lookup(7,head); print(head); return 0; }
static void hello_exit(void) { printk(KERN_ALERT "goodbye,kernel/n"); }
module_init(hello_init); module_exit(hello_exit);
MODULE_AUTHOR("Maplemeo-silence"); MODULE_DESCRIPTION("This is a simple example!/n"); MODULE_VERSION("v1.0"); MODULE_ALIAS("A simplest example");
|
使用make、insmod、demesg、 rmmod命令查看链表是否正常使用,至此整个内核模块实现完成。
