static ssize_t write_kmem(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
ssize_t wrote = 0;
ssize_t virtr = 0;
char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
int err = 0;
if (p < (unsigned long) high_memory) {
unsigned long to_write = min_t(unsigned long, count,
(unsigned long)high_memory - p);
wrote = do_write_kmem(p, buf, to_write, ppos);
if (wrote != to_write)
return wrote;
p += wrote;
buf += wrote;
count -= wrote;
}
if (count > 0) {
kbuf = (char *)__get_free_page(GFP_KERNEL);
if (!kbuf)
return wrote ? wrote : -ENOMEM;
while (count > 0) {
unsigned long sz = size_inside_page(p, count);
unsigned long n;
if (!is_vmalloc_or_module_addr((void *)p)) {
err = -ENXIO;
break;
}
n = copy_from_user(kbuf, buf, sz);
if (n) {
err = -EFAULT;
break;
}
vwrite(kbuf, (char *)p, sz);
count -= sz;
buf += sz;
virtr += sz;
p += sz;
}
free_page((unsigned long)kbuf);
}
*ppos = p;
return virtr + wrote ? : err;
}
2.2 devkmem
类似于devmem相对于/dev/mem,devkmem通过将/dev/kmem映射到用户空间,然后读取内容。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#define DEVKMEM "/dev/kmem"
#define PAGE_SIZE 0x1000
#define PAGE_MASK (~(PAGE_SIZE-1))
int main(int argc, char* argv[])
{
int fd;
char *mbase;
char read_buf[10];
unsigned int varAddr, regAddr;
varAddr = strtoul(argv[1], 0, 16);
unsigned int ptr = varAddr & ~(PAGE_MASK);
fd = open(DEVKMEM, O_RDONLY);
if (fd == -1) {
perror("open");
exit(-1);
}
mbase = mmap(0,PAGE_SIZE,PROT_READ,MAP_SHARED,fd, (varAddr & PAGE_MASK));
if (mbase == MAP_FAILED) {
printf("map failed %s\n",strerror(errno));
}
printf("varAddr = 0x%X \n", varAddr);
printf("mapbase = 0x%X \n", (unsigned int)mbase);
printf("value = 0x%X \n",*(unsigned int*)(mbase+ptr));
close(fd);
munmap(mbase,PAGE_SIZE);
return 0;
}
2.3 devkmem使用
由于devkmem需要输入地址,但由于是虚拟地址,完全地址是没有意义的。
需要通过/proc/kallsyms根据符号找到对应的内核虚拟地址,然后再通过devkmem查看其值。
比如想查看sysctl_sched_rt_runtime的值,首先查看其在内核的虚拟地址:
cat /proc/kallsyms | grep sysctl_sched_rt_runtime
808eb544 D sysctl_sched_rt_runtime
然后查看虚拟地址的值:
./devkmem 808eb544
varAddr = 0x808EB544
mapbase = 0x2ABFB000
value = 0xE7EF0
换算成10进制就是950000.
那么这个值对不对呢?cat /proc/sys/kernel/sched_rt_runtime_us表明结果正确。
改进点:
1.直接输入符号,显示所有符号的值。
2.不同输出格式,16进制、10进制等等。
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx