/dev/kmem


kmemデバイスはCONFIG_DEVKMEM構築下で、メモリデバイスの1つとしてMEM_MAJOR(10)/MINOR(2)のデバイスとして実装されます。

/dev/memとの相違は、参照する領域に制限はありません。ただしhigh_memoryを超える領域は、vmlistにリンクされているvmalloc()で取得されている領域しか参照されません。
#define VMALLOC_OFFSET  (8 * 1024 * 1024)
#define VMALLOC_START   ((unsigned long)high_memory + VMALLOC_OFFSET)

static const struct memdev {
       const char *name;
       umode_t mode;
       const struct file_operations *fops;
       struct backing_dev_info *dev_info;
} devlist[] = {
        [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
#ifdef CONFIG_DEVKMEM
        [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
#endif
        [3] = { "null", 0666, &null_fops, NULL },
#ifdef CONFIG_DEVPORT
        [4] = { "port", 0, &port_fops, NULL },
#endif
        [5] = { "zero", 0666, &zero_fops, &zero_bdi },
        [7] = { "full", 0666, &full_fops, NULL },
        [8] = { "random", 0666, &random_fops, NULL },
        [9] = { "urandom", 0666, &urandom_fops, NULL },
       [11] = { "kmsg", 0, &kmsg_fops, NULL },
#ifdef CONFIG_CRASH_DUMP
       [12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
};

static int __init chr_dev_init(void)
{
       int minor;
       int err;

       err = bdi_init(&zero_bdi);
       if (err)
               return err;

       if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
               printk("unable to get major %d for memory devs\n", MEM_MAJOR);

       mem_class = class_create(THIS_MODULE, "mem");
       if (IS_ERR(mem_class))
               return PTR_ERR(mem_class);

       mem_class->devnode = mem_devnode;
       for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
               if (!devlist[minor].name)
                       continue;
               device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
                             NULL, devlist[minor].name);
       }

       return tty_init();
}

static const struct file_operations kmem_fops = {
       .llseek         = memory_lseek,
       .read           = read_kmem,
       .write          = write_kmem,
       .mmap           = mmap_kmem,
       .open           = open_kmem,
       .get_unmapped_area = get_unmapped_area_mem,
};

static ssize_t read_kmem(struct file *file, char __user *buf,
                        size_t count, loff_t *ppos)
{
       unsigned long p = *ppos;
       ssize_t low_count, read, sz;
       char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
       int err = 0;

       read = 0;
       if (p < (unsigned long) high_memory) {
               low_count = count;
               if (count > (unsigned long)high_memory - p)
                       low_count = (unsigned long)high_memory - p;

#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
               /* we don't have page 0 mapped on sparc and m68k.. */
               if (p < PAGE_SIZE && low_count > 0) {
                       sz = size_inside_page(p, low_count);
                       if (clear_user(buf, sz))
                               return -EFAULT;
                       buf += sz;
                       p += sz;
                       read += sz;
                       low_count -= sz;
                       count -= sz;
               }
#endif
               while (low_count > 0) {
                       sz = size_inside_page(p, low_count);

                       kbuf = xlate_dev_kmem_ptr((char *)p);

                       if (copy_to_user(buf, kbuf, sz))
                               return -EFAULT;
                       buf += sz;
                       p += sz;
                       read += sz;
                       low_count -= sz;
                       count -= sz;
               }
       }

       if (count > 0) {
               kbuf = (char *)__get_free_page(GFP_KERNEL);
               if (!kbuf)
                       return -ENOMEM;
               while (count > 0) {
                       sz = size_inside_page(p, count);
                       if (!is_vmalloc_or_module_addr((void *)p)) {
                               err = -ENXIO;
                               break;
                       }
                       sz = vread(kbuf, (char *)p, sz);
                       if (!sz)
                               break;
                       if (copy_to_user(buf, kbuf, sz)) {
                               err = -EFAULT;
                               break;
                       }
                       count -= sz;
                       buf += sz;
                       read += sz;
                       p += sz;
               }
               free_page((unsigned long)kbuf);
       }
       *ppos = p;
       return read ? read : err;
}

long vread(char *buf, char *addr, unsigned long count)
{
       struct vm_struct *tmp;
       char *vaddr, *buf_start = buf;
       unsigned long buflen = count;
       unsigned long n;

       if ((unsigned long) addr + count < count)
               count = -(unsigned long) addr;

       read_lock(&vmlist_lock);
       for (tmp = vmlist; count && tmp; tmp = tmp->next) {
               vaddr = (char *) tmp->addr;
               if (addr >= vaddr + tmp->size - PAGE_SIZE)
                       continue;
               while (addr < vaddr) {
                       if (count == 0)
                               goto finished;
                       *buf = '\0';
                       buf++;
                       addr++;
                       count--;
               }
               n = vaddr + tmp->size - PAGE_SIZE - addr;
               if (n > count)
                       n = count;
               if (!(tmp->flags & VM_IOREMAP))
                       aligned_vread(buf, addr, n);
               else /* IOREMAP area is treated as memory hole */
                       memset(buf, 0, n);
               buf += n;
               addr += n;
               count -= n;
       }
finished:
       read_unlock(&vmlist_lock);

       if (buf == buf_start)
               return 0;

       if (buf != buf_start + buflen)
               memset(buf, 0, buflen - (buf - buf_start));

       return buflen;
}

補足

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>

static int __init babakaka_init( void )
{
    char    *p;

    p = vmalloc(100);
    printk("vmalloc:%lx\n", (unsigned long)p);
    vfree(p);
    return -1;
}

module_init(babakaka_init);

[root@localhost lkm]# dmesg
  :
[  593.906126] babakaka: module license 'unspecified' taints kernel.
[  593.906146] Disabling lock debugging due to kernel taint
[  593.912994] vmalloc:e0870000   : >VMALLOC_START[((unsigned long)high_memory + VMALLOC_OFFSET)]


最終更新 2016/05/24 18:20:00 - north
(2016/05/24 18:20:00 作成)


検索

アクセス数
3689445
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。