source: src/linux/universal/linux-4.4/arch/mips/kernel/genex.S @ 28606

Last change on this file since 28606 was 28606, checked in by BrainSlayer, 17 months ago

in progress, untested

File size: 11.7 KB
Line 
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2002, 2007  Maciej W. Rozycki
9 * Copyright (C) 2001, 2012 MIPS Technologies, Inc.  All rights reserved.
10 */
11#include <linux/init.h>
12
13#include <asm/asm.h>
14#include <asm/asmmacro.h>
15#include <asm/cacheops.h>
16#include <asm/irqflags.h>
17#include <asm/regdef.h>
18#include <asm/fpregdef.h>
19#include <asm/mipsregs.h>
20#include <asm/stackframe.h>
21#include <asm/war.h>
22#include <asm/thread_info.h>
23
24#ifdef CONFIG_BCM47XX
25# ifdef eret
26#  undef eret
27# endif
28# define eret                                   \
29        .set push;                              \
30        .set noreorder;                         \
31         nop;                                   \
32         nop;                                   \
33         eret;                                  \
34        .set pop;
35#endif
36
37        __INIT
38
39/*
40 * General exception vector for all other CPUs.
41 *
42 * Be careful when changing this, it has to be at most 128 bytes
43 * to fit into space reserved for the exception handler.
44 */
45NESTED(except_vec3_generic, 0, sp)
46        .set    push
47        .set    noat
48#ifdef CONFIG_BCM47XX
49        nop
50#endif
51#if R5432_CP0_INTERRUPT_WAR
52        mfc0    k0, CP0_INDEX
53#endif
54        mfc0    k1, CP0_CAUSE
55        andi    k1, k1, 0x7c
56#ifdef CONFIG_64BIT
57        dsll    k1, k1, 1
58#endif
59        PTR_L   k0, exception_handlers(k1)
60        jr      k0
61        .set    pop
62        END(except_vec3_generic)
63
64/*
65 * General exception handler for CPUs with virtual coherency exception.
66 *
67 * Be careful when changing this, it has to be at most 256 (as a special
68 * exception) bytes to fit into space reserved for the exception handler.
69 */
70NESTED(except_vec3_r4000, 0, sp)
71        .set    push
72        .set    arch=r4000
73        .set    noat
74#ifdef CONFIG_BCM47XX
75        nop
76#endif
77        mfc0    k1, CP0_CAUSE
78        li      k0, 31<<2
79        andi    k1, k1, 0x7c
80        .set    push
81        .set    noreorder
82        .set    nomacro
83        beq     k1, k0, handle_vced
84         li     k0, 14<<2
85        beq     k1, k0, handle_vcei
86#ifdef CONFIG_64BIT
87         dsll   k1, k1, 1
88#endif
89        .set    pop
90        PTR_L   k0, exception_handlers(k1)
91        jr      k0
92
93        /*
94         * Big shit, we now may have two dirty primary cache lines for the same
95         * physical address.  We can safely invalidate the line pointed to by
96         * c0_badvaddr because after return from this exception handler the
97         * load / store will be re-executed.
98         */
99handle_vced:
100        MFC0    k0, CP0_BADVADDR
101        li      k1, -4                                  # Is this ...
102        and     k0, k1                                  # ... really needed?
103        mtc0    zero, CP0_TAGLO
104        cache   Index_Store_Tag_D, (k0)
105        cache   Hit_Writeback_Inv_SD, (k0)
106#ifdef CONFIG_PROC_FS
107        PTR_LA  k0, vced_count
108        lw      k1, (k0)
109        addiu   k1, 1
110        sw      k1, (k0)
111#endif
112        eret
113
114handle_vcei:
115        MFC0    k0, CP0_BADVADDR
116        cache   Hit_Writeback_Inv_SD, (k0)              # also cleans pi
117#ifdef CONFIG_PROC_FS
118        PTR_LA  k0, vcei_count
119        lw      k1, (k0)
120        addiu   k1, 1
121        sw      k1, (k0)
122#endif
123        eret
124        .set    pop
125        END(except_vec3_r4000)
126
127        __FINIT
128
129        .align  5       /* 32 byte rollback region */
130LEAF(__r4k_wait)
131        .set    push
132        .set    noreorder
133        /* start of rollback region */
134        LONG_L  t0, TI_FLAGS($28)
135        nop
136        andi    t0, _TIF_NEED_RESCHED
137        bnez    t0, 1f
138         nop
139        nop
140        nop
141#ifdef CONFIG_CPU_MICROMIPS
142        nop
143        nop
144        nop
145        nop
146#endif
147        .set    MIPS_ISA_ARCH_LEVEL_RAW
148        wait
149        /* end of rollback region (the region size must be power of two) */
1501:
151        jr      ra
152        nop
153        .set    pop
154        END(__r4k_wait)
155
156        .macro  BUILD_ROLLBACK_PROLOGUE handler
157        FEXPORT(rollback_\handler)
158        .set    push
159        .set    noat
160        MFC0    k0, CP0_EPC
161        PTR_LA  k1, __r4k_wait
162        ori     k0, 0x1f        /* 32 byte rollback region */
163        xori    k0, 0x1f
164        bne     k0, k1, 9f
165        MTC0    k0, CP0_EPC
1669:
167        .set pop
168        .endm
169
170        .align  5
171BUILD_ROLLBACK_PROLOGUE handle_int
172NESTED(handle_int, PT_SIZE, sp)
173#ifdef CONFIG_TRACE_IRQFLAGS
174        /*
175         * Check to see if the interrupted code has just disabled
176         * interrupts and ignore this interrupt for now if so.
177         *
178         * local_irq_disable() disables interrupts and then calls
179         * trace_hardirqs_off() to track the state. If an interrupt is taken
180         * after interrupts are disabled but before the state is updated
181         * it will appear to restore_all that it is incorrectly returning with
182         * interrupts disabled
183         */
184        .set    push
185        .set    noat
186        mfc0    k0, CP0_STATUS
187#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
188        and     k0, ST0_IEP
189        bnez    k0, 1f
190
191        mfc0    k0, CP0_EPC
192        .set    noreorder
193        j       k0
194        rfe
195#else
196        and     k0, ST0_IE
197        bnez    k0, 1f
198
199        eret
200#endif
2011:
202        .set pop
203#endif
204        SAVE_ALL
205        CLI
206        TRACE_IRQS_OFF
207
208        LONG_L  s0, TI_REGS($28)
209        LONG_S  sp, TI_REGS($28)
210        PTR_LA  ra, ret_from_irq
211        PTR_LA  v0, plat_irq_dispatch
212        jr      v0
213#ifdef CONFIG_CPU_MICROMIPS
214        nop
215#endif
216        END(handle_int)
217
218        __INIT
219
220/*
221 * Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
222 * This is a dedicated interrupt exception vector which reduces the
223 * interrupt processing overhead.  The jump instruction will be replaced
224 * at the initialization time.
225 *
226 * Be careful when changing this, it has to be at most 128 bytes
227 * to fit into space reserved for the exception handler.
228 */
229NESTED(except_vec4, 0, sp)
2301:      j       1b                      /* Dummy, will be replaced */
231        END(except_vec4)
232
233/*
234 * EJTAG debug exception handler.
235 * The EJTAG debug exception entry point is 0xbfc00480, which
236 * normally is in the boot PROM, so the boot PROM must do an
237 * unconditional jump to this vector.
238 */
239NESTED(except_vec_ejtag_debug, 0, sp)
240        j       ejtag_debug_handler
241#ifdef CONFIG_CPU_MICROMIPS
242         nop
243#endif
244        END(except_vec_ejtag_debug)
245
246        __FINIT
247
248/*
249 * Vectored interrupt handler.
250 * This prototype is copied to ebase + n*IntCtl.VS and patched
251 * to invoke the handler
252 */
253BUILD_ROLLBACK_PROLOGUE except_vec_vi
254NESTED(except_vec_vi, 0, sp)
255        SAVE_SOME
256        SAVE_AT
257        .set    push
258        .set    noreorder
259        PTR_LA  v1, except_vec_vi_handler
260FEXPORT(except_vec_vi_lui)
261        lui     v0, 0           /* Patched */
262        jr      v1
263FEXPORT(except_vec_vi_ori)
264         ori    v0, 0           /* Patched */
265        .set    pop
266        END(except_vec_vi)
267EXPORT(except_vec_vi_end)
268
269/*
270 * Common Vectored Interrupt code
271 * Complete the register saves and invoke the handler which is passed in $v0
272 */
273NESTED(except_vec_vi_handler, 0, sp)
274        SAVE_TEMP
275        SAVE_STATIC
276        CLI
277#ifdef CONFIG_TRACE_IRQFLAGS
278        move    s0, v0
279        TRACE_IRQS_OFF
280        move    v0, s0
281#endif
282
283        LONG_L  s0, TI_REGS($28)
284        LONG_S  sp, TI_REGS($28)
285        PTR_LA  ra, ret_from_irq
286        jr      v0
287        END(except_vec_vi_handler)
288
289/*
290 * EJTAG debug exception handler.
291 */
292NESTED(ejtag_debug_handler, PT_SIZE, sp)
293        .set    push
294        .set    noat
295        MTC0    k0, CP0_DESAVE
296        mfc0    k0, CP0_DEBUG
297
298        sll     k0, k0, 30      # Check for SDBBP.
299        bgez    k0, ejtag_return
300
301        PTR_LA  k0, ejtag_debug_buffer
302        LONG_S  k1, 0(k0)
303        SAVE_ALL
304        move    a0, sp
305        jal     ejtag_exception_handler
306        RESTORE_ALL
307        PTR_LA  k0, ejtag_debug_buffer
308        LONG_L  k1, 0(k0)
309
310ejtag_return:
311        MFC0    k0, CP0_DESAVE
312        .set    mips32
313        deret
314        .set pop
315        END(ejtag_debug_handler)
316
317/*
318 * This buffer is reserved for the use of the EJTAG debug
319 * handler.
320 */
321        .data
322EXPORT(ejtag_debug_buffer)
323        .fill   LONGSIZE
324        .previous
325
326        __INIT
327
328/*
329 * NMI debug exception handler for MIPS reference boards.
330 * The NMI debug exception entry point is 0xbfc00000, which
331 * normally is in the boot PROM, so the boot PROM must do a
332 * unconditional jump to this vector.
333 */
334NESTED(except_vec_nmi, 0, sp)
335        j       nmi_handler
336#ifdef CONFIG_CPU_MICROMIPS
337         nop
338#endif
339        END(except_vec_nmi)
340
341        __FINIT
342
343NESTED(nmi_handler, PT_SIZE, sp)
344        .set    push
345        .set    noat
346        /*
347         * Clear ERL - restore segment mapping
348         * Clear BEV - required for page fault exception handler to work
349         */
350        mfc0    k0, CP0_STATUS
351        ori     k0, k0, ST0_EXL
352        li      k1, ~(ST0_BEV | ST0_ERL)
353        and     k0, k0, k1
354        mtc0    k0, CP0_STATUS
355        _ehb
356        SAVE_ALL
357        move    a0, sp
358        jal     nmi_exception_handler
359        /* nmi_exception_handler never returns */
360        .set    pop
361        END(nmi_handler)
362
363        .macro  __build_clear_none
364        .endm
365
366        .macro  __build_clear_sti
367        TRACE_IRQS_ON
368        STI
369        .endm
370
371        .macro  __build_clear_cli
372        CLI
373        TRACE_IRQS_OFF
374        .endm
375
376        .macro  __build_clear_fpe
377        .set    push
378        /* gas fails to assemble cfc1 for some archs (octeon).*/ \
379        .set    mips1
380        SET_HARDFLOAT
381        cfc1    a1, fcr31
382        .set    pop
383        CLI
384        TRACE_IRQS_OFF
385        .endm
386
387        .macro  __build_clear_msa_fpe
388        _cfcmsa a1, MSA_CSR
389        CLI
390        TRACE_IRQS_OFF
391        .endm
392
393        .macro  __build_clear_ade
394        MFC0    t0, CP0_BADVADDR
395        PTR_S   t0, PT_BVADDR(sp)
396        KMODE
397        .endm
398
399        .macro  __BUILD_silent exception
400        .endm
401
402        /* Gas tries to parse the PRINT argument as a string containing
403           string escapes and emits bogus warnings if it believes to
404           recognize an unknown escape code.  So make the arguments
405           start with an n and gas will believe \n is ok ...  */
406        .macro  __BUILD_verbose nexception
407        LONG_L  a1, PT_EPC(sp)
408#ifdef CONFIG_32BIT
409        PRINT("Got \nexception at %08lx\012")
410#endif
411#ifdef CONFIG_64BIT
412        PRINT("Got \nexception at %016lx\012")
413#endif
414        .endm
415
416        .macro  __BUILD_count exception
417        LONG_L  t0,exception_count_\exception
418        LONG_ADDIU t0, 1
419        LONG_S  t0,exception_count_\exception
420        .comm   exception_count\exception, 8, 8
421        .endm
422
423        .macro  __BUILD_HANDLER exception handler clear verbose ext
424        .align  5
425        NESTED(handle_\exception, PT_SIZE, sp)
426        .set    noat
427        SAVE_ALL
428        FEXPORT(handle_\exception\ext)
429        __build_clear_\clear
430        .set    at
431        __BUILD_\verbose \exception
432        move    a0, sp
433        PTR_LA  ra, ret_from_exception
434        j       do_\handler
435        END(handle_\exception)
436        .endm
437
438        .macro  BUILD_HANDLER exception handler clear verbose
439        __BUILD_HANDLER \exception \handler \clear \verbose _int
440        .endm
441
442        BUILD_HANDLER adel ade ade silent               /* #4  */
443        BUILD_HANDLER ades ade ade silent               /* #5  */
444        BUILD_HANDLER ibe be cli silent                 /* #6  */
445        BUILD_HANDLER dbe be cli silent                 /* #7  */
446        BUILD_HANDLER bp bp sti silent                  /* #9  */
447        BUILD_HANDLER ri ri sti silent                  /* #10 */
448        BUILD_HANDLER cpu cpu sti silent                /* #11 */
449        BUILD_HANDLER ov ov sti silent                  /* #12 */
450        BUILD_HANDLER tr tr sti silent                  /* #13 */
451        BUILD_HANDLER msa_fpe msa_fpe msa_fpe silent    /* #14 */
452        BUILD_HANDLER fpe fpe fpe silent                /* #15 */
453        BUILD_HANDLER ftlb ftlb none silent             /* #16 */
454        BUILD_HANDLER msa msa sti silent                /* #21 */
455        BUILD_HANDLER mdmx mdmx sti silent              /* #22 */
456#ifdef  CONFIG_HARDWARE_WATCHPOINTS
457        /*
458         * For watch, interrupts will be enabled after the watch
459         * registers are read.
460         */
461        BUILD_HANDLER watch watch cli silent            /* #23 */
462#else
463        BUILD_HANDLER watch watch sti verbose           /* #23 */
464#endif
465        BUILD_HANDLER mcheck mcheck cli verbose         /* #24 */
466        BUILD_HANDLER mt mt sti silent                  /* #25 */
467        BUILD_HANDLER dsp dsp sti silent                /* #26 */
468        BUILD_HANDLER reserved reserved sti verbose     /* others */
469
470        .align  5
471        LEAF(handle_ri_rdhwr_vivt)
472        .set    push
473        .set    noat
474        .set    noreorder
475        /* check if TLB contains a entry for EPC */
476        MFC0    k1, CP0_ENTRYHI
477        andi    k1, 0xff        /* ASID_MASK */
478        MFC0    k0, CP0_EPC
479        PTR_SRL k0, _PAGE_SHIFT + 1
480        PTR_SLL k0, _PAGE_SHIFT + 1
481        or      k1, k0
482        MTC0    k1, CP0_ENTRYHI
483        mtc0_tlbw_hazard
484        tlbp
485        tlb_probe_hazard
486        mfc0    k1, CP0_INDEX
487        .set    pop
488        bltz    k1, handle_ri   /* slow path */
489        /* fall thru */
490        END(handle_ri_rdhwr_vivt)
491
492        LEAF(handle_ri_rdhwr)
493        .set    push
494        .set    noat
495        .set    noreorder
496        /* MIPS32:    0x7c03e83b: rdhwr v1,$29 */
497        /* microMIPS: 0x007d6b3c: rdhwr v1,$29 */
498        MFC0    k1, CP0_EPC
499#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2)
500        and     k0, k1, 1
501        beqz    k0, 1f
502        xor     k1, k0
503        lhu     k0, (k1)
504        lhu     k1, 2(k1)
505        ins     k1, k0, 16, 16
506        lui     k0, 0x007d
507        b       docheck
508        ori     k0, 0x6b3c
5091:
510        lui     k0, 0x7c03
511        lw      k1, (k1)
512        ori     k0, 0xe83b
513#else
514        andi    k0, k1, 1
515        bnez    k0, handle_ri
516        lui     k0, 0x7c03
517        lw      k1, (k1)
518        ori     k0, 0xe83b
519#endif
520        .set    reorder
521docheck:
522        bne     k0, k1, handle_ri       /* if not ours */
523
524isrdhwr:
525        /* The insn is rdhwr.  No need to check CAUSE.BD here. */
526        get_saved_sp    /* k1 := current_thread_info */
527        .set    noreorder
528        MFC0    k0, CP0_EPC
529#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
530        ori     k1, _THREAD_MASK
531        xori    k1, _THREAD_MASK
532        LONG_L  v1, TI_TP_VALUE(k1)
533        LONG_ADDIU      k0, 4
534        jr      k0
535         rfe
536#else
537#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
538        LONG_ADDIU      k0, 4           /* stall on $k0 */
539#else
540        .set    at=v1
541        LONG_ADDIU      k0, 4
542        .set    noat
543#endif
544        MTC0    k0, CP0_EPC
545        /* I hope three instructions between MTC0 and ERET are enough... */
546        ori     k1, _THREAD_MASK
547        xori    k1, _THREAD_MASK
548        LONG_L  v1, TI_TP_VALUE(k1)
549        .set    arch=r4000
550        eret
551        .set    mips0
552#endif
553        .set    pop
554        END(handle_ri_rdhwr)
555
556#ifdef CONFIG_64BIT
557/* A temporary overflow handler used by check_daddi(). */
558
559        __INIT
560
561        BUILD_HANDLER  daddi_ov daddi_ov none silent    /* #12 */
562#endif
Note: See TracBrowser for help on using the repository browser.