virt_to_pfn 是否检查页面 table 是否存在

Does virt_to_pfn checks whether the page table exists or not

是否 virt_to_pfn 检查页面 table 是否存在。下面是因页面错误而失败的代码。

#include <linux/module.h>

#define address 0xf0000000
int init_module(void)
{
    struct page *page;
    int32_t reserved;
    int32_t private;
    uint32_t test  = 0xAAAAAAAA;
    uint32_t saveValue;
    unsigned long pfn = 0;
    static uint32_t *testAddr = (uint *)address;

    pfn = virt_to_pfn(address);
    printk("Test!:%x, page frame number:%lu\n", address, pfn);
    if ( !pfn_valid(pfn) ) {
           printk("Page frame number not valid\n");
    } else {
           printk("Page Frame Number valid\n");
    }

     page = ( struct page * )virt_to_page(address);
         if ( page == NULL )
     {
         printk("NO page exist\n");
         return -1;
     }
     reserved = PageReserved( page );
     private = PagePrivate( page );
     if (reserved)
         printk("Page reserved\n");
     if (private)
         printk("Page Private\n");

     saveValue = ( uint32_t )*testAddr;
     printk("Save value:%u\n", saveValue);
    return 0;
}

void cleanup_module(void)
{
    printk("Goodbye Cruel World!\n");
}

MODULE_LICENSE("GPL");

失败并出现以下错误:

root@qemuarm:~# modprobe hello
[   33.283359] hello: loading out-of-tree module taints kernel.
[   33.290515] Test!:f0000000, page frame number:458752
[   33.290708] Page Frame Number valid
[   33.291169] 8<--- cut here ---
[   33.291280] Unable to handle kernel paging request at virtual address f0000000
[   33.291704] pgd = afcbaf1a
[   33.291832] [f0000000] *pgd=80000040007003, *pmd=00000000
[   33.292313] Internal error: Oops: 206 [#1] PREEMPT SMP ARM
[   33.292589] Modules linked in: hello(O+)
[   33.293078] CPU: 0 PID: 323 Comm: modprobe Tainted: G           O      5.4.172-yocto-standard #1
[   33.293368] Hardware name: Generic DT based system
[   33.293926] PC is at init_module+0x94/0xc8 [hello]
[   33.294078] LR is at init_module+0x40/0xc8 [hello]
[   33.294243] pc : [<bf000094>]    lr : [<bf000040>]    psr: 600f0013
[   33.294549] sp : ed879dd0  ip : 2e85d000  fp : bf002000
[   33.294712] r10: ed879f40  r9 : f0815df0  r8 : 00000002
[   33.294838] r7 : 00000000  r6 : c10a78c0  r5 : bf000000  r4 : 00000000
[   33.295019] r3 : f0000000  r2 : 40000000  r1 : 00000007  r0 : bf0010c3
[   33.295255] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
[   33.295510] Control: 30c5387d  Table: 6e13d300  DAC: fffffffd
[   33.295656] Process modprobe (pid: 323, stack limit = 0x04adcafd)

RAM 大小为 1024MB,以下代码适用于 0xc000 0000 - 0xeff ffff 的内核虚拟地址。 0xffff 0000 是高内存区域开始的地方。

高内存区域访问的逻辑会改变吗

当且仅当 virt_addr_valid(kaddr) 为真时,virt_to_pfn(kaddr)virt_to_page(kaddr) 的结果才有效。仅当 kaddr 位于内核虚拟地址 space.

的 linear-mapped (lowmem) 区域时才成立

pfn_valid(virt_to_pfn(kaddr)) 不等同于 virt_addr_valid(kaddr)virt_addr_valid(kaddr) 意味着 pfn_valid(virt_to_pfn(kaddr))pfn_valid(virt_to_pfn(kaddr)) 并不意味着 virt_addr_valid(kaddr).