[1] | 1 | /* |
---|
| 2 | * __cpu_kentry.S - unified kernel entry point |
---|
| 3 | * |
---|
| 4 | * Author Ghassan Almaless (2007,2008,2009,2010,2011,2012) |
---|
| 5 | * |
---|
| 6 | * Copyright (c) UPMC Sorbonne Universites |
---|
| 7 | * |
---|
| 8 | * This file is part of ALMOS-kernel. |
---|
| 9 | * |
---|
| 10 | * ALMOS-kernel is free software; you can redistribute it and/or modify it |
---|
| 11 | * under the terms of the GNU General Public License as published by |
---|
| 12 | * the Free Software Foundation; version 2.0 of the License. |
---|
| 13 | * |
---|
| 14 | * ALMOS-kernel is distributed in the hope that it will be useful, but |
---|
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
| 17 | * General Public License for more details. |
---|
| 18 | * |
---|
| 19 | * You should have received a copy of the GNU General Public License |
---|
| 20 | * along with ALMOS-kernel; if not, write to the Free Software Foundation, |
---|
| 21 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
| 22 | */ |
---|
| 23 | |
---|
| 24 | #include <cpu-regs.h> |
---|
| 25 | #define _ALMOS_ASM_ |
---|
| 26 | #include <boot-info.h> |
---|
| 27 | |
---|
| 28 | #--------------------------------------------------------------------------------- |
---|
| 29 | # This file defines the unique kernel entry point in case of |
---|
| 30 | # Exception / Interrupt/Syscall for a MIPS32 processor core. |
---|
| 31 | # The base address of the segment containing this code TODO [AG] |
---|
| 32 | #--------------------------------------------------------------------------------- |
---|
| 33 | |
---|
| 34 | .section .kentry,"ax",@progbits |
---|
| 35 | .extern cpu_do_interrupt |
---|
| 36 | .extern cpu_do_exception |
---|
| 37 | .extern cpu_do_syscall |
---|
| 38 | .extern cpu_kentry |
---|
| 39 | .extern cpu_kexit |
---|
| 40 | .org 0x180 |
---|
| 41 | .ent kentry |
---|
| 42 | .global kentry |
---|
| 43 | .global kentry_load |
---|
| 44 | .set noat |
---|
| 45 | .set noreorder |
---|
| 46 | |
---|
| 47 | #define SAVE_SIZE REGS_NR*4 |
---|
| 48 | |
---|
| 49 | #FIXME: PROC_WIDTH support only 4 proc clusters! |
---|
| 50 | |
---|
| 51 | #define PROC_WIDTH 2 |
---|
| 52 | #define XY_WIDTH 8 |
---|
| 53 | #define XY_MASK 0xFF |
---|
| 54 | #define MMU_MD_MASK 0xF |
---|
| 55 | |
---|
| 56 | #------------------------------------------------------------------------------- |
---|
| 57 | # Kernel Entry point |
---|
| 58 | #------------------------------------------------------------------------------- |
---|
| 59 | kentry: |
---|
| 60 | mfc0 $26, $12 # read SR |
---|
| 61 | andi $26, $26, 0x10 # KSU bitmask |
---|
| 62 | beq $26, $0, KERNEL_MODE |
---|
| 63 | ori $26, $0, 0x3 # MMU OFF value |
---|
| 64 | |
---|
| 65 | |
---|
| 66 | LOAD_KERNEL_STACK: |
---|
| 67 | mtc2 $26, $1 # set MMU OFF |
---|
| 68 | nop |
---|
| 69 | mfc0 $26, $4, # read current thread pointer ($26) |
---|
| 70 | sw $27, (TLS_K1*4)($26) # save user value |
---|
| 71 | |
---|
| 72 | #$27 register can now be used |
---|
| 73 | sw $29, (SP*4)($26) # save user stack |
---|
| 74 | lw $29, (KSP*4)($26) # read kernel stack |
---|
| 75 | |
---|
| 76 | ori $27, $0, 0xF # MMU old value: assumed ON |
---|
| 77 | sw $27, (MMU_MD*4)($26) # save MMU MODE |
---|
| 78 | |
---|
| 79 | j UNIFIED_MODE |
---|
| 80 | or $27, $0, $26 # pointer to uzone ($27) |
---|
| 81 | |
---|
| 82 | #Use only $26 to save two values: MMU_MODE (4 bits) and XY_DATA_EXT (8bits) |
---|
| 83 | #$26 content (in hex): 0x00000MXY (M is the value of MMU_MODE and XY is ...) |
---|
| 84 | #N.B: MMU MODE is also modified by cpu_do_exception |
---|
| 85 | |
---|
| 86 | KERNEL_MODE: |
---|
| 87 | #get old PADDR_EXT (in $26 at bits 0-7) |
---|
| 88 | and $26, $26, $0 # $26 <= 0x00000000 |
---|
| 89 | mfc2 $26, $24 # $26 <= 0x??????XY |
---|
| 90 | andi $26, $26, XY_MASK # $26 <= 0x000000XY |
---|
| 91 | #set PADDR_EXT to point to local mem |
---|
| 92 | mfc0 $27, $15, 1 # read ebase |
---|
| 93 | andi $27, $27, 0xFFF # extract arch cpu id |
---|
| 94 | srl $27, $27, PROC_WIDTH # extract cluster xy |
---|
| 95 | mtc2 $27, $24 # set XY PADDR_EXT |
---|
| 96 | |
---|
| 97 | #get old MMU MODE (in $26 at bits 8-11) |
---|
| 98 | mfc2 $27, $1 # get MMU MODE old value |
---|
| 99 | andi $27, $27, MMU_MD_MASK # $27 <= 0x0000000M |
---|
| 100 | sll $27, $27, XY_WIDTH # $27 <= 0x00000M00 |
---|
| 101 | or $26, $26, $27 # $26 <= 0x00000MXY <= (0x000000XY or 0x00000M00) |
---|
| 102 | #set MMU OFF |
---|
| 103 | ori $27, $0, 0x3 # MMU OFF value |
---|
| 104 | mtc2 $27, $1 # set MMU OFF |
---|
| 105 | |
---|
| 106 | #save old stack, MMU_MODE and PADDR_EXT |
---|
| 107 | addiu $27, $29, -(SAVE_SIZE) # allocate a region on stack ($27) |
---|
| 108 | sw $29, (SP*4)($27) # save old stack ($29 can be used) |
---|
| 109 | |
---|
| 110 | srl $29, $26, XY_WIDTH # $29 <= 0x0000000M |
---|
| 111 | sw $29, (MMU_MD*4)($27) # save MMU MODE |
---|
| 112 | andi $26, $26, XY_MASK # $26 <= 0x000000XY |
---|
| 113 | sw $26, (DP_EXT*4)($27) # save old DATA PADDR EXT (0x000000XY) |
---|
| 114 | |
---|
| 115 | or $29, $27, $0 # set new stack |
---|
| 116 | mfc0 $26, $4, 2 # $26 <= this thread pointer |
---|
| 117 | |
---|
| 118 | # $27: zone for saving the cpu registers |
---|
| 119 | # $26: current thread pointer ($this) |
---|
| 120 | # $29: kstack |
---|
| 121 | |
---|
| 122 | UNIFIED_MODE: |
---|
| 123 | sw $1, (AT*4)($27) |
---|
| 124 | sw $2, (V0*4)($27) |
---|
| 125 | sw $3, (V1*4)($27) |
---|
| 126 | sw $4, (A0*4)($27) |
---|
| 127 | sw $5, (A1*4)($27) |
---|
| 128 | sw $6, (A2*4)($27) |
---|
| 129 | sw $7, (A3*4)($27) |
---|
| 130 | sw $8, (T0*4)($27) |
---|
| 131 | sw $9, (T1*4)($27) |
---|
| 132 | sw $10, (T2*4)($27) |
---|
| 133 | sw $11, (T3*4)($27) |
---|
| 134 | sw $12, (T4*4)($27) |
---|
| 135 | sw $13, (T5*4)($27) |
---|
| 136 | sw $14, (T6*4)($27) |
---|
| 137 | sw $15, (T7*4)($27) |
---|
| 138 | sw $24, (T8*4)($27) |
---|
| 139 | sw $25, (T9*4)($27) |
---|
| 140 | sw $16, (S0*4)($27) |
---|
| 141 | sw $17, (S1*4)($27) |
---|
| 142 | sw $18, (S2*4)($27) |
---|
| 143 | sw $19, (S3*4)($27) |
---|
| 144 | sw $20, (S4*4)($27) |
---|
| 145 | sw $21, (S5*4)($27) |
---|
| 146 | sw $22, (S6*4)($27) |
---|
| 147 | sw $23, (S7*4)($27) |
---|
| 148 | sw $30, (S8*4)($27) |
---|
| 149 | sw $28, (GP*4)($27) |
---|
| 150 | sw $31, (RA*4)($27) # save RA |
---|
| 151 | |
---|
| 152 | mfc0 $16, $14 # Read EPC |
---|
| 153 | sw $16, (EPC*4)($27) # Save EPC |
---|
| 154 | mflo $14 # read LO |
---|
| 155 | sw $14, (LO*4)($27) # save LO |
---|
| 156 | mfhi $15 # read HI |
---|
| 157 | sw $15, (HI*4)($27) # save HI |
---|
| 158 | |
---|
| 159 | mfc0 $18, $12 # Read current SR |
---|
| 160 | sw $18, (SR*4)($27) # Save SR |
---|
| 161 | srl $3, $18, 5 # put SR in kernel mode, IRQ disabled, clear exl |
---|
| 162 | sll $3, $3, 5 # ... |
---|
| 163 | mtc0 $3, $12 # Set new SR |
---|
| 164 | |
---|
| 165 | mfc0 $17, $13 # read CR |
---|
| 166 | sw $17, (CR*4)($27) # Save CR |
---|
| 167 | andi $1, $17, 0x3F # $1 <= XCODE from CP0_CR |
---|
| 168 | |
---|
| 169 | #if CPU_IN_KERNEL |
---|
| 170 | # First signal that we are entering the kernel |
---|
| 171 | mfc0 $4, $15, 1 # $4 <= cpu_id |
---|
| 172 | andi $4, $4, 0x3 # mask all but CPU_local_id |
---|
| 173 | mfc0 $5, $4, 2 # read current thread pointer |
---|
| 174 | jal cpu_kentry |
---|
| 175 | addiu $29, $29, -8 |
---|
| 176 | addiu $29, $29, 8 |
---|
| 177 | #endif |
---|
| 178 | |
---|
| 179 | # Second, depending on XCODE, call the apropriate function |
---|
| 180 | ori $8, $0, 0x20 # cause syscall |
---|
| 181 | beq $8, $1, cause_sys |
---|
| 182 | or $19, $0, $27 # for kentry_exit |
---|
| 183 | mfc0 $5, $15, 1 |
---|
| 184 | andi $5, $5, 0x1FF # $5 (arg1) <= CPU(X,Y,lid) |
---|
| 185 | or $4, $0, $26 # $4 (arg0) <= this thread |
---|
| 186 | beq $1, $0, cause_int |
---|
| 187 | or $6, $0, $27 # $6 (arg2) <= regs_tbl |
---|
| 188 | |
---|
| 189 | # Exceptions Handler |
---|
| 190 | # --------------------------------------------- |
---|
| 191 | la $1, cpu_do_exception |
---|
| 192 | jalr $1 |
---|
| 193 | addiu $29, $29, -3*4 |
---|
| 194 | j kentry_exit |
---|
| 195 | addiu $29, $29, 3*4 |
---|
| 196 | |
---|
| 197 | # System Call Handler |
---|
| 198 | # ------------------------------------------------ |
---|
| 199 | cause_sys: |
---|
| 200 | la $14, cpu_do_syscall |
---|
| 201 | addiu $29, $29, -4 |
---|
| 202 | jalr $14 |
---|
| 203 | or $4, $0, $27 |
---|
| 204 | j kentry_exit |
---|
| 205 | or $19, $0, $2 |
---|
| 206 | |
---|
| 207 | # Interrupts Handler |
---|
| 208 | # ---------------------------------------------- |
---|
| 209 | cause_int: |
---|
| 210 | la $1, cpu_do_interrupt |
---|
| 211 | srl $7, $17, 10 # extract IP state, 4th arg |
---|
| 212 | addiu $29, $29, -4*4 # cpu_interrupt has 4 arg |
---|
| 213 | jal $1 |
---|
| 214 | andi $7, $7, 0x3F # 6 HW IRQ LINES, 2th arg is irq_state |
---|
| 215 | |
---|
| 216 | # Kentry exit |
---|
| 217 | # ---------------------------------------------- |
---|
| 218 | kentry_exit: |
---|
| 219 | #if CPU_IN_KERNEL |
---|
| 220 | # First signal that we are exiting from the kernel |
---|
| 221 | mfc0 $4, $15, 1 # arg is cpu_id |
---|
| 222 | andi $4, $4, 0x3 # mask all but CPU_local_id |
---|
| 223 | mfc0 $5, $4, 2 # read current thread pointer |
---|
| 224 | jal cpu_kexit |
---|
| 225 | addiu $29, $29, -8 |
---|
| 226 | addiu $29, $29, 8 |
---|
| 227 | #endif |
---|
| 228 | # Then load context ... |
---|
| 229 | or $27, $0, $19 |
---|
| 230 | lw $1, (AT*4)($27) |
---|
| 231 | lw $2, (V0*4)($27) |
---|
| 232 | lw $3, (V1*4)($27) |
---|
| 233 | lw $4, (A0*4)($27) |
---|
| 234 | lw $5, (A1*4)($27) |
---|
| 235 | lw $6, (A2*4)($27) |
---|
| 236 | lw $7, (A3*4)($27) |
---|
| 237 | lw $8, (T0*4)($27) |
---|
| 238 | lw $9, (T1*4)($27) |
---|
| 239 | lw $10, (T2*4)($27) |
---|
| 240 | lw $11, (T3*4)($27) |
---|
| 241 | lw $12, (T4*4)($27) |
---|
| 242 | lw $13, (T5*4)($27) |
---|
| 243 | lw $14, (T6*4)($27) |
---|
| 244 | lw $15, (T7*4)($27) |
---|
| 245 | lw $24, (T8*4)($27) |
---|
| 246 | lw $25, (T9*4)($27) |
---|
| 247 | lw $18, (S2*4)($27) |
---|
| 248 | lw $19, (S3*4)($27) |
---|
| 249 | lw $20, (S4*4)($27) |
---|
| 250 | lw $21, (S5*4)($27) |
---|
| 251 | lw $22, (S6*4)($27) |
---|
| 252 | lw $23, (S7*4)($27) |
---|
| 253 | lw $30, (S8*4)($27) |
---|
| 254 | lw $28, (GP*4)($27) |
---|
| 255 | lw $31, (RA*4)($27) |
---|
| 256 | lw $16, (EPC*4)($27) # load EPC |
---|
| 257 | lw $29, (SP*4)($27) # restore SP |
---|
| 258 | lw $17, (SR*4)($27) # load SR |
---|
| 259 | mfc0 $26, $12 # Read current SR |
---|
| 260 | andi $17, $17, 0x1F |
---|
| 261 | mtc0 $16, $14 # restore EPC |
---|
| 262 | or $26, $26, $17 |
---|
| 263 | lw $16, (LO*4)($27) # load LO |
---|
| 264 | mtc0 $26, $12 # setup new SR |
---|
| 265 | lw $17, (HI*4)($27) # load HI |
---|
| 266 | mtlo $16 # restore LO |
---|
| 267 | mthi $17 # restore HI |
---|
| 268 | |
---|
| 269 | lw $16, (S0*4)($27) |
---|
| 270 | lw $17, (S1*4)($27) |
---|
| 271 | |
---|
| 272 | #TODO: optimize |
---|
| 273 | lw $26, (MMU_MD*4)($27) # load MMU MODE |
---|
| 274 | andi $26, $26, 0xc |
---|
| 275 | beq $26, $0, OUT_MMU_3 # both MSB are 0 (the first two LSB are always set) |
---|
| 276 | andi $26, $26, 0x8 |
---|
| 277 | beq $26, $0, OUT_MMU_7 # first MSB is 0 (bit 2 is set) |
---|
| 278 | lw $26, (DP_EXT*4)($27) # load DP_EXT |
---|
| 279 | |
---|
| 280 | # Possible value for MMU: |
---|
| 281 | #In kernel mode : 0x7/0x3 |
---|
| 282 | #In user mode : 0xF |
---|
| 283 | |
---|
| 284 | # DP_EXT can either be local or remote |
---|
| 285 | #Once these register set we can no longer |
---|
| 286 | #access global data |
---|
| 287 | |
---|
| 288 | #If MMU mode was 0xF |
---|
| 289 | lw $27, (TLS_K1*4)($27) |
---|
| 290 | mtc2 $26, $24 # restore DP EXT |
---|
| 291 | ori $26, $0, 0xF # MMU 0xF value |
---|
| 292 | mtc2 $26, $1 # set MMU MODE |
---|
| 293 | j OUT_KENTRY |
---|
| 294 | nop |
---|
| 295 | |
---|
| 296 | OUT_MMU_7: |
---|
| 297 | #If MMU mode was 0x7 (uspace) |
---|
| 298 | lw $27, (TLS_K1*4)($27) |
---|
| 299 | mtc2 $26, $24 # restore DP EXT |
---|
| 300 | ori $26, $0, 0x7 # MMU 0x7 value |
---|
| 301 | mtc2 $26, $1 # set MMU MODE |
---|
| 302 | j OUT_KENTRY |
---|
| 303 | nop |
---|
| 304 | |
---|
| 305 | OUT_MMU_3: |
---|
| 306 | #If MMU mode was 0x3 |
---|
| 307 | lw $26, (DP_EXT*4)($27) # load DP_EXT |
---|
| 308 | lw $27, (TLS_K1*4)($27) |
---|
| 309 | mtc2 $26, $24 # restore DP EXT |
---|
| 310 | ori $26, $0, 0x3 # MMU 0x3 value |
---|
| 311 | mtc2 $26, $1 # set MMU MODE |
---|
| 312 | nop |
---|
| 313 | |
---|
| 314 | OUT_KENTRY: |
---|
| 315 | nop |
---|
| 316 | eret |
---|
| 317 | |
---|
| 318 | |
---|
| 319 | .end kentry |
---|
| 320 | .set reorder |
---|
| 321 | .set at |
---|
| 322 | |
---|
| 323 | .ent kentry_load |
---|
| 324 | kentry_load: |
---|
| 325 | #theses nops are required to load the eret instruction |
---|
| 326 | #while we are in virtual mode (processor pipeline) ? |
---|
| 327 | mtc2 $26, $1 # set MMU MODE |
---|
| 328 | nop |
---|
| 329 | nop |
---|
| 330 | eret |
---|
| 331 | .end kentry_load |
---|
| 332 | |
---|
| 333 | #------------------------------------------------------------------------------- |
---|
| 334 | |
---|