| 1 | /* SPDX-License-Identifier: GPL-2.0-only */
|
| 2 | /*
|
| 3 | * Exception handling for Microblaze
|
| 4 | *
|
| 5 | * Rewriten interrupt handling
|
| 6 | *
|
| 7 | * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
|
| 8 | * Copyright (C) 2008-2009 PetaLogix
|
| 9 | *
|
| 10 | * uClinux customisation (C) 2005 John Williams
|
| 11 | *
|
| 12 | * MMU code derived from arch/ppc/kernel/head_4xx.S:
|
| 13 | * Copyright (C) 1995-1996 Gary Thomas <gdt@linuxppc.org>
|
| 14 | * Initial PowerPC version.
|
| 15 | * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
|
| 16 | * Rewritten for PReP
|
| 17 | * Copyright (C) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
|
| 18 | * Low-level exception handers, MMU support, and rewrite.
|
| 19 | * Copyright (C) 1997 Dan Malek <dmalek@jlc.net>
|
| 20 | * PowerPC 8xx modifications.
|
| 21 | * Copyright (C) 1998-1999 TiVo, Inc.
|
| 22 | * PowerPC 403GCX modifications.
|
| 23 | * Copyright (C) 1999 Grant Erickson <grant@lcse.umn.edu>
|
| 24 | * PowerPC 403GCX/405GP modifications.
|
| 25 | * Copyright 2000 MontaVista Software Inc.
|
| 26 | * PPC405 modifications
|
| 27 | * PowerPC 403GCX/405GP modifications.
|
| 28 | * Author: MontaVista Software, Inc.
|
| 29 | * frank_rowand@mvista.com or source@mvista.com
|
| 30 | * debbie_chu@mvista.com
|
| 31 | *
|
| 32 | * Original code
|
| 33 | * Copyright (C) 2004 Xilinx, Inc.
|
| 34 | */
|
| 35 |
|
| 36 | /*
|
| 37 | * Here are the handlers which don't require enabling translation
|
| 38 | * and calling other kernel code thus we can keep their design very simple
|
| 39 | * and do all processing in real mode. All what they need is a valid current
|
| 40 | * (that is an issue for the CONFIG_REGISTER_TASK_PTR case)
|
| 41 | * This handlers use r3,r4,r5,r6 and optionally r[current] to work therefore
|
| 42 | * these registers are saved/restored
|
| 43 | * The handlers which require translation are in entry.S --KAA
|
| 44 | *
|
| 45 | * Microblaze HW Exception Handler
|
| 46 | * - Non self-modifying exception handler for the following exception conditions
|
| 47 | * - Unalignment
|
| 48 | * - Instruction bus error
|
| 49 | * - Data bus error
|
| 50 | * - Illegal instruction opcode
|
| 51 | * - Divide-by-zero
|
| 52 | *
|
| 53 | * - Privileged instruction exception (MMU)
|
| 54 | * - Data storage exception (MMU)
|
| 55 | * - Instruction storage exception (MMU)
|
| 56 | * - Data TLB miss exception (MMU)
|
| 57 | * - Instruction TLB miss exception (MMU)
|
| 58 | *
|
| 59 | * Note we disable interrupts during exception handling, otherwise we will
|
| 60 | * possibly get multiple re-entrancy if interrupt handles themselves cause
|
| 61 | * exceptions. JW
|
| 62 | */
|
| 63 |
|
| 64 | #include <asm/exceptions.h>
|
| 65 | #include <asm/unistd.h>
|
| 66 | #include <asm/page.h>
|
| 67 |
|
| 68 | #include <asm/entry.h>
|
| 69 | #include <asm/current.h>
|
| 70 | #include <linux/linkage.h>
|
| 71 | #include <linux/pgtable.h>
|
| 72 |
|
| 73 | #include <asm/mmu.h>
|
| 74 | #include <asm/signal.h>
|
| 75 | #include <asm/registers.h>
|
| 76 | #include <asm/asm-offsets.h>
|
| 77 |
|
| 78 | #undef DEBUG
|
| 79 |
|
| 80 | /* Helpful Macros */
|
| 81 | #define NUM_TO_REG(num) r ## num
|
| 82 |
|
| 83 | #define RESTORE_STATE \
|
| 84 | lwi r5, r1, 0; \
|
| 85 | mts rmsr, r5; \
|
| 86 | nop; \
|
| 87 | lwi r3, r1, PT_R3; \
|
| 88 | lwi r4, r1, PT_R4; \
|
| 89 | lwi r5, r1, PT_R5; \
|
| 90 | lwi r6, r1, PT_R6; \
|
| 91 | lwi r11, r1, PT_R11; \
|
| 92 | lwi r31, r1, PT_R31; \
|
| 93 | lwi r1, r1, PT_R1;
|
| 94 |
|
| 95 | #define LWREG_NOP \
|
| 96 | bri ex_handler_unhandled; \
|
| 97 | nop;
|
| 98 |
|
| 99 | #define SWREG_NOP \
|
| 100 | bri ex_handler_unhandled; \
|
| 101 | nop;
|
| 102 |
|
| 103 | /* r3 is the source */
|
| 104 | #define R3_TO_LWREG_V(regnum) \
|
| 105 | swi r3, r1, 4 * regnum; \
|
| 106 | bri ex_handler_done;
|
| 107 |
|
| 108 | /* r3 is the source */
|
| 109 | #define R3_TO_LWREG(regnum) \
|
| 110 | or NUM_TO_REG (regnum), r0, r3; \
|
| 111 | bri ex_handler_done;
|
| 112 |
|
| 113 | /* r3 is the target */
|
| 114 | #define SWREG_TO_R3_V(regnum) \
|
| 115 | lwi r3, r1, 4 * regnum; \
|
| 116 | bri ex_sw_tail;
|
| 117 |
|
| 118 | /* r3 is the target */
|
| 119 | #define SWREG_TO_R3(regnum) \
|
| 120 | or r3, r0, NUM_TO_REG (regnum); \
|
| 121 | bri ex_sw_tail;
|
| 122 |
|
| 123 | #define R3_TO_LWREG_VM_V(regnum) \
|
| 124 | brid ex_lw_end_vm; \
|
| 125 | swi r3, r7, 4 * regnum;
|
| 126 |
|
| 127 | #define R3_TO_LWREG_VM(regnum) \
|
| 128 | brid ex_lw_end_vm; \
|
| 129 | or NUM_TO_REG (regnum), r0, r3;
|
| 130 |
|
| 131 | #define SWREG_TO_R3_VM_V(regnum) \
|
| 132 | brid ex_sw_tail_vm; \
|
| 133 | lwi r3, r7, 4 * regnum;
|
| 134 |
|
| 135 | #define SWREG_TO_R3_VM(regnum) \
|
| 136 | brid ex_sw_tail_vm; \
|
| 137 | or r3, r0, NUM_TO_REG (regnum);
|
| 138 |
|
| 139 | /* Shift right instruction depending on available configuration */
|
| 140 | #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL == 0
|
| 141 | /* Only the used shift constants defined here - add more if needed */
|
| 142 | #define BSRLI2(rD, rA) \
|
| 143 | srl rD, rA; /* << 1 */ \
|
| 144 | srl rD, rD; /* << 2 */
|
| 145 | #define BSRLI4(rD, rA) \
|
| 146 | BSRLI2(rD, rA); \
|
| 147 | BSRLI2(rD, rD)
|
| 148 | #define BSRLI10(rD, rA) \
|
| 149 | srl rD, rA; /* << 1 */ \
|
| 150 | srl rD, rD; /* << 2 */ \
|
| 151 | srl rD, rD; /* << 3 */ \
|
| 152 | srl rD, rD; /* << 4 */ \
|
| 153 | srl rD, rD; /* << 5 */ \
|
| 154 | srl rD, rD; /* << 6 */ \
|
| 155 | srl rD, rD; /* << 7 */ \
|
| 156 | srl rD, rD; /* << 8 */ \
|
| 157 | srl rD, rD; /* << 9 */ \
|
| 158 | srl rD, rD /* << 10 */
|
| 159 | #define BSRLI20(rD, rA) \
|
| 160 | BSRLI10(rD, rA); \
|
| 161 | BSRLI10(rD, rD)
|
| 162 |
|
| 163 | .macro bsrli, rD, rA, IMM
|
| 164 | .if (\IMM) == 2
|
| 165 | BSRLI2(\rD, \rA)
|
| 166 | .elseif (\IMM) == 10
|
| 167 | BSRLI10(\rD, \rA)
|
| 168 | .elseif (\IMM) == 12
|
| 169 | BSRLI2(\rD, \rA)
|
| 170 | BSRLI10(\rD, \rD)
|
| 171 | .elseif (\IMM) == 14
|
| 172 | BSRLI4(\rD, \rA)
|
| 173 | BSRLI10(\rD, \rD)
|
| 174 | .elseif (\IMM) == 20
|
| 175 | BSRLI20(\rD, \rA)
|
| 176 | .elseif (\IMM) == 24
|
| 177 | BSRLI4(\rD, \rA)
|
| 178 | BSRLI20(\rD, \rD)
|
| 179 | .elseif (\IMM) == 28
|
| 180 | BSRLI4(\rD, \rA)
|
| 181 | BSRLI4(\rD, \rD)
|
| 182 | BSRLI20(\rD, \rD)
|
| 183 | .else
|
| 184 | .error "BSRLI shift macros \IMM"
|
| 185 | .endif
|
| 186 | .endm
|
| 187 | #endif
|
| 188 |
|
| 189 |
|
| 190 | .extern other_exception_handler /* Defined in exception.c */
|
| 191 |
|
| 192 | /*
|
| 193 | * hw_exception_handler - Handler for exceptions
|
| 194 | *
|
| 195 | * Exception handler notes:
|
| 196 | * - Handles all exceptions
|
| 197 | * - Does not handle unaligned exceptions during load into r17, r1, r0.
|
| 198 | * - Does not handle unaligned exceptions during store from r17 (cannot be
|
| 199 | * done) and r1 (slows down common case)
|
| 200 | *
|
| 201 | * Relevant register structures
|
| 202 | *
|
| 203 | * EAR - |----|----|----|----|----|----|----|----|
|
| 204 | * - < ## 32 bit faulting address ## >
|
| 205 | *
|
| 206 | * ESR - |----|----|----|----|----| - | - |-----|-----|
|
| 207 | * - W S REG EXC
|
| 208 | *
|
| 209 | *
|
| 210 | * STACK FRAME STRUCTURE (for CONFIG_MMU=n)
|
| 211 | * ----------------------------------------
|
| 212 | *
|
| 213 | * +-------------+ + 0
|
| 214 | * | MSR |
|
| 215 | * +-------------+ + 4
|
| 216 | * | r1 |
|
| 217 | * | . |
|
| 218 | * | . |
|
| 219 | * | . |
|
| 220 | * | . |
|
| 221 | * | r18 |
|
| 222 | * +-------------+ + 76
|
| 223 | * | . |
|
| 224 | * | . |
|
| 225 | *
|
| 226 | * MMU kernel uses the same 'pt_pool_space' pointed space
|
| 227 | * which is used for storing register values - noMMu style was, that values were
|
| 228 | * stored in stack but in case of failure you lost information about register.
|
| 229 | * Currently you can see register value in memory in specific place.
|
| 230 | * In compare to with previous solution the speed should be the same.
|
| 231 | *
|
| 232 | * MMU exception handler has different handling compare to no MMU kernel.
|
| 233 | * Exception handler use jump table for directing of what happen. For MMU kernel
|
| 234 | * is this approach better because MMU relate exception are handled by asm code
|
| 235 | * in this file. In compare to with MMU expect of unaligned exception
|
| 236 | * is everything handled by C code.
|
| 237 | */
|
| 238 |
|
| 239 | /*
|
| 240 | * every of these handlers is entered having R3/4/5/6/11/current saved on stack
|
| 241 | * and clobbered so care should be taken to restore them if someone is going to
|
| 242 | * return from exception
|
| 243 | */
|
| 244 |
|
| 245 | /* wrappers to restore state before coming to entry.S */
|
| 246 | .section .data
|
| 247 | .align 4
|
| 248 | pt_pool_space:
|
| 249 | .space PT_SIZE
|
| 250 |
|
| 251 | #ifdef DEBUG
|
| 252 | /* Create space for exception counting. */
|
| 253 | .section .data
|
| 254 | .global exception_debug_table
|
| 255 | .align 4
|
| 256 | exception_debug_table:
|
| 257 | /* Look at exception vector table. There is 32 exceptions * word size */
|
| 258 | .space (32 * 4)
|
| 259 | #endif /* DEBUG */
|
| 260 |
|
| 261 | .section .rodata
|
| 262 | .align 4
|
| 263 | _MB_HW_ExceptionVectorTable:
|
| 264 | /* 0 - Undefined */
|
| 265 | .long TOPHYS(ex_handler_unhandled)
|
| 266 | /* 1 - Unaligned data access exception */
|
| 267 | .long TOPHYS(handle_unaligned_ex)
|
| 268 | /* 2 - Illegal op-code exception */
|
| 269 | .long TOPHYS(full_exception_trapw)
|
| 270 | /* 3 - Instruction bus error exception */
|
| 271 | .long TOPHYS(full_exception_trapw)
|
| 272 | /* 4 - Data bus error exception */
|
| 273 | .long TOPHYS(full_exception_trapw)
|
| 274 | /* 5 - Divide by zero exception */
|
| 275 | .long TOPHYS(full_exception_trapw)
|
| 276 | /* 6 - Floating point unit exception */
|
| 277 | .long TOPHYS(full_exception_trapw)
|
| 278 | /* 7 - Privileged instruction exception */
|
| 279 | .long TOPHYS(full_exception_trapw)
|
| 280 | /* 8 - 15 - Undefined */
|
| 281 | .long TOPHYS(ex_handler_unhandled)
|
| 282 | .long TOPHYS(ex_handler_unhandled)
|
| 283 | .long TOPHYS(ex_handler_unhandled)
|
| 284 | .long TOPHYS(ex_handler_unhandled)
|
| 285 | .long TOPHYS(ex_handler_unhandled)
|
| 286 | .long TOPHYS(ex_handler_unhandled)
|
| 287 | .long TOPHYS(ex_handler_unhandled)
|
| 288 | .long TOPHYS(ex_handler_unhandled)
|
| 289 | /* 16 - Data storage exception */
|
| 290 | .long TOPHYS(handle_data_storage_exception)
|
| 291 | /* 17 - Instruction storage exception */
|
| 292 | .long TOPHYS(handle_instruction_storage_exception)
|
| 293 | /* 18 - Data TLB miss exception */
|
| 294 | .long TOPHYS(handle_data_tlb_miss_exception)
|
| 295 | /* 19 - Instruction TLB miss exception */
|
| 296 | .long TOPHYS(handle_instruction_tlb_miss_exception)
|
| 297 | /* 20 - 31 - Undefined */
|
| 298 | .long TOPHYS(ex_handler_unhandled)
|
| 299 | .long TOPHYS(ex_handler_unhandled)
|
| 300 | .long TOPHYS(ex_handler_unhandled)
|
| 301 | .long TOPHYS(ex_handler_unhandled)
|
| 302 | .long TOPHYS(ex_handler_unhandled)
|
| 303 | .long TOPHYS(ex_handler_unhandled)
|
| 304 | .long TOPHYS(ex_handler_unhandled)
|
| 305 | .long TOPHYS(ex_handler_unhandled)
|
| 306 | .long TOPHYS(ex_handler_unhandled)
|
| 307 | .long TOPHYS(ex_handler_unhandled)
|
| 308 | .long TOPHYS(ex_handler_unhandled)
|
| 309 | .long TOPHYS(ex_handler_unhandled)
|
| 310 |
|
| 311 | .global _hw_exception_handler
|
| 312 | .section .text
|
| 313 | .align 4
|
| 314 | .ent _hw_exception_handler
|
| 315 | _hw_exception_handler:
|
| 316 | /*
|
| 317 | * This handler saves into the static pt_pool_space buffer, not into a
|
| 318 | * stack frame, so the plain PT_* offsets are right here -- do not add
|
| 319 | * the PTO of entry.S's frames.
|
| 320 | */
|
| 321 | swi r1, r0, TOPHYS(pt_pool_space + PT_R1); /* GET_SP */
|
| 322 | /* Save date to kernel memory. Here is the problem
|
| 323 | * when you came from user space */
|
| 324 | ori r1, r0, TOPHYS(pt_pool_space);
|
| 325 | swi r3, r1, PT_R3
|
| 326 | swi r4, r1, PT_R4
|
| 327 | swi r5, r1, PT_R5
|
| 328 | swi r6, r1, PT_R6
|
| 329 |
|
| 330 | swi r11, r1, PT_R11
|
| 331 | swi r31, r1, PT_R31
|
| 332 | lwi r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)) /* get saved current */
|
| 333 |
|
| 334 | mfs r5, rmsr;
|
| 335 | nop
|
| 336 | swi r5, r1, 0;
|
| 337 | mfs r4, resr
|
| 338 | nop
|
| 339 | mfs r3, rear;
|
| 340 | nop
|
| 341 |
|
| 342 | andi r5, r4, 0x1F; /* Extract ESR[EXC] */
|
| 343 |
|
| 344 | /* Calculate exception vector offset = r5 << 2 */
|
| 345 | addk r6, r5, r5; /* << 1 */
|
| 346 | addk r6, r6, r6; /* << 2 */
|
| 347 |
|
| 348 | |
| 349 | /* counting which exception happen */
|
| 350 | lwi r5, r0, TOPHYS(exception_debug_table)
|
| 351 | addi r5, r5, 1
|
| 352 | swi r5, r0, TOPHYS(exception_debug_table)
|
| 353 | lwi r5, r6, TOPHYS(exception_debug_table)
|
| 354 | addi r5, r5, 1
|
| 355 | swi r5, r6, TOPHYS(exception_debug_table)
|
| 356 | |
| 357 | /* end */
|
| 358 | /* Load the HW Exception vector */
|
| 359 | lwi r6, r6, TOPHYS(_MB_HW_ExceptionVectorTable)
|
| 360 | bra r6
|
| 361 |
|
| 362 | full_exception_trapw:
|
| 363 | RESTORE_STATE
|
| 364 | bri full_exception_trap
|
| 365 |
|
| 366 | /* 0x01 - Unaligned data access exception
|
| 367 | * This occurs when a word access is not aligned on a word boundary,
|
| 368 | * or when a 16-bit access is not aligned on a 16-bit boundary.
|
| 369 | * This handler perform the access, and returns, except for MMU when
|
| 370 | * the unaligned address is last on a 4k page or the physical address is
|
| 371 | * not found in the page table, in which case unaligned_data_trap is called.
|
| 372 | */
|
| 373 | handle_unaligned_ex:
|
| 374 | /* Working registers already saved: R3, R4, R5, R6
|
| 375 | * R4 = ESR
|
| 376 | * R3 = EAR
|
| 377 | */
|
| 378 | andi r6, r4, 0x1000 /* Check ESR[DS] */
|
| 379 | beqi r6, _no_delayslot /* Branch if ESR[DS] not set */
|
| 380 | mfs r17, rbtr; /* ESR[DS] set - return address in BTR */
|
| 381 | nop
|
| 382 | _no_delayslot:
|
| 383 | /* jump to high level unaligned handler */
|
| 384 | RESTORE_STATE;
|
| 385 | bri unaligned_data_trap
|
| 386 |
|
| 387 | andi r6, r4, 0x3E0; /* Mask and extract the register operand */
|
| 388 | srl r6, r6; /* r6 >> 5 */
|
| 389 | srl r6, r6;
|
| 390 | srl r6, r6;
|
| 391 | srl r6, r6;
|
| 392 | srl r6, r6;
|
| 393 | /* Store the register operand in a temporary location */
|
| 394 | sbi r6, r0, TOPHYS(ex_reg_op);
|
| 395 |
|
| 396 | andi r6, r4, 0x400; /* Extract ESR[S] */
|
| 397 | bnei r6, ex_sw;
|
| 398 | ex_lw:
|
| 399 | andi r6, r4, 0x800; /* Extract ESR[W] */
|
| 400 | beqi r6, ex_lhw;
|
| 401 | lbui r5, r3, 0; /* Exception address in r3 */
|
| 402 | /* Load a word, byte-by-byte from destination address
|
| 403 | and save it in tmp space */
|
| 404 | sbi r5, r0, TOPHYS(ex_tmp_data_loc_0);
|
| 405 | lbui r5, r3, 1;
|
| 406 | sbi r5, r0, TOPHYS(ex_tmp_data_loc_1);
|
| 407 | lbui r5, r3, 2;
|
| 408 | sbi r5, r0, TOPHYS(ex_tmp_data_loc_2);
|
| 409 | lbui r5, r3, 3;
|
| 410 | sbi r5, r0, TOPHYS(ex_tmp_data_loc_3);
|
| 411 | /* Get the destination register value into r4 */
|
| 412 | lwi r4, r0, TOPHYS(ex_tmp_data_loc_0);
|
| 413 | bri ex_lw_tail;
|
| 414 | ex_lhw:
|
| 415 | lbui r5, r3, 0; /* Exception address in r3 */
|
| 416 | /* Load a half-word, byte-by-byte from destination
|
| 417 | address and save it in tmp space */
|
| 418 | sbi r5, r0, TOPHYS(ex_tmp_data_loc_0);
|
| 419 | lbui r5, r3, 1;
|
| 420 | sbi r5, r0, TOPHYS(ex_tmp_data_loc_1);
|
| 421 | /* Get the destination register value into r4 */
|
| 422 | lhui r4, r0, TOPHYS(ex_tmp_data_loc_0);
|
| 423 | ex_lw_tail:
|
| 424 | /* Get the destination register number into r5 */
|
| 425 | lbui r5, r0, TOPHYS(ex_reg_op);
|
| 426 | /* Form load_word jump table offset (lw_table + (8 * regnum)) */
|
| 427 | addik r6, r0, TOPHYS(lw_table);
|
| 428 | addk r5, r5, r5;
|
| 429 | addk r5, r5, r5;
|
| 430 | addk r5, r5, r5;
|
| 431 | addk r5, r5, r6;
|
| 432 | bra r5;
|
| 433 | ex_lw_end: /* Exception handling of load word, ends */
|
| 434 | ex_sw:
|
| 435 | /* Get the destination register number into r5 */
|
| 436 | lbui r5, r0, TOPHYS(ex_reg_op);
|
| 437 | /* Form store_word jump table offset (sw_table + (8 * regnum)) */
|
| 438 | addik r6, r0, TOPHYS(sw_table);
|
| 439 | add r5, r5, r5;
|
| 440 | add r5, r5, r5;
|
| 441 | add r5, r5, r5;
|
| 442 | add r5, r5, r6;
|
| 443 | bra r5;
|
| 444 | ex_sw_tail:
|
| 445 | mfs r6, resr;
|
| 446 | nop
|
| 447 | andi r6, r6, 0x800; /* Extract ESR[W] */
|
| 448 | beqi r6, ex_shw;
|
| 449 | /* Get the word - delay slot */
|
| 450 | swi r4, r0, TOPHYS(ex_tmp_data_loc_0);
|
| 451 | /* Store the word, byte-by-byte into destination address */
|
| 452 | lbui r4, r0, TOPHYS(ex_tmp_data_loc_0);
|
| 453 | sbi r4, r3, 0;
|
| 454 | lbui r4, r0, TOPHYS(ex_tmp_data_loc_1);
|
| 455 | sbi r4, r3, 1;
|
| 456 | lbui r4, r0, TOPHYS(ex_tmp_data_loc_2);
|
| 457 | sbi r4, r3, 2;
|
| 458 | lbui r4, r0, TOPHYS(ex_tmp_data_loc_3);
|
| 459 | sbi r4, r3, 3;
|
| 460 | bri ex_handler_done;
|
| 461 |
|
| 462 | ex_shw:
|
| 463 | /* Store the lower half-word, byte-by-byte into destination address */
|
| 464 | swi r4, r0, TOPHYS(ex_tmp_data_loc_0);
|
| 465 | lbui r4, r0, TOPHYS(ex_tmp_data_loc_2);
|
| 466 | sbi r4, r3, 0;
|
| 467 | lbui r4, r0, TOPHYS(ex_tmp_data_loc_3);
|
| 468 | sbi r4, r3, 1;
|
| 469 | ex_sw_end: /* Exception handling of store word, ends. */
|
| 470 |
|
| 471 | ex_handler_done:
|
| 472 | RESTORE_STATE;
|
| 473 | rted r17, 0
|
| 474 | nop
|
| 475 |
|
| 476 | /* Exception vector entry code. This code runs with address translation
|
| 477 | * turned off (i.e. using physical addresses). */
|
| 478 |
|
| 479 | /* Exception vectors. */
|
| 480 |
|
| 481 | /* 0x10 - Data Storage Exception
|
| 482 | * This happens for just a few reasons. U0 set (but we don't do that),
|
| 483 | * or zone protection fault (user violation, write to protected page).
|
| 484 | * If this is just an update of modified status, we do that quickly
|
| 485 | * and exit. Otherwise, we call heavyweight functions to do the work.
|
| 486 | */
|
| 487 | handle_data_storage_exception:
|
| 488 | /* Working registers already saved: R3, R4, R5, R6
|
| 489 | * R3 = ESR
|
| 490 | */
|
| 491 | mfs r11, rpid
|
| 492 | nop
|
| 493 | /* If we are faulting a kernel address, we have to use the
|
| 494 | * kernel page tables.
|
| 495 | */
|
| 496 | ori r5, r0, CONFIG_KERNEL_START
|
| 497 | cmpu r5, r3, r5
|
| 498 | bgti r5, ex3
|
| 499 | /* First, check if it was a zone fault (which means a user
|
| 500 | * tried to access a kernel or read-protected page - always
|
| 501 | * a SEGV). All other faults here must be stores, so no
|
| 502 | * need to check ESR_S as well. */
|
| 503 | andi r4, r4, ESR_DIZ /* ESR_Z - zone protection */
|
| 504 | bnei r4, ex2
|
| 505 |
|
| 506 | ori r4, r0, swapper_pg_dir
|
| 507 | mts rpid, r0 /* TLB will have 0 TID */
|
| 508 | nop
|
| 509 | bri ex4
|
| 510 |
|
| 511 | /* Get the PGD for the current thread. */
|
| 512 | ex3:
|
| 513 | /* First, check if it was a zone fault (which means a user
|
| 514 | * tried to access a kernel or read-protected page - always
|
| 515 | * a SEGV). All other faults here must be stores, so no
|
| 516 | * need to check ESR_S as well. */
|
| 517 | andi r4, r4, ESR_DIZ /* ESR_Z */
|
| 518 | bnei r4, ex2
|
| 519 | /* get current task address */
|
| 520 | addi r4 ,CURRENT_TASK, TOPHYS(0);
|
| 521 | lwi r4, r4, TASK_THREAD+PGDIR
|
| 522 | ex4:
|
| 523 | tophys(r4,r4)
|
| 524 | /* Create L1 (pgdir/pmd) address */
|
| 525 | bsrli r5, r3, PGDIR_SHIFT - 2
|
| 526 | andi r5, r5, PAGE_SIZE - 4
|
| 527 | /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
|
| 528 | or r4, r4, r5
|
| 529 | lwi r4, r4, 0 /* Get L1 entry */
|
| 530 | andi r5, r4, PAGE_MASK /* Extract L2 (pte) base address */
|
| 531 | beqi r5, ex2 /* Bail if no table */
|
| 532 |
|
| 533 | tophys(r5,r5)
|
| 534 | bsrli r6, r3, PTE_SHIFT /* Compute PTE address */
|
| 535 | andi r6, r6, PAGE_SIZE - 4
|
| 536 | or r5, r5, r6
|
| 537 | lwi r4, r5, 0 /* Get Linux PTE */
|
| 538 |
|
| 539 | andi r6, r4, _PAGE_RW /* Is it writeable? */
|
| 540 | beqi r6, ex2 /* Bail if not */
|
| 541 |
|
| 542 | /* Update 'changed' */
|
| 543 | ori r4, r4, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
|
| 544 | swi r4, r5, 0 /* Update Linux page table */
|
| 545 |
|
| 546 | /* Most of the Linux PTE is ready to load into the TLB LO.
|
| 547 | * We set ZSEL, where only the LS-bit determines user access.
|
| 548 | * We set execute, because we don't have the granularity to
|
| 549 | * properly set this at the page level (Linux problem).
|
| 550 | * If shared is set, we cause a zero PID->TID load.
|
| 551 | * Many of these bits are software only. Bits we don't set
|
| 552 | * here we (properly should) assume have the appropriate value.
|
| 553 | */
|
| 554 | /* Ignore memory coherent, just LSB on ZSEL is used + EX/WR */
|
| 555 | andi r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \
|
| 556 | TLB_ZSEL(1) | TLB_ATTR_MASK
|
| 557 | ori r4, r4, _PAGE_HWEXEC /* make it executable */
|
| 558 |
|
| 559 | /* find the TLB index that caused the fault. It has to be here*/
|
| 560 | mts rtlbsx, r3
|
| 561 | nop
|
| 562 | mfs r5, rtlbx /* DEBUG: TBD */
|
| 563 | nop
|
| 564 | mts rtlblo, r4 /* Load TLB LO */
|
| 565 | nop
|
| 566 | /* Will sync shadow TLBs */
|
| 567 |
|
| 568 | /* Done...restore registers and get out of here. */
|
| 569 | mts rpid, r11
|
| 570 | nop
|
| 571 | bri 4
|
| 572 |
|
| 573 | RESTORE_STATE;
|
| 574 | rted r17, 0
|
| 575 | nop
|
| 576 | ex2:
|
| 577 | /* The bailout. Restore registers to pre-exception conditions
|
| 578 | * and call the heavyweights to help us out. */
|
| 579 | mts rpid, r11
|
| 580 | nop
|
| 581 | bri 4
|
| 582 | RESTORE_STATE;
|
| 583 | bri page_fault_data_trap
|
| 584 |
|
| 585 |
|
| 586 | /* 0x11 - Instruction Storage Exception
|
| 587 | * This is caused by a fetch from non-execute or guarded pages. */
|
| 588 | handle_instruction_storage_exception:
|
| 589 | /* Working registers already saved: R3, R4, R5, R6
|
| 590 | * R3 = ESR
|
| 591 | */
|
| 592 |
|
| 593 | RESTORE_STATE;
|
| 594 | bri page_fault_instr_trap
|
| 595 |
|
| 596 | /* 0x12 - Data TLB Miss Exception
|
| 597 | * As the name implies, translation is not in the MMU, so search the
|
| 598 | * page tables and fix it. The only purpose of this function is to
|
| 599 | * load TLB entries from the page table if they exist.
|
| 600 | */
|
| 601 | handle_data_tlb_miss_exception:
|
| 602 | /* Working registers already saved: R3, R4, R5, R6
|
| 603 | * R3 = EAR, R4 = ESR
|
| 604 | */
|
| 605 | mfs r11, rpid
|
| 606 | nop
|
| 607 |
|
| 608 | /* If we are faulting a kernel address, we have to use the
|
| 609 | * kernel page tables. */
|
| 610 | ori r6, r0, CONFIG_KERNEL_START
|
| 611 | cmpu r4, r3, r6
|
| 612 | bgti r4, ex5
|
| 613 | ori r4, r0, swapper_pg_dir
|
| 614 | mts rpid, r0 /* TLB will have 0 TID */
|
| 615 | nop
|
| 616 | bri ex6
|
| 617 |
|
| 618 | /* Get the PGD for the current thread. */
|
| 619 | ex5:
|
| 620 | /* get current task address */
|
| 621 | addi r4 ,CURRENT_TASK, TOPHYS(0);
|
| 622 | lwi r4, r4, TASK_THREAD+PGDIR
|
| 623 | ex6:
|
| 624 | tophys(r4,r4)
|
| 625 | /* Create L1 (pgdir/pmd) address */
|
| 626 | bsrli r5, r3, PGDIR_SHIFT - 2
|
| 627 | andi r5, r5, PAGE_SIZE - 4
|
| 628 | /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
|
| 629 | or r4, r4, r5
|
| 630 | lwi r4, r4, 0 /* Get L1 entry */
|
| 631 | andi r5, r4, PAGE_MASK /* Extract L2 (pte) base address */
|
| 632 | beqi r5, ex7 /* Bail if no table */
|
| 633 |
|
| 634 | tophys(r5,r5)
|
| 635 | bsrli r6, r3, PTE_SHIFT /* Compute PTE address */
|
| 636 | andi r6, r6, PAGE_SIZE - 4
|
| 637 | or r5, r5, r6
|
| 638 | lwi r4, r5, 0 /* Get Linux PTE */
|
| 639 |
|
| 640 | andi r6, r4, _PAGE_PRESENT
|
| 641 | beqi r6, ex7
|
| 642 |
|
| 643 | ori r4, r4, _PAGE_ACCESSED
|
| 644 | swi r4, r5, 0
|
| 645 |
|
| 646 | /* Most of the Linux PTE is ready to load into the TLB LO.
|
| 647 | * We set ZSEL, where only the LS-bit determines user access.
|
| 648 | * We set execute, because we don't have the granularity to
|
| 649 | * properly set this at the page level (Linux problem).
|
| 650 | * If shared is set, we cause a zero PID->TID load.
|
| 651 | * Many of these bits are software only. Bits we don't set
|
| 652 | * here we (properly should) assume have the appropriate value.
|
| 653 | */
|
| 654 | brid finish_tlb_load
|
| 655 | andi r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \
|
| 656 | TLB_ZSEL(1) | TLB_ATTR_MASK
|
| 657 | ex7:
|
| 658 | /* The bailout. Restore registers to pre-exception conditions
|
| 659 | * and call the heavyweights to help us out.
|
| 660 | */
|
| 661 | mts rpid, r11
|
| 662 | nop
|
| 663 | bri 4
|
| 664 | RESTORE_STATE;
|
| 665 | bri page_fault_data_trap
|
| 666 |
|
| 667 | /* 0x13 - Instruction TLB Miss Exception
|
| 668 | * Nearly the same as above, except we get our information from
|
| 669 | * different registers and bailout to a different point.
|
| 670 | */
|
| 671 | handle_instruction_tlb_miss_exception:
|
| 672 | /* Working registers already saved: R3, R4, R5, R6
|
| 673 | * R3 = ESR
|
| 674 | */
|
| 675 | mfs r11, rpid
|
| 676 | nop
|
| 677 |
|
| 678 | /* If we are faulting a kernel address, we have to use the
|
| 679 | * kernel page tables.
|
| 680 | */
|
| 681 | ori r4, r0, CONFIG_KERNEL_START
|
| 682 | cmpu r4, r3, r4
|
| 683 | bgti r4, ex8
|
| 684 | ori r4, r0, swapper_pg_dir
|
| 685 | mts rpid, r0 /* TLB will have 0 TID */
|
| 686 | nop
|
| 687 | bri ex9
|
| 688 |
|
| 689 | /* Get the PGD for the current thread. */
|
| 690 | ex8:
|
| 691 | /* get current task address */
|
| 692 | addi r4 ,CURRENT_TASK, TOPHYS(0);
|
| 693 | lwi r4, r4, TASK_THREAD+PGDIR
|
| 694 | ex9:
|
| 695 | tophys(r4,r4)
|
| 696 | /* Create L1 (pgdir/pmd) address */
|
| 697 | bsrli r5, r3, PGDIR_SHIFT - 2
|
| 698 | andi r5, r5, PAGE_SIZE - 4
|
| 699 | /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
|
| 700 | or r4, r4, r5
|
| 701 | lwi r4, r4, 0 /* Get L1 entry */
|
| 702 | andi r5, r4, PAGE_MASK /* Extract L2 (pte) base address */
|
| 703 | beqi r5, ex10 /* Bail if no table */
|
| 704 |
|
| 705 | tophys(r5,r5)
|
| 706 | bsrli r6, r3, PTE_SHIFT /* Compute PTE address */
|
| 707 | andi r6, r6, PAGE_SIZE - 4
|
| 708 | or r5, r5, r6
|
| 709 | lwi r4, r5, 0 /* Get Linux PTE */
|
| 710 |
|
| 711 | andi r6, r4, _PAGE_PRESENT
|
| 712 | beqi r6, ex10
|
| 713 |
|
| 714 | ori r4, r4, _PAGE_ACCESSED
|
| 715 | swi r4, r5, 0
|
| 716 |
|
| 717 | /* Most of the Linux PTE is ready to load into the TLB LO.
|
| 718 | * We set ZSEL, where only the LS-bit determines user access.
|
| 719 | * We set execute, because we don't have the granularity to
|
| 720 | * properly set this at the page level (Linux problem).
|
| 721 | * If shared is set, we cause a zero PID->TID load.
|
| 722 | * Many of these bits are software only. Bits we don't set
|
| 723 | * here we (properly should) assume have the appropriate value.
|
| 724 | */
|
| 725 | brid finish_tlb_load
|
| 726 | andi r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \
|
| 727 | TLB_ZSEL(1) | TLB_ATTR_MASK
|
| 728 | ex10:
|
| 729 | /* The bailout. Restore registers to pre-exception conditions
|
| 730 | * and call the heavyweights to help us out.
|
| 731 | */
|
| 732 | mts rpid, r11
|
| 733 | nop
|
| 734 | bri 4
|
| 735 | RESTORE_STATE;
|
| 736 | bri page_fault_instr_trap
|
| 737 |
|
| 738 | /* Both the instruction and data TLB miss get to this point to load the TLB.
|
| 739 | * r3 - EA of fault
|
| 740 | * r4 - TLB LO (info from Linux PTE)
|
| 741 | * r5, r6 - available to use
|
| 742 | * PID - loaded with proper value when we get here
|
| 743 | * Upon exit, we reload everything and RFI.
|
| 744 | * A common place to load the TLB.
|
| 745 | */
|
| 746 | .section .data
|
| 747 | .align 4
|
| 748 | .global tlb_skip
|
| 749 | tlb_skip:
|
| 750 | .long MICROBLAZE_TLB_SKIP
|
| 751 | tlb_index:
|
| 752 | /* MS: storing last used tlb index */
|
| 753 | .long MICROBLAZE_TLB_SIZE/2
|
| 754 | .previous
|
| 755 | finish_tlb_load:
|
| 756 | /* MS: load the last used TLB index. */
|
| 757 | lwi r5, r0, TOPHYS(tlb_index)
|
| 758 | addik r5, r5, 1 /* MS: inc tlb_index -> use next one */
|
| 759 |
|
| 760 | /* MS: FIXME this is potential fault, because this is mask not count */
|
| 761 | andi r5, r5, MICROBLAZE_TLB_SIZE - 1
|
| 762 | ori r6, r0, 1
|
| 763 | cmp r31, r5, r6
|
| 764 | blti r31, ex12
|
| 765 | lwi r5, r0, TOPHYS(tlb_skip)
|
| 766 | ex12:
|
| 767 | /* MS: save back current TLB index */
|
| 768 | swi r5, r0, TOPHYS(tlb_index)
|
| 769 |
|
| 770 | ori r4, r4, _PAGE_HWEXEC /* make it executable */
|
| 771 | mts rtlbx, r5 /* MS: save current TLB */
|
| 772 | nop
|
| 773 | mts rtlblo, r4 /* MS: save to TLB LO */
|
| 774 | nop
|
| 775 |
|
| 776 | /* Create EPN. This is the faulting address plus a static
|
| 777 | * set of bits. These are size, valid, E, U0, and ensure
|
| 778 | * bits 20 and 21 are zero.
|
| 779 | */
|
| 780 | andi r3, r3, PAGE_MASK
|
| 781 | ori r3, r3, TLB_VALID | TLB_PAGESZ(PAGESZ_4K)
|
| 782 | mts rtlbhi, r3 /* Load TLB HI */
|
| 783 | nop
|
| 784 |
|
| 785 | /* Done...restore registers and get out of here. */
|
| 786 | mts rpid, r11
|
| 787 | nop
|
| 788 | bri 4
|
| 789 | RESTORE_STATE;
|
| 790 | rted r17, 0
|
| 791 | nop
|
| 792 |
|
| 793 | /* extern void giveup_fpu(struct task_struct *prev)
|
| 794 | *
|
| 795 | * The MicroBlaze processor may have an FPU, so this should not just
|
| 796 | * return: TBD.
|
| 797 | */
|
| 798 | .globl giveup_fpu;
|
| 799 | .align 4;
|
| 800 | giveup_fpu:
|
| 801 | bralid r15,0 /* TBD */
|
| 802 | nop
|
| 803 |
|
| 804 | /* At present, this routine just hangs. - extern void abort(void) */
|
| 805 | .globl abort;
|
| 806 | .align 4;
|
| 807 | abort:
|
| 808 | br r0
|
| 809 |
|
| 810 | .globl set_context;
|
| 811 | .align 4;
|
| 812 | set_context:
|
| 813 | mts rpid, r5 /* Shadow TLBs are automatically */
|
| 814 | nop
|
| 815 | bri 4 /* flushed by changing PID */
|
| 816 | rtsd r15,8
|
| 817 | nop
|
| 818 |
|
| 819 | .end _hw_exception_handler
|
| 820 |
|
| 821 | /* Unaligned data access exception last on a 4k page for MMU.
|
| 822 | * When this is called, we are in virtual mode with exceptions enabled
|
| 823 | * and registers 1-13,15,17,18 saved.
|
| 824 | *
|
| 825 | * R3 = ESR
|
| 826 | * R4 = EAR
|
| 827 | * R7 = pointer to saved registers (struct pt_regs *regs)
|
| 828 | *
|
| 829 | * This handler perform the access, and returns via ret_from_exc.
|
| 830 | */
|
| 831 | .global _unaligned_data_exception
|
| 832 | .ent _unaligned_data_exception
|
| 833 | _unaligned_data_exception:
|
| 834 | andi r8, r3, 0x3E0; /* Mask and extract the register operand */
|
| 835 | bsrli r8, r8, 2; /* r8 >> 2 = register operand * 8 */
|
| 836 | andi r6, r3, 0x400; /* Extract ESR[S] */
|
| 837 | bneid r6, ex_sw_vm;
|
| 838 | andi r6, r3, 0x800; /* Extract ESR[W] - delay slot */
|
| 839 | ex_lw_vm:
|
| 840 | beqid r6, ex_lhw_vm;
|
| 841 | load1: lbui r5, r4, 0; /* Exception address in r4 - delay slot */
|
| 842 | /* Load a word, byte-by-byte from destination address and save it in tmp space*/
|
| 843 | addik r6, r0, ex_tmp_data_loc_0;
|
| 844 | sbi r5, r6, 0;
|
| 845 | load2: lbui r5, r4, 1;
|
| 846 | sbi r5, r6, 1;
|
| 847 | load3: lbui r5, r4, 2;
|
| 848 | sbi r5, r6, 2;
|
| 849 | load4: lbui r5, r4, 3;
|
| 850 | sbi r5, r6, 3;
|
| 851 | brid ex_lw_tail_vm;
|
| 852 | /* Get the destination register value into r3 - delay slot */
|
| 853 | lwi r3, r6, 0;
|
| 854 | ex_lhw_vm:
|
| 855 | /* Load a half-word, byte-by-byte from destination address and
|
| 856 | * save it in tmp space */
|
| 857 | addik r6, r0, ex_tmp_data_loc_0;
|
| 858 | sbi r5, r6, 0;
|
| 859 | load5: lbui r5, r4, 1;
|
| 860 | sbi r5, r6, 1;
|
| 861 | lhui r3, r6, 0; /* Get the destination register value into r3 */
|
| 862 | ex_lw_tail_vm:
|
| 863 | /* Form load_word jump table offset (lw_table_vm + (8 * regnum)) */
|
| 864 | addik r5, r8, lw_table_vm;
|
| 865 | bra r5;
|
| 866 | ex_lw_end_vm: /* Exception handling of load word, ends */
|
| 867 | brai ret_from_exc;
|
| 868 | ex_sw_vm:
|
| 869 | /* Form store_word jump table offset (sw_table_vm + (8 * regnum)) */
|
| 870 | addik r5, r8, sw_table_vm;
|
| 871 | bra r5;
|
| 872 | ex_sw_tail_vm:
|
| 873 | addik r5, r0, ex_tmp_data_loc_0;
|
| 874 | beqid r6, ex_shw_vm;
|
| 875 | swi r3, r5, 0; /* Get the word - delay slot */
|
| 876 | /* Store the word, byte-by-byte into destination address */
|
| 877 | lbui r3, r5, 0;
|
| 878 | store1: sbi r3, r4, 0;
|
| 879 | lbui r3, r5, 1;
|
| 880 | store2: sbi r3, r4, 1;
|
| 881 | lbui r3, r5, 2;
|
| 882 | store3: sbi r3, r4, 2;
|
| 883 | lbui r3, r5, 3;
|
| 884 | brid ret_from_exc;
|
| 885 | store4: sbi r3, r4, 3; /* Delay slot */
|
| 886 | ex_shw_vm:
|
| 887 | /* Store the lower half-word, byte-by-byte into destination address */
|
| 888 | #ifdef __MICROBLAZEEL__
|
| 889 | lbui r3, r5, 0;
|
| 890 | store5: sbi r3, r4, 0;
|
| 891 | lbui r3, r5, 1;
|
| 892 | brid ret_from_exc;
|
| 893 | store6: sbi r3, r4, 1; /* Delay slot */
|
| 894 | #else
|
| 895 | lbui r3, r5, 2;
|
| 896 | store5: sbi r3, r4, 0;
|
| 897 | lbui r3, r5, 3;
|
| 898 | brid ret_from_exc;
|
| 899 | store6: sbi r3, r4, 1; /* Delay slot */
|
| 900 | #endif
|
| 901 |
|
| 902 | ex_sw_end_vm: /* Exception handling of store word, ends. */
|
| 903 |
|
| 904 | /* We have to prevent cases that get/put_user macros get unaligned pointer
|
| 905 | * to bad page area. We have to find out which origin instruction caused it
|
| 906 | * and called fixup for that origin instruction not instruction in unaligned
|
| 907 | * handler */
|
| 908 | ex_unaligned_fixup:
|
| 909 | ori r5, r7, 0 /* setup pointer to pt_regs */
|
| 910 | lwi r6, r7, PT_PC; /* faulting address is one instruction above */
|
| 911 | addik r6, r6, -4 /* for finding proper fixup */
|
| 912 | swi r6, r7, PT_PC; /* a save back it to PT_PC */
|
| 913 | addik r7, r0, SIGSEGV
|
| 914 | /* call bad_page_fault for finding aligned fixup, fixup address is saved
|
| 915 | * in PT_PC which is used as return address from exception */
|
| 916 | addik r15, r0, ret_from_exc-8 /* setup return address */
|
| 917 | brid bad_page_fault
|
| 918 | nop
|
| 919 |
|
| 920 | /* We prevent all load/store because it could failed any attempt to access */
|
| 921 | .section __ex_table,"a";
|
| 922 | .word load1,ex_unaligned_fixup;
|
| 923 | .word load2,ex_unaligned_fixup;
|
| 924 | .word load3,ex_unaligned_fixup;
|
| 925 | .word load4,ex_unaligned_fixup;
|
| 926 | .word load5,ex_unaligned_fixup;
|
| 927 | .word store1,ex_unaligned_fixup;
|
| 928 | .word store2,ex_unaligned_fixup;
|
| 929 | .word store3,ex_unaligned_fixup;
|
| 930 | .word store4,ex_unaligned_fixup;
|
| 931 | .word store5,ex_unaligned_fixup;
|
| 932 | .word store6,ex_unaligned_fixup;
|
| 933 | .previous;
|
| 934 | .end _unaligned_data_exception
|
| 935 |
|
| 936 | .global ex_handler_unhandled
|
| 937 | ex_handler_unhandled:
|
| 938 | /* FIXME add handle function for unhandled exception - dump register */
|
| 939 | bri 0
|
| 940 |
|
| 941 | /*
|
| 942 | * hw_exception_handler Jump Table
|
| 943 | * - Contains code snippets for each register that caused the unalign exception
|
| 944 | * - Hence exception handler is NOT self-modifying
|
| 945 | * - Separate table for load exceptions and store exceptions.
|
| 946 | * - Each table is of size: (8 * 32) = 256 bytes
|
| 947 | */
|
| 948 |
|
| 949 | .section .text
|
| 950 | .align 4
|
| 951 | lw_table:
|
| 952 | lw_r0: R3_TO_LWREG (0);
|
| 953 | lw_r1: LWREG_NOP;
|
| 954 | lw_r2: R3_TO_LWREG (2);
|
| 955 | lw_r3: R3_TO_LWREG_V (3);
|
| 956 | lw_r4: R3_TO_LWREG_V (4);
|
| 957 | lw_r5: R3_TO_LWREG_V (5);
|
| 958 | lw_r6: R3_TO_LWREG_V (6);
|
| 959 | lw_r7: R3_TO_LWREG (7);
|
| 960 | lw_r8: R3_TO_LWREG (8);
|
| 961 | lw_r9: R3_TO_LWREG (9);
|
| 962 | lw_r10: R3_TO_LWREG (10);
|
| 963 | lw_r11: R3_TO_LWREG (11);
|
| 964 | lw_r12: R3_TO_LWREG (12);
|
| 965 | lw_r13: R3_TO_LWREG (13);
|
| 966 | lw_r14: R3_TO_LWREG (14);
|
| 967 | lw_r15: R3_TO_LWREG (15);
|
| 968 | lw_r16: R3_TO_LWREG (16);
|
| 969 | lw_r17: LWREG_NOP;
|
| 970 | lw_r18: R3_TO_LWREG (18);
|
| 971 | lw_r19: R3_TO_LWREG (19);
|
| 972 | lw_r20: R3_TO_LWREG (20);
|
| 973 | lw_r21: R3_TO_LWREG (21);
|
| 974 | lw_r22: R3_TO_LWREG (22);
|
| 975 | lw_r23: R3_TO_LWREG (23);
|
| 976 | lw_r24: R3_TO_LWREG (24);
|
| 977 | lw_r25: R3_TO_LWREG (25);
|
| 978 | lw_r26: R3_TO_LWREG (26);
|
| 979 | lw_r27: R3_TO_LWREG (27);
|
| 980 | lw_r28: R3_TO_LWREG (28);
|
| 981 | lw_r29: R3_TO_LWREG (29);
|
| 982 | lw_r30: R3_TO_LWREG (30);
|
| 983 | lw_r31: R3_TO_LWREG_V (31);
|
| 984 |
|
| 985 | sw_table:
|
| 986 | sw_r0: SWREG_TO_R3 (0);
|
| 987 | sw_r1: SWREG_NOP;
|
| 988 | sw_r2: SWREG_TO_R3 (2);
|
| 989 | sw_r3: SWREG_TO_R3_V (3);
|
| 990 | sw_r4: SWREG_TO_R3_V (4);
|
| 991 | sw_r5: SWREG_TO_R3_V (5);
|
| 992 | sw_r6: SWREG_TO_R3_V (6);
|
| 993 | sw_r7: SWREG_TO_R3 (7);
|
| 994 | sw_r8: SWREG_TO_R3 (8);
|
| 995 | sw_r9: SWREG_TO_R3 (9);
|
| 996 | sw_r10: SWREG_TO_R3 (10);
|
| 997 | sw_r11: SWREG_TO_R3 (11);
|
| 998 | sw_r12: SWREG_TO_R3 (12);
|
| 999 | sw_r13: SWREG_TO_R3 (13);
|
| 1000 | sw_r14: SWREG_TO_R3 (14);
|
| 1001 | sw_r15: SWREG_TO_R3 (15);
|
| 1002 | sw_r16: SWREG_TO_R3 (16);
|
| 1003 | sw_r17: SWREG_NOP;
|
| 1004 | sw_r18: SWREG_TO_R3 (18);
|
| 1005 | sw_r19: SWREG_TO_R3 (19);
|
| 1006 | sw_r20: SWREG_TO_R3 (20);
|
| 1007 | sw_r21: SWREG_TO_R3 (21);
|
| 1008 | sw_r22: SWREG_TO_R3 (22);
|
| 1009 | sw_r23: SWREG_TO_R3 (23);
|
| 1010 | sw_r24: SWREG_TO_R3 (24);
|
| 1011 | sw_r25: SWREG_TO_R3 (25);
|
| 1012 | sw_r26: SWREG_TO_R3 (26);
|
| 1013 | sw_r27: SWREG_TO_R3 (27);
|
| 1014 | sw_r28: SWREG_TO_R3 (28);
|
| 1015 | sw_r29: SWREG_TO_R3 (29);
|
| 1016 | sw_r30: SWREG_TO_R3 (30);
|
| 1017 | sw_r31: SWREG_TO_R3_V (31);
|
| 1018 |
|
| 1019 | lw_table_vm:
|
| 1020 | lw_r0_vm: R3_TO_LWREG_VM (0);
|
| 1021 | lw_r1_vm: R3_TO_LWREG_VM_V (1);
|
| 1022 | lw_r2_vm: R3_TO_LWREG_VM_V (2);
|
| 1023 | lw_r3_vm: R3_TO_LWREG_VM_V (3);
|
| 1024 | lw_r4_vm: R3_TO_LWREG_VM_V (4);
|
| 1025 | lw_r5_vm: R3_TO_LWREG_VM_V (5);
|
| 1026 | lw_r6_vm: R3_TO_LWREG_VM_V (6);
|
| 1027 | lw_r7_vm: R3_TO_LWREG_VM_V (7);
|
| 1028 | lw_r8_vm: R3_TO_LWREG_VM_V (8);
|
| 1029 | lw_r9_vm: R3_TO_LWREG_VM_V (9);
|
| 1030 | lw_r10_vm: R3_TO_LWREG_VM_V (10);
|
| 1031 | lw_r11_vm: R3_TO_LWREG_VM_V (11);
|
| 1032 | lw_r12_vm: R3_TO_LWREG_VM_V (12);
|
| 1033 | lw_r13_vm: R3_TO_LWREG_VM_V (13);
|
| 1034 | lw_r14_vm: R3_TO_LWREG_VM_V (14);
|
| 1035 | lw_r15_vm: R3_TO_LWREG_VM_V (15);
|
| 1036 | lw_r16_vm: R3_TO_LWREG_VM_V (16);
|
| 1037 | lw_r17_vm: R3_TO_LWREG_VM_V (17);
|
| 1038 | lw_r18_vm: R3_TO_LWREG_VM_V (18);
|
| 1039 | lw_r19_vm: R3_TO_LWREG_VM_V (19);
|
| 1040 | lw_r20_vm: R3_TO_LWREG_VM_V (20);
|
| 1041 | lw_r21_vm: R3_TO_LWREG_VM_V (21);
|
| 1042 | lw_r22_vm: R3_TO_LWREG_VM_V (22);
|
| 1043 | lw_r23_vm: R3_TO_LWREG_VM_V (23);
|
| 1044 | lw_r24_vm: R3_TO_LWREG_VM_V (24);
|
| 1045 | lw_r25_vm: R3_TO_LWREG_VM_V (25);
|
| 1046 | lw_r26_vm: R3_TO_LWREG_VM_V (26);
|
| 1047 | lw_r27_vm: R3_TO_LWREG_VM_V (27);
|
| 1048 | lw_r28_vm: R3_TO_LWREG_VM_V (28);
|
| 1049 | lw_r29_vm: R3_TO_LWREG_VM_V (29);
|
| 1050 | lw_r30_vm: R3_TO_LWREG_VM_V (30);
|
| 1051 | lw_r31_vm: R3_TO_LWREG_VM_V (31);
|
| 1052 |
|
| 1053 | sw_table_vm:
|
| 1054 | sw_r0_vm: SWREG_TO_R3_VM (0);
|
| 1055 | sw_r1_vm: SWREG_TO_R3_VM_V (1);
|
| 1056 | sw_r2_vm: SWREG_TO_R3_VM_V (2);
|
| 1057 | sw_r3_vm: SWREG_TO_R3_VM_V (3);
|
| 1058 | sw_r4_vm: SWREG_TO_R3_VM_V (4);
|
| 1059 | sw_r5_vm: SWREG_TO_R3_VM_V (5);
|
| 1060 | sw_r6_vm: SWREG_TO_R3_VM_V (6);
|
| 1061 | sw_r7_vm: SWREG_TO_R3_VM_V (7);
|
| 1062 | sw_r8_vm: SWREG_TO_R3_VM_V (8);
|
| 1063 | sw_r9_vm: SWREG_TO_R3_VM_V (9);
|
| 1064 | sw_r10_vm: SWREG_TO_R3_VM_V (10);
|
| 1065 | sw_r11_vm: SWREG_TO_R3_VM_V (11);
|
| 1066 | sw_r12_vm: SWREG_TO_R3_VM_V (12);
|
| 1067 | sw_r13_vm: SWREG_TO_R3_VM_V (13);
|
| 1068 | sw_r14_vm: SWREG_TO_R3_VM_V (14);
|
| 1069 | sw_r15_vm: SWREG_TO_R3_VM_V (15);
|
| 1070 | sw_r16_vm: SWREG_TO_R3_VM_V (16);
|
| 1071 | sw_r17_vm: SWREG_TO_R3_VM_V (17);
|
| 1072 | sw_r18_vm: SWREG_TO_R3_VM_V (18);
|
| 1073 | sw_r19_vm: SWREG_TO_R3_VM_V (19);
|
| 1074 | sw_r20_vm: SWREG_TO_R3_VM_V (20);
|
| 1075 | sw_r21_vm: SWREG_TO_R3_VM_V (21);
|
| 1076 | sw_r22_vm: SWREG_TO_R3_VM_V (22);
|
| 1077 | sw_r23_vm: SWREG_TO_R3_VM_V (23);
|
| 1078 | sw_r24_vm: SWREG_TO_R3_VM_V (24);
|
| 1079 | sw_r25_vm: SWREG_TO_R3_VM_V (25);
|
| 1080 | sw_r26_vm: SWREG_TO_R3_VM_V (26);
|
| 1081 | sw_r27_vm: SWREG_TO_R3_VM_V (27);
|
| 1082 | sw_r28_vm: SWREG_TO_R3_VM_V (28);
|
| 1083 | sw_r29_vm: SWREG_TO_R3_VM_V (29);
|
| 1084 | sw_r30_vm: SWREG_TO_R3_VM_V (30);
|
| 1085 | sw_r31_vm: SWREG_TO_R3_VM_V (31);
|
| 1086 |
|
| 1087 | /* Temporary data structures used in the handler */
|
| 1088 | .section .data
|
| 1089 | .align 4
|
| 1090 | ex_tmp_data_loc_0:
|
| 1091 | .byte 0
|
| 1092 | ex_tmp_data_loc_1:
|
| 1093 | .byte 0
|
| 1094 | ex_tmp_data_loc_2:
|
| 1095 | .byte 0
|
| 1096 | ex_tmp_data_loc_3:
|
| 1097 | .byte 0
|
| 1098 | ex_reg_op:
|
| 1099 | .byte 0
|