亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
12下一頁(yè)
最近訪問板塊 發(fā)新帖
查看: 18657 | 回復(fù): 19
打印 上一主題 下一主題

求助:將用戶空間的虛擬地址映射到內(nèi)核態(tài)的邏輯地址。 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2007-01-16 20:08 |只看該作者 |倒序?yàn)g覽
小弟正在寫一個(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;
}

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2007-01-16 20:10 |只看該作者
請(qǐng)大家重點(diǎn)看一下下面的代碼片斷,問題應(yīng)該是出在這里的
      /*
        *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");
Ahill 該用戶已被刪除
3 [報(bào)告]
發(fā)表于 2007-01-16 22:31 |只看該作者
提示: 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽

論壇徽章:
0
4 [報(bào)告]
發(fā)表于 2007-01-16 22:34 |只看該作者
我找到問題所在了。
用__va代替__pa
將物理地址轉(zhuǎn)化為內(nèi)核的邏輯地址是用__va而不是__pa,改動(dòng)以后程序工作正常。

論壇徽章:
0
5 [報(bào)告]
發(fā)表于 2007-01-20 14:17 |只看該作者

回復(fù) #4 onlyflyer 的帖子

雖然你這個(gè)方法是可行的,卻是不提倡的方法,
應(yīng)該用mmap()的方法。
為你的設(shè)備file_operations定義一個(gè)mmap函數(shù),
然后用戶態(tài)調(diào)用系統(tǒng)調(diào)用mmap()把設(shè)備分配的內(nèi)存映射到用戶態(tài),
這是標(biāo)準(zhǔn)的做法。

論壇徽章:
0
6 [報(bào)告]
發(fā)表于 2007-01-20 18:33 |只看該作者
謝謝輪子大俠,mmap的方法我也嘗試過(guò)了,我也想嘗試一下這種方法?
不知道為什么這種方法是不提倡的?能否再深入的指點(diǎn)一下小弟?

論壇徽章:
0
7 [報(bào)告]
發(fā)表于 2007-01-21 13:46 |只看該作者

回復(fù) #6 onlyflyer 的帖子

我覺得是移植性不好,很多操作和體系結(jié)構(gòu),內(nèi)存布局有關(guān)系。
需要處理很多特殊的情況。

比如用戶態(tài)virtual地址和內(nèi)核可以訪問的virtual地址之間的轉(zhuǎn)換
你用__va()來(lái)轉(zhuǎn)換,但如果你的機(jī)器內(nèi)存>896M,
這個(gè)頁(yè)面是highmem的話,就是不對(duì)的,因?yàn)閮?nèi)核沒有這種映射。
需要另外建立內(nèi)核映射。

另外,你的程序還有很多操作也不規(guī)范,
比如你設(shè)置PG_lock,這個(gè)標(biāo)志通常在改變頁(yè)面狀態(tài)時(shí)才設(shè)置,
并且是短時(shí)的,比如要進(jìn)行磁盤I/O時(shí)。
你lock住page后,可能會(huì)影響到內(nèi)核的操作。

還有訪問pte應(yīng)該加鎖(pgtable lock)。

mmap()的方法是傳統(tǒng)的unix的標(biāo)準(zhǔn)方法,內(nèi)核有標(biāo)準(zhǔn)的支持。
換句話說(shuō),是unix的傳統(tǒng),所以我覺得mmap()的方法是對(duì)的。

論壇徽章:
0
8 [報(bào)告]
發(fā)表于 2007-01-22 15:35 |只看該作者

回復(fù) #7 wheelz 的帖子

r u wheelz from CLF?

how about ur health?

俺喜歡忽悠,哈哈。

[ 本帖最后由 sisi8408 于 2007-1-22 15:39 編輯 ]

論壇徽章:
0
9 [報(bào)告]
發(fā)表于 2008-06-25 14:27 |只看該作者

回復(fù) #5 wheelz 的帖子

mmap是用戶空間操作內(nèi)核空間內(nèi)存,但是內(nèi)核地址空間有限,無(wú)法分配很大的內(nèi)存。

論壇徽章:
0
10 [報(bào)告]
發(fā)表于 2008-07-10 11:18 |只看該作者

回復(fù) #1 onlyflyer 的帖子

直接通過(guò)current->mm獲得虛擬地址,這樣可以嗎?我感覺應(yīng)該從pid遍歷到task->mm。
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP