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)
.
是否 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.
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)
.