免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3209 | 回复: 5
打印 上一主题 下一主题

请教关于内核缺页处理的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-08-12 11:13 |只看该作者 |倒序浏览
本帖最后由 Godbach 于 2011-08-12 11:37 编辑

请教大家一个内核方面的问题:

内核在拷贝用户空间的数据时,使用copy_from_user函数,可以将数据正确的拷贝到内核空间。
我理解该函数的目的为:一旦在拷贝数据缺页时,可以处理缺页异常,然后正确的找到数据地址,然后将它拷贝到内核

我想请教的问题是,在发生缺页异常之前用户空间的数据是存在哪里的,缺页异常程序如何正确的找到该数据或者说数据的物理地址?

我做了一个实验:
1.用户空间定义了一个字符数据为初始化数据:

#define DEVICE "/dev/VM-TEST"
#define VM_TEST_GET_VADDR 0
char str[20]= "123456677777";
int main(int argc, char *argv[])
{
        int fd = 0;
        char chr = 0;
        char str1[30];
        fd = open(DEVICE, O_RDWR);
        if (fd < 0) {
                printf("Can't open the %s\n", DEVICE);
                return -1;
        }
       
        printf("vaddress: 0x%08x str: %s\n", (unsigned long)str, str);
       
        ioctl(fd, VM_TEST_GET_VADDR, str);
        while (1) {
                chr = getchar();
                if (chr == 'q') {
                        printf("Byte!!\n");
                        return 0;               
                }       
        }
        return 0;       
}



2.驱动代码:

使用页表直接查找虚拟地址对应的物理地址时,不能找到物理地址,但在调用copy_from_user之后可以找到物理地址

static int
vm_test_ioctl( struct inode * inode, struct file * file,
                                unsigned int cmd, unsigned long arg )
{
        void __user *argp = (void __user *)arg;
        unsigned long vaddr;
        unsigned long paddr;
        unsigned char str[20] = {0};
        switch (cmd)
        {
                case VM_TEST_GET_VADDR:
                        printk("VM_TEST_GET_VADDR:  0x%08x\n", (unsigned long)argp);

                        /* output data from user space */
                        /* copy_from_user(str, argp, 18);  //不调用该函数uva_to_pa不能找到物理地址
                        printk("str:%s\n", str); */
                       
                        //printk("str:%s\n", (unsigned char *)argp);

                        /* Get physical address */
                        struct mm_struct *mm = current->mm;
                        paddr = uva_to_pa(mm, vaddr);
                        if (paddr == 0)
                                printk("Can't find physical address!\n");
                        else
                                printk("paddr: 0x%08x\n", paddr);

                       
                        printk("\n=======Data========\n");
                        unsigned long vpp = ioremap_nocache(paddr, 18);
                        int i = 0;
                        for (i = 0; i < 18; i++) {
                                printk("%c", *(volatile unsigned char *)(vpp + i));
                        }
                        printk("\n=======Data=======\n");
                       
                        return 0;
                default:
                        return -EINVAL;
        }
}
/* 使用进程的虚拟地址查找物理地址 */
static unsigned long uva_to_pa(struct mm_struct *mm, unsigned long addr)
{
        unsigned long ret = 0UL;
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;

        pgd = pgd_offset(mm, addr);
        if (!pgd_none(*pgd)) {
                pud = pud_offset(pgd, addr);
                if (!pud_none(*pud)) {
                        pmd = pmd_offset(pud, addr);
                        if (!pmd_none(*pmd)) {
                                pte = pte_offset_map(pmd, addr);
                                if (!pte_none(*pte) && pte_present(*pte)) {
                                       

                                        /* Use hard PTE */
                                        pte = (pte_t *)((u32)pte - 2048);
                                        if(pte)
                                                ret = (*pte & 0xfffff000) | (addr & 0xfff);
                                } else {
                                        printk("pet is not present:0x%08x\n", (*pte & 0xfffff000) | (addr & 0xfff));                               
                                }
                        }
                }
        }
        return ret;
}

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
2 [报告]
发表于 2011-08-12 11:26 |只看该作者
你可以参见Linker script in Linux中第14页3.3.1.1 Exception Table有一些相关描述

论坛徽章:
0
3 [报告]
发表于 2011-08-12 12:59 |只看该作者
阅读了以下Linker script in Linux中第14页3.3.1.1 Exception Table有一些相关描述
这讲的假设地址不再用户进程地址空间VMA时,kernel如何检查地址无效时,怎么能够正确处理的流程。

但是假如地址在VMA中,如何处理呢,是不是先放到cache中的,然后copy_from_user根据cache中的信息在更新到实际的物理内存中的?

论坛徽章:
0
4 [报告]
发表于 2011-08-13 22:18 |只看该作者
其实copy_from_user有点等于memcpy, 就是比memcpy多了一个你说的这种异常,能够在内核态下处理缺页。

论坛徽章:
0
5 [报告]
发表于 2011-08-14 11:13 |只看该作者
似乎楼上几位都没有说清楚啊,我试着回答一下。

>>我想请教的问题是,在发生缺页异常之前用户空间的数据是存在哪里的,缺页异常程序如何正确的找到该数据或者说数据的物理地址?

1.所有的数据都应该放在page cache中。你的第一个测试程序str[]应该在堆中。而这个堆所在的应该是匿名页中。这个匿名页将来可能会swap到swap file中。
2.由于在str分配空间的时候,已经建立好了映射,因此,在页表中已经存在。而在内核态下,仍然可以访问到页表,也就是用户空间的地址。至于exception table是在用户空间缺页的情况下的异常处理机制。

如有错误,请批评指正。

论坛徽章:
0
6 [报告]
发表于 2011-08-14 12:45 |只看该作者
下面说的是我理解的mips架构的情况:

1)测试程序链接后,str的值123456677777 放在elf的数据段
2)内核通过load_elf_binary-->kernel_read将文件数据读入到page cache
3)接着是elf_map,将代码段数据段BSS段等,映射成进程的vma,此时vma并没有对应到实际的物理地址(即没有建立进程页表项到page cache)
4)copy_from_user 第一次访问str所在vma发生缺页,系统为vma里的地址建立页表映射,之后的访问就有页表映射了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP