/* * arch/mips/kernel/head.S * * Copyright (C) 1994, 1995 Waldorf Electronics, 1996 Paul M. Antoine * Written by Ralf Baechle and Andreas Busse * Modified for DECStation and hence R3000 support by Paul M. Antoine * Further modifications by David S. Miller * * Head.S contains the MIPS exception handler and startup code. * * $Id: head.S,v 1.10 1997/11/13 12:55:29 ralf Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include .text /* * Reserved space for exception handlers. * Necessary for machines which link their kernels at KSEG0. * FIXME: We could overwrite some of the useless handlers * with those actually being used. */ .fill 520 /* * This is space for the interrupt handlers. * After trap_init() they are located at virtual address KSEG0. * * These handlers much be written in a relocatable manner * because based upon the cpu type an arbitrary one of the * following pieces of code will be copied to the KSEG0 * vector location. */ /* TLB refill, EXL == 0, R4xx0, non-R4600 version */ .set noreorder .set noat LEAF(except_vec0_r4000) .set mips3 mfc0 k0, CP0_BADVADDR # Get faulting address _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 # get pgd only bits lw k1, THREAD_PGDIR(k1) # get task pg_dir sll k0, k0, 2 addu k1, k1, k0 # add in pgd offset mfc0 k0, CP0_CONTEXT # get context reg lw k1, (k1) srl k0, k0, 1 # get pte offset and k0, k0, 0xff8 addu k1, k1, k0 # add in offset lw k0, 0(k1) # get even pte lw k1, 4(k1) # get odd pte srl k0, k0, 6 # convert to entrylo0 mtc0 k0, CP0_ENTRYLO0 # load it srl k1, k1, 6 # convert to entrylo1 mtc0 k1, CP0_ENTRYLO1 # load it b 1f tlbwr # write random tlb entry 1: nop eret # return from trap END(except_vec0_r4000) /* TLB refill, EXL == 0, R4600 version */ LEAF(except_vec0_r4600) .set mips3 mfc0 k0, CP0_BADVADDR _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1) srl k0, k0, 1 and k0, k0, 0xff8 addu k1, k1, k0 lw k0, 0(k1) lw k1, 4(k1) srl k0, k0, 6 mtc0 k0, CP0_ENTRYLO0 srl k1, k1, 6 mtc0 k1, CP0_ENTRYLO1 nop tlbwr nop eret END(except_vec0_r4600) /* TLB refill, EXL == 0, R4xx0, non-R4600 version */ .set noreorder .set noat LEAF(except_vec0_nevada) .set mips3 mfc0 k0, CP0_BADVADDR # Get faulting address _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 # get pgd only bits lw k1, THREAD_PGDIR(k1) # get task pg_dir sll k0, k0, 2 addu k1, k1, k0 # add in pgd offset lw k1, (k1) mfc0 k0, CP0_CONTEXT # get context reg srl k0, k0, 1 # get pte offset and k0, k0, 0xff8 addu k1, k1, k0 # add in offset lw k0, 0(k1) # get even pte lw k1, 4(k1) # get odd pte srl k0, k0, 6 # convert to entrylo0 mtc0 k0, CP0_ENTRYLO0 # load it srl k1, k1, 6 # convert to entrylo1 mtc0 k1, CP0_ENTRYLO1 # load it tlbwr # write random tlb entry nop nop eret # return from trap END(except_vec0_nevada) /* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */ LEAF(except_vec0_r45k_bvahwbug) .set mips3 mfc0 k0, CP0_BADVADDR _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1) srl k0, k0, 1 and k0, k0, 0xff8 addu k1, k1, k0 lw k0, 0(k1) lw k1, 4(k1) nop /* XXX */ tlbp srl k0, k0, 6 mtc0 k0, CP0_ENTRYLO0 srl k1, k1, 6 mfc0 k0, CP0_INDEX mtc0 k1, CP0_ENTRYLO1 bltzl k0, 1f tlbwr 1: nop eret END(except_vec0_r45k_bvahwbug) #ifdef __SMP__ /* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */ LEAF(except_vec0_r4k_mphwbug) .set mips3 mfc0 k0, CP0_BADVADDR _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1) srl k0, k0, 1 and k0, k0, 0xff8 addu k1, k1, k0 lw k0, 0(k1) lw k1, 4(k1) nop /* XXX */ tlbp srl k0, k0, 6 mtc0 k0, CP0_ENTRYLO0 srl k1, k1, 6 mfc0 k0, CP0_INDEX mtc0 k1, CP0_ENTRYLO1 bltzl k0, 1f tlbwr 1: nop eret END(except_vec0_r4k_mphwbug) #endif /* TLB refill, EXL == 0, R4000 UP 250MHZ entrylo[01] hwbug version */ LEAF(except_vec0_r4k_250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1) srl k0, k0, 1 and k0, k0, 0xff8 addu k1, k1, k0 lw k0, 0(k1) lw k1, 4(k1) srl k0, k0, 6 mtc0 zero, CP0_ENTRYLO0 mtc0 k0, CP0_ENTRYLO0 srl k1, k1, 6 mtc0 zero, CP0_ENTRYLO1 mtc0 k1, CP0_ENTRYLO1 b 1f tlbwr 1: nop eret END(except_vec0_r4k_250MHZhwbug) #ifdef __SMP__ /* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */ LEAF(except_vec0_r4k_MP250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1) srl k0, k0, 1 and k0, k0, 0xff8 addu k1, k1, k0 lw k0, 0(k1) lw k1, 4(k1) nop /* XXX */ tlbp srl k0, k0, 6 mtc0 zero, CP0_ENTRYLO0 mtc0 k0, CP0_ENTRYLO0 mfc0 k0, CP0_INDEX srl k1, k1, 6 mtc0 zero, CP0_ENTRYLO1 mtc0 k1, CP0_ENTRYLO1 bltzl k0, 1f tlbwr 1: nop eret END(except_vec0_r4k_MP250MHZhwbug) #endif /* TLB refill, EXL == 0, R[23]00 version */ LEAF(except_vec0_r2300) .set mips1 mfc0 k0, CP0_BADVADDR _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1) srl k0, k0, 1 and k0, k0, 0xffc addu k1, k1, k0 lw k0, (k1) srl k0, k0, 12 mtc0 k0, CP0_ENTRYLO0 mfc0 k1, CP0_EPC tlbwr nop nop nop nop jr k1 rfe END(except_vec0_r2300) /* XTLB refill, EXL == 0, R4xx0 cpus only use this... */ NESTED(except_vec1_generic, 0, sp) .set noat .set mips3 /* Register saving is delayed as long as we don't know * which registers really need to be saved. */ mfc0 k1, CP0_CONTEXT dsra k1, 1 lwu k0, (k1) # May cause another exception lwu k1, 4(k1) dsrl k0, 6 # Convert to EntryLo format dsrl k1, 6 # Convert to EntryLo format dmtc0 k0, CP0_ENTRYLO0 dmtc0 k1, CP0_ENTRYLO1 nop # Needed for R4[04]00 pipeline tlbwr nop # Needed for R4[04]00 pipeline nop nop eret nop /* Workaround for R4000 bug. */ eret END(except_vec1_generic) /* Cache Error */ LEAF(except_vec2_generic) /* Famous last words: unreached */ mfc0 a1,CP0_ERROREPC PRINT("Cache error exception: c0_errorepc == %08x\n") 1: j 1b nop END(except_vec2_generic) /* General exception vector R4000 version. */ NESTED(except_vec3_r4000, 0, sp) .set noat mfc0 k1, CP0_CAUSE /* XXX Have to check for VCE's _before_ we do a load or store. */ la k0, exception_handlers andi k1, k1, 0x7c addu k0, k0, k1 lw k0, (k0) nop jr k0 nop END(except_vec3_r4000) .set at /* General exception vector. */ NESTED(except_vec3_generic, 0, sp) .set noat mfc0 k1, CP0_CAUSE la k0, exception_handlers andi k1, k1, 0x7c addu k0, k0, k1 lw k0, (k0) nop jr k0 nop END(except_vec3_generic) .set at /* * Special interrupt vector for embedded MIPS. This is a * dedicated interrupt vector which reduces interrupt processing * overhead. The jump instruction will be inserted here at * initialization time. This handler may only be 8 bytes in size! */ NESTED(except_vec4, 0, sp) 1: j 1b /* Dummy, will be replaced */ nop END(except_vec4) /* * Kernel entry point */ NESTED(kernel_entry, 16, sp) .set noreorder /* The following two symbols are used for kernel profiling. */ EXPORT(stext) EXPORT(_stext) /* Determine which MIPS variant we are running on. */ b cpu_probe nop probe_done: #ifndef CONFIG_SGI /* Get the memory upper limit the bootloader passed to us * in a0 */ la t0, mips_memory_upper nop sw a0, (t0) #else /* On SGI's the firmware/bootloader passes argc/argp/envp * to us as arguments. But clear bss first because * the romvec and other important info is stored there * by prom_init(). */ la t0, _edata sw zero, (t0) la t1, (_end - 4) 1: addiu t0, 4 bne t0, t1, 1b sw zero, (t0) jal prom_init /* prom_init(argc, argv, envp); */ nop jal sgi_sysinit nop #endif /* Get the very one tags we need early in the boot process */ nop jal bi_EarlySnarf nop #ifndef CONFIG_SGI /* Clear BSS first so that there are no surprises... */ la t0, _edata la t1, _end 1: addiu t0, 1 bne t0, t1, 1b sb zero, -1(t0) #endif /* * Determine the mmu/cache attached to this machine, * then flush the tlb and caches. On the r4xx0 * variants this also sets CP0_WIRED to zero. */ jal loadmmu nop la t2, mips_cputype lw t4, (t2) li t1, CPU_R2000 li t2, CPU_R3000 li t3, CPU_R3000A beq t4,t1,2f nop beq t4,t2,2f nop beq t4,t3,2f nop jal wire_mappings_r4xx0 nop b 9f nop 2: jal wire_mappings_r3000 nop /* * Stack for kernel and init */ 9: la t0, init_task_union+KERNEL_STACK_SIZE-32 sw t0, kernelsp subu sp, t0, 4*SZREG /* Disable coprocessors */ mfc0 t0, CP0_STATUS li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX) and t0, t1 or t0, ST0_CU0 mtc0 t0, CP0_STATUS 1: jal start_kernel nop /* * Main should never return here, but * just in case, we know what happens. */ b 1b nop # delay slot END(kernel_entry) /* * wire_mappings - used to map hardware registers, r4xx0 version. */ LEAF(wire_mappings_r4xx0) mtc0 zero, CP0_WIRED nop nop nop j ra nop END(wire_mappings_r4xx0) /* * R3000 version of wire_mappings. */ LEAF(wire_mappings_r3000) /* * Get base address of map0 table for the * the board we're running on */ lw t1, mips_machtype la t0, map0table sll t1, PTRLOG # machtype used as index addu t0, t1 lw t0, (t0) # get base address nop /* Get number of wired TLB entries and * loop over selected map0 table. */ lw t1, (t0) # number of wired TLB entries move t2, zero # TLB entry counter addiu t3, t1, 1 # wire one additional entry beqz t1, 2f # null, exit nop addiu t0, 8 1: lw t4, 24(t0) # PageMask ld t5, 0(t0) # entryHi ld t6, 8(t0) # entryLo0 addiu t2, 1 # increment ctr mtc0 t2, CP0_INDEX # set TLB entry nop mtc0 t5, CP0_ENTRYHI nop mtc0 t6, CP0_ENTRYLO0 addiu t0, 32 bne t1, t2, 1b # next TLB entry tlbwi /* We use only 4k pages. Therefore the PageMask register * is expected to be setup for 4k pages. */ 2: /* Now map the pagetables */ mtc0 zero, CP0_INDEX la t0, TLB_ROOT mtc0 t0, CP0_ENTRYHI nop la t0, swapper_pg_dir srl t0, 12 ori t0, (0x00e0|0x0100) # uncachable, dirty, valid mtc0 t0, CP0_ENTRYLO0 nop tlbwi # delayed /* Load the context register with zero. To see why, look * at how the tlb refill code above works. */ mtc0 zero, CP0_CONTEXT jr ra nop END(wire_mappings_r3000) /* CPU type probing code, called at Kernel entry. */ LEAF(cpu_probe) mfc0 t0, CP0_PRID la t3, mips_cputype andi t1, t0, 0xff00 li t2, PRID_IMP_R2000 bne t1, t2, 1f andi t0, 0x00ff li t2, CPU_R2000 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R3000 bne t1, t2, 1f nop li t2, PRID_REV_R3000A bne t0, t2, 9f nop li t2, CPU_R3000A b probe_done sw t2, (t3) 9: li t2, CPU_R3000 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R6000 bne t1, t2, 1f nop li t2, CPU_R6000 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R4000 bne t1, t2, 1f nop li t2, PRID_REV_R4400 bne t0, t2, 9f nop li t2, CPU_R4400SC b probe_done sw t2, (t3) 9: li t2, CPU_R4000SC b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R6000A bne t1, t2, 1f nop li t2, CPU_R6000A b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R10000 bne t1, t2, 1f nop li t2, CPU_R10000 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R8000 bne t1, t2, 1f nop li t2, CPU_R8000 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R4600 bne t1, t2, 1f nop li t2, CPU_R4600 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R4700 bne t1, t2, 1f nop li t2, CPU_R4700 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R4650 bne t1, t2, 1f nop li t2, CPU_R4650 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_R5000 bne t1, t2, 1f nop li t2, CPU_R5000 b probe_done sw t2, (t3) 1: li t2, PRID_IMP_NEVADA bne t1, t2, 1f nop li t2, CPU_NEVADA b probe_done sw t2, (t3) 1: li t2, CPU_UNKNOWN sw t2, (t3) b probe_done nop END(cpu_probe) .data /* * Build an entry for table of wired entries */ #define MAPDATA(q1,q2,q3,w1) \ .quad q1; \ .quad q2; \ .quad q3; \ .word w1; \ .word 0 /* * Initial mapping tables for supported Mips boards. * First item is always the number of wired TLB entries, * following by EntryHi/EntryLo pairs and page mask. * Since everything must be quad-aligned (8) we insert * some dummy zeros. * * Keep in mind that the PFN does not depend on the page size in the * TLB page mask register. See milo's lib/dumptlb.c for how to decode * and encode these entries. Don't see the same routine in the linux * kernel distribution, since it is older and unreliable. */ /* * Address table of mapping tables for supported Mips boards. * Add your own stuff here but don't forget to define your * target system in bootinfo.h */ map0table: PTR map0_dummy # machtype = unknown PTR map0_rpc # Deskstation rPC44 PTR map0_tyne # Deskstation Tyne PTR map0_pica61 # Acer Pica-61 PTR map0_magnum4000 # MIPS Magnum 4000PC (RC4030) PTR map0_dummy PTR map0_dummy # DEC Personal DECStation 5000/2x (for now) PTR map0_sni_rm200_pci # SNI RM200 PCI PTR map0_dummy # SGI INDY map0_dummy: .word 0 # 0 entries .align 3 /* * Deskstation rpc44 mappings. This machine has its EISA bus at physical * address 0xa0000000 which we map for 32M, but that doesn't match EISA * spec. Not sure what to do about this. Its I/O ports are memory mapped * at physical memory location 0xb0000000. */ map0_rpc: .word 2 # no. of wired TLB entries .word 0 # pad for alignment MAPDATA(0xffffffffe0000000, 0x02800017, 0x00000001, PM_16M) # ISA Memory space MAPDATA(0xffffffffe2000000, 0x02c00017, 0x00000001, PM_64K) # ISA I/O Space /* * Initial mappings for Deskstation Tyne boards. */ map0_tyne: .word 2 # no. of wired TLB entries .word 0 # pad for alignment MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space /* * Initial mapping for ACER PICA-61 boards. * FIXME: These are rather preliminary since many drivers, such as serial, * parallel, scsi and ethernet need some changes to distinguish between "local" * (built-in) and "optional" (ISA/PCI) I/O hardware. Local video ram is mapped * to the same location as the bios maps it to. Console driver has been changed * accordingly (new video type: VIDEO_TYPE_PICA_S3). * FIXME: Remove or merge some of the mappings. */ map0_pica61: .word 7 # no. wired TLB entries .word 0 # dummy MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K) # Local I/O space MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K) # Interrupt source register MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # Local video control MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # Extended video control MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # Local video memory (BIOS mapping) MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # ISA I/O and ISA memory space (both 16M) MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # PCR (???) /* * Initial mapping for Mips Magnum 4000PC systems. * Do you believe me now that the Acer and Mips boxes are nearly the same ? :-) * FIXME: Remove or merge some of the mappings. */ map0_magnum4000: .word 8 # no. wired TLB entries .word 0 # dummy MAPDATA(0xffffffffe1000000, 0x03ffc013, 0x00000001, PM_256K) # 0 MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K) # 1 local I/O MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K) # 2 IRQ source MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # 3 local video ctrl MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # 4 ext. video ctrl MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # 5 local video mem. MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # 6 ISA I/O and mem. MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # 7 PCR /* * The RM200 doesn't need any wired entries. */ map0_sni_rm200_pci: .word 0 # no. wired TLB entries .word 0 # dummy .text .org 0x1000 EXPORT(swapper_pg_dir) .org 0x2000 EXPORT(empty_bad_page) .org 0x3000 EXPORT(empty_bad_page_table) .org 0x4000 EXPORT(empty_zero_page) .org 0x5000 EXPORT(invalid_pte_table) .org 0x6000 /* * init_task_union follows here in the .text segment. * Keep this aligned to a 8kb boundary! */ .data EXPORT(cache_error_buffer) .fill 32*4,1,0 EXPORT(kernelsp) PTR 0