mmap of /dev/mem fails with invalid argument for virt_to_phys address, but address is page aligned

前端 未结 1 1616
广开言路
广开言路 2020-12-06 23:18

For some reason my mmap failed with an Invalid argument message even though my offset is page aligned. Page size is 4096 bytes. Also CONFIG_S

1条回答
  •  难免孤独
    2020-12-06 23:50

    nopat kernel command line argument

    Just add that and it works, as mentioned at: https://stackoverflow.com/a/36634422/895245

    Here is my test setup:

    kernel module:

    #include  /* virt_to_phys */
    #include 
    #include  /* usleep_range */
    #include 
    #include 
    #include 
    #include  /* single_open, single_release */
    #include  /* kmalloc, kfree */
    
    static volatile u32 *i;
    
    static struct dentry *debugfs_file;
    
    static int show(struct seq_file *m, void *v)
    {
        seq_printf(m,
            "*i 0x%llx\n"
            "i %p\n"
            "virt_to_phys 0x%llx\n",
            (unsigned long long)*i,
            i,
            (unsigned long long)virt_to_phys((void *)i)
        );
        return 0;
    }
    
    static int open(struct inode *inode, struct  file *file)
    {
        return single_open(file, show, NULL);
    }
    
    static const struct file_operations fops = {
        .llseek = seq_lseek,
        .open = open,
        .owner = THIS_MODULE,
        .read = seq_read,
        .release = single_release,
    };
    
    static int myinit(void)
    {
        i = kmalloc(sizeof(i), GFP_KERNEL);
        *i = 0x12345678;
        debugfs_file = debugfs_create_file(
            "lkmc_virt_to_phys", S_IRUSR, NULL, NULL, &fops);
        return 0;
    }
    
    static void myexit(void)
    {
        debugfs_remove(debugfs_file);
        kfree((void *)i);
    }
    
    module_init(myinit)
    module_exit(myexit)
    MODULE_LICENSE("GPL");
    

    /dev/mem userland:

    #!/bin/sh
    set -ex
    insmod /virt_to_phys.ko
    cd /sys/kernel/debug
    cat lkmc_virt_to_phys
    # *i = 0x12345678
    addr=$(grep virt_to_phys lkmc_virt_to_phys | cut -d ' ' -f 2)
    devmem2 "$addr"
    devmem2 "$addr" w 0x9ABCDEF0
    cat lkmc_virt_to_phys
    # *i = 0x9ABCDEF0
    rmmod virt_to_phys
    

    nopat being passed at: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/2eca9280e12dbab79ccb67d0640b2a0edc2c9ffc/runqemu#L65

    Also try xp on QEMU monitor.

    And devmem2 is upstreamed by Buildroot itself: http://free-electrons.com/pub/mirror/devmem2.c See also: Accessing physical address from user space

    0 讨论(0)
提交回复
热议问题