Issue
Does virt_to_pfn checks whether the page table is present or not. Below is the code which is failing with page fault.
#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");
Fails with the below error:
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 Size is 1024MB, the below code works with kernel virtual addresses from 0xc000 0000 - 0xefff ffff. 0xffff 0000 is where the high mem region starts.
Will the logic changes for high mem region access
Solution
The results of virt_to_pfn(kaddr)
and virt_to_page(kaddr)
are valid if and only if virt_addr_valid(kaddr)
is true. That is only true if kaddr
is in the linear-mapped (lowmem) region of kernel virtual address space.
pfn_valid(virt_to_pfn(kaddr))
is not equivalent to virt_addr_valid(kaddr)
. virt_addr_valid(kaddr)
implies pfn_valid(virt_to_pfn(kaddr))
but pfn_valid(virt_to_pfn(kaddr))
does not imply virt_addr_valid(kaddr)
.
Answered By - Ian Abbott Answer Checked By - Senaida (WPSolving Volunteer)