• 通过/dev/mem只能访问高端内存以下的内核线性地址空间


    http://blog.chinaunix.net/uid-20564848-id-74706.html

     

    《/proc/iomem和/proc /ioports对应的fops》
    《浅析pc机上如何将vmlinuz- 2.6.31-14-generic解压出vmlinux》
    fs_initcall(chr_dev_init);
    chr_dev_init
    ==> register_chrdev(MEM_MAJOR,"mem",&memory_fops); // 建立/dev/mem字符节点
    memory_open会根据inode的minor来定位具体的fops,
    比如
    1,1为mem_fops
    1,2为kmem_fops
    1,8为random_fops
    等等(具体见下面的devlist[])
    static const struct file_operations memory_fops = {
        .open        = memory_open,    /* just a selector for the real open */
    };
    static const struct {
        unsigned int        minor;
        char            *name;
        umode_t            mode;
        const struct file_operations    *fops;
    } devlist[] = { /* list of minor devices */
    #ifdef CONFIG_DEVMEM
        {1, "mem",     S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
        {2, "kmem",    S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
    #endif
        {3, "null",    S_IRUGO | S_IWUGO,           &null_fops},
    #ifdef CONFIG_DEVPORT
        {4, "port",    S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
    #endif
        {5, "zero",    S_IRUGO | S_IWUGO,           &zero_fops},
        {7, "full",    S_IRUGO | S_IWUGO,           &full_fops},
        {8, "random",  S_IRUGO | S_IWUSR,           &random_fops},
        {9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops},
        {11,"kmsg",    S_IRUGO | S_IWUSR,           &kmsg_fops},
    #ifdef CONFIG_CRASH_DUMP
        {12,"oldmem",    S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops},
    #endif
    };
    static int memory_open(struct inode * inode, struct file * filp)
    {
        // 根据inode的minor子节点号定位具体功能驱动fops
        switch (iminor(inode)) {
    #ifdef CONFIG_DEVMEM
            case 1:
                filp->f_op = &mem_fops;
                filp->f_mapping->backing_dev_info =
                    &directly_mappable_cdev_bdi;
                break;
            case 2:
                filp->f_op = &kmem_fops;
                filp->f_mapping->backing_dev_info =
                    &directly_mappable_cdev_bdi;
                break;
    #endif
            case 3:
                filp->f_op = &null_fops;
                break;
    #ifdef CONFIG_DEVPORT
            case 4:
                filp->f_op = &port_fops;
                break;
    #endif
            case 5:
                filp->f_mapping->backing_dev_info = &zero_bdi;
                filp->f_op = &zero_fops;
                break;
            case 7:
                filp->f_op = &full_fops;
                break;
            case 8:
                filp->f_op = &random_fops;
                break;
            case 9:
                filp->f_op = &urandom_fops;
                break;
            case 11:
                filp->f_op = &kmsg_fops;
                break;
    #ifdef CONFIG_CRASH_DUMP
            case 12:
                filp->f_op = &oldmem_fops;
                break;
    #endif
            default:
                return -ENXIO;
        }
        if (filp->f_op && filp->f_op->open)
            return filp->f_op->open(inode,filp);
        return 0;
    }
    crw-rw-rw-  1 root root        1,   9 2010-05-16 09:18 urandom
    crw-rw-rw-  1 root root        1,   3 2010-05-16 17:17 null
    crw-rw-rw-  1 root root        1,   8 2010-05-16 17:17 random
    crw-rw-rw-  1 root root        1,   5 2010-05-16 17:17 zero
    brw-rw----  1 root disk        1,   9 2010-05-16 17:17 ram9
    brw-rw----  1 root disk        1,   8 2010-05-16 17:17 ram8
    brw-rw----  1 root disk        1,   7 2010-05-16 17:18 ram7
    crw-r-----  1 root kmem        1,   4 2010-05-16 17:18 port
    crw-rw----  1 root root        1,  12 2010-05-16 17:18 oldmem
    crw-r-----  1 root kmem        1,   1 2010-05-16 17:18 mem
    crw-rw----  1 root root        1,  11 2010-05-16 17:18 kmsg
    crw-rw-rw-  1 root root        1,   7 2010-05-16 17:18 full
    我们来看看/dev/mem都能读取到些什么
    static const struct file_operations mem_fops = {
        .llseek        = memory_lseek,
        .read        = read_mem,
        .write        = write_mem,
        .mmap        = mmap_mem,
        .open        = open_mem,
        .get_unmapped_area = get_unmapped_area_mem,
    };
    /*
    * This funcion reads the *physical* memory. The f_pos points directly to the
    * memory location.
    */
    static ssize_t read_mem(struct file * file, char __user * buf,
                size_t count, loff_t *ppos)
    {
        unsigned long p = *ppos;
        ssize_t read, sz;
        char *ptr;
    /*
    // for arm
    int valid_phys_addr_range(unsigned long addr, size_t size)
    {
        if (addr < PHYS_OFFSET) // 只能CONFIG_DRAM_BASE这个DDR物理内存首地址开始的空间~到高端内存之间内核线性地址
            return 0;
        if (addr + size > __pa(high_memory))
            return 0;
        return 1;
    }
    // for x86
    static inline int valid_phys_addr_range(unsigned long addr, size_t count)
    {
        if (addr + count > __pa(high_memory)) // 只有高端内存以下的地址才能访问.
            return 0;
        return 1;
    }
    */
        if (!valid_phys_addr_range(p, count))
            return -EFAULT;
        read = 0;
    #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
        /* we don't have page 0 mapped on sparc and m68k.. */
        if (p < PAGE_SIZE) {
            sz = PAGE_SIZE - p;
            if (sz > count)
                sz = count;
            if (sz > 0) {
                if (clear_user(buf, sz))
                    return -EFAULT;
                buf += sz;
                p += sz;
                count -= sz;
                read += sz;
            }
        }
    #endif
        while (count > 0) {
            /*
             * Handle first page in case it's not aligned
             */
            if (-p & (PAGE_SIZE - 1))
                sz = -p & (PAGE_SIZE - 1);
            else
                sz = PAGE_SIZE;
            sz = min_t(unsigned long, sz, count);
            /*
             * On ia64 if a page has been mapped somewhere as
             * uncached, then it must also be accessed uncached
             * by the kernel or data corruption may occur
             */
            ptr = xlate_dev_mem_ptr(p); // 将物理地址p转化为内核线性虚拟地址
    //        #define xlate_dev_mem_ptr(p)    __va(p)
    //        #define __va(x)            ((void *)((unsigned long)(x)+PAGE_OFFSET))
    //        #define PAGE_OFFSET        ((unsigned long)__PAGE_OFFSET)
    //        #define __PAGE_OFFSET        _AC(CONFIG_PAGE_OFFSET, UL)
    //        vim arch/x86/configs/i386_defconfig 我们获取的参数[luther.gliethttp]
    //        CONFIG_PAGE_OFFSET=0xC0000000
            if (copy_to_user(buf, ptr, sz))
                return -EFAULT;
            buf += sz;
            p += sz;
            count -= sz;
            read += sz;
        }
        *ppos += read;
        return read;
    }
    让我们实际演练演练,我们读取释放到内存中的kernel代码
    tatic struct resource code_resource = {
        .name    = "Kernel code",
        .start    = 0,
        .end    = 0,
        .flags    = IORESOURCE_BUSY | IORESOURCE_MEM
    };
    start_kernel
    ==> setup_arch
        code_resource.start = virt_to_phys(_text); // _text内核代码相对DDR物理内存的偏移量,也就是内核线性地址偏移量[luther.gliethttp]
        code_resource.end = virt_to_phys(_etext)-1;
        data_resource.start = virt_to_phys(_etext);
        data_resource.end = virt_to_phys(_edata)-1;
        bss_resource.start = virt_to_phys(&__bss_start);
        bss_resource.end = virt_to_phys(&__bss_stop)-1;
    subsys_initcall(request_standard_resources);
    request_standard_resources
    ==> init_iomem_resources(&code_resource, &data_resource, &bss_resource);// 这样/proc/iomem就可以看到这里设置的信息了
        request_resource(res, code_resource);
        request_resource(res, data_resource);
        request_resource(res, bss_resource);
    ==> request_resource(&iomem_resource, &video_ram_resource);
    luther@gliethttp:~$ cat /proc/iomem
    00000000-00001fff : System RAM
    00002000-00005fff : reserved
    00006000-0009dbff : System RAM
    0009dc00-0009ffff : reserved
    000a0000-000bffff : Video RAM area
    000c0000-000cefff : Video ROM
    000cf000-000d07ff : Adapter ROM
    000d2000-000fffff : reserved
      000f0000-000fffff : System ROM
    00100000-5bf0ffff : System RAM
      00100000-00575553 : Kernel code
      00575554-0078d307 : Kernel data
      0081a000-008a809f : Kernel bss
    以上的
    00100000-00575553 : Kernel code
    就是kernel代码存储区了
    0x00100000等于1048576
    0x00575553等于5723475
    luther@gliethttp:~$ sudo dd bs=1 skip=1048576 count=208 if=/dev/mem 2>/dev/null | xxd -g 1
    0000000: f6 86 11 02 00 00 40 75 14 0f 01 15 22 8e 74 00  ......@u....".t.
    0000010: b8 18 00 00 00 8e d8 8e c0 8e e0 8e e8 fc 31 c0  ..............1.
    0000020: bf 00 a0 81 00 b9 a0 80 8a 00 29 f9 c1 e9 02 f3  ..........).....
    0000030: ab bf c0 56 7c 00 b9 00 04 00 00 fc f3 a5 8b 35  ...V|..........5
    0000040: e8 58 7c 00 21 f6 74 0c bf e0 2a 7c 00 b9 00 02  .X|.!.t...*|....
    0000050: 00 00 f3 a5 66 81 3d c6 58 7c 00 07 02 72 1c a1  ....f.=.X|...r..
    0000060: fc 58 7c 00 3d 03 00 00 00 73 0e 8b 04 85 80 22  .X|.=....s....."
    0000070: 7c 00 2d 00 00 00 c0 ff e0 0f 0b bf 00 90 8a 00  |.-.............
    0000080: ba 00 a0 81 00 b8 03 00 00 00 8d 4f 67 89 0a 89  ...........Og...
    0000090: 8a 00 0c 00 00 83 c2 04 b9 00 04 00 00 ab 05 00  ................
    00000a0: 10 00 00 e2 f8 bd 03 90 a4 00 39 e8 72 dc 81 c7  ..........9.r...
    00000b0: 00 00 00 c0 89 3d 80 a5 74 00 c1 e8 0c a3 84 f0  .....=..t.......
    00000c0: 81 00 b8 67 b0 81 00 a3 fc af 81 00 e9 6d 6b 46  ...g.........mkF

  • 相关阅读:
    878. 第 N 个神奇数字
    Leetcode 239. 滑动窗口最大值
    欢天喜地七仙女——Beta冲刺三
    欢天喜地七仙女——Beta冲刺二
    欢天喜地七仙女——Beta冲刺一
    欢天喜地七仙女——Beta冲刺凡事预则立
    欢天喜地七仙女——Beta冲刺代码规范与计划
    欢天喜地七仙女Alpha总结展望——前事不忘后事之师
    欢天喜地七仙女——Alpha测试随笔
    欢天喜地七仙女——Alpha冲刺总结
  • 原文地址:https://www.cnblogs.com/cute/p/4633532.html
Copyright © 2020-2023  润新知