1 /* 2 * Interrupt and TLB miss handling support. 3 * 4 * Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "memory.h" 21 #include "mips.h" 22 23 .text 24 .extern interrupt_handler 25 .extern current_registers 26 .extern current_stack_pointer 27 .globl _tlb_entry 28 .globl _exc_entry 29 .globl _irq_entry 30 .globl _end_entries 31 .set noreorder 32 33 _tlb_entry: 34 /* Get the bad address. */ 35 36 mfc0 $k0, CP0_ENTRYHI 37 nop 38 andi $k1, $k0, 0xff /* ASID */ 39 40 /* For ASID == 0... */ 41 42 beqz $k1, _tlb_entry_direct 43 nop 44 45 /* Otherwise, load the page table entries. */ 46 47 andi $k1, $k0, 0xff /* ASID */ 48 li $k0, STAGE2_PAGE_TABLE_TASK 49 mul $k0, $k0, $k1 /* [ASID] (ASID * STAGE2_PAGE_TABLE_TASK) */ 50 li $k1, STAGE2_PAGE_TABLE /* page_table */ 51 addu $k1, $k0, $k1 /* page_table[ASID] */ 52 53 mfc0 $k0, CP0_CONTEXT 54 nop 55 srl $k0, $k0, 1 /* use 8 byte - not 16 byte - entries */ 56 addu $k0, $k0, $k1 /* page_table[ASID][entry] */ 57 58 lw $k1, 0($k0) /* page_table[ASID][entry][0] */ 59 mtc0 $k1, CP0_ENTRYLO0 60 61 lw $k1, 4($k0) /* page_table[ASID][entry][1] */ 62 mtc0 $k1, CP0_ENTRYLO1 63 /* page size is 4KB */ 64 mtc0 $zero, CP0_PAGEMASK 65 nop 66 67 tlbwr 68 nop 69 70 eret 71 nop 72 73 _tlb_entry_direct: 74 /* Otherwise, just translate the address directly. */ 75 76 li $k1, 0xffffe000 77 and $k0, $k0, $k1 /* VPN2 (8KB resolution) */ 78 srl $k0, $k0, 6 /* PFN (maintain 8KB resolution, bit 6 remaining zero) */ 79 ori $k0, $k0, 0x1e /* flags */ 80 81 mtc0 $k0, CP0_ENTRYLO0 82 ori $k0, $k0, 0x40 /* page size is 4KB (bit 6 set) */ 83 mtc0 $k0, CP0_ENTRYLO1 84 nop /* page size is 4KB */ 85 mtc0 $zero, CP0_PAGEMASK 86 nop 87 88 tlbwr 89 nop 90 91 eret 92 nop 93 94 _exc_entry: 95 /* Handle TLB refill exceptions. */ 96 97 mfc0 $k0, CP0_CAUSE 98 li $k1, 0x0000007c 99 and $k0, $k0, $k1 /* ExcCode << 2 */ 100 srl $k0, $k0, 2 /* ExcCode */ 101 addi $k1, $k0, -2 /* ExcCode == 2 */ 102 beqz $k1, _tlb_entry 103 addi $k1, $k0, -3 /* ExcCode == 3 */ 104 beqz $k1, _tlb_entry 105 nop 106 _fail: 107 b _fail 108 nop 109 110 _irq_entry: 111 /* Set the ASID. */ 112 113 mtc0 $zero, CP0_ENTRYHI 114 nop 115 116 /* Obtain the kernel global offset table. */ 117 118 move $k0, $gp 119 lui $gp, %hi(_GLOBAL_OFFSET_TABLE_) 120 ori $gp, $gp, %lo(_GLOBAL_OFFSET_TABLE_) 121 122 /* Obtain a store of registers for the current task. */ 123 124 la $k1, current_registers 125 lw $k1, 0($k1) 126 127 /* Save registers that the assembler wants to trash. */ 128 129 sw $t9, 100($k1) 130 sw $k0, 104($k1) /* old gp */ 131 sw $ra, 112($k1) 132 133 /* Record the stack pointer. */ 134 135 la $k1, current_stack_pointer 136 lw $k1, 0($k1) /* &stack_pointers[current_task] */ 137 sw $sp, 0($k1) 138 139 /* Switch to the kernel exception stack. */ 140 141 li $sp, STAGE2_EXCEPTION_STACK 142 143 /* Invoke the rest of the interrupt handling process. */ 144 145 la $k0, interrupt_handler 146 jr $k0 147 nop 148 149 _end_entries: 150 151 .set reorder