devmem读写物理内存和devkmem读取内核虚拟内存(6)

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/12046.html