1 /* $Id: head.S,v 1.61 1999/05/25 16:53:10 jj Exp $
2 * head.S: Initial boot code for the Sparc64 port of Linux.
4 * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
6 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7 * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
10 #include <linux/config.h>
11 #include <linux/version.h>
12 #include <linux/errno.h>
13 #include <asm/asm_offsets.h>
15 #include <asm/pstate.h>
16 #include <asm/ptrace.h>
17 #include <asm/spitfire.h>
19 #include <asm/pgtable.h>
20 #include <asm/errno.h>
21 #include <asm/signal.h>
22 #include <asm/processor.h>
25 #include <asm/ttable.h>
27 /* This section from from _start to sparc64_boot_end should fit into
28 * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
29 * with bootup_user_stack, which is from 0x0000.0000.0040.4000 to
30 * 0x0000.0000.0040.6000 and empty_bad_page, which is from
31 * 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000.
35 .globl start, _start, stext, _stext
43 flushw /* Flush register file. */
45 /* This stuff has to be in sync with SILO and other potential boot loaders
46 * Fields should be kept upward compatible and whenever any change is made,
47 * HdrS version should be incremented.
49 .global root_flags, ram_flags, root_dev
50 .global sparc_ramdisk_image, sparc_ramdisk_size
54 .word LINUX_VERSION_CODE
55 .half 0x0202 /* HdrS version */
69 /* We must be careful, 32-bit OpenBOOT will get confused if it
70 * tries to save away a register window to a 64-bit kernel
71 * stack address. Flush all windows, disable interrupts,
72 * remap if necessary, jump onto kernel trap table, then kernel
73 * stack, or else we die.
75 * PROM entry point is on %o4
78 /* Typically PROM has already enabled both MMU's and both on-chip
79 * caches, but we do it here anyway just to be paranoid.
81 mov (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1
82 stxa %g1, [%g0] ASI_LSU_CONTROL
85 * Make sure we are in privileged mode, have address masking,
86 * using the ordinary globals and have enabled floating
89 * Again, typically PROM has left %pil at 13 or similar, and
90 * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate.
92 wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
96 /* Ugly but necessary... */
97 sethi %hi(KERNBASE), %g7
98 sethi %hi(sparc64_cpu_startup), %g5
99 or %g5, %lo(sparc64_cpu_startup), %g5
101 sethi %hi(sparc64_cpu_startup_end), %g6
102 or %g6, %lo(sparc64_cpu_startup_end), %g6
104 sethi %hi(smp_trampoline), %g3
105 or %g3, %lo(smp_trampoline), %g3
118 /* %g5 holds the tlb data */
119 sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
121 or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
123 /* Base of physical memory cannot reliably be assumed to be
124 * at 0x0! Figure out where it happens to be. -DaveM
127 /* Put PADDR tlb data mask into %g3. */
128 sethi %uhi(_PAGE_PADDR), %g3
129 or %g3, %ulo(_PAGE_PADDR), %g3
131 sethi %hi(_PAGE_PADDR), %g7
132 or %g7, %lo(_PAGE_PADDR), %g7
135 /* Walk through entire ITLB, looking for entry which maps
136 * our %pc currently, stick PADDR from there into %g5 tlb data.
138 clr %l0 /* TLB entry walker. */
139 set 0x1fff, %l2 /* Page mask. */
141 andn %l3, %l2, %g2 /* vaddr comparator */
143 /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
144 ldxa [%l0] ASI_ITLB_TAG_READ, %g1
148 andn %g1, %l2, %g1 /* Get vaddr */
150 be,a,pn %xcc, got_tlbentry
151 ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
154 add %l0, (1 << 3), %l0
157 /* Nops here again, perhaps Cheetah/Blackbird are better behaved... */
161 and %g1, %g3, %g1 /* Mask to just get paddr bits. */
162 sub %g1, %g2, %g1 /* Get rid of %pc offset to get base. */
164 /* NOTE: We hold on to %g1 paddr base as we need it below to lock
165 * NOTE: the PROM cif code into the TLB.
168 or %g5, %g1, %g5 /* Or it into TAG being built. */
170 clr %l0 /* TLB entry walker. */
171 sethi %hi(KERNBASE), %g3 /* 4M lower limit */
172 sethi %hi(KERNBASE<<1), %g7 /* 8M upper limit */
173 mov TLB_TAG_ACCESS, %l7
175 /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
176 ldxa [%l0] ASI_ITLB_TAG_READ, %g1
180 andn %g1, %l2, %g1 /* Get vaddr */
186 stxa %g0, [%l7] ASI_IMMU
187 stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS
191 add %l0, (1 << 3), %l0
195 clr %l0 /* TLB entry walker. */
197 /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
198 ldxa [%l0] ASI_DTLB_TAG_READ, %g1
202 andn %g1, %l2, %g1 /* Get vaddr */
208 stxa %g0, [%l7] ASI_DMMU
209 stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
213 add %l0, (1 << 3), %l0
218 /* PROM never puts any TLB entries into the MMU with the lock bit
219 * set. So we gladly use tlb entry 63 for KERNBASE.
222 sethi %hi(KERNBASE), %g3
224 stxa %g3, [%l7] ASI_DMMU /* KERNBASE into TLB TAG */
225 stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */
227 stxa %g3, [%l7] ASI_IMMU /* KERNBASE into TLB TAG */
228 stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */
241 mov PRIMARY_CONTEXT, %g7
242 stxa %g0, [%g7] ASI_DMMU
245 mov SECONDARY_CONTEXT, %g7
246 stxa %g0, [%g7] ASI_DMMU
249 sethi %uhi(PAGE_OFFSET), %g4
252 /* We are now safely (we hope) in Nucleus context (0), rewrite
253 * the KERNBASE TTE's so they no longer have the global bit set.
254 * Don't forget to setup TAG_ACCESS first 8-)
256 mov TLB_TAG_ACCESS, %g2
257 stxa %g3, [%g2] ASI_IMMU
258 stxa %g3, [%g2] ASI_DMMU
261 ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
262 andn %g1, (_PAGE_G), %g1
263 stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
266 ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
267 andn %g1, (_PAGE_G), %g1
268 stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
271 /* Kill instruction prefetch queues. */
275 sethi %hi(init_task_union), %g6
276 or %g6, %lo(init_task_union), %g6
280 #if 0 /* We don't do it like this anymore, but for historical hack value
281 * I leave this snippet here to show how crazy we can be sometimes. 8-)
284 /* Setup "Linux Current Register", thanks Sun 8-) */
291 sllx %g5, (PAGE_SHIFT + 1), %g5
292 sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
301 or %l2, %lo(8191), %l2
302 sethi %hi(__bss_start), %l0
303 or %l0, %lo(__bss_start), %l0
305 or %l1, %lo(_end), %l1
318 /* Now clear empty_zero_page */
323 mov %l6, %o1 ! OpenPROM stack
325 mov %l7, %o0 ! OpenPROM cif handler
332 /* IMPORTANT NOTE: Whenever making changes here, check
333 * trampoline.S as well. -jj */
335 setup_tba: /* i0 = is_starfire */
339 sethi %hi(prom_tba), %o1
340 or %o1, %lo(prom_tba), %o1
343 /* Setup "Linux" globals 8-) */
346 wrpr %o1, (PSTATE_AG|PSTATE_IE), %pstate
347 sethi %hi(sparc64_ttable_tl0), %g5
351 /* Set up MMU globals */
352 wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate
354 /* Set fixed globals used by dTLB miss handler. */
355 #define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
356 #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
357 #ifdef THIS_IS_CHEETAH
358 #error Dave, make sure you took care of other issues in rest of sparc64 code...
359 #define VPTE_BASE 0xffe0000000000000
360 #else /* Spitfire/Blackbird */
361 #define VPTE_BASE 0xfffffffe00000000
364 stxa %g0, [%g1] ASI_DMMU
367 sethi %uhi(KERN_HIGHBITS), %g2
368 or %g2, %ulo(KERN_HIGHBITS), %g2
370 or %g2, KERN_LOWBITS, %g2
371 sethi %uhi(VPTE_BASE), %g3
372 or %g3, %ulo(VPTE_BASE), %g3
379 /* Setup Interrupt globals */
380 wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate
382 sethi %hi(__up_workvec), %g5
383 or %g5, %lo(__up_workvec), %g1
385 /* By definition of where we are, this is boot_cpu. */
386 sethi %hi(cpu_data), %g5
387 or %g5, %lo(cpu_data), %g5
389 brz,pt %i0, not_starfire
390 sethi %hi(0x1fff4000), %g1
391 or %g1, %lo(0x1fff4000), %g1
394 lduwa [%g1] ASI_PHYS_BYPASS_EC_E, %g1
395 b,pt %xcc, set_worklist
399 ldxa [%g0] ASI_UPA_CONFIG, %g1
403 /* In theory this is: &(cpu_data[boot_cpu_id].irq_worklists[0]) */
410 /* Kill PROM timer */
411 wr %g0, 0, %tick_cmpr
413 /* Ok, we're done setting up all the state our trap mechanims needs,
414 * now get back into normal globals and let the PROM know what is up.
416 wrpr %g0, %g0, %wstate
417 wrpr %o1, PSTATE_IE, %pstate
419 sethi %hi(sparc64_ttable_tl0), %g5
420 call prom_set_trap_table
424 or %o1, PSTATE_IE, %o1
431 .skip 0x2000 + _start - sparc64_boot_end
432 bootup_user_stack_end:
434 .globl empty_bad_page
439 /* This is just a hack to fool make depend config.h discovering
440 strategy: As the .S files below need config.h, but
441 make depend does not find it for them, we include config.h
451 .globl swapper_pg_dir
457 #include "winfixup.S"
460 /* This is just anal retentiveness on my part... */
467 .section ".fixup",#alloc,#execinstr
471 restore %g0, -EFAULT, %o0