內核新特性——Patch physical to virtual translations at runtime

Linux/arm 3.4.67 Kernel Configuration中多了一項:

Patch physical to virtual translations at runtime

幫助信息解釋如下:

CONFIG_ARM_PATCH_PHYS_VIRT:    
  │                                                                    
  │ Patch phys-to-virt and virt-to-phys translation functions at       
  │ boot and module load time according to the position of the       
  │ kernel in system memory.                                         
  │                                                                 
  │ This can only be used with non-XIP MMU kernels where the base       
  │ of physical memory is at a 16MB boundary.                  
  │                                                                   
  │ Only disable this option if you know that you do not require      
  │ this feature (eg, building a kernel for a single machine) and       
  │ you need to shrink the kernel to the minimal size. 

意思就是對物理-虛擬地址互相轉換進行修改,該功能會根據內核在系統中的位置自動計算出相應地址。

體現在代碼上的改動可以在

arch/arm/include/asm/memory.h:

#ifndef __virt_to_phys
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT

/*
 * Constants used to force the right instruction encodings and shifts
 * so that all we need to do is modify the 8-bit constant field.
 */
#define __PV_BITS_31_24	0x81000000

extern unsigned long __pv_phys_offset;
#define PHYS_OFFSET __pv_phys_offset

#define __pv_stub(from,to,instr,type)			\
	__asm__("@ __pv_stub\n"				\
	"1:	" instr "	%0, %1, %2\n"		\
	"	.pushsection .pv_table,\"a\"\n"		\
	"	.long	1b\n"				\
	"	.popsection\n"				\
	: "=r" (to)					\
	: "r" (from), "I" (type))

static inline unsigned long __virt_to_phys(unsigned long x)
{
	unsigned long t;
	__pv_stub(x, t, "add", __PV_BITS_31_24);
	return t;
}

static inline unsigned long __phys_to_virt(unsigned long x)
{
	unsigned long t;
	__pv_stub(x, t, "sub", __PV_BITS_31_24);
	return t;
}
#else
#define __virt_to_phys(x)	((x) - PAGE_OFFSET + PHYS_OFFSET)
#define __phys_to_virt(x)	((x) - PHYS_OFFSET + PAGE_OFFSET)
#endif
#endif

另外,再額外提供一段有用的信息,也是在這個文件裏面:

#ifndef PHYS_OFFSET
#ifdef PLAT_PHYS_OFFSET
#define PHYS_OFFSET	PLAT_PHYS_OFFSET
#else
#define PHYS_OFFSET	UL(CONFIG_PHYS_OFFSET)
#endif
#endif

/*
 * PFNs are used to describe any physical page; this means
 * PFN 0 == physical address 0.
 *
 * This is the PFN of the first RAM page in the kernel
 * direct-mapped view.  We assume this is the first page
 * of RAM in the mem_map as well.
 */
#define PHYS_PFN_OFFSET	(PHYS_OFFSET >> PAGE_SHIFT)

/*
 * These are *only* valid on the kernel direct mapped RAM memory.
 * Note: Drivers should NOT use these.  They are the wrong
 * translation for translating DMA addresses.  Use the driver
 * DMA support - see dma-mapping.h.
 */
static inline phys_addr_t virt_to_phys(const volatile void *x)
{
	return __virt_to_phys((unsigned long)(x));
}

static inline void *phys_to_virt(phys_addr_t x)
{
	return (void *)(__phys_to_virt((unsigned long)(x)));
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章