5031e5a2e78bffc7e5aced270c6dc7435344f454
[linux-2.6-microblaze.git] / arch / arm / kernel / phys2virt.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  *  Copyright (C) 1994-2002 Russell King
4  *  Copyright (c) 2003 ARM Limited
5  *  All Rights Reserved
6  */
7
8 #include <linux/init.h>
9 #include <linux/linkage.h>
10 #include <asm/assembler.h>
11 #include <asm/page.h>
12
13 #ifdef __ARMEB__
14 #define LOW_OFFSET      0x4
15 #define HIGH_OFFSET     0x0
16 #else
17 #define LOW_OFFSET      0x0
18 #define HIGH_OFFSET     0x4
19 #endif
20
21 /*
22  * __fixup_pv_table - patch the stub instructions with the delta between
23  *                    PHYS_OFFSET and PAGE_OFFSET, which is assumed to be
24  *                    16MiB aligned.
25  *
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
29  */
30         __HEAD
31 ENTRY(__fixup_pv_table)
32         adr     r0, 1f
33         ldmia   r0, {r3-r7}
34         mvn     ip, #0
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
45         bne     0f
46         str     r3, [r7, #LOW_OFFSET]   @ save to __pv_offset low bits
47         b       __fixup_a_pv_table
48 0:      mov     r0, r0                  @ deadloop on error
49         b       0b
50 ENDPROC(__fixup_pv_table)
51
52         .align
53 1:      .long   .
54         .long   __pv_table_begin
55         .long   __pv_table_end
56 2:      .long   __pv_phys_pfn_offset
57         .long   __pv_offset
58
59         .text
60 __fixup_a_pv_table:
61         adr     r0, 3f
62         ldr     r6, [r0]
63         add     r6, r6, r3
64         ldr     r0, [r6, #HIGH_OFFSET]  @ pv_offset high word
65         ldr     r6, [r6, #LOW_OFFSET]   @ pv_offset low word
66         mov     r6, r6, lsr #24
67         cmn     r0, #1
68 #ifdef CONFIG_THUMB2_KERNEL
69         moveq   r0, #0x200000           @ set bit 21, mov to mvn instruction
70         lsls    r6, #24
71         beq     .Lnext
72         clz     r7, r6
73         lsr     r6, #24
74         lsl     r6, r7
75         bic     r6, #0x0080
76         lsrs    r7, #1
77         orrcs   r6, #0x0080
78         orr     r6, r6, r7, lsl #12
79         orr     r6, #0x4000
80         b       .Lnext
81 .Lloop: add     r7, r3
82         ldrh    ip, [r7, #2]
83 ARM_BE8(rev16   ip, ip)
84         tst     ip, #0x4000
85         and     ip, #0x8f00
86         orrne   ip, r6                  @ mask in offset bits 31-24
87         orreq   ip, r0                  @ mask in offset bits 7-0
88 ARM_BE8(rev16   ip, ip)
89         strh    ip, [r7, #2]
90         bne     .Lnext
91         ldrh    ip, [r7]
92 ARM_BE8(rev16   ip, ip)
93         bic     ip, #0x20
94         orr     ip, ip, r0, lsr #16
95 ARM_BE8(rev16   ip, ip)
96         strh    ip, [r7]
97 #else
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
103 #else
104 #define PV_BIT22        0x00400000
105 #define PV_IMM8_MASK    0x000000ff
106 #define PV_ROT_MASK     0xf00
107 #endif
108
109         moveq   r0, #0x400000           @ set bit 22, mov to mvn instruction
110         b       .Lnext
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)
117         str     ip, [r7, r3]
118 #endif
119
120 .Lnext:
121         cmp     r4, r5
122         ldrcc   r7, [r4], #4            @ use branch for delay slot
123         bcc     .Lloop
124         ret     lr
125 ENDPROC(__fixup_a_pv_table)
126
127         .align
128 3:      .long __pv_offset
129
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)
138
139         .data
140         .align  2
141         .globl  __pv_phys_pfn_offset
142         .type   __pv_phys_pfn_offset, %object
143 __pv_phys_pfn_offset:
144         .word   0
145         .size   __pv_phys_pfn_offset, . -__pv_phys_pfn_offset
146
147         .globl  __pv_offset
148         .type   __pv_offset, %object
149 __pv_offset:
150         .quad   0
151         .size   __pv_offset, . -__pv_offset