Subversion Repositories HelenOS

Rev

Rev 2326 | Rev 2341 | 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.  
  60. inline static void setup_stack_and_save_regs()
  61. {
  62. asm volatile(   "ldr r13, =exc_stack        \n\
  63.     stmfd r13!, {r0}            \n\
  64.     mrs r0, spsr                \n\
  65.     and r0, r0, #0x1f           \n\
  66.     cmp r0, #0x10               \n\
  67.     bne 1f                  \n\
  68.                         \n\
  69.     @prev mode was usermode         \n\
  70.     ldmfd r13!, {r0}            \n\
  71.     ldr r13, =supervisor_sp         \n\
  72.     ldr r13, [r13]              \n\
  73.     stmfd r13!, {lr}            \n\
  74.     stmfd r13!, {r0-r12}            \n\
  75.     stmfd r13!, {r13, lr}^          \n\
  76.     mrs r0, spsr                \n\
  77.     stmfd r13!, {r0}            \n\
  78.     b 2f                    \n\
  79.                         \n\
  80.     @prev mode was not usermode     \n\
  81. 1:                      \n\
  82.     stmfd r13!, {r1, r2, r3}        \n\
  83.     mrs r1, cpsr                \n\
  84.     mov r2, lr              \n\
  85.     bic r1, r1, #0x1f           \n\
  86.     orr r1, r1, r0              \n\
  87.     mrs r0, cpsr                \n\
  88.     msr cpsr_c, r1              \n\
  89.                         \n\
  90.     mov r3, r13             \n\
  91.     stmfd r13!, {r2}            \n\
  92.     mov r2, lr              \n\
  93.     stmfd r13!, {r4-r12}            \n\
  94.     mov r1, r13             \n\
  95.     @following two lines are for debugging  \n\
  96.     mov sp, #0              \n\
  97.     mov lr, #0              \n\
  98.     msr cpsr_c, r0              \n\
  99.                         \n\
  100.     ldmfd r13!, {r4, r5, r6, r7}        \n\
  101.     stmfd r1!, {r4, r5, r6}         \n\
  102.     stmfd r1!, {r7}             \n\
  103.     stmfd r1!, {r2}             \n\
  104.     stmfd r1!, {r3}             \n\
  105.     mrs r0, spsr                \n\
  106.     stmfd r1!, {r0}             \n\
  107.     mov r13, r1             \n\
  108. 2:"
  109. );
  110. }
  111.  
  112.  
  113. inline static void load_regs()
  114. {
  115. asm volatile(   "ldmfd r13!, {r0}       \n\
  116.     msr spsr, r0                \n\
  117.     and r0, r0, #0x1f           \n\
  118.     cmp r0, #0x10               \n\
  119.     bne 3f                  \n\
  120.                         \n\
  121.     @return to user mode            \n\
  122.     ldmfd r13!, {r13, lr}^          \n\
  123.     b 4f                    \n\
  124.                         \n\
  125.     @return to non-user mode        \n\
  126. 3:                      \n\
  127.     ldmfd r13!, {r1, r2}            \n\
  128.     mrs r3, cpsr                \n\
  129.     bic r3, r3, #0x1f           \n\
  130.     orr r3, r3, r0              \n\
  131.     mrs r0, cpsr                \n\
  132.     msr cpsr_c, r3              \n\
  133.                         \n\
  134.     mov r13, r1             \n\
  135.     mov lr, r2              \n\
  136.     msr cpsr_c, r0              \n\
  137.                         \n\
  138.     @actual return              \n\
  139. 4:  ldmfd r13, {r0-r12, pc}^"
  140. );
  141. }
  142.  
  143.  
  144.  
  145. /*#define SAVE_REGS_TO_STACK            \
  146.     asm("stmfd r13!, {r0-r12, r13, lr}");   \
  147.     asm("mrs r14, spsr");           \
  148.     asm("stmfd r13!, {r14}");
  149. */
  150.  
  151.  
  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. /**Loads registers from the stack and resets SPSR before exitting exception
  159.  * handler.
  160.  
  161. #define LOAD_REGS_FROM_STACK            \
  162.     asm("ldmfd r13!, {r14}");       \
  163.     asm("msr spsr, r14");           \
  164.     asm("ldmfd r13!, {r0-r12, r13, pc}^");
  165.  */
  166.  
  167.    
  168. /** General exception handler.
  169.  *  Stores registers, dispatches the exception,
  170.  *  and finally restores registers and returns from exception processing.
  171.  *
  172.  *  @param exception Exception number.
  173.  */
  174. #define PROCESS_EXCEPTION(exception)        \
  175.     setup_stack_and_save_regs();        \
  176.     CALL_EXC_DISPATCH(exception)        \
  177.     load_regs();
  178.  
  179. /* #define PROCESS_EXCEPTION(exception)     \
  180.     SAVE_REGS_TO_STACK      \
  181.     CALL_EXC_DISPATCH(exception)        \
  182.     LOAD_REGS_FROM_STACK*/
  183.  
  184.  
  185. /** Updates specified exception vector to jump to given handler.
  186.  *  Addresses of handlers are stored in memory following exception vectors.
  187.  */
  188. static void install_handler (unsigned handler_addr, unsigned* vector)
  189. {
  190.     /* relative address (related to exc. vector) of the word
  191.      * where handler's address is stored
  192.     */
  193.     volatile uint32_t handler_address_ptr = EXC_VECTORS_SIZE - PREFETCH_OFFSET;
  194.    
  195.     /* make it LDR instruction and store at exception vector */
  196.     *vector = handler_address_ptr | LDR_OPCODE;
  197.    
  198.     /* store handler's address */
  199.     *(vector + EXC_VECTORS) = handler_addr;
  200.  
  201. }
  202.  
  203.  
  204. /** Low-level Reset Exception handler. */
  205. static void reset_exception_entry()
  206. {
  207.     PROCESS_EXCEPTION(EXC_RESET);
  208. }
  209.  
  210.  
  211. /** Low-level Software Interrupt Exception handler. */
  212. static void swi_exception_entry()
  213. {
  214.     PROCESS_EXCEPTION(EXC_SWI);
  215. }
  216.  
  217.  
  218. /** Low-level Undefined Instruction Exception handler. */
  219. static void undef_instr_exception_entry()
  220. {
  221.     PROCESS_EXCEPTION(EXC_UNDEF_INSTR);
  222. }
  223.  
  224.  
  225. /** Low-level Fast Interrupt Exception handler. */
  226. static void fiq_exception_entry()
  227. {
  228.     PROCESS_EXCEPTION(EXC_FIQ);
  229. }
  230.  
  231.  
  232. /** Low-level Prefetch Abort Exception handler. */
  233. static void prefetch_abort_exception_entry()
  234. {
  235.     asm("sub lr, lr, #4");
  236.     PROCESS_EXCEPTION(EXC_PREFETCH_ABORT);
  237. }
  238.  
  239.  
  240. /** Low-level Data Abort Exception handler. */
  241. static void data_abort_exception_entry()
  242. {
  243.     asm("sub lr, lr, #8");
  244.     PROCESS_EXCEPTION(EXC_DATA_ABORT);
  245. }
  246.  
  247.  
  248. /** Low-level Interrupt Exception handler. */
  249. static void irq_exception_entry()
  250. {
  251.     asm("sub lr, lr, #4");
  252.     PROCESS_EXCEPTION(EXC_IRQ);
  253. }
  254.  
  255.  
  256. /** Software Interrupt handler.
  257.  *
  258.  * Dispatches the syscall.
  259.  */
  260. static void swi_exception(int exc_no, istate_t *istate)
  261. {
  262.     dprintf("SYSCALL: r0-r4: %x, %x, %x, %x, %x; pc: %x\n", istate->r0,
  263.         istate->r1, istate->r2, istate->r3, istate->r4, istate->pc);
  264.  
  265.     istate->r0 = syscall_handler(
  266.         istate->r0,
  267.         istate->r1,
  268.         istate->r2,
  269.         istate->r3,
  270.         istate->r4);
  271. }
  272.  
  273.  
  274. /** Interrupt Exception handler.
  275.  *
  276.  * Determines the sources of interrupt, and calls their handlers.
  277.  */
  278. static void irq_exception(int exc_no, istate_t *istate)
  279. {
  280.     machine_irq_exception(exc_no, istate);
  281. }
  282.  
  283.  
  284. /** Fills exception vectors with appropriate exception handlers. */
  285. void install_exception_handlers(void)
  286. {
  287.     install_handler((unsigned)reset_exception_entry,
  288.              (unsigned*)EXC_RESET_VEC);
  289.    
  290.     install_handler((unsigned)undef_instr_exception_entry,
  291.              (unsigned*)EXC_UNDEF_INSTR_VEC);
  292.    
  293.     install_handler((unsigned)swi_exception_entry,
  294.              (unsigned*)EXC_SWI_VEC);
  295.    
  296.     install_handler((unsigned)prefetch_abort_exception_entry,
  297.              (unsigned*)EXC_PREFETCH_ABORT_VEC);
  298.    
  299.     install_handler((unsigned)data_abort_exception_entry,
  300.              (unsigned*)EXC_DATA_ABORT_VEC);
  301.    
  302.     install_handler((unsigned)irq_exception_entry,
  303.              (unsigned*)EXC_IRQ_VEC);
  304.    
  305.     install_handler((unsigned)fiq_exception_entry,
  306.              (unsigned*)EXC_FIQ_VEC);
  307. }
  308.  
  309.  
  310. #ifdef HIGH_EXCEPTION_VECTORS
  311. /** Activates use of high exception vectors addresses. */
  312. static void high_vectors()
  313. {
  314.     uint32_t control_reg;
  315.    
  316.     asm volatile( "mrc p15, 0, %0, c1, c1": "=r" (control_reg));
  317.    
  318.     //switch on the high vectors bit
  319.     control_reg |= CP15_R1_HIGH_VECTORS_BIT;
  320.    
  321.     asm volatile( "mcr p15, 0, %0, c1, c1" : : "r" (control_reg));
  322. }
  323. #endif
  324.  
  325.  
  326. /** Initializes exception handling.
  327.  *
  328.  * Installs low-level exception handlers and then registers
  329.  * exceptions and their handlers to kernel exception dispatcher.
  330.  */
  331. void exception_init(void)
  332. {
  333. #ifdef HIGH_EXCEPTION_VECTORS
  334.     high_vectors();
  335. #endif
  336.     install_exception_handlers();
  337.    
  338.     exc_register(EXC_IRQ, "interrupt", (iroutine) irq_exception);
  339.     exc_register(EXC_PREFETCH_ABORT, "prefetch abort", (iroutine) prefetch_abort);
  340.     exc_register(EXC_DATA_ABORT, "data abort", (iroutine) data_abort);
  341.     exc_register(EXC_SWI, "software interrupt", (iroutine) swi_exception);
  342.     /* TODO add next */
  343. }
  344.  
  345.  
  346. /** Sets stack pointers in all supported exception modes. */
  347. void setup_exception_stacks()
  348. {
  349.         /* switch to particular mode and set "r13" there */
  350.  
  351.         uint32_t cspr = current_status_reg_read();
  352.  
  353.         /* IRQ stack */
  354.         current_status_reg_control_write(
  355.                         (cspr & ~STATUS_REG_MODE_MASK) | IRQ_MODE
  356.         );
  357.         asm("ldr r13, =exc_stack");
  358.  
  359.         /* abort stack */
  360.         current_status_reg_control_write(
  361.                         (cspr & ~STATUS_REG_MODE_MASK) | ABORT_MODE
  362.         );
  363.         asm("ldr r13, =exc_stack");
  364.  
  365.         /* TODO if you want to test other exceptions than IRQ,
  366.         make stack analogous to irq_stack (in start.S),
  367.         and then set stack pointer here */
  368.  
  369.         current_status_reg_control_write(cspr);
  370. }
  371.  
  372.  
  373. /** Prints #istate_t structure content.
  374.  *
  375.  * @param istate Structure to be printed.
  376.  */
  377. void print_istate(istate_t *istate)
  378. {
  379.     dprintf("istate dump:\n");
  380.  
  381.     dprintf(" r0: %x    r1: %x    r2: %x    r3: %x\n",
  382.         istate->r0, istate->r1, istate->r2, istate->r3);
  383.     dprintf(" r4: %x    r5: %x    r6: %x    r7: %x\n",
  384.         istate->r4, istate->r5, istate->r6, istate->r7);
  385.     dprintf(" r8: %x    r8: %x   r10: %x   r11: %x\n",
  386.         istate->r8, istate->r9, istate->r10, istate->r11);
  387.     dprintf(" r12: %x    sp: %x    lr: %x  spsr: %x\n",
  388.         istate->r12, istate->sp, istate->lr, istate->spsr);
  389.  
  390.     dprintf(" pc: %x\n", istate->pc);
  391. }
  392.  
  393.  
  394. /** @}
  395.  */
  396.