source: src/linux/universal/linux-4.9/arch/mips/kernel/genex.S @ 31884

Last change on this file since 31884 was 31884, checked in by brainslayer, 7 days ago

update kernels

File size: 13.0 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, \handler
165        MTC0    k0, CP0_EPC
166        .set pop
167        .endm
168
169        .align  5
170BUILD_ROLLBACK_PROLOGUE handle_int
171NESTED(handle_int, PT_SIZE, sp)
172#ifdef CONFIG_TRACE_IRQFLAGS
173        /*
174         * Check to see if the interrupted code has just disabled
175         * interrupts and ignore this interrupt for now if so.
176         *
177         * local_irq_disable() disables interrupts and then calls
178         * trace_hardirqs_off() to track the state. If an interrupt is taken
179         * after interrupts are disabled but before the state is updated
180         * it will appear to restore_all that it is incorrectly returning with
181         * interrupts disabled
182         */
183        .set    push
184        .set    noat
185        mfc0    k0, CP0_STATUS
186#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
187        and     k0, ST0_IEP
188        bnez    k0, 1f
189
190        mfc0    k0, CP0_EPC
191        .set    noreorder
192        j       k0
193         rfe
194#else
195        and     k0, ST0_IE
196        bnez    k0, 1f
197
198        eret
199#endif
2001:
201        .set pop
202#endif
203        SAVE_ALL
204        CLI
205        TRACE_IRQS_OFF
206
207        LONG_L  s0, TI_REGS($28)
208        LONG_S  sp, TI_REGS($28)
209
210        /*
211         * SAVE_ALL ensures we are using a valid kernel stack for the thread.
212         * Check if we are already using the IRQ stack.
213         */
214        move    s1, sp # Preserve the sp
215
216        /* Get IRQ stack for this CPU */
217        ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
218#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
219        lui     k1, %hi(irq_stack)
220#else
221        lui     k1, %highest(irq_stack)
222        daddiu  k1, %higher(irq_stack)
223        dsll    k1, 16
224        daddiu  k1, %hi(irq_stack)
225        dsll    k1, 16
226#endif
227        LONG_SRL        k0, SMP_CPUID_PTRSHIFT
228        LONG_ADDU       k1, k0
229        LONG_L  t0, %lo(irq_stack)(k1)
230
231        # Check if already on IRQ stack
232        PTR_LI  t1, ~(_THREAD_SIZE-1)
233        and     t1, t1, sp
234        beq     t0, t1, 2f
235
236        /* Switch to IRQ stack */
237        li      t1, _IRQ_STACK_SIZE
238        PTR_ADD sp, t0, t1
239
2402:
241        jal     plat_irq_dispatch
242
243        /* Restore sp */
244        move    sp, s1
245
246        j       ret_from_irq
247#ifdef CONFIG_CPU_MICROMIPS
248        nop
249#endif
250        END(handle_int)
251
252        __INIT
253
254/*
255 * Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
256 * This is a dedicated interrupt exception vector which reduces the
257 * interrupt processing overhead.  The jump instruction will be replaced
258 * at the initialization time.
259 *
260 * Be careful when changing this, it has to be at most 128 bytes
261 * to fit into space reserved for the exception handler.
262 */
263NESTED(except_vec4, 0, sp)
2641:      j       1b                      /* Dummy, will be replaced */
265        END(except_vec4)
266
267/*
268 * EJTAG debug exception handler.
269 * The EJTAG debug exception entry point is 0xbfc00480, which
270 * normally is in the boot PROM, so the boot PROM must do an
271 * unconditional jump to this vector.
272 */
273NESTED(except_vec_ejtag_debug, 0, sp)
274        j       ejtag_debug_handler
275#ifdef CONFIG_CPU_MICROMIPS
276         nop
277#endif
278        END(except_vec_ejtag_debug)
279
280        __FINIT
281
282/*
283 * Vectored interrupt handler.
284 * This prototype is copied to ebase + n*IntCtl.VS and patched
285 * to invoke the handler
286 */
287BUILD_ROLLBACK_PROLOGUE except_vec_vi
288NESTED(except_vec_vi, 0, sp)
289        SAVE_SOME
290        SAVE_AT
291        .set    push
292        .set    noreorder
293        PTR_LA  v1, except_vec_vi_handler
294FEXPORT(except_vec_vi_lui)
295        lui     v0, 0           /* Patched */
296        jr      v1
297FEXPORT(except_vec_vi_ori)
298         ori    v0, 0           /* Patched */
299        .set    pop
300        END(except_vec_vi)
301EXPORT(except_vec_vi_end)
302
303/*
304 * Common Vectored Interrupt code
305 * Complete the register saves and invoke the handler which is passed in $v0
306 */
307NESTED(except_vec_vi_handler, 0, sp)
308        SAVE_TEMP
309        SAVE_STATIC
310        CLI
311#ifdef CONFIG_TRACE_IRQFLAGS
312        move    s0, v0
313        TRACE_IRQS_OFF
314        move    v0, s0
315#endif
316
317        LONG_L  s0, TI_REGS($28)
318        LONG_S  sp, TI_REGS($28)
319
320        /*
321         * SAVE_ALL ensures we are using a valid kernel stack for the thread.
322         * Check if we are already using the IRQ stack.
323         */
324        move    s1, sp # Preserve the sp
325
326        /* Get IRQ stack for this CPU */
327        ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
328#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
329        lui     k1, %hi(irq_stack)
330#else
331        lui     k1, %highest(irq_stack)
332        daddiu  k1, %higher(irq_stack)
333        dsll    k1, 16
334        daddiu  k1, %hi(irq_stack)
335        dsll    k1, 16
336#endif
337        LONG_SRL        k0, SMP_CPUID_PTRSHIFT
338        LONG_ADDU       k1, k0
339        LONG_L  t0, %lo(irq_stack)(k1)
340
341        # Check if already on IRQ stack
342        PTR_LI  t1, ~(_THREAD_SIZE-1)
343        and     t1, t1, sp
344        beq     t0, t1, 2f
345
346        /* Switch to IRQ stack */
347        li      t1, _IRQ_STACK_SIZE
348        PTR_ADD sp, t0, t1
349
3502:
351        jalr    v0
352
353        /* Restore sp */
354        move    sp, s1
355
356        j       ret_from_irq
357        END(except_vec_vi_handler)
358
359/*
360 * EJTAG debug exception handler.
361 */
362NESTED(ejtag_debug_handler, PT_SIZE, sp)
363        .set    push
364        .set    noat
365        MTC0    k0, CP0_DESAVE
366        mfc0    k0, CP0_DEBUG
367
368        sll     k0, k0, 30      # Check for SDBBP.
369        bgez    k0, ejtag_return
370
371        PTR_LA  k0, ejtag_debug_buffer
372        LONG_S  k1, 0(k0)
373        SAVE_ALL
374        move    a0, sp
375        jal     ejtag_exception_handler
376        RESTORE_ALL
377        PTR_LA  k0, ejtag_debug_buffer
378        LONG_L  k1, 0(k0)
379
380ejtag_return:
381        MFC0    k0, CP0_DESAVE
382        .set    mips32
383        deret
384        .set    pop
385        END(ejtag_debug_handler)
386
387/*
388 * This buffer is reserved for the use of the EJTAG debug
389 * handler.
390 */
391        .data
392EXPORT(ejtag_debug_buffer)
393        .fill   LONGSIZE
394        .previous
395
396        __INIT
397
398/*
399 * NMI debug exception handler for MIPS reference boards.
400 * The NMI debug exception entry point is 0xbfc00000, which
401 * normally is in the boot PROM, so the boot PROM must do a
402 * unconditional jump to this vector.
403 */
404NESTED(except_vec_nmi, 0, sp)
405        j       nmi_handler
406#ifdef CONFIG_CPU_MICROMIPS
407         nop
408#endif
409        END(except_vec_nmi)
410
411        __FINIT
412
413NESTED(nmi_handler, PT_SIZE, sp)
414        .set    push
415        .set    noat
416        /*
417         * Clear ERL - restore segment mapping
418         * Clear BEV - required for page fault exception handler to work
419         */
420        mfc0    k0, CP0_STATUS
421        ori     k0, k0, ST0_EXL
422        li      k1, ~(ST0_BEV | ST0_ERL)
423        and     k0, k0, k1
424        mtc0    k0, CP0_STATUS
425        _ehb
426        SAVE_ALL
427        move    a0, sp
428        jal     nmi_exception_handler
429        /* nmi_exception_handler never returns */
430        .set    pop
431        END(nmi_handler)
432
433        .macro  __build_clear_none
434        .endm
435
436        .macro  __build_clear_sti
437        TRACE_IRQS_ON
438        STI
439        .endm
440
441        .macro  __build_clear_cli
442        CLI
443        TRACE_IRQS_OFF
444        .endm
445
446        .macro  __build_clear_fpe
447        .set    push
448        /* gas fails to assemble cfc1 for some archs (octeon).*/ \
449        .set    mips1
450        SET_HARDFLOAT
451        cfc1    a1, fcr31
452        .set    pop
453        CLI
454        TRACE_IRQS_OFF
455        .endm
456
457        .macro  __build_clear_msa_fpe
458        _cfcmsa a1, MSA_CSR
459        CLI
460        TRACE_IRQS_OFF
461        .endm
462
463        .macro  __build_clear_ade
464        MFC0    t0, CP0_BADVADDR
465        PTR_S   t0, PT_BVADDR(sp)
466        KMODE
467        .endm
468
469        .macro  __BUILD_silent exception
470        .endm
471
472        /* Gas tries to parse the PRINT argument as a string containing
473           string escapes and emits bogus warnings if it believes to
474           recognize an unknown escape code.  So make the arguments
475           start with an n and gas will believe \n is ok ...  */
476        .macro  __BUILD_verbose nexception
477        LONG_L  a1, PT_EPC(sp)
478#ifdef CONFIG_32BIT
479        PRINT("Got \nexception at %08lx\012")
480#endif
481#ifdef CONFIG_64BIT
482        PRINT("Got \nexception at %016lx\012")
483#endif
484        .endm
485
486        .macro  __BUILD_count exception
487        LONG_L  t0,exception_count_\exception
488        LONG_ADDIU      t0, 1
489        LONG_S  t0,exception_count_\exception
490        .comm   exception_count\exception, 8, 8
491        .endm
492
493        .macro  __BUILD_HANDLER exception handler clear verbose ext
494        .align  5
495        NESTED(handle_\exception, PT_SIZE, sp)
496        .set    noat
497        SAVE_ALL
498        FEXPORT(handle_\exception\ext)
499        __build_clear_\clear
500        .set    at
501        __BUILD_\verbose \exception
502        move    a0, sp
503        PTR_LA  ra, ret_from_exception
504        j       do_\handler
505        END(handle_\exception)
506        .endm
507
508        .macro  BUILD_HANDLER exception handler clear verbose
509        __BUILD_HANDLER \exception \handler \clear \verbose _int
510        .endm
511
512        BUILD_HANDLER adel ade ade silent               /* #4  */
513        BUILD_HANDLER ades ade ade silent               /* #5  */
514        BUILD_HANDLER ibe be cli silent                 /* #6  */
515        BUILD_HANDLER dbe be cli silent                 /* #7  */
516        BUILD_HANDLER bp bp sti silent                  /* #9  */
517        BUILD_HANDLER ri ri sti silent                  /* #10 */
518        BUILD_HANDLER cpu cpu sti silent                /* #11 */
519        BUILD_HANDLER ov ov sti silent                  /* #12 */
520        BUILD_HANDLER tr tr sti silent                  /* #13 */
521        BUILD_HANDLER msa_fpe msa_fpe msa_fpe silent    /* #14 */
522        BUILD_HANDLER fpe fpe fpe silent                /* #15 */
523        BUILD_HANDLER ftlb ftlb none silent             /* #16 */
524        BUILD_HANDLER msa msa sti silent                /* #21 */
525        BUILD_HANDLER mdmx mdmx sti silent              /* #22 */
526#ifdef  CONFIG_HARDWARE_WATCHPOINTS
527        /*
528         * For watch, interrupts will be enabled after the watch
529         * registers are read.
530         */
531        BUILD_HANDLER watch watch cli silent            /* #23 */
532#else
533        BUILD_HANDLER watch watch sti verbose           /* #23 */
534#endif
535        BUILD_HANDLER mcheck mcheck cli verbose         /* #24 */
536        BUILD_HANDLER mt mt sti silent                  /* #25 */
537        BUILD_HANDLER dsp dsp sti silent                /* #26 */
538        BUILD_HANDLER reserved reserved sti verbose     /* others */
539
540        .align  5
541        LEAF(handle_ri_rdhwr_tlbp)
542        .set    push
543        .set    noat
544        .set    noreorder
545        /* check if TLB contains a entry for EPC */
546        MFC0    k1, CP0_ENTRYHI
547        andi    k1, MIPS_ENTRYHI_ASID | MIPS_ENTRYHI_ASIDX
548        MFC0    k0, CP0_EPC
549        PTR_SRL k0, _PAGE_SHIFT + 1
550        PTR_SLL k0, _PAGE_SHIFT + 1
551        or      k1, k0
552        MTC0    k1, CP0_ENTRYHI
553        mtc0_tlbw_hazard
554        tlbp
555        tlb_probe_hazard
556        mfc0    k1, CP0_INDEX
557        .set    pop
558        bltz    k1, handle_ri   /* slow path */
559        /* fall thru */
560        END(handle_ri_rdhwr_tlbp)
561
562        LEAF(handle_ri_rdhwr)
563        .set    push
564        .set    noat
565        .set    noreorder
566        /* MIPS32:    0x7c03e83b: rdhwr v1,$29 */
567        /* microMIPS: 0x007d6b3c: rdhwr v1,$29 */
568        MFC0    k1, CP0_EPC
569#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2)
570        and     k0, k1, 1
571        beqz    k0, 1f
572         xor    k1, k0
573        lhu     k0, (k1)
574        lhu     k1, 2(k1)
575        ins     k1, k0, 16, 16
576        lui     k0, 0x007d
577        b       docheck
578         ori    k0, 0x6b3c
5791:
580        lui     k0, 0x7c03
581        lw      k1, (k1)
582        ori     k0, 0xe83b
583#else
584        andi    k0, k1, 1
585        bnez    k0, handle_ri
586         lui    k0, 0x7c03
587        lw      k1, (k1)
588        ori     k0, 0xe83b
589#endif
590        .set    reorder
591docheck:
592        bne     k0, k1, handle_ri       /* if not ours */
593
594isrdhwr:
595        /* The insn is rdhwr.  No need to check CAUSE.BD here. */
596        get_saved_sp    /* k1 := current_thread_info */
597        .set    noreorder
598        MFC0    k0, CP0_EPC
599#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
600        ori     k1, _THREAD_MASK
601        xori    k1, _THREAD_MASK
602        LONG_L  v1, TI_TP_VALUE(k1)
603        LONG_ADDIU      k0, 4
604        jr      k0
605         rfe
606#else
607#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
608        LONG_ADDIU      k0, 4           /* stall on $k0 */
609#else
610        .set    at=v1
611        LONG_ADDIU      k0, 4
612        .set    noat
613#endif
614        MTC0    k0, CP0_EPC
615        /* I hope three instructions between MTC0 and ERET are enough... */
616        ori     k1, _THREAD_MASK
617        xori    k1, _THREAD_MASK
618        LONG_L  v1, TI_TP_VALUE(k1)
619        .set    arch=r4000
620        eret
621        .set    mips0
622#endif
623        .set    pop
624        END(handle_ri_rdhwr)
625
626#ifdef CONFIG_64BIT
627/* A temporary overflow handler used by check_daddi(). */
628
629        __INIT
630
631        BUILD_HANDLER  daddi_ov daddi_ov none silent    /* #12 */
632#endif
Note: See TracBrowser for help on using the repository browser.