20135319zl内核模块编译报告
内核模块编程学习报告
1.编写一个简单的输出信息的模块
源代码:
Makefile
编译模块
加载模块
测试模块(dmesg)
卸载模块
Sudo rmmod 1
使用dmesg查看情况
2.输出当前进程信息
源代码(作为2.c)
修改makefile中的目标文件为2.o
编译,加载并测试模块
3.进程列表读取功能(3.c)
源代码
修改makefile为3.o
编译,加载并测试模块:
4.可读写的文件节点内核模块
在/proc文件系统中创建一个文件节点exp2
源代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h> // for basic filesystem
#include <linux/proc_fs.h> // for the proc filesystem
#include <linux/seq_file.h> // for sequence files
#include <linux/jiffies.h> // for jiffies
#include <linux/slab.h> // for kzalloc, kfree
#include <linux/uaccess.h> // for copy_from_user
//static struct task_struct *pcurrent;
int print_current_task_info(void);
// global var
static char *str = NULL;
// seq_operations -> show
static int jif_show(struct seq_file *m, void *v)
{
//seq_printf(m, "current kernel time is %llu\n", (unsigned long long) get_jiffies_64());
seq_printf(m, "str is %s\n", str);
return 0; //!! must be 0, or will show nothing T.T
}
// file_operations -> write
static ssize_t jif_write(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos)
{
//分配临时缓冲区
char *tmp = kzalloc((count+1), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
//将用户态write的字符串拷贝到内核空间
//copy_to|from_user(to,from,cnt)
if (copy_from_user(tmp, buffer, count)) {
kfree(tmp);
return -EFAULT;
}
//将str的旧空间释放,然后将tmp赋值给str
kfree(str);
str = tmp;
return count;
}
// seq_operations -> open
static int jif_open(struct inode *inode, struct file *file)
{
return single_open(file, jif_show, NULL);
}
static const struct file_operations jif_fops =
{
.owner = THIS_MODULE,
.open = jif_open,
.read = seq_read,
.write = jif_write,
.llseek = seq_lseek,
.release = single_release,
};
// module init
static int __init jif_init(void)
{
struct proc_dir_entry* jif_file;
jif_file = proc_create("exp2", 0, NULL, &jif_fops);
if (NULL == jif_file)
{
return -ENOMEM;
}
return 0;
}
// module exit
static void __exit jif_exit(void)
{
printk("******************************************\n");
remove_proc_entry("exp2", NULL);
kfree(str);
}
module_init(jif_init);
module_exit(jif_exit);
MODULE_AUTHOR("why");
MODULE_LICENSE("GPL");
编译,加载模块
往新建立的exp2文件中写入字符串”zhuli”,可见结果:
5.虚拟地址转换模块
源代码:
#include <linux/module.h>
#include <asm/pgtable.h>
#include <linux/version.h>
#include <asm/page.h>
#include <linux/gfp.h>
#include <linux/page-flags.h>
#include <linux/sched.h>//find_task_by_vpid
#include <linux/mm.h>//find_vma
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CONVERT USER VIRTUAL ADDRESS TO PHYADDRESS");
static int pid;
static unsigned long va;
module_param(pid,int,0644);
module_param(va,ulong,0644);
static int find_pgd_init(void)
{
unsigned long pa=0;
struct task_struct *pcb_tmp=NULL;
pgd_t *pgd_tmp=NULL;
pud_t *pud_tmp=NULL;
pmd_t *pmd_tmp=NULL;
pte_t *pte_tmp=NULL;
printk(KERN_ALERT "test:va=0x%lx,pid=%d.\n",va,pid);
rcu_read_lock();
if( !( pcb_tmp = pid_task(find_vpid(pid), PIDTYPE_PID) ) )
{
rcu_read_unlock();
printk(KERN_ALERT "Can't find the task %d.\n",pid);
return 0;
}
rcu_read_unlock();
printk("The page index_table address = 0x%p\n\n",pcb_tmp->mm->pgd);
printk(KERN_ALERT "pgd=0x%p\n",pcb_tmp->mm->pgd);
if(!find_vma(pcb_tmp->mm,va))
{
printk(KERN_ALERT "virt_addr 0x%lx not available.\n",va);
return 0;
}
pgd_tmp=pgd_offset(pcb_tmp->mm,va);
printk(KERN_ALERT "pgd_tmp=0x%p\n",pgd_tmp);
printk(KERN_ALERT "pgd_val(*pgd_tmp)=0x%lx\n\n",pgd_val(*pgd_tmp));
if(pgd_none(*pgd_tmp))
{
printk(KERN_ALERT "Not mapped in pgd.\n");
return 0;
}
pud_tmp=pud_offset(pgd_tmp,va);
pmd_tmp=pmd_offset(pud_tmp,va);
pte_tmp=pte_offset_kernel(pmd_tmp,va);
if(pte_none(*pte_tmp))
{
printk(KERN_ALERT "Not mapped in pte.\n");
return 0;
}
if(!pte_present(*pte_tmp))
{
printk(KERN_ALERT "pte not in RAM,maybe swaped.\n");
return 0;
}
pa=(pte_val(*pte_tmp)&PAGE_MASK)|(va&~PAGE_MASK);
printk(KERN_ALERT "Virtual address: 0x%lx in RAM is 0x%lx.\n",va,pa);
printk(KERN_ALERT "Part content in 0x%lx is 0x%lx.\n",pa,*(unsigned long*)((char *)pa+PAGE_OFFSET));
int i;
printk("some content:\n");
for(i=0;i<40;i=i+4)
{
printk("%lx\n",*(unsigned long*)((char*)pa+PAGE_OFFSET+i));
}
return 0;
}
static void find_pgd_exit(void)
{
printk(KERN_ALERT "Goodbye.\n");
}
module_init(find_pgd_init);
module_exit(find_pgd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Why");
MODULE_DESCRIPTION("GET WESSAGE");
源代码中find_pgd_init()为模块初始化函数,find_pgd_exit为模块析构函数。
代码中还定义了所要传入的参数,即所指定进程的进程号pid,数据类型为int,模块参数以module_param(name,type,perm)的形式定义,其中name为参数名,type为参数的数据类型,perm是一个权限值,控制谁可以存取模块参数在sysfs中的表示。此处还要注意的是要对内核模块的初始化函数和析构函数进行声明,即指明哪个函数是内核模块的初始化函数,哪个是内核模块的析构函数。
module_init()指明的是模块初始化函数,module_exit()指明的是模块析构函数。
MODULE LICENSE、MODULE_AUTHOR、MODULE_DESCRIPTION 分别为模块证书、模块作者和模块描述。
选取gedit验证模块
查询当前开启的gedit的pid
查询gedit的虚拟地址
可见此时gedit的pid为5207,虚拟地址的16进制表示为0x805e604,使用计算器转换为10进制为134604292
编译,加载并测试模块,可见:(加载模块时需要做如下操作)
测试结果:
可见,输出序列为53,83,ec ,08…
验证模块功能
6.使用文件节点存储页表查询结果
源代码:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h> // for basic filesystem
#include <linux/proc_fs.h> // for the proc filesystem
#include <linux/seq_file.h> // for sequence files
#include <linux/jiffies.h> // for jiffies
#include <linux/slab.h> // for kzalloc, kfree
#include <linux/uaccess.h> // for copy_from_user
#include <asm/pgtable.h>
#include <linux/version.h>
#include <asm/page.h>
#include <linux/gfp.h>
#include <linux/page-flags.h>
#include <linux/sched.h>//find_task_by_vpid
#include <linux/mm.h>//find_vma
static unsigned long pid=5263;
static unsigned long va=134604292;
int i=0;
unsigned long pa = 0;
//static struct task_struct *pcurrent;
int print_current_task_info(void);
static int jif_show(struct seq_file *m, void *v);
// global var
//static char *str = NULL;
// file_operations -> write
static ssize_t jif_write(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos)
{
unsigned long *tmp = kzalloc((count+1), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
//copy_to|from_user(to,from,cnt)
if (copy_from_user(tmp, buffer, count)) {
kfree(tmp);
return -EFAULT;
}
kfree(tmp);
//pid = *tmp;
return count;
}
// seq_operations -> open
static int jif_open(struct inode *inode, struct file *file)
{
return single_open(file, jif_show, NULL);
}
static const struct file_operations jif_fops =
{
.owner = THIS_MODULE,
.open = jif_open,
.read = seq_read,
.write = jif_write,
.llseek = seq_lseek,
.release = single_release,
};
// module init
static int __init jif_init(void)
{
struct proc_dir_entry* jif_file;
jif_file = proc_create("exp4", 0, NULL, &jif_fops);
if (NULL == jif_file)
{
return -ENOMEM;
}
return 0;
}
// module exit
static void __exit jif_exit(void)
{
printk("******************************************\n");
remove_proc_entry("exp4", NULL);
kfree(pid);
}
static int find_pgd_init(struct seq_file *m)
{
struct task_struct *pcb_tmp = NULL;
pgd_t *pgd_tmp = NULL;
pte_t *pte_tmp = NULL;
pud_t *pud_tmp = NULL;
pmd_t *pmd_tmp = NULL;
seq_printf(m,"test:va=0x%lx,pid=%ld.\n",va,pid);
rcu_read_lock();
if(!(pcb_tmp = pid_task(find_vpid(pid),PIDTYPE_PID)))
{
seq_printf(m,"can not find pro %ld .\n", pid);
return 0;
}
rcu_read_unlock();
seq_printf(m,"ye_mu_lu_biao_ji_zhi = 0x%p\n",pcb_tmp->mm->pgd);
if(!find_vma(pcb_tmp->mm,va))
{
seq_printf(m,"xu_ni_di_zhi%lxbu_cun_zai\n",va);
return 0;
}
pgd_tmp=pgd_offset(pcb_tmp->mm,va);
seq_printf(m,"\npgd=----0x%p\n",pgd_tmp);
pud_tmp=pud_offset(pgd_tmp,va);
pmd_tmp=pmd_offset(pud_tmp,va);
pte_tmp=pte_offset_kernel(pmd_tmp,va);
seq_printf(m,"\npte=----0x%p\n",pte_tmp);
seq_printf(m,"\n\n pid=%ld\nva=%lx\n\n",pid,va);
pa=(pte_val(*pte_tmp)&PAGE_MASK)|(va&~PAGE_MASK);
seq_printf(m, "xu_ni_di_zhi %lx qi_zai_nei_cun_zhong %lx.\n",va,pa);
seq_printf(m, "bu_fen_nei_rong 0x%lx is 0x%lx.\n.\n",pa,pa);
for(i=0;i<40;i=i+4)
seq_printf(m,"\t%lx\n",*(unsigned long*)((char*)pa+PAGE_OFFSET+i));
return 0;
}
// seq_operations -> show
static int jif_show(struct seq_file *m, void *v)
{
//seq_printf(m, "current kernel time is %llu\n", (unsigned long long) get_jiffies_64());
//seq_printf(m, "str is %s\n", str);
find_pgd_init(m);
return 0; //!! must be 0, or will show nothing T.T
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ny");
MODULE_DESCRIPTION("GET WESSAGE");
module_init(jif_init);
module_exit(jif_exit);
其中参数pid和va在一开始写入源代码。
编译,加载模块后,直接显示创建的文件exp4内容,可见:
模块功能实现
20135319zl内核模块编译报告的更多相关文章
- linux/module.h: No such file or directory 内核模块编译过程
1.缺少Linux kernel头文件 To install just the headers in Ubuntu: sudo apt-get install linux-headers-$(unam ...
- linux内核模块编译makefile
linux内核可加载模块的makefile 在开发linux内核驱动时,免不了要接触到makefile的编写和修改,尽管网上的makefile模板一大堆,做一些简单的修改就能用到自己的项目上,但是,对 ...
- Ubuntu 编译安装 Linux 4.0.5 内核,并修复 vmware 网络内核模块编译错误
. . . . . 今天把 Ubuntu 14.04 升级到了最新的 4.0.5 的内核版本,本来不打算记录下来的,但是升级的过程中确实遇到了一些问题,所以还是记录下来,分享给遇到同样问题的猿友. 先 ...
- ubuntu下helloworld内核模块编译
1.hello.c #include<linux/init.h> #include<linux/module.h> MODULE_LICENSE("Dual BSD/ ...
- firefly rk3288 内核模块编译
在驱动开发的过程中,常常需要对代码进行返回的调试,如果返回的编译再烧写内核,势必会浪费开发人员大量的时间和心力,加班加点那是时常的事.为此linux提供了编译内核模块的方式,无需返回烧写内核,只需in ...
- 20135323符运锦----LINUX第二次实践:内核模块编译
Linux实践二--模块 一.知识点总结 ①Linux模块是一些可以作为独立程序来编译的函数和数据类型的集合.之所以提供模块机制,是因为Linux本身是一个单内核.单内核由于所有内容都集成在一起,效率 ...
- Android内核模块编译执行
Author: GeneBlue 0X01 前言 内核驱动是漏洞的高发区,了解Android驱动代码的编写是分析.利用驱动漏洞的基础.本文以一个"hello"驱动为例,简单介绍内核 ...
- Linux 4.1内核编译报告
编译环境 Arch Linux on VirtualBox 下载内核 https://www.kernel.org/ 下载的内核压缩包,此时的最新内核版本为4.1: 解压包 # tar -xvJf l ...
- Linux 内核模块编译 Makefile
驱动编译分为静态编译和动态编译:静态编译即为将驱动直接编译进内核,动态编译即为将驱动编译成模块. 而动态编译又分为两种: a -- 内部编译 在内核源码目录内编译 b -- 外部编译 在内核源码的目录 ...
随机推荐
- Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第7节: 获取异线程释放的对象
Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第七节: 获取异线程释放的对象 上一小节分析了异线程回收对象, 原理是通过与stack关联的WeakOrder ...
- Workbook对象的方法总结(二)
(1).Worksheet 对象有 row_dimensions 和 column_dimensions 属性,控制行高和列宽. 例如: >>> sheet.row_dimensio ...
- Python中fnmatch模块的使用
fnmatch()函数匹配能力介于简单的字符串方法和强大的正则表达式之间,如果在数据处理操作中只需要简单的通配符就能完成的时候,这通常是一个比较合理的方案.此模块的主要作用是文件名称的匹配,并且匹配的 ...
- 暑假作业app博客
一.光照传感器 界面 简介 运用了传感器类,通过手机的感应区根据当时的光照强度显示出数据. 核心代码 protected void onCreate(Bundle savedInstanceState ...
- Sprint4
进展:今天一天满课,晚上也没有做什么,所以今天一天没什么进展. 燃尽图:
- Java基础第一节.Java简介
第一节 Java简介 Java是一个由Sun公司开发而成的新一代的编程语言. Java语言是对软件开发有深远影响.应用前景广泛.具有丰富的类库.继承了C++的传统(摈弃了某些不足)广泛使用的网络编程语 ...
- JS学习:JavaScript的核心
分享到 分类 JS学习 发布 ourjs 2013-12-02 注意 转载须保留原文链接,译文链接,作者译者等信息. 作者: JeremyWei 原文: JavaScript The ...
- Effective Modern C++翻译(2)-条款1:明白模板类型推导
第一章 类型推导 C++98有一套单一的类型推导的规则:用来推导函数模板,C++11轻微的修改了这些规则并且增加了两个,一个用于auto,一个用于decltype,接着C++14扩展了auto和dec ...
- vue 里面的watch 选项详解
早就想好好写写这个watch了,一直顾不上,因为想深刻的记录一下,其实这些东西只要是好好看看官网的说明,都在里面呢. 虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器.这就是为什么 V ...
- 蜗牛慢慢爬 LeetCode 11. Container With Most Water [Difficulty: Medium]
题目 Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai ...