Можно ли vmap памяти модуля ядра? - PullRequest
2 голосов
/ 21 июня 2011

Есть ли какие-либо ограничения для памяти модуля ядра отображения через vmap? В моей системе я пишу простой KMOD, который отображает функцию ядра (printk) и функцию модуля (printx) и проверяет, равны ли отображения. Результат показывает мне, что есть проблема с printx модуля отображения - отображение и код функции не равны. Может ли кто-нибудь объяснить мне, что я делаю неправильно? И вот код:

// vmap-test.c

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

int printx(void)
{
    return 0;
}


void vmap_action(unsigned long address)
{
    void * mapping;
    struct page * page;

    page = virt_to_page(address);
    mapping = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
    if (mapping) {
        int i = 0;
        void * data = mapping + offset_in_page(address);

        printk("VMAP: src %p -> dst %p\n", (void *)address, data);
        for (i=0; i<16; i++) {
            printk("%.02x %.02x\n", ((u8 *)address)[i], ((u8 *)data)[i]);
        }
        vunmap(mapping);
    }
}

int my_module_init(void)
{
    vmap_action((unsigned long)printk);
    vmap_action((unsigned long)printx);

    return 0;
}
module_init(my_module_init);

void my_module_exit(void)
{
}
module_exit(my_module_exit);

И результат с dmesg:

VMAP (printk)

[88107.398146] VMAP: src ffffffff813dfaef -> dst ffffc900117ddaef
[88107.398148] 55 55
[88107.398149] 48 48
[88107.398150] 89 89
[88107.398151] e5 e5
[88107.398152] 48 48
[88107.398153] 83 83
[88107.398154] ec ec
[88107.398155] 50 50
[88107.398156] 0f 0f
[88107.398156] 1f 1f
[88107.398157] 44 44
[88107.398158] 00 00
[88107.398159] 00 00
[88107.398160] 48 48
[88107.398161] 8d 8d
[88107.398162] 45 45

VMAP (printx)

[88107.398164] VMAP: src ffffffffa009a010 -> dst ffffc900117fd010
[88107.398166] 55 35
[88107.398167] 48 fb
[88107.398168] 89 53
[88107.398169] e5 d5
[88107.398170] 0f f7
[88107.398171] 1f 97
[88107.398171] 44 ee
[88107.398172] 00 fd
[88107.398173] 00 d5
[88107.398174] 31 2d
[88107.398175] c0 bf
[88107.398176] 5d f6
[88107.398177] c3 2d
[88107.398178] 0f bd
[88107.398179] 1f b7
[88107.398180] 00 99

Любые предложения приветствуются :) Спасибо.

1 Ответ

0 голосов
/ 21 июня 2011

Ну, я обнаружил, что подобная функция реализована в KSplice проекте, и вот оно:

/*
 * map_writable creates a shadow page mapping of the range
 * [addr, addr + len) so that we can write to code mapped read-only.
 *
 * It is similar to a generalized version of x86's text_poke.  But
 * because one cannot use vmalloc/vfree() inside stop_machine, we use
 * map_writable to map the pages before stop_machine, then use the
 * mapping inside stop_machine, and unmap the pages afterwards.
 */
static void *map_writable(void *addr, size_t len)
{
    void *vaddr;
    int nr_pages = DIV_ROUND_UP(offset_in_page(addr) + len, PAGE_SIZE);
    struct page **pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
    void *page_addr = (void *)((unsigned long)addr & PAGE_MASK);
    int i;

    if (pages == NULL)
        return NULL;

    for (i = 0; i < nr_pages; i++) {
        if (__module_address((unsigned long)page_addr) == NULL) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) || !defined(CONFIG_X86_64)
            pages[i] = virt_to_page(page_addr);
#else /* LINUX_VERSION_CODE < && CONFIG_X86_64 */
/* e3ebadd95cb621e2c7436f3d3646447ac9d5c16d was after 2.6.21
 * This works around a broken virt_to_page() from the RHEL 5 backport
 * of x86-64 relocatable kernel support.
 */
            pages[i] =
                pfn_to_page(__pa_symbol(page_addr) >> PAGE_SHIFT);
#endif /* LINUX_VERSION_CODE || !CONFIG_X86_64 */
            WARN_ON(!PageReserved(pages[i]));
        } else {
            pages[i] = vmalloc_to_page(addr);
        }
        if (pages[i] == NULL) {
            kfree(pages);
            return NULL;
        }
        page_addr += PAGE_SIZE;
    }
    vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
    kfree(pages);
    if (vaddr == NULL)
        return NULL;
    return vaddr + offset_in_page(addr);
}

Таким образом, по-разному обрабатывается память ядра и модуля. Если страница не принадлежит ни одному модулю, тогда используется vmalloc_to_page, а не virt_to_phys. Я проверю, поможет ли это, и опубликую результат позже.

...