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)));
}