通过/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);
[email protected]:~$ 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
[email protected]:~$ 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  [email protected]".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

时间: 2024-11-05 22:38:37

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

Linux高端内存

Linux高端内存是针对物理内存来说的,虚拟内存没有高端这个概念.Linux系统将虚拟内存分为两个部分,即用户地 址空间和内核地址空间,对于32位系统来说,虚拟地址空间为4GB,其中用户空间范围为0-3GB,内核空间范围为 3-4GB.Linux将3GB开始的内核虚拟地址空间的896M地址直接映射到物理地址空间的0-896M,这部分是永久性映 射,剩下的128M则可根据需要进行动态映射,也称临时性映射.如果没有动态映射,那么1GB的内核虚拟地址空间最 多只能访问1GB的物理内存,那么如果物理内存

Linux内核高端内存 转

Linux内核地址映射模型x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图.   Linux内核地址空间划分 通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间.注意这里是32位内核地址空间划分,64位内核地址空间划分是不同的.   Linux内核高端内存的由来 当内核模块代码或线程访问内存时,代码中的内存地址都为逻辑地址,而对应到真正的物理内存地址,需要地址一对一的映射,如逻辑地址0xc00

【转】linux 用户空间与内核空间——高端内存详解

摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中.用户空间的内存映射采用段页式,而内核空间有自己的规则:本文旨在探讨内核空间的地址映射. Linux内核地址空间划分 通常32位Linux内核虚拟地址空间划分0~3G为用户空间,3~4G为内核空间(注意,内核可以使用的线性地址只有1G).注意这里是32位内核地址空间划分,64位

Linux高端内存的由来

抱着拿来主义,自己挑选了部分,以下内容摘自网络. Linux内核地址空间划分 通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间.注意这里是32位内核地址空间划分,64位内核地址空间划分是不同的. Linux内核高端内存的由来 当内核模块代码或线程访问内存时,代码中的内存地址都为逻辑地址,而对应到真正的物理内存地址,需要地址一对一的映射,如逻辑地址0xc0000003对应的物理地址为0×3,0xc0000004对应的物理地址为0×4,- -,逻辑地址与物理地址对应的关系为

linux用户空间和内核空间(内核高端内存)_转

转自:Linux用户空间与内核空间(理解高端内存) 参考: 1. 进程内核栈.用户栈 2. 解惑-Linux内核空间 3. linux kernel学习笔记-5 内存管理 Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中. Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地

Linux内核空间-理解高端内存

Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中. Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图. Linux内核地址空间划分 通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间.注意这里是32位

Linux高端内存映射(上)【转】

转自:http://blog.csdn.net/vanbreaker/article/details/7579941 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 高端内存概述 永久内核映射 高端内存概述 在32位的系统上,内核占有从第3GB~第4GB的线性地址空间,共1GB大小,内核将其中的前896MB与物理内存的0~896MB进行直接映射,即线性映射,将剩余的128M线性地址空间作为访问高于896M的内存的一个窗口.引入高端内存映射这样一个概念的主要原因就是我们所安

高端内存映射之kmap持久内核映射--Linux内存管理(二十)

1 高端内存与内核映射 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供了其他函数用于将ZONE_HIGHMEM页帧显式映射到内核空间, 这些函数与vmalloc机制无关. 因此, 这就造成了混乱. 而在高端内存的页不能永久地映射到内核地址空间. 因此, 通过alloc_pages()函数以__GFP_HIGHMEM标志获得的内存页就不可能有逻辑地址. 在x86_32体系结构总,

虚拟地址的高端内存

1.由来原因 虚拟地址分为用户空间和内核空间,用户空间为3G,高1G为内核空间. 用户空间的虚拟地址到实际物理地址的映射我们之前有谈及此处不赘述. 高1G(3G-4G)为虚拟内核空间这一空间的映射比较暴力,直接在物理内存 的0开始映射,一一对应.那么这样会有一个问题,1G的虚拟内存只能映射 1G的物理内存,对于大于1G的物理内存就无能为力了,我们想用1G的线性 空间访问整个(大于1G)物理内存.可是想想,我们的线性地址空间是有限的 对于内核来说就是1G,那我们访问整个物理空间有什么意义呢?这个问