Subversion Repositories HelenOS

Rev

Rev 2344 | Rev 2408 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2007 Petr Stepan
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup arm32
  30.  * @{
  31.  */
  32. /** @file
  33.     @brief  Exception handlers and exception initialization routines.
  34.  */
  35.  
  36.  
  37. #include <arch/exception.h>
  38. #include <arch/debug/print.h>
  39. #include <arch/memstr.h>
  40. #include <arch/regutils.h>
  41. #include <interrupt.h>
  42. #include <arch/machine.h>
  43. #include <arch/mm/page_fault.h>
  44. #include <print.h>
  45. #include <syscall/syscall.h>
  46.  
  47.  
  48. #define PREFETCH_OFFSET      0x8
  49. #define BRANCH_OPCODE        0xea000000
  50. #define LDR_OPCODE           0xe59ff000
  51. #define VALID_BRANCH_MASK    0xff000000
  52. #define EXC_VECTORS_SIZE     0x20
  53. #define EXC_VECTORS          0x8
  54.  
  55.  
  56. extern uintptr_t supervisor_sp;
  57. extern uintptr_t exc_stack;
  58.  
  59. /** Switches to kernel stack and saves all registers there.
  60.  *
  61.  * Temporary exception stack is used to save a few registers
  62.  * before stack switch takes place.
  63.  */
  64. inline static void setup_stack_and_save_regs()
  65. {
  66. asm volatile("ldr r13, =exc_stack       \n\
  67.     stmfd r13!, {r0}            \n\
  68.     mrs r0, spsr                \n\
  69.     and r0, r0, #0x1f           \n\
  70.     cmp r0, #0x10               \n\
  71.     bne 1f                  \n\
  72.                         \n\
  73.     @prev mode was usermode         \n\
  74.     ldmfd r13!, {r0}            \n\
  75.     ldr r13, =supervisor_sp         \n\
  76.     ldr r13, [r13]              \n\
  77.     stmfd r13!, {lr}            \n\
  78.     stmfd r13!, {r0-r12}            \n\
  79.     stmfd r13!, {r13, lr}^          \n\
  80.     mrs r0, spsr                \n\
  81.     stmfd r13!, {r0}            \n\
  82.     b 2f                    \n\
  83.                         \n\
  84.     @prev mode was not usermode     \n\
  85. 1:                      \n\
  86.     stmfd r13!, {r1, r2, r3}        \n\
  87.     mrs r1, cpsr                \n\
  88.     mov r2, lr              \n\
  89.     bic r1, r1, #0x1f           \n\
  90.     orr r1, r1, r0              \n\
  91.     mrs r0, cpsr                \n\
  92.     msr cpsr_c, r1              \n\
  93.                         \n\
  94.     mov r3, r13             \n\
  95.     stmfd r13!, {r2}            \n\
  96.     mov r2, lr              \n\
  97.     stmfd r13!, {r4-r12}            \n\
  98.     mov r1, r13             \n\
  99.     @following two lines are for debugging  \n\
  100.     mov sp, #0              \n\
  101.     mov lr, #0              \n\
  102.     msr cpsr_c, r0              \n\
  103.                         \n\
  104.     ldmfd r13!, {r4, r5, r6, r7}        \n\
  105.     stmfd r1!, {r4, r5, r6}         \n\
  106.     stmfd r1!, {r7}             \n\
  107.     stmfd r1!, {r2}             \n\
  108.     stmfd r1!, {r3}             \n\
  109.     mrs r0, spsr                \n\
  110.     stmfd r1!, {r0}             \n\
  111.     mov r13, r1             \n\
  112. 2:"
  113. );
  114. }
  115.  
  116. /** Returns from exception mode.
  117.  *
  118.  * Previously saved state of registers (including control register)
  119.  * is restored from the stack.
  120.  */
  121. inline static void load_regs()
  122. {
  123. asm volatile(   "ldmfd r13!, {r0}       \n\
  124.     msr spsr, r0                \n\
  125.     and r0, r0, #0x1f           \n\
  126.     cmp r0, #0x10               \n\
  127.     bne 3f                  \n\
  128.                         \n\
  129.     @return to user mode            \n\
  130.     ldmfd r13!, {r13, lr}^          \n\
  131.     b 4f                    \n\
  132.                         \n\
  133.     @return to non-user mode        \n\
  134. 3:                      \n\
  135.     ldmfd r13!, {r1, r2}            \n\
  136.     mrs r3, cpsr                \n\
  137.     bic r3, r3, #0x1f           \n\
  138.     orr r3, r3, r0              \n\
  139.     mrs r0, cpsr                \n\
  140.     msr cpsr_c, r3              \n\
  141.                         \n\
  142.     mov r13, r1             \n\
  143.     mov lr, r2              \n\
  144.     msr cpsr_c, r0              \n\
  145.                         \n\
  146.     @actual return              \n\
  147. 4:  ldmfd r13, {r0-r12, pc}^"
  148. );
  149. }
  150.  
  151. /** Calls exception dispatch routine. */
  152. #define CALL_EXC_DISPATCH(exception)        \
  153.     asm("mov r0, %0" : : "i" (exception));  \
  154.     asm("mov r1, r13");         \
  155.     asm("bl exc_dispatch");    
  156.  
  157.    
  158. /** General exception handler.
  159.  *
  160.  *  Stores registers, dispatches the exception,
  161.  *  and finally restores registers and returns from exception processing.
  162.  *
  163.  *  @param exception Exception number.
  164.  */
  165. #define PROCESS_EXCEPTION(exception)        \
  166.     setup_stack_and_save_regs();        \
  167.     CALL_EXC_DISPATCH(exception)        \
  168.     load_regs();
  169.  
  170.  
  171. /** Updates specified exception vector to jump to given handler.
  172.  *
  173.  *  Addresses of handlers are stored in memory following exception vectors.
  174.  */
  175. static void install_handler (unsigned handler_addr, unsigned* vector)
  176. {
  177.     /* relative address (related to exc. vector) of the word
  178.      * where handler's address is stored
  179.     */
  180.     volatile uint32_t handler_address_ptr = EXC_VECTORS_SIZE - PREFETCH_OFFSET;
  181.    
  182.     /* make it LDR instruction and store at exception vector */
  183.     *vector = handler_address_ptr | LDR_OPCODE;
  184.    
  185.     /* store handler's address */
  186.     *(vector + EXC_VECTORS) = handler_addr;
  187.  
  188. }
  189.  
  190.  
  191. /** Low-level Reset Exception handler. */
  192. static void reset_exception_entry()
  193. {
  194.     PROCESS_EXCEPTION(EXC_RESET);
  195. }
  196.  
  197.  
  198. /** Low-level Software Interrupt Exception handler. */
  199. static void swi_exception_entry()
  200. {
  201.     PROCESS_EXCEPTION(EXC_SWI);
  202. }
  203.  
  204.  
  205. /** Low-level Undefined Instruction Exception handler. */
  206. static void undef_instr_exception_entry()
  207. {
  208.     PROCESS_EXCEPTION(EXC_UNDEF_INSTR);
  209. }
  210.  
  211.  
  212. /** Low-level Fast Interrupt Exception handler. */
  213. static void fiq_exception_entry()
  214. {
  215.     PROCESS_EXCEPTION(EXC_FIQ);
  216. }
  217.  
  218.  
  219. /** Low-level Prefetch Abort Exception handler. */
  220. static void prefetch_abort_exception_entry()
  221. {
  222.     asm("sub lr, lr, #4");
  223.     PROCESS_EXCEPTION(EXC_PREFETCH_ABORT);
  224. }
  225.  
  226.  
  227. /** Low-level Data Abort Exception handler. */
  228. static void data_abort_exception_entry()
  229. {
  230.     asm("sub lr, lr, #8");
  231.     PROCESS_EXCEPTION(EXC_DATA_ABORT);
  232. }
  233.  
  234.  
  235. /** Low-level Interrupt Exception handler.
  236.  *
  237.  * CPU is switched to Undefined mode before further interrupt processing
  238.  * because of possible occurence of nested interrupt exception, which
  239.  * would overwrite (and thus spoil) stack pointer.
  240.  */
  241. static void irq_exception_entry()
  242. {
  243.     asm("sub lr, lr, #4");
  244.     setup_stack_and_save_regs();
  245.  
  246.     /* switch to Undefined mode */
  247.     asm("stmfd sp!, {r0-r3}");
  248.     asm("mov r1, sp");
  249.     asm("mov r2, lr");
  250.     asm("mrs r0, cpsr");
  251.     asm("bic r0, r0, #0x1f");
  252.     asm("orr r0, r0, #0x1b");
  253.     asm("msr cpsr_c, r0");
  254.     asm("mov sp, r1");
  255.     asm("mov lr, r2");
  256.     asm("ldmfd sp!, {r0-r3}");
  257.  
  258.     CALL_EXC_DISPATCH(EXC_IRQ)
  259.  
  260.     load_regs();
  261. }
  262.  
  263.  
  264. /** Software Interrupt handler.
  265.  *
  266.  * Dispatches the syscall.
  267.  */
  268. static void swi_exception(int exc_no, istate_t *istate)
  269. {
  270.     /*
  271.     dprintf("SYSCALL: r0-r4: %x, %x, %x, %x, %x; pc: %x\n", istate->r0,
  272.         istate->r1, istate->r2, istate->r3, istate->r4, istate->pc);
  273.     */
  274.  
  275.     istate->r0 = syscall_handler(
  276.         istate->r0,
  277.         istate->r1,
  278.         istate->r2,
  279.         istate->r3,
  280.         istate->r4);
  281. }
  282.  
  283.  
  284. /** Interrupt Exception handler.
  285.  *
  286.  * Determines the sources of interrupt, and calls their handlers.
  287.  */
  288. static void irq_exception(int exc_no, istate_t *istate)
  289. {
  290.     machine_irq_exception(exc_no, istate);
  291. }
  292.  
  293.  
  294. /** Fills exception vectors with appropriate exception handlers. */
  295. void install_exception_handlers(void)
  296. {
  297.     install_handler((unsigned)reset_exception_entry,
  298.              (unsigned*)EXC_RESET_VEC);
  299.    
  300.     install_handler((unsigned)undef_instr_exception_entry,
  301.              (unsigned*)EXC_UNDEF_INSTR_VEC);
  302.    
  303.     install_handler((unsigned)swi_exception_entry,
  304.              (unsigned*)EXC_SWI_VEC);
  305.    
  306.     install_handler((unsigned)prefetch_abort_exception_entry,
  307.              (unsigned*)EXC_PREFETCH_ABORT_VEC);
  308.    
  309.     install_handler((unsigned)data_abort_exception_entry,
  310.              (unsigned*)EXC_DATA_ABORT_VEC);
  311.    
  312.     install_handler((unsigned)irq_exception_entry,
  313.              (unsigned*)EXC_IRQ_VEC);
  314.    
  315.     install_handler((unsigned)fiq_exception_entry,
  316.              (unsigned*)EXC_FIQ_VEC);
  317. }
  318.  
  319.  
  320. #ifdef HIGH_EXCEPTION_VECTORS
  321. /** Activates use of high exception vectors addresses. */
  322. static void high_vectors()
  323. {
  324.     uint32_t control_reg;
  325.    
  326.     asm volatile( "mrc p15, 0, %0, c1, c1": "=r" (control_reg));
  327.    
  328.     //switch on the high vectors bit
  329.     control_reg |= CP15_R1_HIGH_VECTORS_BIT;
  330.    
  331.     asm volatile( "mcr p15, 0, %0, c1, c1" : : "r" (control_reg));
  332. }
  333. #endif
  334.  
  335.  
  336. /** Initializes exception handling.
  337.  *
  338.  * Installs low-level exception handlers and then registers
  339.  * exceptions and their handlers to kernel exception dispatcher.
  340.  */
  341. void exception_init(void)
  342. {
  343. #ifdef HIGH_EXCEPTION_VECTORS
  344.     high_vectors();
  345. #endif
  346.     install_exception_handlers();
  347.    
  348.     exc_register(EXC_IRQ, "interrupt", (iroutine) irq_exception);
  349.     exc_register(EXC_PREFETCH_ABORT, "prefetch abort", (iroutine) prefetch_abort);
  350.     exc_register(EXC_DATA_ABORT, "data abort", (iroutine) data_abort);
  351.     exc_register(EXC_SWI, "software interrupt", (iroutine) swi_exception);
  352. }
  353.  
  354.  
  355. /** Prints #istate_t structure content.
  356.  *
  357.  * @param istate Structure to be printed.
  358.  */
  359. void print_istate(istate_t *istate)
  360. {
  361.     dprintf("istate dump:\n");
  362.  
  363.     dprintf(" r0: %x    r1: %x    r2: %x    r3: %x\n",
  364.         istate->r0, istate->r1, istate->r2, istate->r3);
  365.     dprintf(" r4: %x    r5: %x    r6: %x    r7: %x\n",
  366.         istate->r4, istate->r5, istate->r6, istate->r7);
  367.     dprintf(" r8: %x    r8: %x   r10: %x   r11: %x\n",
  368.         istate->r8, istate->r9, istate->r10, istate->r11);
  369.     dprintf(" r12: %x    sp: %x    lr: %x  spsr: %x\n",
  370.         istate->r12, istate->sp, istate->lr, istate->spsr);
  371.  
  372.     dprintf(" pc: %x\n", istate->pc);
  373. }
  374.  
  375.  
  376. /** @}
  377.  */
  378.