source: mainline/kernel/arch/sparc64/src/sun4u/start.S

Last change on this file was 65f3117, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 2 years ago

Make bootstrap stack statically, rather than dynamically allocated

With aligment requirements being part of the language now, it is
simple to allocate the extra stack area in kernel data, and we
don't need to go to so much trouble with manual allocation.
It also makes it slightly more straightforward to use the stack
from assembly, without having to dig through a saved context
structure.

  • Property mode set to 100644
File size: 11.7 KB
Line 
1#
2# Copyright (c) 2005 Jakub Jermar
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8#
9# - Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# - Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# - The name of the author may not be used to endorse or promote products
15# derived from this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28
29#include <abi/asmtool.h>
30
31#include <arch/arch.h>
32#include <arch/cpu.h>
33#include <arch/regdef.h>
34#include <arch/boot/boot.h>
35#include <arch/stack.h>
36
37#include <arch/mm/mmu.h>
38#include <arch/mm/tlb.h>
39#include <arch/mm/tte.h>
40#include <arch/mm/cache_spec.h>
41
42#ifdef CONFIG_SMP
43#include <arch/context_struct.h>
44#endif
45
46.register %g2, #scratch
47.register %g3, #scratch
48
49.section K_TEXT_START, "ax"
50
51#define BSP_FLAG 1
52
53/*
54 * 2^PHYSMEM_ADDR_SIZE is the size of the physical address space on
55 * a given processor.
56 */
57#if defined (US)
58 #define PHYSMEM_ADDR_SIZE 41
59#elif defined (US3)
60 #define PHYSMEM_ADDR_SIZE 43
61#endif
62
63/*
64 * Here is where the kernel is passed control from the boot loader.
65 *
66 * The registers are expected to be in this state:
67 * - %o0 starting address of physical memory
68 * + bootstrap processor flag
69 * bits 63...1: physical memory starting address / 2
70 * bit 0: non-zero on BSP processor, zero on AP processors
71 * - %o1 bootinfo structure address (BSP only)
72 *
73 *
74 * Moreover, we depend on boot having established the following environment:
75 * - TLBs are on
76 * - identity mapping for the kernel image
77 *
78 */
79
80SYMBOL(kernel_image_start)
81 mov BSP_FLAG, %l0
82 and %o0, %l0, %l7 ! l7 <= bootstrap processor?
83 andn %o0, %l0, %l6 ! l6 <= start of physical memory
84
85 ! Get bits (PHYSMEM_ADDR_SIZE - 1):13 of physmem_base.
86 srlx %l6, 13, %l5
87
88 ! l5 <= physmem_base[(PHYSMEM_ADDR_SIZE - 1):13]
89 sllx %l5, 13 + (63 - (PHYSMEM_ADDR_SIZE - 1)), %l5
90 srlx %l5, 63 - (PHYSMEM_ADDR_SIZE - 1), %l5
91
92 /*
93 * Setup basic runtime environment.
94 */
95
96 wrpr %g0, NWINDOWS - 2, %cansave ! set maximum saveable windows
97 wrpr %g0, 0, %canrestore ! get rid of windows we will
98 ! never need again
99 wrpr %g0, 0, %otherwin ! make sure the window state is
100 ! consistent
101 wrpr %g0, NWINDOWS - 1, %cleanwin ! prevent needless clean_window
102 ! traps for kernel
103
104 wrpr %g0, 0, %wstate ! use default spill/fill trap
105
106 wrpr %g0, 0, %tl ! TL = 0, primary context
107 ! register is used
108
109 wrpr %g0, PSTATE_PRIV_BIT, %pstate ! disable interrupts and disable
110 ! 32-bit address masking
111
112 wrpr %g0, 0, %pil ! intialize %pil
113
114 /*
115 * Switch to kernel trap table.
116 */
117 sethi %hi(trap_table), %g1
118 wrpr %g1, %lo(trap_table), %tba
119
120 /*
121 * Take over the DMMU by installing locked TTE entry identically
122 * mapping the first 4M of memory.
123 *
124 * In case of DMMU, no FLUSH instructions need to be issued. Because of
125 * that, the old DTLB contents can be demapped pretty straightforwardly
126 * and without causing any traps.
127 */
128
129 wr %g0, ASI_DMMU, %asi
130
131#define SET_TLB_DEMAP_CMD(r1, context_id) \
132 set (TLB_DEMAP_CONTEXT << TLB_DEMAP_TYPE_SHIFT) | (context_id << \
133 TLB_DEMAP_CONTEXT_SHIFT), %r1
134
135 ! demap context 0
136 SET_TLB_DEMAP_CMD(g1, TLB_DEMAP_NUCLEUS)
137 stxa %g0, [%g1] ASI_DMMU_DEMAP
138 membar #Sync
139
140#define SET_TLB_TAG(r1, context) \
141 set VMA | (context << TLB_TAG_ACCESS_CONTEXT_SHIFT), %r1
142
143 ! write DTLB tag
144 SET_TLB_TAG(g1, MEM_CONTEXT_KERNEL)
145 stxa %g1, [VA_DMMU_TAG_ACCESS] %asi
146 membar #Sync
147
148#ifdef CONFIG_VIRT_IDX_DCACHE
149#define TTE_LOW_DATA(imm) (TTE_CP | TTE_CV | TTE_P | LMA | (imm))
150#else /* CONFIG_VIRT_IDX_DCACHE */
151#define TTE_LOW_DATA(imm) (TTE_CP | TTE_P | LMA | (imm))
152#endif /* CONFIG_VIRT_IDX_DCACHE */
153
154#define SET_TLB_DATA(r1, r2, imm) \
155 set TTE_LOW_DATA(imm), %r1; \
156 or %r1, %l5, %r1; \
157 mov PAGESIZE_4M, %r2; \
158 sllx %r2, TTE_SIZE_SHIFT, %r2; \
159 or %r1, %r2, %r1; \
160 mov 1, %r2; \
161 sllx %r2, TTE_V_SHIFT, %r2; \
162 or %r1, %r2, %r1;
163
164 ! write DTLB data and install the kernel mapping
165 SET_TLB_DATA(g1, g2, TTE_L | TTE_W) ! use non-global mapping
166 stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG
167 membar #Sync
168
169 /*
170 * Because we cannot use global mappings (because we want to have
171 * separate 64-bit address spaces for both the kernel and the
172 * userspace), we prepare the identity mapping also in context 1. This
173 * step is required by the code installing the ITLB mapping.
174 */
175 ! write DTLB tag of context 1 (i.e. MEM_CONTEXT_TEMP)
176 SET_TLB_TAG(g1, MEM_CONTEXT_TEMP)
177 stxa %g1, [VA_DMMU_TAG_ACCESS] %asi
178 membar #Sync
179
180 ! write DTLB data and install the kernel mapping in context 1
181 SET_TLB_DATA(g1, g2, TTE_W) ! use non-global mapping
182 stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG
183 membar #Sync
184
185 /*
186 * Now is time to take over the IMMU. Unfortunatelly, it cannot be done
187 * as easily as the DMMU, because the IMMU is mapping the code it
188 * executes.
189 *
190 * [ Note that brave experiments with disabling the IMMU and using the
191 * DMMU approach failed after a dozen of desparate days with only little
192 * success. ]
193 *
194 * The approach used here is inspired from OpenBSD. First, the kernel
195 * creates IMMU mapping for itself in context 1 (MEM_CONTEXT_TEMP) and
196 * switches to it. Context 0 (MEM_CONTEXT_KERNEL) can be demapped
197 * afterwards and replaced with the kernel permanent mapping. Finally,
198 * the kernel switches back to context 0 and demaps context 1.
199 *
200 * Moreover, the IMMU requires use of the FLUSH instructions. But that
201 * is OK because we always use operands with addresses already mapped by
202 * the taken over DTLB.
203 */
204
205 set kernel_image_start, %g5
206
207 ! write ITLB tag of context 1
208 SET_TLB_TAG(g1, MEM_CONTEXT_TEMP)
209 mov VA_DMMU_TAG_ACCESS, %g2
210 stxa %g1, [%g2] ASI_IMMU
211 flush %g5
212
213 ! write ITLB data and install the temporary mapping in context 1
214 SET_TLB_DATA(g1, g2, 0) ! use non-global mapping
215 stxa %g1, [%g0] ASI_ITLB_DATA_IN_REG
216 flush %g5
217
218 ! switch to context 1
219 mov MEM_CONTEXT_TEMP, %g1
220 stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi ! ASI_DMMU is correct here !!!
221 flush %g5
222
223 ! demap context 0
224 SET_TLB_DEMAP_CMD(g1, TLB_DEMAP_NUCLEUS)
225 stxa %g0, [%g1] ASI_IMMU_DEMAP
226 flush %g5
227
228 ! write ITLB tag of context 0
229 SET_TLB_TAG(g1, MEM_CONTEXT_KERNEL)
230 mov VA_DMMU_TAG_ACCESS, %g2
231 stxa %g1, [%g2] ASI_IMMU
232 flush %g5
233
234 ! write ITLB data and install the permanent kernel mapping in context 0
235 SET_TLB_DATA(g1, g2, TTE_L) ! use non-global mapping
236 stxa %g1, [%g0] ASI_ITLB_DATA_IN_REG
237 flush %g5
238
239 ! enter nucleus - using context 0
240 wrpr %g0, 1, %tl
241
242 ! demap context 1
243 SET_TLB_DEMAP_CMD(g1, TLB_DEMAP_PRIMARY)
244 stxa %g0, [%g1] ASI_IMMU_DEMAP
245 flush %g5
246
247 ! set context 0 in the primary context register
248 stxa %g0, [VA_PRIMARY_CONTEXT_REG] %asi ! ASI_DMMU is correct here !!!
249 flush %g5
250
251 ! leave nucleus - using primary context, i.e. context 0
252 wrpr %g0, 0, %tl
253
254 brz %l7, 1f ! skip if you are not the bootstrap CPU
255 nop
256
257 /*
258 * Save physmem_base for use by the mm subsystem.
259 * %l6 contains starting physical address
260 */
261 sethi %hi(physmem_base), %l4
262 stx %l6, [%l4 + %lo(physmem_base)]
263
264 /*
265 * Precompute kernel 8K TLB data template.
266 * %l5 contains starting physical address
267 * bits [(PHYSMEM_ADDR_SIZE - 1):13]
268 */
269 sethi %hi(kernel_8k_tlb_data_template), %l4
270 ldx [%l4 + %lo(kernel_8k_tlb_data_template)], %l3
271 or %l3, %l5, %l3
272 stx %l3, [%l4 + %lo(kernel_8k_tlb_data_template)]
273
274 ! flush the whole D-cache
275 set (DCACHE_SIZE - DCACHE_LINE_SIZE), %g1
276 stxa %g0, [%g1] ASI_DCACHE_TAG
277
2780:
279 membar #Sync
280 subcc %g1, DCACHE_LINE_SIZE, %g1
281 bnz,pt %xcc, 0b
282 stxa %g0, [%g1] ASI_DCACHE_TAG
283 membar #Sync
284
285 /*
286 * So far, we have not touched the stack.
287 * It is a good idea to set the kernel stack to a known state now.
288 */
289 sethi %hi(temporary_boot_stack), %sp
290 or %sp, %lo(temporary_boot_stack), %sp
291 sub %sp, STACK_BIAS, %sp
292
293 /*
294 * Call sparc64_pre_main(bootinfo)
295 */
296 call sparc64_pre_main
297 mov %o1, %o0
298
299 /*
300 * Create the first stack frame.
301 */
302 save %sp, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
303 flushw
304 add %g0, -STACK_BIAS, %fp
305
306 call main_bsp
307 nop
308
309 /* Not reached. */
310
3110:
312 ba,a %xcc, 0b
313
314
3151:
316#ifdef CONFIG_SMP
317 /*
318 * Determine the width of the MID and save its mask to %g3. The width
319 * is
320 * * 5 for US and US-IIIi,
321 * * 10 for US3 except US-IIIi.
322 */
323#if defined(US)
324 mov 0x1f, %g3
325#elif defined(US3)
326 mov 0x3ff, %g3
327 rdpr %ver, %g2
328 sllx %g2, 16, %g2
329 srlx %g2, 48, %g2
330 cmp %g2, IMPL_ULTRASPARCIII_I
331 move %xcc, 0x1f, %g3
332#endif
333
334 /*
335 * Read MID from the processor.
336 */
337 ldxa [%g0] ASI_ICBUS_CONFIG, %g1
338 srlx %g1, ICBUS_CONFIG_MID_SHIFT, %g1
339 and %g1, %g3, %g1
340
341 /*
342 * Active loop for APs until the BSP picks them up. A processor cannot
343 * leave the loop until the global variable 'waking_up_mid' equals its
344 * MID.
345 */
346 set waking_up_mid, %g2
3472:
348 ldx [%g2], %g3
349 cmp %g3, %g1
350 bne %xcc, 2b
351 nop
352
353 /*
354 * Configure stack for the AP.
355 * The AP is expected to use the stack saved
356 * in the ctx global variable.
357 */
358 set bootstrap_stack_top, %g1
359 ldx [%g1], %o6
360
361 /*
362 * Create the first stack frame.
363 */
364 save %sp, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
365 flushw
366 add %g0, -STACK_BIAS, %fp
367
368 call main_ap
369 nop
370
371 /* Not reached. */
372#endif
373
3740:
375 ba,a %xcc, 0b
376
377
378.section K_DATA_START, "aw", @progbits
379
380/*
381 * Create small stack to be used by the bootstrap processor. It is going to be
382 * used only for a very limited period of time, but we switch to it anyway,
383 * just to be sure we are properly initialized.
384 */
385
386#define INITIAL_STACK_SIZE 1024
387
388.align STACK_ALIGNMENT
389 .space INITIAL_STACK_SIZE
390.align STACK_ALIGNMENT
391temporary_boot_stack:
392 .space STACK_WINDOW_SAVE_AREA_SIZE
393
394
395.data
396
397.align 8
398SYMBOL(physmem_base) ! copy of the physical memory base address
399 .quad 0
400
401/*
402 * The fast_data_access_mmu_miss_data_hi label, the end_of_identity,
403 * kernel_8k_tlb_data_template and tlb_tag_access_context_mask variables
404 * are meant to stay together, aligned on a 32B boundary.
405 */
406
407.align 32
408/*
409 * This label is used by the fast_data_access_MMU_miss trap handler.
410 */
411SYMBOL(fast_data_access_mmu_miss_data_hi)
412/*
413 * This variable is used by the fast_data_access_MMU_miss trap handler.
414 * In runtime, it is modified to contain the address of the end of physical
415 * memory.
416 */
417SYMBOL(end_of_identity)
418 .quad -1
419/*
420 * This variable is used by the fast_data_access_MMU_miss trap handler.
421 * In runtime, it is further modified to reflect the starting address of
422 * physical memory.
423 */
424SYMBOL(kernel_8k_tlb_data_template)
425#ifdef CONFIG_VIRT_IDX_DCACHE
426 .quad ((1 << TTE_V_SHIFT) | (PAGESIZE_8K << TTE_SIZE_SHIFT) | TTE_CP | \
427 TTE_CV | TTE_P | TTE_W)
428#else /* CONFIG_VIRT_IDX_DCACHE */
429 .quad ((1 << TTE_V_SHIFT) | (PAGESIZE_8K << TTE_SIZE_SHIFT) | TTE_CP | \
430 TTE_P | TTE_W)
431#endif /* CONFIG_VIRT_IDX_DCACHE */
432
433/*
434 * This variable is used by the fast_data_access_MMU_miss trap handler.
435 * It allows us to save one precious instruction slot of this handler.
436 */
437SYMBOL(tlb_tag_access_context_mask)
438 .quad TLB_TAG_ACCESS_CONTEXT_MASK
439
Note: See TracBrowser for help on using the repository browser.