/dev/kmem
kmemデバイスはCONFIG_DEVKMEM構築下で、メモリデバイスの1つとしてMEM_MAJOR(10)/MINOR(2)のデバイスとして実装されます。
/dev/memとの相違は、参照する領域に制限はありません。ただしhigh_memoryを超える領域は、vmlistにリンクされているvmalloc()で取得されている領域しか参照されません。
/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)]