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