AFAIK,/dev/mem
向用户提供物理内存,它通常用于通过 MMIO 读取/写入设备。在我的用例中,我想修改当前进程的 pte,以便两个 pte 指向同一个物理页面。特别是,我将 x86_64 二进制文件移动到 4G 虚拟空间之上,并将 mmap 虚拟空间移动到 4G 之下。我想让 pte 以上的 4G 和 pte 以下的 4G 指向同一个物理页面,这样当我写入 vaddr 以上的 4G 并从 pte 以下的 4G 读取时,我会得到相同的结果。示例代码可能如下所示:
*(unsigned char *)vaddr1 = 7 // write into 4G above vaddr1
val = *(unsigned char *)vaddr2; // read from 4G below vaddr2
printf("val should be 7, %d\n", val);
但是在我修改 4G below pte 以指向 4G above pte through 指向的物理页面后/dev/mem
,内核在下面给我消息,
BUG: Bad page map in process mmap pte:8000000007eb2067 pmd:07acb067
page:ffffea00001fac80 count:0 mapcount:-1 mapping: (null) index:0x101b7b
page flags: 0x4000000000000014(referenced|dirty)
addr:0000000101b7b000 vm_flags:00100073 anon_vma:ffff880007ab0708 mapping: (null) index:101b7b
Pid: 609, comm: mmap Tainted: G B 3.5.3 #7
Call Trace:
[<ffffffff8107abcc>] ? print_bad_pte+0x1d2/0x1ea
[<ffffffff8107bf18>] ? unmap_single_vma+0x3a0/0x56d
[<ffffffff8107c745>] ? unmap_vmas+0x2c/0x46
[<ffffffff8108106b>] ? exit_mmap+0x6e/0xdd
[<ffffffff8101cc4f>] ? do_page_fault+0x30f/0x348
[<ffffffff81020ce6>] ? mmput+0x20/0xb4
[<ffffffff810256ae>] ? exit_mm+0x105/0x110
[<ffffffff8103bb6c>] ? hrtimer_try_to_cancel+0x67/0x70
[<ffffffff81026b59>] ? do_exit+0x211/0x711
[<ffffffff810272e0>] ? do_group_exit+0x76/0xa0
[<ffffffff8102731c>] ? sys_exit_group+0x12/0x19
[<ffffffff812f3662>] ? system_call_fastpath+0x16/0x1b
BUG: Bad rss-counter state mm:ffff880007a496c0 idx:0 val:-1
BUG: Bad rss-counter state mm:ffff880007a496c0 idx:1 val:1
我猜内核会检查 pte 是否已被修改,我做错了什么。这是我的 pte 重写之前/之后的 vaddr1 和 vaddr2 的 pte。
above 4G pte: 0x8000000007eb2067
below 4G pte: 0x0000000007ea7067
after rewriting pte...
above 4G pte: 0x8000000007eb2067
below 4G pte: 0x8000000007eb2067
任何想法?谢谢。
注意:现在我知道我应该释放 vaddr2 的 pte 指向的物理页面,否则内核会注意到物理页面没有被任何 pte 指向并给出这些错误。但是怎么做?我尝试使用__free_page
,但出现以下错误。
BUG: unable to handle kernel paging request at ffffebe00008001c
IP: [<ffffffff8106b908>] __free_pages+0x4/0x2a
PGD 0
Oops: 0000 [#2] PREEMPT SMP
CPU 0