我制作了一个内核模块,它获取两个变量的虚拟地址,将它们称为foo和bar,并遍历页表直到它们的物理地址。
我想修改foo的页表条目,使其与bar的页表条目相同,从而使其成为foo 和 bar 位于同一页框架中。你能帮我实现这个目标吗?
下面是我编写的用于遍历页表的代码。
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *ptep, pte;
pgd = pgd_offset(mm, address);
if (pgd_none(*pgd) || pgd_bad(*pgd))
return -EINVAL;
pud = pud_offset(pgd, address);
if (pud_none(*pud) || pud_bad(*pud))
return -EINVAL;
pmd = pmd_offset(pud, address);
if (pmd_none(*pmd) || pmd_bad(*pmd))
return -EINVAL;
ptep = pte_offset(pmd, address);
if (!ptep)
return -EINVAL;
pte = *ptep;
我确信我需要刷新 TLB,也许还需要修改一些标志才能实现我想要的目标,但我缺乏所需的知识。
非常感谢任何帮助!
最佳答案
我写这个答案是希望这对将来的人有用。
我已经成功修改了两个变量foo和bar的虚拟地址的页表,这样mm就会将它们视为驻留在同一物理页中。
执行此操作的代码如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/thread_info.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
#include <asm/pgtable.h>
pgd_t *foo_pgd, *bar_pgd;
pud_t *foo_pud, *bar_pud;
pmd_t *foo_pmd, *bar_pmd;
pte_t *foo_ptep, *bar_ptep, foo_pte, bar_pte;
/* We will step through the page tables until we reach the
* PTE for both foo and bar */
/* Get PGD */
foo_pgd = pgd_offset(current->mm, foo_address);
if (pgd_none(*foo_pgd) || pgd_bad(*foo_pgd))
return -EINVAL;
bar_pgd = pgd_offset(current->mm, bar_address);
if (pgd_none(*bar_pgd) || pgd_bad(*bar_pgd))
return -EINVAL;
/* Get PUD */
foo_pud = pud_offset(foo_pgd, foo_address);
if (pud_none(*foo_pud) || pud_bad(*foo_pud))
return -EINVAL;
bar_pud = pud_offset(bar_pgd, bar_address);
if (pud_none(*bar_pud) || pud_bad(*bar_pud))
return -EINVAL;
/* Get PMD */
foo_pmd = pmd_offset(foo_pud, foo_address);
if (pmd_none(*foo_pmd) || pmd_bad(*foo_pmd))
return -EINVAL;
bar_pmd = pmd_offset(bar_pud, bar_address);
if (pmd_none(*bar_pmd) || pmd_bad(*bar_pmd))
return -EINVAL;
/* Get PTE */
spin_lock(current->mm->page_table_lock);
foo_ptep = pte_offset_map(foo_pmd, foo_address);
if (!pte_present(*foo_ptep))
return -EINVAL;
bar_ptep = pte_offset_map(bar_pmd, bar_address);
if (!pte_present(*bar_ptep))
return -EINVAL;
/* Trick foo into thinking he resides in the same page as bar */
*foo_ptep = *bar_ptep;
spin_unlock(current->mm->page_table_lock);
/* We need to flush the tlb afterwards */
__native_flush_tlb();
这可能不像@GilHamilton 想象的那么强大,但这为我完成了工作。
我希望这会很有用!
爱德华
关于c - 在 x64 Ubuntu 14.04 上用另一个页表条目覆盖页表条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34983626/