linux virtual page pfn physical的关系

基于linux4.14.79, TI AM5728 SDK。

phys:physical物理地址
pfn:物理页帧号(也有叫页框号的?)
page:描述物理页的结构体
virt:virtual虚拟地址

#define PAGE_SHIFT		12
/* 物理内存起始地址 */
#define PHYS_OFFSET	((phys_addr_t)__pv_phys_pfn_offset << PAGE_SHIFT)
/* 物理内存起始页帧号 */
#define PHYS_PFN_OFFSET	(__pv_phys_pfn_offset)
#define ARCH_PFN_OFFSET		PHYS_PFN_OFFSET
/* 内核虚拟空间起始地址 */
#define PAGE_OFFSET		UL(CONFIG_PAGE_OFFSET)
/* 物理内存page结构体指针,指向第一个page结构体 */
struct page *mem_map;

phys <=> pfn :

#define PHYS_PFN(x)	((unsigned long)((x) >> PAGE_SHIFT))
#define PFN_PHYS(x)	((phys_addr_t)(x) << PAGE_SHIFT)

pfn <=> page:

#define page_to_pfn __page_to_pfn
#define pfn_to_page __pfn_to_page

#define __pfn_to_page(pfn)	(mem_map + ((pfn) - ARCH_PFN_OFFSET))
#define __page_to_pfn(page)	((unsigned long)((page) - mem_map) + \
				 ARCH_PFN_OFFSET)

pfn - ARCH_PFN_OFFSET表示物理内存对应的页帧号。mem_map是物理内存的page结构体存放地址,加上物理内存的页帧号得到对应物理页的page结构体存放地址(虚拟)。

page <=> virt:

虚拟地址和page结构体地址的转换需要区分线性映射区vmalloc区(vmalloc/ioremap动态映射,以及使用iotable_init()的机器相关的静态映射),前者属于低端内存,后者属于高端内存
关于高端内存和低端内存的介绍:https://mp.csdn.net/console/editor/html/100771734
线性映射区
线性映射区page 和 virt的转换需要先转换为pfn, page和pfn的转换前面已经介绍了,下面时 virt 和 pfn的转换(同样只适用于线性映射区),根据不同的

/* virt_to_pfn的一种简单实现 */
#define virt_to_pfn(kaddr) \
	((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \
	 PHYS_PFN_OFFSET)

/* 下面是常规的 */
#define virt_to_pfn(kaddr)	(__pa(kaddr) >> PAGE_SHIFT)
#define pfn_to_virt(pfn)	__va((pfn) << PAGE_SHIFT)

#define __pa(x)			__virt_to_phys((unsigned long)(x))
#define __va(x)			((void *)__phys_to_virt((phys_addr_t)(x)))

#define __virt_to_phys(x)	__virt_to_phys_nodebug(x)
/* 这2个函数根据不同的配置,实现不一样 */
static inline unsigned long __phys_to_virt(phys_addr_t x);
static inline phys_addr_t __virt_to_phys_nodebug(unsigned long x);

/* 下面是一种实现 */
static inline phys_addr_t __virt_to_phys_nodebug(unsigned long x)
{
	return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET;
}
static inline unsigned long __phys_to_virt(phys_addr_t x)
{
	return x - PHYS_OFFSET + PAGE_OFFSET;
}

virt和page的转换: 

#define virt_to_page(addr)	pfn_to_page(virt_to_pfn(addr))
#define page_to_virt(page)	pfn_to_virt(page_to_pfn(page))

vmalloc区

struct page *vmalloc_to_page(const void *vmalloc_addr);

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值