* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / arch / mips / kernel / head.S
blob0264b8aa476a77b71873e2c070ccfec4bdb4244b
1 /* $Id: head.S,v 1.11 1998/10/18 13:27:12 tsbogend Exp $
2  *
3  * arch/mips/kernel/head.S
4  *
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
7  * for more details.
8  *
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
15  *
16  * Head.S contains the MIPS exception handler and startup code.
17  */
18 #include <linux/config.h>
19 #include <linux/threads.h>
21 #include <asm/asm.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>
32 #include <asm/cpu.h>
34         .text
35         /*
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
39          * variants.
40          */
41         .fill   0x280
42 /*      
43  * This is space for the interrupt handlers.
44  * After trap_init() they are located at virtual address KSEG0.
45  *
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
49  * vector location.
50  */
51         /* TLB refill, EXL == 0, R4xx0, non-R4600 version */
52         .set    noreorder
53         .set    noat
54         LEAF(except_vec0_r4000)
55         .set    mips3
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
60         sll     k0, k0, 2
61         addu    k1, k1, k0                      # add in pgd offset
62         mfc0    k0, CP0_CONTEXT                 # get context reg
63         lw      k1, (k1)
64         srl     k0, k0, 1                       # get pte offset
65         and     k0, k0, 0xff8
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
73         b       1f
74          tlbwr                                  # write random tlb entry
75 1:      
76         nop
77         eret                                    # return from trap
78         END(except_vec0_r4000)
80         /* TLB refill, EXL == 0, R4600 version */
81         LEAF(except_vec0_r4600)
82         .set    mips3
83         mfc0    k0, CP0_BADVADDR
84         _GET_CURRENT(k1)                        # get current task ptr
85         srl     k0, k0, 22
86         lw      k1, THREAD_PGDIR(k1)
87         sll     k0, k0, 2
88         addu    k1, k1, k0
89         mfc0    k0, CP0_CONTEXT
90         lw      k1, (k1)
91         srl     k0, k0, 1
92         and     k0, k0, 0xff8
93         addu    k1, k1, k0
94         lw      k0, 0(k1)
95         lw      k1, 4(k1)
96         srl     k0, k0, 6
97         mtc0    k0, CP0_ENTRYLO0
98         srl     k1, k1, 6
99         mtc0    k1, CP0_ENTRYLO1
100         nop
101         tlbwr
102         nop
103         eret
104         END(except_vec0_r4600)
106         /* TLB refill, EXL == 0, R4xx0, non-R4600 version */
107         .set    noreorder
108         .set    noat
109         LEAF(except_vec0_nevada)
110         .set    mips3
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
115         sll     k0, k0, 2
116         addu    k1, k1, k0                      # add in pgd offset
117         lw      k1, (k1)
118         mfc0    k0, CP0_CONTEXT                 # get context reg
119         srl     k0, k0, 1                       # get pte offset
120         and     k0, k0, 0xff8
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
129         nop
130         nop
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)
136         .set    mips3
137         mfc0    k0, CP0_BADVADDR
138         _GET_CURRENT(k1)                        # get current task ptr
139         srl     k0, k0, 22
140         lw      k1, THREAD_PGDIR(k1)
141         sll     k0, k0, 2
142         addu    k1, k1, k0
143         mfc0    k0, CP0_CONTEXT
144         lw      k1, (k1)
145         srl     k0, k0, 1
146         and     k0, k0, 0xff8
147         addu    k1, k1, k0
148         lw      k0, 0(k1)
149         lw      k1, 4(k1)
150         nop                             /* XXX */
151         tlbp
152         srl     k0, k0, 6
153         mtc0    k0, CP0_ENTRYLO0
154         srl     k1, k1, 6
155         mfc0    k0, CP0_INDEX
156         mtc0    k1, CP0_ENTRYLO1
157         bltzl   k0, 1f
158         tlbwr
160         nop
161         eret
162         END(except_vec0_r45k_bvahwbug)
164 #ifdef __SMP__
165         /* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */
166         LEAF(except_vec0_r4k_mphwbug)
167         .set    mips3
168         mfc0    k0, CP0_BADVADDR
169         _GET_CURRENT(k1)                        # get current task ptr
170         srl     k0, k0, 22
171         lw      k1, THREAD_PGDIR(k1)
172         sll     k0, k0, 2
173         addu    k1, k1, k0
174         mfc0    k0, CP0_CONTEXT
175         lw      k1, (k1)
176         srl     k0, k0, 1
177         and     k0, k0, 0xff8
178         addu    k1, k1, k0
179         lw      k0, 0(k1)
180         lw      k1, 4(k1)
181         nop                             /* XXX */
182         tlbp
183         srl     k0, k0, 6
184         mtc0    k0, CP0_ENTRYLO0
185         srl     k1, k1, 6
186         mfc0    k0, CP0_INDEX
187         mtc0    k1, CP0_ENTRYLO1
188         bltzl   k0, 1f
189         tlbwr
191         nop
192         eret
193         END(except_vec0_r4k_mphwbug)
194 #endif
196         /* TLB refill, EXL == 0, R4000 UP 250MHZ entrylo[01] hwbug version */
197         LEAF(except_vec0_r4k_250MHZhwbug)
198         .set    mips3
199         mfc0    k0, CP0_BADVADDR
200         _GET_CURRENT(k1)                        # get current task ptr
201         srl     k0, k0, 22
202         lw      k1, THREAD_PGDIR(k1)
203         sll     k0, k0, 2
204         addu    k1, k1, k0
205         mfc0    k0, CP0_CONTEXT
206         lw      k1, (k1)
207         srl     k0, k0, 1
208         and     k0, k0, 0xff8
209         addu    k1, k1, k0
210         lw      k0, 0(k1)
211         lw      k1, 4(k1)
212         srl     k0, k0, 6
213         mtc0    zero, CP0_ENTRYLO0
214         mtc0    k0, CP0_ENTRYLO0
215         srl     k1, k1, 6
216         mtc0    zero, CP0_ENTRYLO1
217         mtc0    k1, CP0_ENTRYLO1
218         b       1f
219         tlbwr
221         nop
222         eret
223         END(except_vec0_r4k_250MHZhwbug)
225 #ifdef __SMP__
226         /* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */
227         LEAF(except_vec0_r4k_MP250MHZhwbug)
228         .set    mips3
229         mfc0    k0, CP0_BADVADDR
230         _GET_CURRENT(k1)                        # get current task ptr
231         srl     k0, k0, 22
232         lw      k1, THREAD_PGDIR(k1)
233         sll     k0, k0, 2
234         addu    k1, k1, k0
235         mfc0    k0, CP0_CONTEXT
236         lw      k1, (k1)
237         srl     k0, k0, 1
238         and     k0, k0, 0xff8
239         addu    k1, k1, k0
240         lw      k0, 0(k1)
241         lw      k1, 4(k1)
242         nop                             /* XXX */
243         tlbp
244         srl     k0, k0, 6
245         mtc0    zero, CP0_ENTRYLO0
246         mtc0    k0, CP0_ENTRYLO0
247         mfc0    k0, CP0_INDEX
248         srl     k1, k1, 6
249         mtc0    zero, CP0_ENTRYLO1
250         mtc0    k1, CP0_ENTRYLO1
251         bltzl   k0, 1f
252         tlbwr
254         nop
255         eret
256         END(except_vec0_r4k_MP250MHZhwbug)
257 #endif
259         /* TLB refill, EXL == 0, R[23]00 version */
260         LEAF(except_vec0_r2300)
261         .set    mips1
262         mfc0    k0, CP0_BADVADDR
263         _GET_CURRENT(k1)                        # get current task ptr
264         srl     k0, k0, 22
265         lw      k1, THREAD_PGDIR(k1)
266         sll     k0, k0, 2
267         addu    k1, k1, k0
268         mfc0    k0, CP0_CONTEXT
269         lw      k1, (k1)
270         srl     k0, k0, 1
271         and     k0, k0, 0xffc
272         addu    k1, k1, k0
273         lw      k0, (k1)
274         srl     k0, k0, 12
275         mtc0    k0, CP0_ENTRYLO0
276         mfc0    k1, CP0_EPC
277         tlbwr
278         nop
279         nop
280         nop
281         nop
282         jr      k1
283         rfe
284         END(except_vec0_r2300)
287         /* XTLB refill, EXL == 0, R4xx0 cpus only use this... */
288         NESTED(except_vec1_generic, 0, sp)
289         .set    noat
290         .set    mips3
291         /* Register saving is delayed as long as we don't know
292          * which registers really need to be saved.
293          */
294         mfc0    k1, CP0_CONTEXT
295         dsra    k1, 1
296         lwu     k0,  (k1)               # May cause another exception
297         lwu     k1, 4(k1)
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
303         tlbwr
304         nop                             # Needed for R4[04]00 pipeline
305         nop
306         nop
307         eret
308         nop                             /* Workaround for R4000 bug. */
309         eret
310         END(except_vec1_generic)
312         /* Cache Error */
313         LEAF(except_vec2_generic)
314         /* Famous last words: unreached */
315         mfc0    a1,CP0_ERROREPC
316         PRINT("Cache error exception: c0_errorepc == %08x\n")
318         j       1b
319          nop
320         END(except_vec2_generic)
322         /* General exception vector R4000 version. */
323         NESTED(except_vec3_r4000, 0, sp)
324         .set    noat
325         mfc0    k1, CP0_CAUSE
326         andi    k1, k1, 0x7c
327         li      k0, 31<<2
328         beq     k1, k0, handle_vced
329          li     k0, 14<<2
330         beq     k1, k0, handle_vcei
331          la     k0, exception_handlers
332         addu    k0, k0, k1
333         lw      k0, (k0)
334         nop
335         jr      k0
336          nop
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.
343  */
344 handle_vced:
345         mfc0    k0, CP0_BADVADDR
346  li k1, -4
347  and k0, k1
348         mtc0    zero, CP0_TAGLO
349  //     nop;nop
350         cache   Index_Store_Tag_D,(k0)
351  //     nop;nop
352         cache   Hit_Writeback_Inv_SD,(k0)
353         lui     k0, %hi(vced_count)
354         lw      k1, %lo(vced_count)(k0)
355         addiu   k1, 1
356         sw      k1, %lo(vced_count)(k0)
357         eret
359 handle_vcei:
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)
364         addiu   k1, 1
365         sw      k1, %lo(vcei_count)(k0)
366         eret
368         END(except_vec3_r4000)
369         .set    at
371         /* General exception vector. */
372         NESTED(except_vec3_generic, 0, sp)
373         .set    noat
374         mfc0    k1, CP0_CAUSE
375         la      k0, exception_handlers
376         andi    k1, k1, 0x7c
377         addu    k0, k0, k1
378         lw      k0, (k0)
379         nop
380         jr      k0
381          nop
382         END(except_vec3_generic)
383         .set    at
385         /*
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!
390          */
391         NESTED(except_vec4, 0, sp)
392 1:      j       1b                      /* Dummy, will be replaced */
393          nop
394         END(except_vec4)
397  * Kernel entry point
398  */
399 NESTED(kernel_entry, 16, sp)
400         .set    noreorder
401         /* The following two symbols are used for kernel profiling. */
402         EXPORT(stext)
403         EXPORT(_stext)
405         /* Determine which MIPS variant we are running on. */
406         b       cpu_probe
407          nop
409 probe_done:
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
414          * by prom_init().
415          */
416         la      t0, _edata
417         sw      zero, (t0)
418         la      t1, (_end - 4)
420         addiu   t0, 4
421         bne     t0, t1, 1b
422          sw     zero, (t0)
424         jal     prom_init /* prom_init(argc, argv, envp); */
425          nop
426 #ifdef CONFIG_SGI
427         jal     sgi_sysinit
428          nop
429 #endif
431 #ifdef CONFIG_COBALT_MICRO_SERVER
432         jal     SetUpBootInfo
433          nop
434 #endif
436         /*
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.
440          */
441         jal     loadmmu
442          nop
444         /*
445          * Stack for kernel and init, current variable
446          */
447         la      $28, init_task_union
448         addiu   t0, $28, KERNEL_STACK_SIZE-32
449         sw      t0, kernelsp
450         subu    sp, t0, 4*SZREG
452         /* Disable coprocessors */
453         mfc0    t0, CP0_STATUS
454         li      t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX)
455         and     t0, t1
456         or      t0, ST0_CU0
457         mtc0    t0, CP0_STATUS
459 1:      jal     start_kernel
460          nop
461         /*
462          * Main should never return here, but
463          * just in case, we know what happens.
464          */
465         b       1b
466          nop                                    # delay slot
467         END(kernel_entry)
469         /* CPU type probing code, called at Kernel entry. */
470         LEAF(cpu_probe)
471         mfc0    t0, CP0_PRID
472         la      t3, mips_cputype
473         andi    t1, t0, 0xff00
474         li      t2, PRID_IMP_R2000
475         bne     t1, t2, 1f
476          andi   t0, 0x00ff
478         li      t2, CPU_R2000
479         b       probe_done
480          sw     t2, (t3)
482         li      t2, PRID_IMP_R3000
483         bne     t1, t2, 1f
484          nop
486         li      t2, PRID_REV_R3000A
487         bne     t0, t2, 9f
488          nop
490         li      t2, CPU_R3000A
491         b       probe_done
492         sw      t2, (t3)
494         li      t2, CPU_R3000
495         b       probe_done
496          sw     t2, (t3)
498         li      t2, PRID_IMP_R6000
499         bne     t1, t2, 1f
500          nop
502         li      t2, CPU_R6000
503         b       probe_done
504          sw     t2, (t3)
506         li      t2, PRID_IMP_R4000
507         bne     t1, t2, 1f
508          nop
510         li      t2, PRID_REV_R4400
511         bne     t0, t2, 9f
512          nop
514         li      t2, CPU_R4400SC
515         b       probe_done
516          sw     t2, (t3)
518         li      t2, CPU_R4000SC
519         b       probe_done
520          sw     t2, (t3)
522         li      t2, PRID_IMP_R6000A
523         bne     t1, t2, 1f
524          nop
526         li      t2, CPU_R6000A
527         b       probe_done
528          sw     t2, (t3)
530         li      t2, PRID_IMP_R10000
531         bne     t1, t2, 1f
532          nop
534         li      t2, CPU_R10000
535         b       probe_done
536          sw     t2, (t3)
538         li      t2, PRID_IMP_R8000
539         bne     t1, t2, 1f
540          nop
542         li      t2, CPU_R8000
543         b       probe_done
544          sw     t2, (t3)
546         li      t2, PRID_IMP_R4600
547         bne     t1, t2, 1f
548          nop
550         li      t2, CPU_R4600
551         b       probe_done
552          sw     t2, (t3)
554         li      t2, PRID_IMP_R4700
555         bne     t1, t2, 1f
556          nop
558         li      t2, CPU_R4700
559         b       probe_done
560          sw     t2, (t3)
562         li      t2, PRID_IMP_R4650
563         bne     t1, t2, 1f
564          nop
566         li      t2, CPU_R4650
567         b       probe_done
568          sw     t2, (t3)
570         li      t2, PRID_IMP_R5000
571         bne     t1, t2, 1f
572          nop
574         li      t2, CPU_R5000
575         b       probe_done
576          sw     t2, (t3)
578         li      t2, PRID_IMP_NEVADA
579         bne     t1, t2, 1f
580          nop
582         li      t2, CPU_NEVADA
583         b       probe_done
584          sw     t2, (t3)
586         li      t2, CPU_UNKNOWN
587         sw      t2, (t3)
589         b       probe_done
590          nop
591         END(cpu_probe)
594  * This buffer is reserved for the use of the cache error handler.
595  */
596                 .data
597                 EXPORT(cache_error_buffer)
598                 .fill   32*4,1,0
600 EXPORT(kernelsp)
601                 PTR     0
602                 .text
604                 .org    0x1000
605 EXPORT(swapper_pg_dir)
607                 .org    0x2000
608 EXPORT(empty_bad_page)
610                 .org    0x3000
611 EXPORT(empty_bad_page_table)
613                 .org    0x4000
614 EXPORT(invalid_pte_table)
616                 .org    0x5000
617 /* XXX This label is required to keep GAS trying to be too clever ...
618    Bug?  */
619 dummy:
621  * Align to 8kb boundary for init_task_union which follows in the
622  * .text segment.
623  */
624                 .align  13