mirror of
https://github.com/gatieme/LDD-LinuxDeviceDrivers.git
synced 2026-09-23 13:13:40 +08:00
增加了自己的驱动学习...
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Author: HIT CS HDMC team.
|
||||
* Create: 2010-3-12 8:20:01
|
||||
* Last modified: 2010-6-13 14:13:47
|
||||
*/
|
||||
|
||||
#ifndef _MEMORY_ENGINE_H
|
||||
#define _MEMORY_ENGINE_H
|
||||
|
||||
/*
|
||||
* common include header files
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#define MAX_LINE 256 /// max length of a line
|
||||
#define DELIMITER '\n' /// the char is used to split the taskinfo
|
||||
#define PERMISSION 0644 /// proc node permission
|
||||
/*
|
||||
* return values
|
||||
*/
|
||||
#define OK 0
|
||||
#define FAIL -1
|
||||
#define PGD_NONE -2
|
||||
#define PUD_NONE -3
|
||||
#define PMD_NONE -4
|
||||
#define PTE_NONE -5
|
||||
#define PTE_NOT_PRESENT -6
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* request command
|
||||
*/
|
||||
#define REQUEST_TASK_INFO 1 /// get a task's memory map information
|
||||
#define REQUEST_V2P 2 /// convert a process's linear address to physical address
|
||||
#define REQUEST_KV2P 3 /// convert kernel virtual address to physical address
|
||||
#define REQUEST_KFUNC_VA 4 /// get kernel function's addr(kernel virtual address)
|
||||
#define REQUEST_READ_KFUNC 5 /// 请求读取内核函数起始地址内容
|
||||
#define REQUEST_WRITE_KFUNC 6 /// 请求改写内核函数起始地址内容
|
||||
///#define REQUEST_WRITE 10 /// 请求改写指定物理地址内容,改为用户态实现此功能
|
||||
///#define REQUEST_MEM 11 /// 请求获取全部物理内存信息
|
||||
///#define REQUEST_ADDR_STOP 12 ///
|
||||
|
||||
/*
|
||||
* ack signals
|
||||
*/
|
||||
#define ACK_TASK_INFO REQUEST_TASK_INFO
|
||||
#define ACK_V2P REQUEST_V2P
|
||||
#define ACK_KV2P REQUEST_KV2P
|
||||
#define ACK_KFUNC_VA REQUEST_KFUNC_VA
|
||||
#define ACK_READ_KFUNC REQUEST_READ_KFUNC
|
||||
#define ACK_WRITE_KFUNC REQUEST_WRITE_KFUNC
|
||||
///#define REQUEST_WRITE REQUEST_WRITE
|
||||
///#define ACK_MEM REQUEST_MEM
|
||||
///#define ACK_ADDR_STOP REQUEST_ADDR_STOP
|
||||
|
||||
/*
|
||||
* #define DEBUG ,dbginfo() will add more debug information into nomal printk.
|
||||
* #define SILENCE ,dbginfo() will print nothing.
|
||||
* Otherwise ,dbginfo() equals to printk.
|
||||
*/
|
||||
#ifdef __FUNCTION__
|
||||
#ifdef __LINE__
|
||||
#ifdef DEBUG
|
||||
//printk with line and function name
|
||||
#define dbginfo(format,args...); \
|
||||
printk(KERN_INFO "%s-L%d:"format,__FUNCTION__,__LINE__,##args);
|
||||
#elif defined SILENCE
|
||||
#define dbginfo(format,args...);
|
||||
#else //printk normally
|
||||
#define dbginfo(format,args...); printk(KERN_INFO format,##args);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* safe sprintf
|
||||
* It will not be out of range.
|
||||
*/
|
||||
#define safe_sprintf(start, n, p, format, args...); \
|
||||
{ if( (p - start) < n ) { snprintf( (char *)p, (n - (p - start)), format, ##args ); } }
|
||||
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs);
|
||||
struct task_struct *findTaskByPid(pid_t pid);
|
||||
long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus);
|
||||
long kv2p(unsigned long va,int *pStatus);
|
||||
long kFunc2v(char *funcName);
|
||||
struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va);
|
||||
pte_t * getPte(struct mm_struct *pMM,unsigned long va);
|
||||
int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags);
|
||||
int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags);
|
||||
int getTaskInfo(struct task_struct *pTask, char *pData, int length);
|
||||
|
||||
/*
|
||||
* proc entry function
|
||||
*/
|
||||
int proc_write_pid(struct file *file,const char __user *buffer,unsigned long count,void * data);
|
||||
int proc_read_virtualAddr(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
int proc_write_virtualAddr(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
int proc_write_ctl(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
int proc_read_signal(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
int proc_write_signal(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# Makefile for the memory fault injection engine.
|
||||
#
|
||||
# Author: HIT CS HDMC team.
|
||||
# Create: 2010-3-12 8:46
|
||||
# Last modified: 2010-6-13 13:55:29
|
||||
# Description:
|
||||
# This program is loaded as a kernel(v2.6.18 or later) module.
|
||||
# Use "make install" to load it into kernel.
|
||||
# Use "make remove" to remove the module out of kernel.
|
||||
#
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
obj-m := memoryEngine.o
|
||||
|
||||
else
|
||||
|
||||
obj-m := memoryEngine.o
|
||||
|
||||
KERNELDIR=/lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD=$(shell pwd)
|
||||
|
||||
all:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
install:
|
||||
insmod memoryEngine.ko
|
||||
|
||||
remove:
|
||||
rmmod memoryEngine
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/`uname -r`/build M=`pwd` clean
|
||||
rm -f modules.order Module.symvers Module.markers
|
||||
|
||||
endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Author: HIT CS HDMC team.
|
||||
* Create: 2010-3-12 8:20:01
|
||||
* Last modified: 2010-6-13 14:13:47
|
||||
*/
|
||||
|
||||
#ifndef _MEMORY_ENGINE_H
|
||||
#define _MEMORY_ENGINE_H
|
||||
|
||||
/*
|
||||
* common include header files
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#define MAX_LINE 256 /// max length of a line
|
||||
#define DELIMITER '\n' /// the char is used to split the taskinfo
|
||||
#define PERMISSION 0644 /// proc node permission
|
||||
/*
|
||||
* return values
|
||||
*/
|
||||
#define OK 0
|
||||
#define FAIL -1
|
||||
#define PGD_NONE -2
|
||||
#define PUD_NONE -3
|
||||
#define PMD_NONE -4
|
||||
#define PTE_NONE -5
|
||||
#define PTE_NOT_PRESENT -6
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* request command
|
||||
*/
|
||||
#define REQUEST_TASK_INFO 1 /// get a task's memory map information
|
||||
#define REQUEST_V2P 2 /// convert a process's linear address to physical address
|
||||
#define REQUEST_KV2P 3 /// convert kernel virtual address to physical address
|
||||
#define REQUEST_KFUNC_VA 4 /// get kernel function's addr(kernel virtual address)
|
||||
#define REQUEST_READ_KFUNC 5 /// 请求读取内核函数起始地址内容
|
||||
#define REQUEST_WRITE_KFUNC 6 /// 请求改写内核函数起始地址内容
|
||||
///#define REQUEST_WRITE 10 /// 请求改写指定物理地址内容,改为用户态实现此功能
|
||||
///#define REQUEST_MEM 11 /// 请求获取全部物理内存信息
|
||||
///#define REQUEST_ADDR_STOP 12 ///
|
||||
|
||||
/*
|
||||
* ack signals
|
||||
*/
|
||||
#define ACK_TASK_INFO REQUEST_TASK_INFO
|
||||
#define ACK_V2P REQUEST_V2P
|
||||
#define ACK_KV2P REQUEST_KV2P
|
||||
#define ACK_KFUNC_VA REQUEST_KFUNC_VA
|
||||
#define ACK_READ_KFUNC REQUEST_READ_KFUNC
|
||||
#define ACK_WRITE_KFUNC REQUEST_WRITE_KFUNC
|
||||
///#define REQUEST_WRITE REQUEST_WRITE
|
||||
///#define ACK_MEM REQUEST_MEM
|
||||
///#define ACK_ADDR_STOP REQUEST_ADDR_STOP
|
||||
|
||||
/*
|
||||
* #define DEBUG ,dbginfo() will add more debug information into nomal printk.
|
||||
* #define SILENCE ,dbginfo() will print nothing.
|
||||
* Otherwise ,dbginfo() equals to printk.
|
||||
*/
|
||||
#ifdef __FUNCTION__
|
||||
#ifdef __LINE__
|
||||
#ifdef DEBUG
|
||||
//printk with line and function name
|
||||
#define dbginfo(format,args...); \
|
||||
printk(KERN_INFO "%s-L%d:"format,__FUNCTION__,__LINE__,##args);
|
||||
#elif defined SILENCE
|
||||
#define dbginfo(format,args...);
|
||||
#else //printk normally
|
||||
#define dbginfo(format,args...); printk(KERN_INFO format,##args);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* safe sprintf
|
||||
* It will not be out of range.
|
||||
*/
|
||||
#define safe_sprintf(start, n, p, format, args...); \
|
||||
{ if( (p - start) < n ) { snprintf( (char *)p, (n - (p - start)), format, ##args ); } }
|
||||
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs);
|
||||
struct task_struct *findTaskByPid(pid_t pid);
|
||||
long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus);
|
||||
long kv2p(unsigned long va,int *pStatus);
|
||||
long kFunc2v(char *funcName);
|
||||
struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va);
|
||||
pte_t * getPte(struct mm_struct *pMM,unsigned long va);
|
||||
int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags);
|
||||
int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags);
|
||||
int getTaskInfo(struct task_struct *pTask, char *pData, int length);
|
||||
|
||||
/*
|
||||
* proc entry function
|
||||
*/
|
||||
int proc_write_pid(struct file *file,const char __user *buffer,unsigned long count,void * data);
|
||||
int proc_read_virtualAddr(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
int proc_write_virtualAddr(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
int proc_write_ctl(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
int proc_read_signal(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
int proc_write_signal(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Author: HIT CS HDMC team.
|
||||
* Last modified by zhaozhilong: 2010-1-14
|
||||
*/
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// 当前字符是数字
|
||||
#define IsDigit(c) (c >= '0' && c <= '9')
|
||||
|
||||
/// 当前字符是8进制数据
|
||||
#define IsOctDigit(c) (c >= '0' && c <= '7')
|
||||
|
||||
/// 当前字符是16进制数据
|
||||
#define IsHexDigit(c) (IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
|
||||
|
||||
/// 当前字符是字母或者_
|
||||
#define IsLetter(c) ((c >= 'a' && c <= 'z') || (c == '_') || (c >= 'A' && c <= 'Z'))
|
||||
|
||||
/// 当前自负是否满足C的变量命名规则
|
||||
#define IsLetterOrDigit(c) (IsLetter(c) || IsDigit(c))
|
||||
#define IsIdentifier IsLetterOrDigit
|
||||
|
||||
/// 当前字符是空白字符
|
||||
#define IsSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
|
||||
|
||||
|
||||
|
||||
/// 取出当前信息的高4位
|
||||
#define HIGH_4BIT(v) ((v) >> (8 * sizeof(int) - 4) & 0x0f)
|
||||
/// 取出当前信息的高3位
|
||||
#define HIGH_3BIT(v) ((v) >> (8 * sizeof(int) - 3) & 0x07)
|
||||
/// 取出当前信息的高1位
|
||||
#define HIGH_1BIT(v) ((v) >> (8 * sizeof(int) - 1) & 0x01)
|
||||
//#define ALIGN(size, align) ((size + align - 1) & (~(align - 1)))
|
||||
|
||||
#define BitGet(number, pos) ((number) >> (pos) & 1) /// 用宏得到某数的某位
|
||||
#define BitSet(number, pos) ((number) |= 1 << (pos)) /// 把某位置1
|
||||
#define BitClr(number, pos) ((number) &= ~(1 << (pos))) /// 把某位清0
|
||||
#define BitCpl(number, pos) ((number) ^= 1 << (pos)) /// 把number的POS位取反
|
||||
|
||||
|
||||
///03: 得到指定地址上的一个字节或字
|
||||
#define MEM_B(x) (*((byte *)(x)))
|
||||
#define MEM_W(x) (*((word *)(x)))
|
||||
|
||||
///04: 求最大值和最小值
|
||||
#define MAX(x,y) (((x)>(y)) ? (x) : (y))
|
||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
///05: 得到一个field在结构体(struct)中的偏移量
|
||||
#define FPOS(type,field) ((dword)&((type *)0)->field)
|
||||
|
||||
///06: 得到一个结构体中field所占用的字节数
|
||||
#define FSIZ(type,field) sizeof(((type *)0)->field)
|
||||
|
||||
///07: 按照LSB格式把两个字节转化为一个Word
|
||||
#define FLIPW(ray) ((((word)(ray)[0]) * 256) + (ray)[1])
|
||||
|
||||
///08: 按照LSB格式把一个Word转化为两个字节
|
||||
#define FLOPW(ray,val) (ray)[0] = ((val)/256); (ray)[1] = ((val) & 0xFF)
|
||||
|
||||
///09: 得到一个变量的地址(word宽度)
|
||||
#define B_PTR(var) ((byte *) (void *) &(var))
|
||||
#define W_PTR(var) ((word *) (void *) &(var))
|
||||
|
||||
///10: 得到一个字的高位和低位字节
|
||||
#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))
|
||||
#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))
|
||||
|
||||
///11: 返回一个比X大的最接近的8的倍数
|
||||
#define RND8(x) ((((x) + 7)/8) * 8)
|
||||
|
||||
///12: 将一个字母转换为大写
|
||||
#define UPCASE(c) (((c)>='a' && (c) <= 'z') ? ((c) - 0x20) : (c))
|
||||
#define ToUpper(c) (c & ~0x20)
|
||||
|
||||
///13: 判断字符是不是10进值的数字
|
||||
#define DECCHK(c) ((c)>='0' && (c)<='9')
|
||||
|
||||
///14: 判断字符是不是16进值的数字
|
||||
#define HEXCHK(c) (((c) >= '0' && (c)<='9') ((c)>='A' && (c)<= 'F') \
|
||||
((c)>='a' && (c)<='f'))
|
||||
|
||||
///15: 防止溢出的一个方法
|
||||
#define INC_SAT(val) (val=((val)+1>(val)) ? (val)+1 : (val))
|
||||
|
||||
///16: 返回数组元素的个数
|
||||
#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))
|
||||
|
||||
///17: 返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)
|
||||
#define MOD_BY_POWER_OF_TWO( val, mod_by ) ((dword)(val) & (dword)((mod_by)-1))
|
||||
|
||||
///18: 对于IO空间映射在存储空间的结构,输入输出处理
|
||||
#define inp(port) (*((volatile byte *)(port)))
|
||||
#define inpw(port) (*((volatile word *)(port)))
|
||||
#define inpdw(port) (*((volatile dword *)(port)))
|
||||
#define outp(port,val) (*((volatile byte *)(port))=((byte)(val)))
|
||||
#define outpw(port, val) (*((volatile word *)(port))=((word)(val)))
|
||||
#define outpdw(port, val) (*((volatile dword *)(port))=((dword)(val)))
|
||||
|
||||
|
||||
|
||||
#define DEBUG
|
||||
|
||||
/**
|
||||
* Macros to help with debugging. Set SCULL_DEBUG to 1 enable
|
||||
* debugging (which you can do from the Makefile); these macros work
|
||||
* in both kernelspace and userspace.
|
||||
*/
|
||||
|
||||
/* undef it, just in case someone else defined it. */
|
||||
|
||||
#ifdef dbgprint
|
||||
#undef dbgprint
|
||||
#endif // dbgprint
|
||||
|
||||
#ifdef dprint
|
||||
#undef dprint
|
||||
#endif // dprint
|
||||
|
||||
#ifdef dout
|
||||
#undef dount
|
||||
#endif // dout
|
||||
|
||||
|
||||
/**when you define DEBUG macro
|
||||
dbgprint to use printk with line and funcitonname in kernel
|
||||
dprint to use print without line and funcitonname in kernel
|
||||
|
||||
|
||||
dbgprint to use printf with line and funcitonname in userspace
|
||||
dprint to use printf without line and funcitonname in userspace
|
||||
it's the same to dbgcout and dcout in userspace
|
||||
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#ifdef __FILE__
|
||||
#ifdef __LINE__
|
||||
//printk with line and function name
|
||||
#define dbgprint(format, args...) \
|
||||
printk(KERN_INFO "[%s, %d] : "format, __FILE__, __LINE__, ##args)
|
||||
#endif // __FILE__ && __LINE__
|
||||
#endif // __FILE__ && __LINE__
|
||||
|
||||
//printk without line and function name
|
||||
#define dprint(format,args...) printk(KERN_INFO format, ##args)
|
||||
#define dprintk(format,args...) printk(KERN_INFO format, ##args)
|
||||
|
||||
|
||||
#else // userspace
|
||||
|
||||
#ifdef __FILE__
|
||||
#ifdef __LINE__
|
||||
//printf with line and function name
|
||||
#define dbgprint(format, args...) \
|
||||
printf("[%s,%d] : "format, __FILE__, __LINE__, ##args)
|
||||
#define dbgcout std::cout <<"[" <<__FILE__ <<", " <<__LINE__ <<"] : "
|
||||
|
||||
#endif // __FILE__ && __LINE__
|
||||
#endif // __FILE__ && __LINE__
|
||||
|
||||
/* Debugging is on and we are in userspace. */
|
||||
#define dprint(format, args...) printf(format, ## args)
|
||||
#define dprintf(format, args...) printf(format, ## args)
|
||||
#define dcout cout
|
||||
|
||||
|
||||
#endif // __KERNEL__
|
||||
|
||||
#else /* Not debugging: do nothing. */
|
||||
#define dbgprint(format,args...)
|
||||
|
||||
#define dprint(format, args...)
|
||||
#define dprintf(format, args...)
|
||||
#define dcout 0 && cout
|
||||
#endif
|
||||
|
||||
/* PDEBUGG is a placeholder that makes it easy to "comment out" the debugging
|
||||
statements without deleting them. */
|
||||
#undef undprint
|
||||
#define undprint(format, args...)
|
||||
|
||||
#undef undcout
|
||||
#define undcout 0 && count
|
||||
|
||||
#undef undbgprint
|
||||
#define undprint(format, args...)
|
||||
|
||||
#undef undbgcout
|
||||
#define undbgcout 0 && cout
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* #define DEBUG ,dbginfo() will add more debug information into nomal printk.
|
||||
* #define SILENCE ,dbginfo() will print nothing.
|
||||
* Otherwise ,dbginfo() equals to printk.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __FUNCTION__
|
||||
#ifdef __LINE__
|
||||
#ifdef DEBUG
|
||||
//printk with line and function name
|
||||
#define dbginfo(format,args...); \
|
||||
printk(KERN_INFO"MemFI-[%s, %d] : "format, __FUNCTION__, __LINE__, ##args);
|
||||
#elif defined SILENCE
|
||||
#define dbginfo(format,args...);
|
||||
#else //printk normally
|
||||
#define dbginfo(format,args...); printk(KERN_INFO format, ##args);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* safe sprintf
|
||||
* It will not be out of range.
|
||||
*/
|
||||
#define safe_sprintf(start, n, p, format, args...); \
|
||||
{ if( (p - start) < n ) { snprintf( (char *)p, (n - (p - start)), format, ##args ); } }
|
||||
|
||||
|
||||
#endif /* _COMMON_H_ */
|
||||
@@ -0,0 +1,21 @@
|
||||
# Makefile for the memory fault injection engine.
|
||||
#
|
||||
# Author: HIT CS HDMC team.
|
||||
# Create: 2010-3-12 8:46
|
||||
# Last modified: 2010-6-13 13:55:29
|
||||
# Description:
|
||||
# This program is loaded as a kernel(v2.6.18 or later) module.
|
||||
# Use "make install" to load it into kernel.
|
||||
# Use "make remove" to remove the module out of kernel.
|
||||
#
|
||||
|
||||
obj-m := mem.o
|
||||
all:
|
||||
make -C /lib/modules/`uname -r`/build M=`pwd` modules
|
||||
install:
|
||||
insmod memoryEngine.ko
|
||||
remove:
|
||||
rmmod memoryEngine
|
||||
clean:
|
||||
make -C /lib/modules/`uname -r`/build M=`pwd` clean
|
||||
rm -f modules.order Module.symvers Module.markers
|
||||
@@ -0,0 +1,125 @@
|
||||
/*****************************************************************
|
||||
文件名:mem.c
|
||||
输入参数:
|
||||
pid 接收待查询进程的PID
|
||||
va 接收待查询的虚拟地址
|
||||
*****************************************************************/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
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_INFO"PAGE_OFFSET = 0x%lx\n", PAGE_OFFSET);
|
||||
printk(KERN_INFO"PGDIR_SHIFT = %d\n", PGDIR_SHIFT);
|
||||
printk(KERN_INFO"PUD_SHIFT = %d\n", PUD_SHIFT);
|
||||
printk(KERN_INFO"PMD_SHIFT = %d\n", PMD_SHIFT);
|
||||
printk(KERN_INFO"PAGE_SHIFT = %d\n", PAGE_SHIFT);
|
||||
|
||||
printk(KERN_INFO"PTRS_PER_PGD = %d\n", PTRS_PER_PGD);
|
||||
printk(KERN_INFO"PTRS_PER_PUD = %d\n", PTRS_PER_PUD);
|
||||
printk(KERN_INFO"PTRS_PER_PMD = %d\n", PTRS_PER_PMD);
|
||||
printk(KERN_INFO"PTRS_PER_PTE = %d\n", PTRS_PER_PTE);
|
||||
|
||||
printk(KERN_INFO"PAGE_MASK = 0x%lx\n", PAGE_MASK);
|
||||
|
||||
//if(!(pcb_tmp = find_task_by_vpid(pid))) linux-3.0
|
||||
if(!(pcb_tmp = find_task_by_pid(pid))) // linux-2.6
|
||||
{
|
||||
printk(KERN_INFO"Can't find the task %d .\n", pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
printk(KERN_INFO"pgd = 0x%p\n", pcb_tmp->mm->pgd);
|
||||
|
||||
/* 判断给出的地址va是否合法(va<vm_end)*/
|
||||
if(!find_vma(pcb_tmp->mm, va))
|
||||
{
|
||||
printk(KERN_INFO"virt_addr 0x%lx not available.\n", va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pgd_tmp = pgd_offset(pcb_tmp->mm, va);
|
||||
printk(KERN_INFO"pgd_tmp = 0x%p\n", pgd_tmp);
|
||||
printk(KERN_INFO"pgd_val(*pgd_tmp) = 0x%lx\n", pgd_val(*pgd_tmp));
|
||||
if(pgd_none(*pgd_tmp))
|
||||
{
|
||||
printk(KERN_INFO"Not mapped in pgd.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pud_tmp = pud_offset(pgd_tmp, va);
|
||||
printk(KERN_INFO"pud_tmp = 0x%p\n", pud_tmp);
|
||||
printk(KERN_INFO"pud_val(*pud_tmp) = 0x%lx\n", pud_val(*pud_tmp));
|
||||
|
||||
if(pud_none(*pud_tmp))
|
||||
{
|
||||
printk(KERN_INFO"Not mapped in pud.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pmd_tmp = pmd_offset(pud_tmp, va);
|
||||
printk(KERN_INFO"pmd_tmp = 0x%p\n", pmd_tmp);
|
||||
printk(KERN_INFO"pmd_val(*pmd_tmp) = 0x%lx\n", pmd_val(*pmd_tmp));
|
||||
if(pmd_none(*pmd_tmp))
|
||||
{
|
||||
printk(KERN_INFO"Not mapped in pmd.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*在这里,把原来的pte_offset_map()改成了pte_offset_kernel*/
|
||||
pte_tmp = pte_offset_kernel(pmd_tmp, va);
|
||||
|
||||
printk(KERN_INFO"pte_tmp = 0x%p\n", pte_tmp);
|
||||
printk(KERN_INFO"pte_val(*pte_tmp) = 0x%lx\n", pte_val(*pte_tmp));
|
||||
|
||||
if(pte_none(*pte_tmp))
|
||||
{
|
||||
printk(KERN_INFO"Not mapped in pte.\n");
|
||||
return 0;
|
||||
}
|
||||
if(!pte_present(*pte_tmp))
|
||||
{
|
||||
printk(KERN_INFO"pte not in RAM.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pa = (pte_val(*pte_tmp) & PAGE_MASK) | (va & ~PAGE_MASK);
|
||||
printk(KERN_INFO"virt_addr 0x%lx in RAM is 0x%lx .\n", va, pa);
|
||||
printk(KERN_INFO"contect in 0x%lx is 0x%lx\n", pa, *(unsigned long *)((char *)pa + PAGE_OFFSET));
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void find_pgd_exit(void)
|
||||
{
|
||||
printk(KERN_INFO"Goodbye!\n");
|
||||
}
|
||||
|
||||
module_init(find_pgd_init);
|
||||
module_exit(find_pgd_exit);
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define page_map_file "/proc/self/pagemap"
|
||||
#define PFN_MASK ((((uint64_t)1)<<55)-1)
|
||||
#define PFN_PRESENT_FLAG (((uint64_t)1)<<63)
|
||||
|
||||
|
||||
int mem_addr_vir2phy(unsigned long vir, unsigned long *phy)
|
||||
{
|
||||
int fd;
|
||||
int page_size = getpagesize();
|
||||
unsigned long vir_page_idx = vir / page_size;
|
||||
unsigned long pfn_item_offset = vir_page_idx * sizeof(uint64_t);
|
||||
uint64_t pfn_item;
|
||||
|
||||
fd = open(page_map_file, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf("open %s failed", page_map_file);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if ((off_t)-1 == lseek(fd, pfn_item_offset, SEEK_SET))
|
||||
{
|
||||
printf("lseek %s failed", page_map_file);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t)))
|
||||
{
|
||||
printf("read %s failed", page_map_file);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (0==(pfn_item & PFN_PRESENT_FLAG))
|
||||
{
|
||||
printf("page is not present");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
*phy = (pfn_item & PFN_MASK)*page_size + vir % page_size;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long viraddress;
|
||||
unsigned long phyaddress;
|
||||
|
||||
if(argc != 2)
|
||||
{
|
||||
printf("Usage : %s viraddress\n", argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sscanf(argv[1], "%d", &viraddress);
|
||||
|
||||
mem_addr_vir2phy(viraddress, &phyaddress);
|
||||
|
||||
printf("%x", phyaddress);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Author: HIT CS HDMC team.
|
||||
* Create: 2010-3-12 8:20:01
|
||||
* Last modified: 2010-6-13 14:13:47
|
||||
*/
|
||||
|
||||
#ifndef _MEMORY_ENGINE_H
|
||||
#define _MEMORY_ENGINE_H
|
||||
|
||||
/*
|
||||
* common include header files
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define MAX_LINE 256 /// max length of a line
|
||||
#define DELIMITER '\n' /// the char is used to split the taskinfo
|
||||
#define PERMISSION 0644 /// proc node permission
|
||||
/*
|
||||
* return values
|
||||
*/
|
||||
#define OK 0
|
||||
#define FAIL -1
|
||||
#define PGD_NONE -2
|
||||
#define PUD_NONE -3
|
||||
#define PMD_NONE -4
|
||||
#define PTE_NONE -5
|
||||
#define PTE_NOT_PRESENT -6
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* request command
|
||||
*/
|
||||
#define REQUEST_TASK_INFO 1 /// get a task's memory map information
|
||||
#define REQUEST_V2P 2 /// convert a process's linear address to physical address
|
||||
#define REQUEST_KV2P 3 /// convert kernel virtual address to physical address
|
||||
#define REQUEST_KFUNC_VA 4 /// get kernel function's addr(kernel virtual address)
|
||||
#define REQUEST_READ_KFUNC 5 /// 请求读取内核函数起始地址内容
|
||||
#define REQUEST_WRITE_KFUNC 6 /// 请求改写内核函数起始地址内容
|
||||
///#define REQUEST_WRITE 10 /// 请求改写指定物理地址内容,改为用户态实现此功能
|
||||
///#define REQUEST_MEM 11 /// 请求获取全部物理内存信息
|
||||
///#define REQUEST_ADDR_STOP 12 ///
|
||||
|
||||
/*
|
||||
* ack signals
|
||||
*/
|
||||
#define ACK_TASK_INFO REQUEST_TASK_INFO
|
||||
#define ACK_V2P REQUEST_V2P
|
||||
#define ACK_KV2P REQUEST_KV2P
|
||||
#define ACK_KFUNC_VA REQUEST_KFUNC_VA
|
||||
#define ACK_READ_KFUNC REQUEST_READ_KFUNC
|
||||
#define ACK_WRITE_KFUNC REQUEST_WRITE_KFUNC
|
||||
///#define REQUEST_WRITE REQUEST_WRITE
|
||||
///#define ACK_MEM REQUEST_MEM
|
||||
///#define ACK_ADDR_STOP REQUEST_ADDR_STOP
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs);
|
||||
|
||||
struct task_struct *findTaskByPid(pid_t pid);
|
||||
|
||||
long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus);
|
||||
|
||||
long kv2p(unsigned long va,int *pStatus);
|
||||
|
||||
long kFunc2v(char *funcName);
|
||||
|
||||
struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va);
|
||||
|
||||
pte_t * getPte(struct mm_struct *pMM,unsigned long va);
|
||||
|
||||
int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags);
|
||||
|
||||
int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags);
|
||||
|
||||
int getTaskInfo(struct task_struct *pTask, char *pData, int length);
|
||||
|
||||
/*
|
||||
* proc entry function
|
||||
*/
|
||||
int proc_write_pid(struct file *file,const char __user *buffer,unsigned long count,void * data);
|
||||
|
||||
int proc_read_virtualAddr(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
int proc_write_virtualAddr(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
|
||||
int proc_write_ctl(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
|
||||
int proc_read_signal(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
int proc_write_signal(struct file *file,const char *buffer,unsigned long count,void * data);
|
||||
|
||||
int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data);
|
||||
|
||||
static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
CC=gcc
|
||||
INCLUDEDIR = /home/linux/include/
|
||||
MODCFLAGS :=-Wall -O -DMODULE -D__KERNEL__ -DLINUX -I$(INCLUDEDIR)
|
||||
map_driver.o: map_driver.c
|
||||
$(CC) $(MODCFLAGS) -c map_driver.c
|
||||
@@ -0,0 +1,216 @@
|
||||
#define _VERSION__
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#if CONFIG_MODVERSIOINS==1
|
||||
#define MODVERSIONS
|
||||
#include <linux/modversions.h>
|
||||
#endif
|
||||
#include<linux/fs.h>
|
||||
#include<linux/string.h>
|
||||
#include<linux/errno.h>
|
||||
|
||||
#include<linux/mm.h>
|
||||
#include<linux/vmalloc.h>
|
||||
#include<linux/wrapper.h>
|
||||
#include<linux/slab.h>
|
||||
#include<asm/io.h>
|
||||
#include<linux/mman.h>
|
||||
|
||||
#define MAPLEN (4096*10)
|
||||
/* device open */
|
||||
int mapdrv_open(struct inode *inode,struct file *file);
|
||||
/* device close */
|
||||
int mapdrv_release(struct inode *inode,struct file *file);
|
||||
/*device mmap */
|
||||
int mapdrv_mmap(struct file *file,struct vm_area_struct *vma);
|
||||
|
||||
/* vm area open */
|
||||
void map_vopen(struct vm_area_struct *vma);
|
||||
/* vm area close */
|
||||
void map_vclose(struct vm_area_struct *vma);
|
||||
/* vm area nopage */
|
||||
struct page *map_nopage(struct vm_area_struct *vma,unsigned long address,int write_access);
|
||||
|
||||
static struct file_operations mapdrv_fops=
|
||||
{
|
||||
owner : THIS_MODULE,
|
||||
mmap : mapdrv_mmap,
|
||||
open : mapdrv_open,
|
||||
release:mapdrv_release,
|
||||
};
|
||||
|
||||
static struct vm_operations_struct map_vm_ops=
|
||||
{
|
||||
open : map_vopen,
|
||||
close : map_vclose,
|
||||
nopage: map_nopage,
|
||||
};
|
||||
|
||||
static int *vmalloc_area = NULL;
|
||||
|
||||
static int major; // major number of device
|
||||
|
||||
volatile void *vaddr_to_kaddr(volatile void *address)
|
||||
{
|
||||
pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte;
|
||||
unsigned long va, ret = 0UL;
|
||||
va=VMALLOC_VMADDR((unsigned long)address);
|
||||
/* get the page directory. Use the kernel memory map. */
|
||||
pgd = pgd_offset_k(va);
|
||||
/* check whether we found an entry */
|
||||
if (!pgd_none(*pgd))
|
||||
{
|
||||
/* get the page middle directory */
|
||||
pmd = pmd_offset(pgd, va);
|
||||
/* check whether we found an entry */
|
||||
if (!pmd_none(*pmd))
|
||||
{
|
||||
/* get a pointer to the page table entry */
|
||||
ptep = pte_offset(pmd, va);
|
||||
pte = *ptep;
|
||||
/* check for a valid page */
|
||||
if (pte_present(pte))
|
||||
{
|
||||
/* get the address the page is refering to */
|
||||
ret = (unsigned long)page_address(pte_page(pte));
|
||||
/* add the offset within the page to the page address */ ret |= (va & (PAGE_SIZE -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return((volatile void *)ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int __init mapdrv_init(void)
|
||||
{
|
||||
|
||||
unsigned long virt_addr;
|
||||
if ((major=register_chrdev(0, "mapdrv", &mapdrv_fops))<0)
|
||||
{
|
||||
printk("mapdrv: unable to register character device\n");
|
||||
return (-EIO);
|
||||
}
|
||||
/* get a memory area that is only virtual contigous. */
|
||||
vmalloc_area=vmalloc(MAPLEN/*+2*PAGE_SIZE*/);
|
||||
|
||||
|
||||
for (virt_addr=(unsigned long)vmalloc_area;virt_addr<(unsigned long)(&(vmalloc_area[MAPLEN/sizeof(int)]));virt_addr+=PAGE_SIZE)
|
||||
{
|
||||
|
||||
mem_map_reserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
}
|
||||
/* set a hello message to kernel space for read by user */
|
||||
strcpy((char*)vmalloc_area,"hello world from kernel space !");
|
||||
|
||||
|
||||
printk("vmalloc_area at 0x%p (phys 0x%lx)\n", vmalloc_area,
|
||||
virt_to_phys((void *)vaddr_to_kaddr(vmalloc_area)));
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static void __exit mapdrv_exit(void)
|
||||
{
|
||||
unsigned long virt_addr;
|
||||
/* unreserve all pages */
|
||||
for (virt_addr=(unsigned long)vmalloc_area;virt_addr<(unsigned long)(&(vmalloc_area[MAPLEN/sizeof(int)]));virt_addr+=PAGE_SIZE)
|
||||
{
|
||||
mem_map_unreserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
}
|
||||
/* and free the two areas */
|
||||
if (vmalloc_area)
|
||||
vfree(vmalloc_area);
|
||||
/* unregister the device */
|
||||
unregister_chrdev(major, "mapdrv");
|
||||
return;
|
||||
|
||||
}
|
||||
/* device open method */
|
||||
int mapdrv_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
MOD_INC_USE_COUNT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* device close method */
|
||||
int mapdrv_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
MOD_DEC_USE_COUNT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int mapdrv_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long offset = vma->vm_pgoff<<PAGE_SHIFT;
|
||||
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
if (offset & ~PAGE_MASK)
|
||||
{
|
||||
printk("offset not aligned: %ld\n", offset);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (size>MAPLEN)
|
||||
{
|
||||
printk("size too big\n");
|
||||
return(-ENXIO);
|
||||
}
|
||||
/* only support shared mappings.*/
|
||||
if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
|
||||
{
|
||||
printk("writeable mappings must be shared, rejecting\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
/* do not want to have this area swapped out, lock it */
|
||||
vma->vm_flags |= VM_LOCKED;
|
||||
if (offset == 0)
|
||||
{
|
||||
vma->vm_ops = &map_vm_ops;
|
||||
/* call the open routine to increment the usage count */
|
||||
map_vopen(vma);
|
||||
}else
|
||||
{
|
||||
printk("offset out of range\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/* open handler for vm area */
|
||||
void map_vopen(struct vm_area_struct *vma)
|
||||
{
|
||||
/* needed to prevent the unloading of the module while
|
||||
somebody still has memory mapped */
|
||||
MOD_INC_USE_COUNT;
|
||||
}
|
||||
|
||||
/* close handler form vm area */
|
||||
void map_vclose(struct vm_area_struct *vma)
|
||||
{
|
||||
MOD_DEC_USE_COUNT;
|
||||
}
|
||||
|
||||
/* page fault handler */
|
||||
struct page *map_nopage(struct vm_area_struct *vma, unsigned long address, int write_access)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long virt_addr;
|
||||
/* determine the offset within the vmalloc'd area */
|
||||
offset = address - vma->vm_start + (vma->vm_pgoff<<PAGE_SHIFT);
|
||||
/* translate the vmalloc address to kmalloc address */
|
||||
virt_addr = (unsigned long)vaddr_to_kaddr(&vmalloc_area[offset/sizeof(int)]);
|
||||
if (virt_addr == 0UL)
|
||||
{
|
||||
return((struct page *)0UL);
|
||||
}
|
||||
/* increment the usage count of the page */
|
||||
atomic_inc(&(virt_to_page(virt_addr)->count));
|
||||
printk("map_drv: page fault for offset 0x%lx (kseg x%lx)\n",offset, virt_addr);
|
||||
return(virt_to_page(virt_addr));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
module_init(mapdrv_init);
|
||||
module_exit(mapdrv_exit);
|
||||
@@ -0,0 +1,21 @@
|
||||
# Makefile for the memory fault injection engine.
|
||||
#
|
||||
# Author: HIT CS HDMC team.
|
||||
# Create: 2010-3-12 8:46
|
||||
# Last modified: 2010-6-13 13:55:29
|
||||
# Description:
|
||||
# This program is loaded as a kernel(v2.6.18 or later) module.
|
||||
# Use "make install" to load it into kernel.
|
||||
# Use "make remove" to remove the module out of kernel.
|
||||
#
|
||||
|
||||
obj-m := map_driver.o
|
||||
all:
|
||||
make -C /lib/modules/`uname -r`/build M=`pwd` modules
|
||||
install:
|
||||
insmod memoryEngine.ko
|
||||
remove:
|
||||
rmmod memoryEngine
|
||||
clean:
|
||||
make -C /lib/modules/`uname -r`/build M=`pwd` clean
|
||||
rm -f modules.order Module.symvers Module.markers
|
||||
@@ -0,0 +1,345 @@
|
||||
#define _VERSION__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#if CONFIG_MODVERSIOINS==1
|
||||
|
||||
#define MODVERSIONS
|
||||
#include <linux/modversions.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include<linux/fs.h>
|
||||
#include<linux/string.h>
|
||||
#include<linux/errno.h>
|
||||
|
||||
#include<linux/mm.h>
|
||||
#include<linux/vmalloc.h>
|
||||
//#include<linux/wrapper.h>
|
||||
#include<linux/slab.h>
|
||||
#include<asm/io.h>
|
||||
#include<linux/mman.h>
|
||||
|
||||
#define MAPLEN (4096*10)
|
||||
|
||||
|
||||
/*
|
||||
* 将代码从linux2.4移植到linux2.6.*
|
||||
*
|
||||
* ==A==
|
||||
* 2.4内核中,模块自身通过 MOD_INC_USE_COUNT, MOD_DEC_USE_COUNT宏来管理自己被使用的计数。
|
||||
* 2.6内核提供了更健壮、灵活的模块计数管理接口 try_module_get(&module), module_put(&module)
|
||||
* 取代2.4中的模块使用计数管理宏;模块的使用计数不必由自身管理,
|
||||
* 而且在管理模块使用计数时考虑到 SMP与PREEMPT机制的影响。
|
||||
*
|
||||
* ==B==
|
||||
* em_map_reserve是2.4的函数 而到2.6被SetPageReserved取代
|
||||
* */
|
||||
|
||||
|
||||
/* device open */
|
||||
int mapdrv_open(struct inode *inode,struct file *file);
|
||||
|
||||
/* device close */
|
||||
int mapdrv_release(struct inode *inode,struct file *file);
|
||||
|
||||
/*device mmap */
|
||||
int mapdrv_mmap(struct file *file,struct vm_area_struct *vma);
|
||||
|
||||
/* vm area open */
|
||||
void map_vopen(struct vm_area_struct *vma);
|
||||
|
||||
/* vm area close */
|
||||
void map_vclose(struct vm_area_struct *vma);
|
||||
|
||||
/* vm area nopage */
|
||||
struct page *map_nopage(struct vm_area_struct *vma,unsigned long address,int write_access);
|
||||
|
||||
static struct file_operations mapdrv_fops=
|
||||
{
|
||||
owner : THIS_MODULE,
|
||||
mmap : mapdrv_mmap,
|
||||
open : mapdrv_open,
|
||||
release:mapdrv_release,
|
||||
};
|
||||
|
||||
static struct vm_operations_struct map_vm_ops=
|
||||
{
|
||||
open : map_vopen,
|
||||
close : map_vclose,
|
||||
nopage: map_nopage,
|
||||
};
|
||||
|
||||
static int *vmalloc_area = NULL;
|
||||
|
||||
static int major; // major number of device
|
||||
|
||||
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
|
||||
|
||||
volatile void *vaddr_to_kaddr(volatile void *address)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *ptep, pte;
|
||||
|
||||
unsigned long va;
|
||||
unsigned long ret = 0UL;
|
||||
|
||||
va = VMALLOC_VMADDR((unsigned long)address);
|
||||
|
||||
/* get the page directory. Use the kernel memory map. */
|
||||
pgd = pgd_offset_k(va);
|
||||
/* check whether we found an entry */
|
||||
if (pgd_none(*pgd))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the page upper directory */
|
||||
pud = pud_offset(pgd, va);
|
||||
/* check whether we found an entry */
|
||||
if (pud_none(*pud))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* get the page middle directory */
|
||||
pmd = pmd_offset(pud, va);
|
||||
/* check whether we found an entry */
|
||||
if (pmd_none(*pmd))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get a pointer to the page table entry */
|
||||
/*ptep = pte_offset(pmd, va); implicit declaration of function ‘pte_offset’`. */
|
||||
ptep = pte_offset_kernel(pmd, va);
|
||||
pte = *ptep;
|
||||
|
||||
/* check for a valid page */
|
||||
if (pte_present(pte))
|
||||
{
|
||||
|
||||
/* get the address the page is refering to */
|
||||
ret = (unsigned long)page_address(pte_page(pte));
|
||||
|
||||
/* add the offset within the page to the page address */
|
||||
ret |= (va & (PAGE_SIZE -1));
|
||||
}
|
||||
|
||||
return((volatile void *)ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int __init mapdrv_init(void)
|
||||
{
|
||||
unsigned long virt_addr;
|
||||
if ((major = register_chrdev(0, "mapdrv", &mapdrv_fops)) < 0)
|
||||
{
|
||||
printk("mapdrv: unable to register character device\n");
|
||||
|
||||
return (-EIO);
|
||||
}
|
||||
|
||||
/* get a memory area that is only virtual contigous. */
|
||||
vmalloc_area = vmalloc(MAPLEN/* + 2 * PAGE_SIZE*/);
|
||||
|
||||
|
||||
for (virt_addr = (unsigned long)vmalloc_area;
|
||||
virt_addr < (unsigned long)(&(vmalloc_area[MAPLEN / sizeof(int)]));
|
||||
virt_addr += PAGE_SIZE)
|
||||
{
|
||||
/*
|
||||
error: implicit declaration of function ‘mem_map_reserve’
|
||||
`mem_map_reserve` can be found in linux-2.4, but not define in linux-2.6
|
||||
you can use `SetPageReserved` instead...
|
||||
|
||||
#define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags)
|
||||
#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))
|
||||
|
||||
so the code
|
||||
|
||||
mem_map_reserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
|
||||
use the next instead
|
||||
|
||||
SetPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
|
||||
it's the same to mem_map_unreserve
|
||||
*/
|
||||
SetPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
}
|
||||
|
||||
/* set a hello message to kernel space for read by user */
|
||||
strcpy((char*)vmalloc_area, "hello world from kernel space !");
|
||||
|
||||
|
||||
printk("vmalloc_area at 0x%p (phys 0x%lx)\n",
|
||||
vmalloc_area,
|
||||
virt_to_phys((void *)vaddr_to_kaddr(vmalloc_area)));
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static void __exit mapdrv_exit(void)
|
||||
{
|
||||
unsigned long virt_addr;
|
||||
|
||||
/* unreserve all pages */
|
||||
for (virt_addr = (unsigned long)vmalloc_area;
|
||||
virt_addr < (unsigned long)(&(vmalloc_area[MAPLEN / sizeof(int)]));
|
||||
virt_addr += PAGE_SIZE)
|
||||
{
|
||||
/*
|
||||
* error: implicit declaration of function ‘mem_map_unreserve’`.
|
||||
* it's the same to mem_map_reserve
|
||||
|
||||
so the code
|
||||
|
||||
mem_map_unreserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
|
||||
use the next code instead...
|
||||
|
||||
ClearPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
*/
|
||||
ClearPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));
|
||||
}
|
||||
/* and free the two areas */
|
||||
if (vmalloc_area)
|
||||
{
|
||||
vfree(vmalloc_area);
|
||||
}
|
||||
|
||||
/* unregister the device */
|
||||
unregister_chrdev(major, "mapdrv");
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
/* device open method */
|
||||
int mapdrv_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
the code in linux-2.4
|
||||
MOD_INC_USE_COUNT;
|
||||
use the next instead...
|
||||
try_module_get(THIS_MODULE);
|
||||
*/
|
||||
try_module_get(THIS_MODULE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* device close method */
|
||||
int mapdrv_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
the code in linux-2.4
|
||||
MOD_DEC_USE_COUNT;
|
||||
use the next instead
|
||||
module_put(THIS_MODULE);
|
||||
*/
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int mapdrv_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long offset = vma->vm_pgoff<<PAGE_SHIFT;
|
||||
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
if (offset & ~PAGE_MASK)
|
||||
{
|
||||
printk("offset not aligned: %ld\n", offset);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (size>MAPLEN)
|
||||
{
|
||||
printk("size too big\n");
|
||||
return(-ENXIO);
|
||||
}
|
||||
/* only support shared mappings.*/
|
||||
if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
|
||||
{
|
||||
printk("writeable mappings must be shared, rejecting\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
/* do not want to have this area swapped out, lock it */
|
||||
vma->vm_flags |= VM_LOCKED;
|
||||
if (offset == 0)
|
||||
{
|
||||
vma->vm_ops = &map_vm_ops;
|
||||
/* call the open routine to increment the usage count */
|
||||
map_vopen(vma);
|
||||
}else
|
||||
{
|
||||
printk("offset out of range\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/* open handler for vm area */
|
||||
void map_vopen(struct vm_area_struct *vma)
|
||||
{
|
||||
/* needed to prevent the unloading of the module while
|
||||
somebody still has memory mapped */
|
||||
// MOD_INC_USE_COUNT;
|
||||
|
||||
/*
|
||||
the code in linux-2.4
|
||||
MOD_INC_USE_COUNT;
|
||||
use the next instead...
|
||||
try_module_get(THIS_MODULE);
|
||||
*/
|
||||
try_module_get(THIS_MODULE);
|
||||
}
|
||||
|
||||
/* close handler form vm area */
|
||||
void map_vclose(struct vm_area_struct *vma)
|
||||
{
|
||||
|
||||
/*
|
||||
the code in linux-2.4
|
||||
MOD_DEC_USE_COUNT;
|
||||
use the next instead
|
||||
module_put(THIS_MODULE);
|
||||
*/
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/* page fault handler */
|
||||
struct page *map_nopage(struct vm_area_struct *vma, unsigned long address, int write_access)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long virt_addr;
|
||||
|
||||
/* determine the offset within the vmalloc'd area */
|
||||
offset = address - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT);
|
||||
|
||||
/* translate the vmalloc address to kmalloc address */
|
||||
virt_addr = (unsigned long)vaddr_to_kaddr(&vmalloc_area[offset / sizeof(int)]);
|
||||
if (virt_addr == 0UL)
|
||||
{
|
||||
return((struct page *)0UL);
|
||||
}
|
||||
|
||||
/* increment the usage count of the page */
|
||||
atomic_inc(&(virt_to_page(virt_addr)->_count));
|
||||
printk("map_drv: page fault for offset 0x%lx (kseg x%lx)\n",offset, virt_addr);
|
||||
|
||||
return(virt_to_page(virt_addr));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
module_init(mapdrv_init);
|
||||
module_exit(mapdrv_exit);
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#define LEN (10*4096)
|
||||
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fd;
|
||||
unsigned int *vadr;
|
||||
|
||||
if ((fd=open("mapfile", O_RDWR))<0)
|
||||
{
|
||||
perror("open");
|
||||
exit(-1);
|
||||
}
|
||||
(char *)vadr = (char*)mmap(0, LEN, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
if (vadr == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("%s\n",vadr);
|
||||
close(fd);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
程序组成
|
||||
map_driver.c 它是以模块形式加载的虚拟字符驱动程序。
|
||||
该驱动负责将一定长的内核虚拟地址(vmalloc分配的)映射到设备文件上。
|
||||
|
||||
其中主要的函数有——vaddress_to_kaddress()负责对vmalloc分配的地址进行页表解析,以
|
||||
找到对应的内核物理映射地址(kmalloc分配的地址);
|
||||
map_nopage()负责在进程访问一个当前并不存在的VMA页时,寻找该地址对应的物理页,并返回该页的指针。
|
||||
|
||||
|
||||
test.c 它利用上述驱动模块对应的设备文件在用户空间读取读取内核内存。结果可以看到内核虚拟地址的内容(ok!),被显示在了屏幕上。
|
||||
|
||||
执行步骤
|
||||
|
||||
编译map_driver.c为map_driver.o模块,具体参数见Makefile
|
||||
|
||||
加载模块 :insmod map_driver.o
|
||||
生成对应的设备文件
|
||||
|
||||
1 在/proc/devices下找到map_driver对应的设备命和设备号:grep mapdrv /proc/devices
|
||||
|
||||
2 建立设备文件mknod mapfile c 254 0 (在我的系统里设备号为254)
|
||||
|
||||
利用maptest读取mapfile文件,将取自内核的信息打印到屏幕上。
|
||||
|
||||
|
||||
全部程序下载 mmap.tar (感谢Martin Frey,该程序的主体出自他的灵感)
|
||||
return(0);
|
||||
http://blog.chinaunix.net/uid-24227137-id-3723898.html
|
||||
@@ -0,0 +1,105 @@
|
||||
/*****************************************************************
|
||||
文件名:mem.c
|
||||
输入参数:
|
||||
pid 接收待查询进程的PID
|
||||
va 接收待查询的虚拟地址
|
||||
*****************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
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_INFO"PAGE_OFFSET = 0x%lx\n",PAGE_OFFSET);
|
||||
printk(KERN_INFO"PGDIR_SHIFT = %d\n",PGDIR_SHIFT);
|
||||
printk(KERN_INFO"PUD_SHIFT = %d\n",PUD_SHIFT);
|
||||
printk(KERN_INFO"PMD_SHIFT = %d\n",PMD_SHIFT);
|
||||
printk(KERN_INFO"PAGE_SHIFT = %d\n",PAGE_SHIFT);
|
||||
|
||||
printk(KERN_INFO"PTRS_PER_PGD = %d\n",PTRS_PER_PGD);
|
||||
printk(KERN_INFO"PTRS_PER_PUD = %d\n",PTRS_PER_PUD);
|
||||
printk(KERN_INFO"PTRS_PER_PMD = %d\n",PTRS_PER_PMD);
|
||||
printk(KERN_INFO"PTRS_PER_PTE = %d\n",PTRS_PER_PTE);
|
||||
|
||||
printk(KERN_INFO"PAGE_MASK = 0x%lx\n",PAGE_MASK);
|
||||
|
||||
if(!(pcb_tmp = find_task_by_pid(pid))) {
|
||||
printk(KERN_INFO"Can't find the task %d .\n",pid);
|
||||
return 0;
|
||||
}
|
||||
printk(KERN_INFO"pgd = 0x%p\n",pcb_tmp->mm->pgd);
|
||||
/* 判断给出的地址va是否合法(va<vm_end)*/
|
||||
if(!find_vma(pcb_tmp->mm,va)){
|
||||
printk(KERN_INFO"virt_addr 0x%lx not available.\n",va);
|
||||
return 0;
|
||||
}
|
||||
pgd_tmp = pgd_offset(pcb_tmp->mm,va);
|
||||
printk(KERN_INFO"pgd_tmp = 0x%p\n",pgd_tmp);
|
||||
printk(KERN_INFO"pgd_val(*pgd_tmp) = 0x%lx\n",pgd_val(*pgd_tmp));
|
||||
if(pgd_none(*pgd_tmp)){
|
||||
printk(KERN_INFO"Not mapped in pgd.\n");
|
||||
return 0;
|
||||
}
|
||||
pud_tmp = pud_offset(pgd_tmp,va);
|
||||
printk(KERN_INFO"pud_tmp = 0x%p\n",pud_tmp);
|
||||
printk(KERN_INFO"pud_val(*pud_tmp) = 0x%lx\n",pud_val(*pud_tmp));
|
||||
if(pud_none(*pud_tmp)){
|
||||
printk(KERN_INFO"Not mapped in pud.\n");
|
||||
return 0;
|
||||
}
|
||||
pmd_tmp = pmd_offset(pud_tmp,va);
|
||||
printk(KERN_INFO"pmd_tmp = 0x%p\n",pmd_tmp);
|
||||
printk(KERN_INFO"pmd_val(*pmd_tmp) = 0x%lx\n",pmd_val(*pmd_tmp));
|
||||
if(pmd_none(*pmd_tmp)){
|
||||
printk(KERN_INFO"Not mapped in pmd.\n");
|
||||
return 0;
|
||||
}
|
||||
/*在这里,把原来的pte_offset_map()改成了pte_offset_kernel*/
|
||||
pte_tmp = pte_offset_kernel(pmd_tmp,va);
|
||||
|
||||
printk(KERN_INFO"pte_tmp = 0x%p\n",pte_tmp);
|
||||
printk(KERN_INFO"pte_val(*pte_tmp) = 0x%lx\n",pte_val(*pte_tmp));
|
||||
if(pte_none(*pte_tmp)){
|
||||
printk(KERN_INFO"Not mapped in pte.\n");
|
||||
return 0;
|
||||
}
|
||||
if(!pte_present(*pte_tmp)){
|
||||
printk(KERN_INFO"pte not in RAM.\n");
|
||||
return 0;
|
||||
}
|
||||
pa = (pte_val(*pte_tmp) & PAGE_MASK) |(va & ~PAGE_MASK);
|
||||
printk(KERN_INFO"virt_addr 0x%lx in RAM is 0x%lx .\n",va,pa);
|
||||
printk(KERN_INFO"contect in 0x%lx is 0x%lx\n",pa,
|
||||
*(unsigned long *)((char *)pa + PAGE_OFFSET));
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void find_pgd_exit(void)
|
||||
{
|
||||
printk(KERN_INFO"Goodbye!\n");
|
||||
|
||||
}
|
||||
|
||||
module_init(find_pgd_init);
|
||||
module_exit(find_pgd_exit);
|
||||
@@ -0,0 +1,11 @@
|
||||
obj-m := list.o
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERNELDIR) M=$(PWD) clean
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <linux /list.h>
|
||||
|
||||
#include <linux /module.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
#define METHOD 2
|
||||
|
||||
static int list_init(void)
|
||||
|
||||
{
|
||||
|
||||
struct task_struct *task, *p;
|
||||
|
||||
struct list_head *pos;
|
||||
|
||||
int count;
|
||||
|
||||
char *method;
|
||||
|
||||
count = 0; /*下面这些初始化完全是为了消除编译时的警告信息*/
|
||||
|
||||
p = NULL;
|
||||
|
||||
task = NULL;
|
||||
|
||||
pos = NULL;
|
||||
|
||||
method = NULL;
|
||||
|
||||
task = &init_task;
|
||||
|
||||
printk(KERN_ALERT"PID/tCOMM/n");
|
||||
|
||||
switch(METHOD) {
|
||||
|
||||
case 1:
|
||||
|
||||
method="list_for_each";
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
method="for_each_process";
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
||||
method="list_for_each_entry";
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
printk( "The method is %s/n", method );
|
||||
|
||||
#if METHOD == 1
|
||||
|
||||
list_for_each( pos, &task->tasks ) {
|
||||
|
||||
p = list_entry( pos, struct task_struct, tasks );
|
||||
|
||||
count++;
|
||||
|
||||
printk( KERN_ALERT "%d/t%s/n", p->pid, p->comm );
|
||||
|
||||
}
|
||||
|
||||
#elif METHOD == 2
|
||||
|
||||
for_each_process(task) {
|
||||
|
||||
count++;
|
||||
|
||||
printk( KERN_ALERT "%d/t%s/n", task->pid, task->comm );
|
||||
|
||||
}
|
||||
|
||||
#elif METHOD == 3
|
||||
|
||||
list_for_each_entry( p, &task->tasks, tasks ) {
|
||||
|
||||
count++;
|
||||
|
||||
printk( KERN_ALERT "%d/t%s/n", p->pid, p->comm );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
printk("系统当前共 %d 个进程!!", count);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void list_exit(void)
|
||||
{
|
||||
printk( KERN_ALERT "GOOD BYE!!/n");
|
||||
}
|
||||
|
||||
module_init( list_init );
|
||||
|
||||
module_exit( list_exit );
|
||||
|
||||
MODULE_AUTHOR( "Along" );
|
||||
|
||||
MODULE_LICENSE( "GPL" );
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
obj-m := mem_dev.o
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
make -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERNELDIR) M=$(PWD) clean
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define DEVKMEM "/dev/kmem"
|
||||
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define PAGE_MASK (~(PAGE_SIZE-1))
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc != 2)
|
||||
{
|
||||
printf("usage...");
|
||||
exit(-1);
|
||||
}
|
||||
int fd;
|
||||
char *mbase;
|
||||
char read_buf[10];
|
||||
unsigned int regAddr;
|
||||
unsigned int varAddr;
|
||||
|
||||
varAddr = strtoul(argv[1], 0, 16);
|
||||
|
||||
unsigned int ptr = varAddr & ~(PAGE_MASK);
|
||||
|
||||
fd = open(DEVKMEM, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
printf("%s %d", __func__, __LINE__);
|
||||
perror("open");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
mbase = (char *)mmap(0, PAGE_SIZE, PROT_READ, MAP_SHARED,fd, (varAddr & PAGE_MASK));
|
||||
if (mbase == MAP_FAILED)
|
||||
{
|
||||
printf("map failed %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
printf("varAddr = 0x%X \n", varAddr);
|
||||
printf("mapbase = 0x%X \n", (unsigned int)mbase);
|
||||
printf("value = 0x%X \n",*(unsigned int*)(mbase+ptr));
|
||||
printf("char = %c%c%c%c \n",
|
||||
*(char *)(mbase+ptr), *(char *)(mbase+ptr+1),
|
||||
*(char *)(mbase+ptr+2), *(char *)(mbase+ptr+3));
|
||||
|
||||
close(fd);
|
||||
munmap(mbase,PAGE_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* devmem2.c: Simple program to read/write from/to any location in memory.
|
||||
*
|
||||
* Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
|
||||
*
|
||||
*
|
||||
* This software has been developed for the LART computing board
|
||||
* (http://www.lart.tudelft.nl/). The development has been sponsored by
|
||||
* the Mobile MultiMedia Communications (http://www.mmc.tudelft.nl/)
|
||||
* and Ubiquitous Communications (http://www.ubicom.tudelft.nl/)
|
||||
* projects.
|
||||
*
|
||||
* The author can be reached at:
|
||||
*
|
||||
* Jan-Derk Bakker
|
||||
* Information and Communication Theory Group
|
||||
* Faculty of Information Technology and Systems
|
||||
* Delft University of Technology
|
||||
* P.O. Box 5031
|
||||
* 2600 GA Delft
|
||||
* The Netherlands
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
|
||||
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
|
||||
|
||||
#define MAP_SIZE 4096UL
|
||||
#define MAP_MASK (MAP_SIZE - 1)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int fd;
|
||||
void *map_base, *virt_addr;
|
||||
unsigned long read_result, writeval;
|
||||
off_t target;
|
||||
int access_type = 'w';
|
||||
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "\nUsage:\t%s { address } [ type [ data ] ]\n"
|
||||
"\taddress : memory address to act upon\n"
|
||||
"\ttype : access operation type : [b]yte, [h]alfword, [w]ord\n"
|
||||
"\tdata : data to be written\n\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
target = strtoul(argv[1], 0, 0);
|
||||
|
||||
if(argc > 2)
|
||||
access_type = tolower(argv[2][0]);
|
||||
|
||||
|
||||
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
|
||||
printf("/dev/mem opened.\n");
|
||||
fflush(stdout);
|
||||
|
||||
/* Map one page */
|
||||
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
|
||||
if(map_base == (void *) -1) FATAL;
|
||||
printf("Memory mapped at address %p.\n", map_base);
|
||||
fflush(stdout);
|
||||
|
||||
virt_addr = map_base + (target & MAP_MASK);
|
||||
switch(access_type) {
|
||||
case 'b':
|
||||
read_result = *((unsigned char *) virt_addr);
|
||||
break;
|
||||
case 'h':
|
||||
read_result = *((unsigned short *) virt_addr);
|
||||
break;
|
||||
case 'w':
|
||||
read_result = *((unsigned long *) virt_addr);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Illegal data type '%c'.\n", access_type);
|
||||
exit(2);
|
||||
}
|
||||
printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result);
|
||||
fflush(stdout);
|
||||
|
||||
if(argc > 3)
|
||||
{
|
||||
writeval = strtoul(argv[3], 0, 0);
|
||||
switch(access_type) {
|
||||
case 'b':
|
||||
*((unsigned char *) virt_addr) = writeval;
|
||||
read_result = *((unsigned char *) virt_addr);
|
||||
break;
|
||||
case 'h':
|
||||
*((unsigned short *) virt_addr) = writeval;
|
||||
read_result = *((unsigned short *) virt_addr);
|
||||
break;
|
||||
case 'w':
|
||||
*((unsigned long *) virt_addr) = writeval;
|
||||
read_result = *((unsigned long *) virt_addr);
|
||||
break;
|
||||
}
|
||||
printf("Written 0x%X; readback 0x%X\n", writeval, read_result);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if(munmap(map_base, MAP_SIZE) == -1) FATAL;
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
|
||||
/*
|
||||
* getjiff.c
|
||||
*
|
||||
* this toolkit shows how to get jiffies value from user space:
|
||||
* 1. find jiffies's address from kernel image.
|
||||
* 2. access virtual address space to get jiffies value.
|
||||
* 3. access physical address sapce to get jiffies value.
|
||||
*
|
||||
* demostrate following techniques:
|
||||
* o get ELF object symbol address by calling nlist()
|
||||
* o access virtual memory space from /dev/kmem
|
||||
* o access virtual memory space from /dev/mem
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> //exit
|
||||
#include <linux/a.out.h> //nlist
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <memory.h>
|
||||
|
||||
#define LONG *(volatile unsigned long*)
|
||||
|
||||
/* read from virtual memory */
|
||||
int read_kmem(off_t offset, void* buf, size_t count)
|
||||
{
|
||||
int fd;
|
||||
int n;
|
||||
|
||||
fd = open("/dev/kmem", O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("open /dev/kmem failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
n = read(fd, buf, count);
|
||||
if (n != count)
|
||||
perror("/dev/kmem read failed");
|
||||
else
|
||||
printf("/dev/kmem read buf = %ld\n", *(unsigned long *)buf);
|
||||
|
||||
close(fd);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* read from physical memory */
|
||||
int read_mem(off_t offset, void* buf, size_t count)
|
||||
{
|
||||
int fd;
|
||||
int n;
|
||||
int page_size;
|
||||
void *map_base;
|
||||
unsigned long value;
|
||||
|
||||
printf("/dev/mem: the offset is %lx\n", offset);
|
||||
|
||||
fd = open("/dev/mem", O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("open /dev/mem failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(1){
|
||||
page_size = getpagesize();
|
||||
printf("the page size = %d\n", page_size);
|
||||
map_base = mmap(0,page_size,PROT_READ,MAP_SHARED,fd,offset);
|
||||
if (map_base == MAP_FAILED){
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
value = LONG(map_base);
|
||||
printf("/dev/mem: the value is %ld\n", value);
|
||||
buf = (unsigned long *)map_base;
|
||||
}
|
||||
|
||||
if(0){
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
n = read(fd, buf, count);
|
||||
if (n != count)
|
||||
perror("/dev/mem read failed");
|
||||
else
|
||||
printf("/dev/mem read buf = %ld\n", *(unsigned long *)buf);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return n;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
char addr_str[11]="0x";
|
||||
char var[51];
|
||||
unsigned long addr;
|
||||
unsigned long jiffies;
|
||||
char ch;
|
||||
int r;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr,"usage: %s System.map\n",argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ((fp = fopen(argv[1],"r")) == NULL) {
|
||||
perror("fopen");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
do {
|
||||
r = fscanf(fp,"%8s %c %50s\n",&addr_str[2],&ch,var); // format of System.map
|
||||
if (strcmp(var,"jiffies")==0)
|
||||
break;
|
||||
} while(r > 0);
|
||||
if (r < 0) {
|
||||
printf("could not find jiffies\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
addr = strtoul(addr_str,NULL,16); //Convert string to unsigned long integer
|
||||
printf("found jiffies at (%s) %08lx\n",addr_str,addr);
|
||||
|
||||
read_kmem(addr, &jiffies, sizeof(jiffies));
|
||||
printf("jiffies=%ld (read from virtual memory)\n\n", jiffies);
|
||||
|
||||
jiffies = 0; //reinit for checking read_mem() below
|
||||
|
||||
read_mem(addr-0xC0000000, &jiffies, sizeof(jiffies));
|
||||
printf("jiffies=%ld (read from physical memory)\n", jiffies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*************************************************************************
|
||||
> File Name: process.c
|
||||
> Author: GatieMe
|
||||
> Mail: gatieme@163.com
|
||||
> Created Time: 2016年04月01日 星期五 21时09分29秒
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
|
||||
|
||||
//#define METHOD 2
|
||||
static unsigned int METHOD = 1;
|
||||
module_param(METHOD, uint,0400);
|
||||
|
||||
long readPhysicsAddress(unsigned long pa, int *pStatus);
|
||||
|
||||
long writePhysicsAddress(unsigned long pa, unsigned long data, int *pStatus);
|
||||
|
||||
|
||||
|
||||
static int mem_dev_init(void)
|
||||
{
|
||||
|
||||
readPhysicsAddress(0x12345, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mem_dev_exit(void)
|
||||
{
|
||||
printk( KERN_ALERT "GOOD BYE!!\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** add by gatieme */
|
||||
/*
|
||||
*
|
||||
*/
|
||||
long readPhysicsAddress(unsigned long pa, int *pStatus)
|
||||
{
|
||||
long data = -1;
|
||||
//long *point = (long *)pa;
|
||||
data = *(long *)pa;
|
||||
printk(KERN_INFO "physics address : 0x%lx, data : 0x%lx", pa, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
long writePhysicsAddress(unsigned long pa, unsigned long data, int *pStatus)
|
||||
{
|
||||
long oldData = -1;
|
||||
|
||||
oldData = *(long *)pa;
|
||||
printk(KERN_INFO "physics address : 0x%lx, old data : 0x%lx", pa, *(long *)pa);
|
||||
|
||||
*(long *)pa = data;
|
||||
printk(KERN_INFO "physics address : 0x%lx, new data : 0x%lx", pa, *(long *)pa);
|
||||
|
||||
return oldData;
|
||||
}
|
||||
|
||||
module_init(mem_dev_init);
|
||||
module_exit(mem_dev_exit);
|
||||
|
||||
MODULE_AUTHOR("gatieme");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user