/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)]






