AFAIK,/dev/mem
向用户显示物理内存,它通常用于通过MMIO进行设备读/写。在我的用例中,我想修改当前进程的pte,以便两个ptes指向同一个物理页面。特别是,我将x86_64二进制文件移到4G虚拟空间以上,并将mmap虚拟空间移动到4G以下。我想将4G高于pte,4G低于pte指向相同的物理页面,这样当我在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);
但是在我将pte下面的4G修改为指向通过/dev/mem
以上的4G指向的物理页面后,内核会在下面给出消息,
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