一个简单的内核模块编写到测试的全过程testmodule 之内核版本2.4.20.8

 

一个简单的内核模块编写到测试的全过程。由于是初学者,第一次接触内核模块编写,所以今天花了5个小时才完全搞通。本文针对的linux内核版本号是:linux-2.4.20.8

1.       模块程序的编写

建立testmodule.c 文件,输入以下代码

#ifndef __KERNEL__

#define __KERNEL__

#endif

#ifndef MODULE

#define MODULE

#endif

代码为:

#include "linux/kernel.h"

#include "linux/module.h"

#include "linux/fs.h"

#include "asm/uaccess.h"                 

#include "linux/errno.h"

 

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include<linux/modversions.h>

#endif

 

int open(struct inode *inode,struct file *filp)

{

MOD_INC_USE_COUNT;

printk("This module is in open!\n");

return 0;

}

void release(struct inode *inode,struct file *filp)

{

MOD_DEC_USE_COUNT;

//       return 0;

#ifdef DEBUG

           printk("release(%p,%p)\n",inode,filp);

#endif

}

int read(struct file *filp,char *buf,int count,loff_t *t)

{

int leave;

char ch='a';

//if(verify_area(VERIFY_WRITE,buf,count)==DEFAULT)

           //return -1; 这里之所以注释掉是因为我没找到DEFAULT的定义

verify_area(VERIFY_WRITE,buf,count);

for(leave=count;leave>0;leave--)

{

           __put_user('A',buf);

           //if(__copy_to_user(buf,&ch,1))

                    //printk("copy_to_user failed!\n");

           buf++;

}

return count;

}

int write(struct inode *inode,struct file *filp,const char *buf,int count)

{

return count;

}

struct file_operations chr_fops={

owner:THIS_MODULE,

read:read,

write:write,

open:open,

release:release

};

//struct file_operations chr_fops;

int dev;

int init_module()

{

int res;

printk("Hello! This is a testing moudle!\n");

if((res=register_chrdev(0,"gogogog",&chr_fops))<0)

           printk("register failed!\n");

dev=res;

return 0;

}

 

void cleanup_module()

{

unregister_chrdev(dev,"gogogog");

printk("Sorry! The testing module is unloading now!\n");

}

2.       编译选项为:

gcc -O2 -Wall -DMODULE -D__KERNEL__ -DLINUX -I /usr/src/linux-2.4.20-8/include/  -c testmodule.c

编译后出现以下情况

我看都是警告,所以就没继续修改(也不知道怎么修改,如果您知道了,希望能相告,共同学习!

参数解释:

l  -O2 表示需要对模块程序进行优化编译、链接

l  -Wall 参数向装在程序传递all。

l  -I /usr/src/linux-2.4.20-8/include/ 这个参数很重要。否则会提示错误`struct file' declared inside parameter list、`struct inode' declared inside parameter list、In file included from /usr/include/linux/fs.h:23,from testmodule.c:4:

/usr/include/linux/string.h:8:2: warning: #warning Using kernel header in userland!等错误。

#warning Using kernel header in userland! 这个也许会好奇,我怎么加了-I参数后还会有这个警告呢。原因很简单,你包含头文件时用的是尖括号。尖括号大家都知道是去系统默认路径中找。所以这里应该改成双引号包含!!!

当然如果嫌输入的编译命令太多,那么可以写makefile文件。

3.       编写测试程序test.c

代码如下:

#include<stdio.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

int main()

{

int i,testmoduledev;

char buf[10]={0};

testmoduledev=open("/dev/moduledev",O_RDWR);

printf("%d\n",testmoduledev);

if(testmoduledev==-1)

{

           printf("can't open the file!\n");

           exit(0);

}

read(testmoduledev,buf,10);

for(i=0;i<10;i++)

           printf("%d\n",buf[i]);

close(testmoduledev);

return 0;

}

4.       装载模块

Insmod testmodule.o

此时模块装入到内核中。

5.       然后我们要做的是这个模块设备创建设备文件moduledev(一个名字而已)。使用命令mknod /dev/moduledev c major minjor.其中c表示moduledev是字符设备。major是该设备的主设备号。其实后面读该设备时用到的也是主设备号。这个主设备号不能自己随意而定而是由系统分配的。因为装载模块后只要你的驱动程序通过函数register_chrdev(0,"gogogog",&chr_fops))注册后便会在系统中得到主设备号,此时只需要通过命令cat /proc/devices 查看便可,所以上面的major要到这里查看得到的值。

此时已经建立好了该设备的设备文件。然后便可以编译运行测试文件,从该设备文件中读取字符。

注意:

l  #include "asm/uaccess.h" 这个头文件,如果不包含头文件会提示警告:warning: implicit declaration of function `__put_user' 如果你不管这个警告,继续强行装入模块时,会遇到下面的无法解析sysbol 的错误。

以上是自己经过一晚上的努力才搞通的一个简单系统模块。贴出来跟大家分享~。我的内核版本是:2.4.20-8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮你回答这个问题。下面是一个简单的高通滤波器模块的Verilog代码: ``` module high_pass_filter(input clk, input reset, input signed [15:0] data_in, output reg signed [15:0] data_out); parameter CUTOFF_FREQ = 1000; parameter SAMPLE_RATE = 16000; parameter COEFFICIENT = (2 * 3.1415926 * CUTOFF_FREQ) / SAMPLE_RATE; reg signed [15:0] x1; reg signed [15:0] y1; always @(posedge clk) begin if (reset) begin x1 <= 0; y1 <= 0; data_out <= 0; end else begin x1 <= data_in; y1 <= (COEFFICIENT * (data_in - x1) + y1); data_out <= (data_in - x1 - y1); end end endmodule ``` 该模块包含了一个时钟输入 `clk`,一个复位输入 `reset`,一个带符号的16位数据输入 `data_in`,和一个带符号的16位数据输出 `data_out`。它还定义了三个参数:`CUTOFF_FREQ` 是截止频率,`SAMPLE_RATE` 是采样率,`COEFFICIENT` 是滤波器系数。 该模块使用一个一阶差分方程来实现高通滤波器。在每个时钟上升沿时,它将输入数据 `data_in` 和上一个时刻的输入数据 `x1` 做差,然后乘以系数 `COEFFICIENT`,并加上上一个时刻的输出数据 `y1`。最后,它将该结果减去输入数据和上一个时刻的输入数据的差,然后输出到 `data_out` 中。 为了验证该模块的正确性,我们可以编写一个测试程序,生成一些随机的输入数据,并将其送入模块中。我们可以使用一个仿真器来模拟模块的行为,并检查输出数据是否与预期的结果相同。以下是一个简单测试程序的Verilog代码: ``` module testbench; reg clk; reg reset; reg signed [15:0] data_in; wire signed [15:0] data_out; integer i; high_pass_filter dut( .clk(clk), .reset(reset), .data_in(data_in), .data_out(data_out) ); initial begin clk = 0; reset = 1; data_in = 0; #100 reset = 0; for (i = 0; i < 1000; i = i + 1) begin data_in = $random; #10; end $finish; end always begin #5 clk = ~clk; end endmodule ``` 该测试程序使用一个时钟输入 `clk`,一个复位输入 `reset`,一个带符号的16位数据输入 `data_in`,和一个带符号的16位数据输出 `data_out`。它实例化了我们之前定义的高通滤波器模块 `dut`,并将输入和输出端口连接到相应的信号上。在仿真开始时,它将时钟和复位信号初始化为0,并等待100个时钟周期后将复位信号拉高。然后,它使用一个 `for` 循环生成1000个随机的输入数据,每隔10个时钟周期更新一次输入数据,并在仿真完成后结束仿真。 为了运行该测试程序,我们需要使用一个Verilog仿真器,例如ModelSim。我们可以将上面的两个代码文件保存为 `high_pass_filter.v` 和 `testbench.v`,并在ModelSim命令行中输入以下命令来编译和运行仿真: ``` vlog high_pass_filter.v testbench.v vsim testbench run -all ``` 在仿真完成后,我们可以检查输出数据 `data_out` 是否与预期的结果相同,以验证该模块的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值