简体   繁体   中英

How to print the information of mem_map using proc file?

I'm trying to print virtual address of mem_map,physical address of mem_map and the number of struct page now. so I tried running code of this article ,but it seemed like it didn't show correct address. Could you tell me how I can fix this?

Below is the result of execution.

mem_map virt addr: (null) mem_map phys addr: 131941395333120 mem_map phys pages: 18446744072101367984

I'm using Ubuntu12.04(64bit) and kernel version is 3.13.

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

#include <asm/switch_to.h>
#include <linux/types.h> /* size_t */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/fs.h>       // for basic filesystem
#include <linux/proc_fs.h>  // for the proc filesystem
#include <linux/seq_file.h> // for sequence files
#include <linux/mm.h>

MODULE_LICENSE("Dual BSD/GPL");

static struct proc_dir_entry* proc_file;
struct page *mem_map;
EXPORT_SYMBOL(mem_map);

/* memory map functions */
int mem_map_show(struct seq_file *m, void *v);
//virtual_to_physical
inline unsigned long virt_to_phy(unsigned long addr);

inline unsigned long virt_to_phy(unsigned long addr){
    return __pa(addr);
}

char buf[300];

int mem_map_show(struct seq_file *m, void *v){

    int ret_val = 0;

    printk(KERN_INFO "Proc file read \n");
    ret_val =  seq_printf(m, "mem_map virt addr: %p \n", mem_map);
    ret_val += seq_printf(m, "mem_map phys addr: %lu \n",virt_to_phy((unsigned long)mem_map));
    ret_val += seq_printf(m, "mem_map phys pages: %lu \n", (long unsigned int)get_num_physpages);
    return ret_val;
}

static int mem_map_open(struct inode *inode, struct file *file){
    return single_open(file, mem_map_show, NULL);
}

struct file_operations mem_map_fops = {
    .owner = THIS_MODULE,
    .open = mem_map_open,
    .read = seq_read,
    .llseek = seq_lseek,
    .release = single_release,
};

static int __init mem_map_init(void){
    printk(KERN_INFO "Loaded mem_map module\n");
    proc_file = proc_create("mem_map", 0, NULL, &mem_map_fops);
    if(!proc_file){
        printk(KERN_ALERT "Error: Could not initialize /proc/mem_map");
        return -ENOMEM;
    }   
    return 0;
}

static void __exit mem_map_exit(void){
    remove_proc_entry("mem_map",NULL);  
    printk(KERN_INFO "Proc file unloaded \n");
}


/* Declaration of the init and exit functions */
module_init(mem_map_init);
module_exit(mem_map_exit);

If I understand correctly, you want to print the address of the global mem_map array, right from your kernel module. The pointer that you're looking for is global ,therefore it has already been exported for you to use in your kernel module. All you have to do is find its' symbol.

Finding an exported symbol is easy, by including <linux/kallsyms.h> you'll have the power of using kallsyms_lookup_name() which takes a char * and returns the address of the symbol it represents. All you have to do now, is assigning the address to the empty pointer, possibly in your init function.

mem_map = (struct page *) kallsyms_lookup_name("mem_map");

Now your mem_map pointer actually points to the mem_map array that you're after. Cool.

Next, you're declaring virt_to_phy() and using __pa() inside it. Why? You can simply use virt_to_phys() that is already declared (and doing exactly the same in your case) in asm/io.h . Please not that you're trying to print an address, therefore the right printf format would be %lx instead of %lu .

Last but not least, ridiculous the number of pages you're examining is actually the decimal value of the address of get_num_physpages , which is a function. If you wish to print the return value of get_num_physpages you should call it as a function, get_num_physpages() because now your code prints the value of the pointer to get_num_physpages .

This is how I think your code should have looked like:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/mm.h>
#include <linux/kallsyms.h>
#include <asm/io.h>

#define ERROR -1

MODULE_LICENSE("Dual BSD/GPL");

static struct proc_dir_entry* proc_file;
struct page *mem_map;

int mem_map_show(struct seq_file *m, void *v)
{
    int ret_val = 0;

    printk(KERN_INFO "Proc file read\n");
    ret_val =  seq_printf(m, "mem_map virt addr:\t0x%p\n", mem_map);
    ret_val += seq_printf(m, "mem_map phys addr:\t0x%016llx\n", ((unsigned long long) virt_to_phys((volatile void *) mem_map)));
    ret_val += seq_printf(m, "mem_map phys pages:\t%lu\n", (long unsigned int) get_num_physpages());
    return ret_val;
}

static int mem_map_open(struct inode *inode, struct file *file)
{
    return single_open(file, mem_map_show, NULL);
}

struct file_operations mem_map_fops = {
    .owner = THIS_MODULE,
    .open = mem_map_open,
    .read = seq_read,
    .llseek = seq_lseek,
    .release = single_release,
};

static int __init mem_map_init(void)
{
    printk(KERN_INFO "Loaded mem_map module\n");
    mem_map = (struct page *) kallsyms_lookup_name("mem_map");
    if (!mem_map) {
        printk(KERN_ALERT "Error: Unable to find address of global 'mem_map'\n");
                return ERROR;
        }
    proc_file = proc_create("mem_map", 0, NULL, &mem_map_fops);
    if (!proc_file) {
        printk(KERN_ALERT "Error: Could not initialize /proc/mem_map\n");
        return -ENOMEM;
    }
    return 0;
}

static void __exit mem_map_exit(void)
{
    remove_proc_entry("mem_map",NULL);
    printk(KERN_INFO "Proc file unloaded\n");
}


/* Declaration of the init and exit functions */
module_init(mem_map_init);
module_exit(mem_map_exit);

and more specifically, if you want to comply with how values in procfs are printed, I would implement mem_map_show somewhat like this:

int mem_map_show(struct seq_file *m, void *v)
{
    int ret_val = 0;

    ret_val =  seq_printf(m, "0x%p 0x%016llx %lu\n",
            mem_map, 
            ((unsigned long long) virt_to_phys((volatile void *) mem_map)),
            (long unsigned int) get_num_physpages());
    return ret_val;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM