1 /* $Id: head.S,v 1.11 1998/10/18 13:27:12 tsbogend Exp $
3 * arch/mips/kernel/head.S
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License. See the file "COPYING" in the main directory of this archive
9 * Copyright (C) 1994, 1995 Waldorf Electronics
10 * Written by Ralf Baechle and Andreas Busse
11 * Copyright (C) 1995, 1996, 1997, 1998 Ralf Baechle
12 * Copyright (C) 1996 Paul M. Antoine
13 * Modified for DECStation and hence R3000 support by Paul M. Antoine
14 * Further modifications by David S. Miller
16 * Head.S contains the MIPS exception handler and startup code.
18 #include <linux/config.h>
19 #include <linux/threads.h>
22 #include <asm/cacheops.h>
23 #include <asm/current.h>
24 #include <asm/offset.h>
25 #include <asm/processor.h>
26 #include <asm/regdef.h>
27 #include <asm/cachectl.h>
28 #include <asm/mipsregs.h>
29 #include <asm/mipsconfig.h>
30 #include <asm/stackframe.h>
31 #include <asm/bootinfo.h>
36 * Reserved space for exception handlers.
37 * Necessary for machines which link their kernels at KSEG0.
38 * FIXME: Use the initcode feature to get rid of unused handler
43 * This is space for the interrupt handlers.
44 * After trap_init() they are located at virtual address KSEG0.
46 * These handlers much be written in a relocatable manner
47 * because based upon the cpu type an arbitrary one of the
48 * following pieces of code will be copied to the KSEG0
51 /* TLB refill, EXL == 0, R4xx0, non-R4600 version */
54 LEAF(except_vec0_r4000)
56 mfc0 k0, CP0_BADVADDR # Get faulting address
57 _GET_CURRENT(k1) # get current task ptr
58 srl k0, k0, 22 # get pgd only bits
59 lw k1, THREAD_PGDIR(k1) # get task pg_dir
61 addu k1, k1, k0 # add in pgd offset
62 mfc0 k0, CP0_CONTEXT # get context reg
64 srl k0, k0, 1 # get pte offset
66 addu k1, k1, k0 # add in offset
67 lw k0, 0(k1) # get even pte
68 lw k1, 4(k1) # get odd pte
69 srl k0, k0, 6 # convert to entrylo0
70 mtc0 k0, CP0_ENTRYLO0 # load it
71 srl k1, k1, 6 # convert to entrylo1
72 mtc0 k1, CP0_ENTRYLO1 # load it
74 tlbwr # write random tlb entry
77 eret # return from trap
78 END(except_vec0_r4000)
80 /* TLB refill, EXL == 0, R4600 version */
81 LEAF(except_vec0_r4600)
84 _GET_CURRENT(k1) # get current task ptr
86 lw k1, THREAD_PGDIR(k1)
104 END(except_vec0_r4600)
106 /* TLB refill, EXL == 0, R4xx0, non-R4600 version */
109 LEAF(except_vec0_nevada)
111 mfc0 k0, CP0_BADVADDR # Get faulting address
112 _GET_CURRENT(k1) # get current task ptr
113 srl k0, k0, 22 # get pgd only bits
114 lw k1, THREAD_PGDIR(k1) # get task pg_dir
116 addu k1, k1, k0 # add in pgd offset
118 mfc0 k0, CP0_CONTEXT # get context reg
119 srl k0, k0, 1 # get pte offset
121 addu k1, k1, k0 # add in offset
122 lw k0, 0(k1) # get even pte
123 lw k1, 4(k1) # get odd pte
124 srl k0, k0, 6 # convert to entrylo0
125 mtc0 k0, CP0_ENTRYLO0 # load it
126 srl k1, k1, 6 # convert to entrylo1
127 mtc0 k1, CP0_ENTRYLO1 # load it
128 tlbwr # write random tlb entry
131 eret # return from trap
132 END(except_vec0_nevada)
134 /* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */
135 LEAF(except_vec0_r45k_bvahwbug)
137 mfc0 k0, CP0_BADVADDR
138 _GET_CURRENT(k1) # get current task ptr
140 lw k1, THREAD_PGDIR(k1)
153 mtc0 k0, CP0_ENTRYLO0
156 mtc0 k1, CP0_ENTRYLO1
162 END(except_vec0_r45k_bvahwbug)
165 /* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */
166 LEAF(except_vec0_r4k_mphwbug)
168 mfc0 k0, CP0_BADVADDR
169 _GET_CURRENT(k1) # get current task ptr
171 lw k1, THREAD_PGDIR(k1)
184 mtc0 k0, CP0_ENTRYLO0
187 mtc0 k1, CP0_ENTRYLO1
193 END(except_vec0_r4k_mphwbug)
196 /* TLB refill, EXL == 0, R4000 UP 250MHZ entrylo[01] hwbug version */
197 LEAF(except_vec0_r4k_250MHZhwbug)
199 mfc0 k0, CP0_BADVADDR
200 _GET_CURRENT(k1) # get current task ptr
202 lw k1, THREAD_PGDIR(k1)
213 mtc0 zero, CP0_ENTRYLO0
214 mtc0 k0, CP0_ENTRYLO0
216 mtc0 zero, CP0_ENTRYLO1
217 mtc0 k1, CP0_ENTRYLO1
223 END(except_vec0_r4k_250MHZhwbug)
226 /* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */
227 LEAF(except_vec0_r4k_MP250MHZhwbug)
229 mfc0 k0, CP0_BADVADDR
230 _GET_CURRENT(k1) # get current task ptr
232 lw k1, THREAD_PGDIR(k1)
245 mtc0 zero, CP0_ENTRYLO0
246 mtc0 k0, CP0_ENTRYLO0
249 mtc0 zero, CP0_ENTRYLO1
250 mtc0 k1, CP0_ENTRYLO1
256 END(except_vec0_r4k_MP250MHZhwbug)
259 /* TLB refill, EXL == 0, R[23]00 version */
260 LEAF(except_vec0_r2300)
262 mfc0 k0, CP0_BADVADDR
263 _GET_CURRENT(k1) # get current task ptr
265 lw k1, THREAD_PGDIR(k1)
275 mtc0 k0, CP0_ENTRYLO0
284 END(except_vec0_r2300)
287 /* XTLB refill, EXL == 0, R4xx0 cpus only use this... */
288 NESTED(except_vec1_generic, 0, sp)
291 /* Register saving is delayed as long as we don't know
292 * which registers really need to be saved.
296 lwu k0, (k1) # May cause another exception
298 dsrl k0, 6 # Convert to EntryLo format
299 dsrl k1, 6 # Convert to EntryLo format
300 dmtc0 k0, CP0_ENTRYLO0
301 dmtc0 k1, CP0_ENTRYLO1
302 nop # Needed for R4[04]00 pipeline
304 nop # Needed for R4[04]00 pipeline
308 nop /* Workaround for R4000 bug. */
310 END(except_vec1_generic)
313 LEAF(except_vec2_generic)
314 /* Famous last words: unreached */
316 PRINT("Cache error exception: c0_errorepc == %08x\n")
320 END(except_vec2_generic)
322 /* General exception vector R4000 version. */
323 NESTED(except_vec3_r4000, 0, sp)
328 beq k1, k0, handle_vced
330 beq k1, k0, handle_vcei
331 la k0, exception_handlers
339 * Big shit, we now may have two dirty primary cache lines for the same
340 * physical address. We can savely invalidate the line pointed to by
341 * c0_badvaddr because after return from this exception handler the load /
342 * store will be re-executed.
345 mfc0 k0, CP0_BADVADDR
350 cache Index_Store_Tag_D,(k0)
352 cache Hit_Writeback_Inv_SD,(k0)
353 lui k0, %hi(vced_count)
354 lw k1, %lo(vced_count)(k0)
356 sw k1, %lo(vced_count)(k0)
360 mfc0 k0, CP0_BADVADDR
361 cache Hit_Writeback_Inv_SD,(k0) # also cleans pi
362 lui k0, %hi(vcei_count)
363 lw k1, %lo(vcei_count)(k0)
365 sw k1, %lo(vcei_count)(k0)
368 END(except_vec3_r4000)
371 /* General exception vector. */
372 NESTED(except_vec3_generic, 0, sp)
375 la k0, exception_handlers
382 END(except_vec3_generic)
386 * Special interrupt vector for embedded MIPS. This is a
387 * dedicated interrupt vector which reduces interrupt processing
388 * overhead. The jump instruction will be inserted here at
389 * initialization time. This handler may only be 8 bytes in size!
391 NESTED(except_vec4, 0, sp)
392 1: j 1b /* Dummy, will be replaced */
399 NESTED(kernel_entry, 16, sp)
401 /* The following two symbols are used for kernel profiling. */
405 /* Determine which MIPS variant we are running on. */
411 /* The firmware/bootloader passes argc/argp/envp
412 * to us as arguments. But clear bss first because
413 * the romvec and other important info is stored there
424 jal prom_init /* prom_init(argc, argv, envp); */
431 #ifdef CONFIG_COBALT_MICRO_SERVER
437 * Determine the mmu/cache attached to this machine,
438 * then flush the tlb and caches. On the r4xx0
439 * variants this also sets CP0_WIRED to zero.
445 * Stack for kernel and init, current variable
447 la $28, init_task_union
448 addiu t0, $28, KERNEL_STACK_SIZE-32
452 /* Disable coprocessors */
454 li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX)
462 * Main should never return here, but
463 * just in case, we know what happens.
469 /* CPU type probing code, called at Kernel entry. */
474 li t2, PRID_IMP_R2000
482 li t2, PRID_IMP_R3000
486 li t2, PRID_REV_R3000A
498 li t2, PRID_IMP_R6000
506 li t2, PRID_IMP_R4000
510 li t2, PRID_REV_R4400
522 li t2, PRID_IMP_R6000A
530 li t2, PRID_IMP_R10000
538 li t2, PRID_IMP_R8000
546 li t2, PRID_IMP_R4600
554 li t2, PRID_IMP_R4700
562 li t2, PRID_IMP_R4650
570 li t2, PRID_IMP_R5000
578 li t2, PRID_IMP_NEVADA
594 * This buffer is reserved for the use of the cache error handler.
597 EXPORT(cache_error_buffer)
605 EXPORT(swapper_pg_dir)
608 EXPORT(empty_bad_page)
611 EXPORT(empty_bad_page_table)
614 EXPORT(invalid_pte_table)
617 /* XXX This label is required to keep GAS trying to be too clever ...
621 * Align to 8kb boundary for init_task_union which follows in the