- 論壇徽章:
- 0
|
小弟正在寫一個(gè)測(cè)試程序,程序的目的是用戶空間的虛擬地址映射為內(nèi)核空間的邏輯地址,然后內(nèi)核空間的驅(qū)動(dòng)程序?qū)υ搩?nèi)存空間直接操作,寫入相應(yīng)的字符串,最后再由用戶空間讀出該字符串以驗(yàn)證程序的正確性。
程序的流程大概是這樣的。
-----------------內(nèi)核空間------------------------
驅(qū)動(dòng)程序注冊(cè)一個(gè)字符設(shè)備
實(shí)現(xiàn)iotctl調(diào)用。
ioctl將用戶空間傳遞的虛擬地址通過(guò)進(jìn)行頁(yè)表查詢轉(zhuǎn)換為物理地址,然后再將物理地址轉(zhuǎn)化為邏輯地址,最后向該邏輯地址中寫入“hello kmap”字符串
返回
-----------------用戶空間------------------------
使用valloc分配一頁(yè)內(nèi)存
調(diào)用memset清空該內(nèi)存
然后打開驅(qū)動(dòng)程序注冊(cè)的字符設(shè)備接口
調(diào)用字符設(shè)備的iotcl,將上述分配的一頁(yè)內(nèi)存的虛擬地址傳遞給內(nèi)核驅(qū)動(dòng)程序
此時(shí)內(nèi)存里面應(yīng)該已有驅(qū)動(dòng)程序?qū)懭氲淖址畔,調(diào)用printf打印該內(nèi)存。
小弟按照上述思路實(shí)現(xiàn)了程序,但是運(yùn)行以后,發(fā)生了oops。不知道問題具體出在哪里,下面貼下代碼,請(qǐng)各位指點(diǎn)迷津。謝謝
---------------------------------kernel.h--------------------------------------
/*
* kernel.h 公用頭文件
*/
#ifndef KMAP_KERNEL_H
#define KMAP_KERNEL_H
#ifdef KMAP_KERNEL
#define __DEBUG_MSG(a,x...) do{printk(KERN_ALERT"%s %s %d:"a,__FILE__,__FUNCTION__,__LINE__,##x);}while(0)
#else
#define __DEBUG_MSG(a,x...) do{fprintf(stderr, "%s %s %d:"a, __FILE__, __FUNCTION__, __LINE__, ##x);}while(0)
#endif
#define DEVICE_NAME "kmap"
#define KMAP_IOC_MAGIC 'q'
#define KMAP_IOC_SET_PID_AND_VADDR _IOW(KMAP_IOC_MAGIC, 1, char *)
#ifdef KMAP_KERNEL
int init_module(void);
void cleanup_module(void);
static int kmap_open(struct inode *, struct file *);
static int kmap_ioctl(struct inode *, struct file *,
unsigned int, unsigned long);
#endif
struct ioctl_arg
{
pid_t pid;
unsigned long vaddr;
};
#endif
------------------------------------kernel.c-------------------------------------
/*
*kernel.c 內(nèi)核實(shí)現(xiàn)部分
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fcntl.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/if_packet.h>
#include <linux/wireless.h>
#include <linux/kmod.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>
#include <linux/mempolicy.h>
#include <linux/rmap.h>
#include <linux/fs.h>
#include <linux/shm.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/hugetlb.h>
#include <linux/mman.h>
#include <linux/slab.h>
#include <linux/swapops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/tlb.h>
#include <asm/tlbflush.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#define KMAP_KERNEL
#include "kernel.h"
static int major = 0;
static struct file_operations fops =
{
.open = kmap_open,
.ioctl = kmap_ioctl
};
int init_module(void)
{
major = register_chrdev(0, DEVICE_NAME, &fops);
if ( major < 0 )
{
printk(KERN_ALERT"register chrdev failed:%d\n", major);
return major;
}
printk(KERN_ALERT"mknod /dev/%s c %d 0\n", DEVICE_NAME, major);
return 0;
}
void cleanup_module(void)
{
/*unregister the device*/
int ret = unregister_chrdev(major, DEVICE_NAME);
if ( ret < 0 )
{
__DEBUG_MSG("Error in unregister_chrdev:%d\n", ret);
}
}
static int kmap_open(struct inode *inode, struct file *filp)
{
__DEBUG_MSG("enter kmap_open\n");
return 0;
}
static int kmap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd , unsigned long arg)
{
pid_t pid = 0;
unsigned long vaddr = 0;
unsigned long phy = 0;
unsigned long laddr = 0;
int err = 0, retval = 0;
pgd_t *pgd = NULL;
pud_t *pud = NULL;
pmd_t *pmd = NULL;
pte_t *pte = NULL;
struct page *mypage;
struct ioctl_arg k_arg;
__memset_generic(&k_arg, 0, sizeof(struct ioctl_arg));
/*get arg*/
err = !access_ok(VERIFY_READ, arg, sizeof(struct ioctl_arg));
if ( err )
{
__DEBUG_MSG("access vaild failed\n");
return -EFAULT;
}
err = copy_from_user((void *)&k_arg, (const void *)arg,
sizeof(struct ioctl_arg));
pid = k_arg.pid;
vaddr = k_arg.vaddr;
__DEBUG_MSG("pid:%d vaddr:%lu\n", pid, vaddr);
/*
*convert vaddr to kernel logic addr
*1,get the current task by pid
*2,get the phyaddr
*3,convert phyaddr to kernel logic addr
*4,write sth. in the buffer
*NOTE:step 1 is not necessay,because now current is pointed to task
*/
__DEBUG_MSG("The pid which user passed in is:%d\n"
" The current pid is:%d\n", pid, current->pid);
/*get phyaddr*/
pgd = pgd_offset(current->mm, vaddr);
if ( pgd_none(*pgd) || pgd_bad(*pgd) )
{
__DEBUG_MSG("invalid pgd\n");
retval = -1;
goto error;
}
pud = pud_offset(pgd, vaddr);
if ( pud_none(*pud) || pud_bad(*pud) )
{
__DEBUG_MSG("invalid pud\n");
retval = -1;
goto error;
}
pmd = pmd_offset(pud, vaddr);
if ( pmd_none(*pmd) || pmd_bad(*pmd) )
{
__DEBUG_MSG("invalid pmd\n");
retval = -1;
goto error;
}
__DEBUG_MSG("before pte_offset_map\n");
pte = pte_offset_map(pmd, vaddr);
__DEBUG_MSG("after pte_offset_map\n");
pte_unmap(pte);
if ( pte_none(*pte) )
{
__DEBUG_MSG("bad pte va: %X pte: %p pteval: %lX\n", vaddr, pte, pte_val(*pte));
retval = -1;
goto error;
}
phy = (pte_val(*pte)) & PAGE_MASK;
__DEBUG_MSG("the phy addr is %lu\n", phy);
mypage = pte_page(*pte);
set_bit(PG_locked, &mypage->flags);
atomic_inc(&mypage->_count);
/*convert phy to kernel logic addr*/
laddr = __pa(phy);
strcpy((char *)laddr, "hello kmap");
error:
return retval;
}
------------------------------------user.c-------------------------------------
/*
*user.c 用戶空間部分
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>/*getpagesize*/
#include <errno.h>
#include "kernel.h"
#define CHAR_DEV_PATH "/dev/"DEVICE_NAME
int main(int argc, char **argv)
{
int fd = -1;
pid_t pid = 0;
unsigned int vaddr = 0;
int result = 0;
int page_size =0;
struct ioctl_arg arg;
int retval = 0;
memset(&arg, 0, sizeof(struct ioctl_arg));
/*get page size*/
page_size = getpagesize();
/*get pid*/
pid = getpid();
vaddr = (unsigned long)valloc(page_size);
memset((char *)vaddr, 0, page_size);
strcpy((char *)vaddr, "hello kmap");
/*assemble arg*/
__DEBUG_MSG("The pid and the vaddr is:%d, %lu\n", pid, vaddr);
arg.pid = pid;
arg.vaddr = vaddr;
/*open the device*/
fd = open(CHAR_DEV_PATH, O_RDWR);
if ( fd < 0 )
{
__DEBUG_MSG("error when open device file:%s\n", strerror(errno));
retval = -1;
goto error;
}
/*pass the arg to kernel*/
result = ioctl(fd, KMAP_IOC_SET_PID_AND_VADDR, &arg);
if ( result )
{
__DEBUG_MSG("error when ioctl:%s\n", strerror(errno));
}
printf("after ioctl we get the memory:%s\n", (char *)vaddr);
error:
if ( fd != -1 )
{
close(fd);
}
return retval;
} |
|