aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/include
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-01-04 14:09:43 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-02-17 18:27:32 -0500
commitdc21af99fadcfa0ae65b52fd0895f85824f0c288 (patch)
treed2d293d79fdb405f25ca7fb18aa16aba6ecea261 /arch/arm/include
parent5b7de4547b388d3949620e21d072e35b6f2638fa (diff)
ARM: P2V: introduce phys_to_virt/virt_to_phys runtime patching
This idea came from Nicolas, Eric Miao produced an initial version, which was then rewritten into this. Patch the physical to virtual translations at runtime. As we modify the code, this makes it incompatible with XIP kernels, but allows us to achieve this with minimal loss of performance. As many translations are of the form: physical = virtual + (PHYS_OFFSET - PAGE_OFFSET) virtual = physical - (PHYS_OFFSET - PAGE_OFFSET) we generate an 'add' instruction for __virt_to_phys(), and a 'sub' instruction for __phys_to_virt(). We calculate at run time (PHYS_OFFSET - PAGE_OFFSET) by comparing the address prior to MMU initialization with where it should be once the MMU has been initialized, and place this constant into the above add/sub instructions. Once we have (PHYS_OFFSET - PAGE_OFFSET), we can calculate the real PHYS_OFFSET as PAGE_OFFSET is a build-time constant, and save this for the C-mode PHYS_OFFSET variable definition to use. At present, we are unable to support Realview with Sparsemem enabled as this uses a complex mapping function, and MSM as this requires a constant which will not fit in our math instruction. Add a module version magic string for this feature to prevent incompatible modules being loaded. Tested-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org> Tested-by: Nicolas Pitre <nicolas.pitre@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/include')
-rw-r--r--arch/arm/include/asm/memory.h55
-rw-r--r--arch/arm/include/asm/module.h15
2 files changed, 56 insertions, 14 deletions
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 2efec578a62e..7197879e1cb7 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -24,8 +24,6 @@
24 */ 24 */
25#define UL(x) _AC(x, UL) 25#define UL(x) _AC(x, UL)
26 26
27#define PHYS_OFFSET PLAT_PHYS_OFFSET
28
29#ifdef CONFIG_MMU 27#ifdef CONFIG_MMU
30 28
31/* 29/*
@@ -135,16 +133,6 @@
135#endif 133#endif
136 134
137/* 135/*
138 * Physical vs virtual RAM address space conversion. These are
139 * private definitions which should NOT be used outside memory.h
140 * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
141 */
142#ifndef __virt_to_phys
143#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
144#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
145#endif
146
147/*
148 * Convert a physical address to a Page Frame Number and back 136 * Convert a physical address to a Page Frame Number and back
149 */ 137 */
150#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT) 138#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT)
@@ -159,6 +147,49 @@
159#ifndef __ASSEMBLY__ 147#ifndef __ASSEMBLY__
160 148
161/* 149/*
150 * Physical vs virtual RAM address space conversion. These are
151 * private definitions which should NOT be used outside memory.h
152 * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
153 */
154#ifndef __virt_to_phys
155#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
156
157extern unsigned long __pv_phys_offset;
158#define PHYS_OFFSET __pv_phys_offset
159
160#define __pv_stub(from,to,instr) \
161 __asm__("@ __pv_stub\n" \
162 "1: " instr " %0, %1, %2\n" \
163 " .pushsection .pv_table,\"a\"\n" \
164 " .long 1b\n" \
165 " .popsection\n" \
166 : "=r" (to) \
167 : "r" (from), "I" (0x81000000))
168
169static inline unsigned long __virt_to_phys(unsigned long x)
170{
171 unsigned long t;
172 __pv_stub(x, t, "add");
173 return t;
174}
175
176static inline unsigned long __phys_to_virt(unsigned long x)
177{
178 unsigned long t;
179 __pv_stub(x, t, "sub");
180 return t;
181}
182#else
183#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
184#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
185#endif
186#endif
187
188#ifndef PHYS_OFFSET
189#define PHYS_OFFSET PLAT_PHYS_OFFSET
190#endif
191
192/*
162 * The DMA mask corresponding to the maximum bus address allocatable 193 * The DMA mask corresponding to the maximum bus address allocatable
163 * using GFP_DMA. The default here places no restriction on DMA 194 * using GFP_DMA. The default here places no restriction on DMA
164 * allocations. This must be the smallest DMA mask in the system, 195 * allocations. This must be the smallest DMA mask in the system,
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 12c8e680cbff..d072c21332ee 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -25,8 +25,19 @@ struct mod_arch_specific {
25}; 25};
26 26
27/* 27/*
28 * Include the ARM architecture version. 28 * Add the ARM architecture version to the version magic string
29 */ 29 */
30#define MODULE_ARCH_VERMAGIC "ARMv" __stringify(__LINUX_ARM_ARCH__) " " 30#define MODULE_ARCH_VERMAGIC_ARMVSN "ARMv" __stringify(__LINUX_ARM_ARCH__) " "
31
32/* Add __virt_to_phys patching state as well */
33#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
34#define MODULE_ARCH_VERMAGIC_P2V "p2v8 "
35#else
36#define MODULE_ARCH_VERMAGIC_P2V ""
37#endif
38
39#define MODULE_ARCH_VERMAGIC \
40 MODULE_ARCH_VERMAGIC_ARMVSN \
41 MODULE_ARCH_VERMAGIC_P2V
31 42
32#endif /* _ASM_ARM_MODULE_H */ 43#endif /* _ASM_ARM_MODULE_H */