1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Copyright (C) 1994-2002 Russell King
4 * Copyright (c) 2003 ARM Limited
8 #include <linux/init.h>
9 #include <linux/linkage.h>
10 #include <asm/assembler.h>
14 #define LOW_OFFSET 0x4
15 #define HIGH_OFFSET 0x0
17 #define LOW_OFFSET 0x0
18 #define HIGH_OFFSET 0x4
22 * __fixup_pv_table - patch the stub instructions with the delta between
23 * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be
26 * Called from head.S, which expects the following registers to be preserved:
27 * r1 = machine no, r2 = atags or dtb,
28 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
31 ENTRY(__fixup_pv_table)
35 subs r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
36 add r4, r4, r3 @ adjust table start address
37 add r5, r5, r3 @ adjust table end address
38 add r6, r6, r3 @ adjust __pv_phys_pfn_offset address
39 add r7, r7, r3 @ adjust __pv_offset address
40 mov r0, r8, lsr #PAGE_SHIFT @ convert to PFN
41 str r0, [r6] @ save computed PHYS_OFFSET to __pv_phys_pfn_offset
42 strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits
43 mov r6, r3, lsr #24 @ constant for add/sub instructions
44 teq r3, r6, lsl #24 @ must be 16MiB aligned
46 str r3, [r7, #LOW_OFFSET] @ save to __pv_offset low bits
48 0: mov r0, r0 @ deadloop on error
50 ENDPROC(__fixup_pv_table)
54 .long __pv_table_begin
56 2: .long __pv_phys_pfn_offset
64 ldr r0, [r6, #HIGH_OFFSET] @ pv_offset high word
65 ldr r6, [r6, #LOW_OFFSET] @ pv_offset low word
68 #ifdef CONFIG_THUMB2_KERNEL
69 moveq r0, #0x200000 @ set bit 21, mov to mvn instruction
78 orr r6, r6, r7, lsl #12
86 orrne ip, r6 @ mask in offset bits 31-24
87 orreq ip, r0 @ mask in offset bits 7-0
94 orr ip, ip, r0, lsr #16
98 #ifdef CONFIG_CPU_ENDIAN_BE8
99 @ in BE8, we load data in BE, but instructions still in LE
100 #define PV_BIT22 0x00004000
101 #define PV_IMM8_MASK 0xff000000
102 #define PV_ROT_MASK 0x000f0000
104 #define PV_BIT22 0x00400000
105 #define PV_IMM8_MASK 0x000000ff
106 #define PV_ROT_MASK 0xf00
109 moveq r0, #0x400000 @ set bit 22, mov to mvn instruction
111 .Lloop: ldr ip, [r7, r3]
112 bic ip, ip, #PV_IMM8_MASK
113 tst ip, #PV_ROT_MASK @ check the rotation field
114 orrne ip, ip, r6 ARM_BE8(, lsl #24) @ mask in offset bits 31-24
115 biceq ip, ip, #PV_BIT22 @ clear bit 22
116 orreq ip, ip, r0 ARM_BE8(, ror #8) @ mask in offset bits 7-0 (or bit 22)
122 ldrcc r7, [r4], #4 @ use branch for delay slot
125 ENDPROC(__fixup_a_pv_table)
130 ENTRY(fixup_pv_table)
131 stmfd sp!, {r4 - r7, lr}
132 mov r3, #0 @ no offset
133 mov r4, r0 @ r0 = table start
134 add r5, r0, r1 @ r1 = table size
135 bl __fixup_a_pv_table
136 ldmfd sp!, {r4 - r7, pc}
137 ENDPROC(fixup_pv_table)
141 .globl __pv_phys_pfn_offset
142 .type __pv_phys_pfn_offset, %object
143 __pv_phys_pfn_offset:
145 .size __pv_phys_pfn_offset, . -__pv_phys_pfn_offset
148 .type __pv_offset, %object
151 .size __pv_offset, . -__pv_offset