Skip to content

Commit e26a9e0

Browse files
author
Russell King
committed
ARM: Better virt_to_page() handling
virt_to_page() is incredibly inefficient when virt-to-phys patching is enabled. This is because we end up with this calculation: page = &mem_map[asm virt_to_phys(addr) >> 12 - __pv_phys_offset >> 12] in assembly. The asm virt_to_phys() is equivalent this this operation: addr - PAGE_OFFSET + __pv_phys_offset and we can see that because this is assembly, the compiler has no chance to optimise some of that away. This should reduce down to: page = &mem_map[(addr - PAGE_OFFSET) >> 12] for the common cases. Permit the compiler to make this optimisation by giving it more of the information it needs - do this by providing a virt_to_pfn() macro. Another issue which makes this more complex is that __pv_phys_offset is a 64-bit type on all platforms. This is needlessly wasteful - if we store the physical offset as a PFN, we can save a lot of work having to deal with 64-bit values, which sometimes ends up producing incredibly horrid code: a4c: e3009000 movw r9, #0 a4c: R_ARM_MOVW_ABS_NC __pv_phys_offset a50: e3409000 movt r9, #0 ; r9 = &__pv_phys_offset a50: R_ARM_MOVT_ABS __pv_phys_offset a54: e3002000 movw r2, #0 a54: R_ARM_MOVW_ABS_NC __pv_phys_offset a58: e3402000 movt r2, #0 ; r2 = &__pv_phys_offset a58: R_ARM_MOVT_ABS __pv_phys_offset a5c: e5999004 ldr r9, [r9, #4] ; r9 = high word of __pv_phys_offset a60: e3001000 movw r1, #0 a60: R_ARM_MOVW_ABS_NC mem_map a64: e592c000 ldr ip, [r2] ; ip = low word of __pv_phys_offset Reviewed-by: Nicolas Pitre <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent 83b3f64 commit e26a9e0

File tree

3 files changed

+34
-26
lines changed

3 files changed

+34
-26
lines changed

arch/arm/include/asm/memory.h

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,17 @@
169169
* Physical vs virtual RAM address space conversion. These are
170170
* private definitions which should NOT be used outside memory.h
171171
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
172+
*
173+
* PFNs are used to describe any physical page; this means
174+
* PFN 0 == physical address 0.
172175
*/
173-
#ifndef __virt_to_phys
174-
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
176+
#if defined(__virt_to_phys)
177+
#define PHYS_OFFSET PLAT_PHYS_OFFSET
178+
#define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT))
179+
180+
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
181+
182+
#elif defined(CONFIG_ARM_PATCH_PHYS_VIRT)
175183

176184
/*
177185
* Constants used to force the right instruction encodings and shifts
@@ -180,12 +188,17 @@
180188
#define __PV_BITS_31_24 0x81000000
181189
#define __PV_BITS_7_0 0x81
182190

183-
extern u64 __pv_phys_offset;
191+
extern unsigned long __pv_phys_pfn_offset;
184192
extern u64 __pv_offset;
185193
extern void fixup_pv_table(const void *, unsigned long);
186194
extern const void *__pv_table_begin, *__pv_table_end;
187195

188-
#define PHYS_OFFSET __pv_phys_offset
196+
#define PHYS_OFFSET ((phys_addr_t)__pv_phys_pfn_offset << PAGE_SHIFT)
197+
#define PHYS_PFN_OFFSET (__pv_phys_pfn_offset)
198+
199+
#define virt_to_pfn(kaddr) \
200+
((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \
201+
PHYS_PFN_OFFSET)
189202

190203
#define __pv_stub(from,to,instr,type) \
191204
__asm__("@ __pv_stub\n" \
@@ -246,6 +259,7 @@ static inline unsigned long __phys_to_virt(phys_addr_t x)
246259
#else
247260

248261
#define PHYS_OFFSET PLAT_PHYS_OFFSET
262+
#define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT))
249263

250264
static inline phys_addr_t __virt_to_phys(unsigned long x)
251265
{
@@ -257,18 +271,11 @@ static inline unsigned long __phys_to_virt(phys_addr_t x)
257271
return x - PHYS_OFFSET + PAGE_OFFSET;
258272
}
259273

260-
#endif
261-
#endif
274+
#define virt_to_pfn(kaddr) \
275+
((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \
276+
PHYS_PFN_OFFSET)
262277

263-
/*
264-
* PFNs are used to describe any physical page; this means
265-
* PFN 0 == physical address 0.
266-
*
267-
* This is the PFN of the first RAM page in the kernel
268-
* direct-mapped view. We assume this is the first page
269-
* of RAM in the mem_map as well.
270-
*/
271-
#define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT))
278+
#endif
272279

273280
/*
274281
* These are *only* valid on the kernel direct mapped RAM memory.
@@ -346,9 +353,9 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
346353
*/
347354
#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET
348355

349-
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
356+
#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
350357
#define virt_addr_valid(kaddr) (((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) \
351-
&& pfn_valid(__pa(kaddr) >> PAGE_SHIFT) )
358+
&& pfn_valid(virt_to_pfn(kaddr)))
352359

353360
#endif
354361

arch/arm/kernel/armksyms.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,6 @@ EXPORT_SYMBOL(__gnu_mcount_nc);
158158
#endif
159159

160160
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
161-
EXPORT_SYMBOL(__pv_phys_offset);
161+
EXPORT_SYMBOL(__pv_phys_pfn_offset);
162162
EXPORT_SYMBOL(__pv_offset);
163163
#endif

arch/arm/kernel/head.S

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -584,9 +584,10 @@ __fixup_pv_table:
584584
subs r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
585585
add r4, r4, r3 @ adjust table start address
586586
add r5, r5, r3 @ adjust table end address
587-
add r6, r6, r3 @ adjust __pv_phys_offset address
587+
add r6, r6, r3 @ adjust __pv_phys_pfn_offset address
588588
add r7, r7, r3 @ adjust __pv_offset address
589-
str r8, [r6, #LOW_OFFSET] @ save computed PHYS_OFFSET to __pv_phys_offset
589+
mov r0, r8, lsr #12 @ convert to PFN
590+
str r0, [r6, #LOW_OFFSET] @ save computed PHYS_OFFSET to __pv_phys_pfn_offset
590591
strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits
591592
mov r6, r3, lsr #24 @ constant for add/sub instructions
592593
teq r3, r6, lsl #24 @ must be 16MiB aligned
@@ -600,7 +601,7 @@ ENDPROC(__fixup_pv_table)
600601
1: .long .
601602
.long __pv_table_begin
602603
.long __pv_table_end
603-
2: .long __pv_phys_offset
604+
2: .long __pv_phys_pfn_offset
604605
.long __pv_offset
605606

606607
.text
@@ -688,11 +689,11 @@ ENTRY(fixup_pv_table)
688689
ENDPROC(fixup_pv_table)
689690

690691
.data
691-
.globl __pv_phys_offset
692-
.type __pv_phys_offset, %object
693-
__pv_phys_offset:
694-
.quad 0
695-
.size __pv_phys_offset, . -__pv_phys_offset
692+
.globl __pv_phys_pfn_offset
693+
.type __pv_phys_pfn_offset, %object
694+
__pv_phys_pfn_offset:
695+
.word 0
696+
.size __pv_phys_pfn_offset, . -__pv_phys_pfn_offset
696697

697698
.globl __pv_offset
698699
.type __pv_offset, %object

0 commit comments

Comments
 (0)