Commit | Line | Data |
---|---|---|
e03167b2 RK |
1 | /* |
2 | * Early kernel startup code for Hexagon | |
3 | * | |
7c6a5df4 | 4 | * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. |
e03167b2 RK |
5 | * |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 and | |
9 | * only version 2 as published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
19 | * 02110-1301, USA. | |
20 | */ | |
21 | ||
22 | #include <linux/linkage.h> | |
23 | #include <linux/init.h> | |
24 | #include <asm/asm-offsets.h> | |
25 | #include <asm/mem-layout.h> | |
26 | #include <asm/vm_mmu.h> | |
27 | #include <asm/page.h> | |
20f704b6 RK |
28 | #include <asm/hexagon_vm.h> |
29 | ||
30 | #define SEGTABLE_ENTRIES #0x0e0 | |
e03167b2 RK |
31 | |
32 | __INIT | |
33 | ENTRY(stext) | |
34 | /* | |
35 | * VMM will already have set up true vector page, MMU, etc. | |
36 | * To set up initial kernel identity map, we have to pass | |
37 | * the VMM a pointer to some canonical page tables. In | |
38 | * this implementation, we're assuming that we've got | |
39 | * them precompiled. Generate value in R24, as we'll need | |
40 | * it again shortly. | |
41 | */ | |
42 | r24.L = #LO(swapper_pg_dir) | |
43 | r24.H = #HI(swapper_pg_dir) | |
44 | ||
45 | /* | |
46 | * Symbol is kernel segment address, but we need | |
47 | * the logical/physical address. | |
48 | */ | |
8f5a0b9d RK |
49 | r25 = pc; |
50 | r2.h = #0xffc0; | |
51 | r2.l = #0x0000; | |
52 | r25 = and(r2,r25); /* R25 holds PHYS_OFFSET now */ | |
53 | r1.h = #HI(PAGE_OFFSET); | |
54 | r1.l = #LO(PAGE_OFFSET); | |
55 | r24 = sub(r24,r1); /* swapper_pg_dir - PAGE_OFFSET */ | |
56 | r24 = add(r24,r25); /* + PHYS_OFFSET */ | |
e03167b2 | 57 | |
8f5a0b9d | 58 | r0 = r24; /* aka __pa(swapper_pg_dir) */ |
e03167b2 RK |
59 | |
60 | /* | |
8f5a0b9d | 61 | * Initialize page dir to make the virtual and physical |
e03167b2 | 62 | * addresses where the kernel was loaded be identical. |
8f5a0b9d | 63 | * Done in 4MB chunks. |
e03167b2 RK |
64 | */ |
65 | #define PTE_BITS ( __HVM_PTE_R | __HVM_PTE_W | __HVM_PTE_X \ | |
66 | | __HEXAGON_C_WB_L2 << 6 \ | |
67 | | __HVM_PDE_S_4MB) | |
68 | ||
20f704b6 RK |
69 | /* |
70 | * Get number of VA=PA entries; only really needed for jump | |
71 | * to hyperspace; gets blown away immediately after | |
72 | */ | |
73 | ||
74 | { | |
75 | r1.l = #LO(_end); | |
76 | r2.l = #LO(stext); | |
77 | r3 = #1; | |
78 | } | |
79 | { | |
80 | r1.h = #HI(_end); | |
81 | r2.h = #HI(stext); | |
82 | r3 = asl(r3, #22); | |
83 | } | |
84 | { | |
85 | r1 = sub(r1, r2); | |
86 | r3 = add(r3, #-1); | |
87 | } /* r1 = _end - stext */ | |
88 | r1 = add(r1, r3); /* + (4M-1) */ | |
89 | r26 = lsr(r1, #22); /* / 4M = # of entries */ | |
90 | ||
91 | r1 = r25; | |
92 | r2.h = #0xffc0; | |
93 | r2.l = #0x0000; /* round back down to 4MB boundary */ | |
94 | r1 = and(r1,r2); | |
e03167b2 RK |
95 | r2 = lsr(r1, #22) /* 4MB page number */ |
96 | r2 = asl(r2, #2) /* times sizeof(PTE) (4bytes) */ | |
97 | r0 = add(r0,r2) /* r0 = address of correct PTE */ | |
98 | r2 = #PTE_BITS | |
99 | r1 = add(r1,r2) /* r1 = 4MB PTE for the first entry */ | |
100 | r2.h = #0x0040 | |
20f704b6 RK |
101 | r2.l = #0x0000 /* 4MB increments */ |
102 | loop0(1f,r26); | |
103 | 1: | |
e03167b2 | 104 | memw(r0 ++ #4) = r1 |
20f704b6 | 105 | { r1 = add(r1, r2); } :endloop0 |
e03167b2 | 106 | |
20f704b6 RK |
107 | /* Also need to overwrite the initial 0xc0000000 entries */ |
108 | /* PAGE_OFFSET >> (4MB shift - 4 bytes per entry shift) */ | |
109 | R1.H = #HI(PAGE_OFFSET >> (22 - 2)) | |
110 | R1.L = #LO(PAGE_OFFSET >> (22 - 2)) | |
111 | ||
112 | r0 = add(r1, r24); /* advance to 0xc0000000 entry */ | |
113 | r1 = r25; | |
114 | r2.h = #0xffc0; | |
115 | r2.l = #0x0000; /* round back down to 4MB boundary */ | |
116 | r1 = and(r1,r2); /* for huge page */ | |
117 | r2 = #PTE_BITS | |
118 | r1 = add(r1,r2); | |
119 | r2.h = #0x0040 | |
120 | r2.l = #0x0000 /* 4MB increments */ | |
121 | ||
122 | loop0(1f,SEGTABLE_ENTRIES); | |
123 | 1: | |
124 | memw(r0 ++ #4) = r1; | |
125 | { r1 = add(r1,r2); } :endloop0 | |
126 | ||
127 | r0 = r24; | |
e03167b2 RK |
128 | |
129 | /* | |
130 | * The subroutine wrapper around the virtual instruction touches | |
131 | * no memory, so we should be able to use it even here. | |
20f704b6 RK |
132 | * Note that in this version, R1 and R2 get "clobbered"; see |
133 | * vm_ops.S | |
e03167b2 | 134 | */ |
20f704b6 | 135 | r1 = #VM_TRANS_TYPE_TABLE |
e03167b2 RK |
136 | call __vmnewmap; |
137 | ||
138 | /* Jump into virtual address range. */ | |
139 | ||
140 | r31.h = #hi(__head_s_vaddr_target) | |
141 | r31.l = #lo(__head_s_vaddr_target) | |
142 | jumpr r31 | |
143 | ||
144 | /* Insert trippy space effects. */ | |
145 | ||
146 | __head_s_vaddr_target: | |
147 | /* | |
148 | * Tear down VA=PA translation now that we are running | |
20f704b6 | 149 | * in kernel virtual space. |
e03167b2 RK |
150 | */ |
151 | r0 = #__HVM_PDE_S_INVALID | |
20f704b6 RK |
152 | |
153 | r1.h = #0xffc0; | |
154 | r1.l = #0x0000; | |
155 | r2 = r25; /* phys_offset */ | |
156 | r2 = and(r1,r2); | |
157 | ||
158 | r1.l = #lo(swapper_pg_dir) | |
159 | r1.h = #hi(swapper_pg_dir) | |
160 | r2 = lsr(r2, #22) /* 4MB page number */ | |
161 | r2 = asl(r2, #2) /* times sizeof(PTE) (4bytes) */ | |
162 | r1 = add(r1,r2); | |
163 | loop0(1f,r26) | |
164 | ||
e03167b2 RK |
165 | 1: |
166 | { | |
167 | memw(R1 ++ #4) = R0 | |
168 | }:endloop0 | |
169 | ||
170 | r0 = r24 | |
20f704b6 | 171 | r1 = #VM_TRANS_TYPE_TABLE |
e03167b2 RK |
172 | call __vmnewmap |
173 | ||
174 | /* Go ahead and install the trap0 return so angel calls work */ | |
175 | r0.h = #hi(_K_provisional_vec) | |
176 | r0.l = #lo(_K_provisional_vec) | |
177 | call __vmsetvec | |
178 | ||
179 | /* | |
180 | * OK, at this point we should start to be much more careful, | |
181 | * we're going to enter C code and start touching memory | |
182 | * in all sorts of places. | |
183 | * This means: | |
184 | * SGP needs to be OK | |
185 | * Need to lock shared resources | |
186 | * A bunch of other things that will cause | |
187 | * all kinds of painful bugs | |
188 | */ | |
189 | ||
190 | /* | |
191 | * Stack pointer should be pointed at the init task's | |
192 | * thread stack, which should have been declared in arch/init_task.c. | |
193 | * So uhhhhh... | |
194 | * It's accessible via the init_thread_union, which is a union | |
195 | * of a thread_info struct and a stack; of course, the top | |
196 | * of the stack is not for you. The end of the stack | |
197 | * is simply init_thread_union + THREAD_SIZE. | |
198 | */ | |
199 | ||
200 | {r29.H = #HI(init_thread_union); r0.H = #HI(_THREAD_SIZE); } | |
201 | {r29.L = #LO(init_thread_union); r0.L = #LO(_THREAD_SIZE); } | |
202 | ||
203 | /* initialize the register used to point to current_thread_info */ | |
204 | /* Fixme: THREADINFO_REG can't be R2 because of that memset thing. */ | |
205 | {r29 = add(r29,r0); THREADINFO_REG = r29; } | |
206 | ||
207 | /* Hack: zero bss; */ | |
208 | { r0.L = #LO(__bss_start); r1 = #0; r2.l = #LO(__bss_stop); } | |
209 | { r0.H = #HI(__bss_start); r2.h = #HI(__bss_stop); } | |
210 | ||
211 | r2 = sub(r2,r0); | |
212 | call memset; | |
213 | ||
20f704b6 | 214 | /* Set PHYS_OFFSET; should be in R25 */ |
8f5a0b9d RK |
215 | #ifdef CONFIG_HEXAGON_PHYS_OFFSET |
216 | r0.l = #LO(__phys_offset); | |
217 | r0.h = #HI(__phys_offset); | |
218 | memw(r0) = r25; | |
219 | #endif | |
220 | ||
e03167b2 RK |
221 | /* Time to make the doughnuts. */ |
222 | call start_kernel | |
223 | ||
224 | /* | |
225 | * Should not reach here. | |
226 | */ | |
227 | 1: | |
228 | jump 1b | |
229 | ||
230 | .p2align PAGE_SHIFT | |
231 | ENTRY(external_cmdline_buffer) | |
232 | .fill _PAGE_SIZE,1,0 | |
233 | ||
234 | .data | |
235 | .p2align PAGE_SHIFT | |
236 | ENTRY(empty_zero_page) | |
237 | .fill _PAGE_SIZE,1,0 |