Subversion Repositories HelenOS

Rev

Rev 2264 | Rev 2277 | 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. #include <arch/exception.h>
  37. #include <arch/debug_print/print.h>
  38. #include <arch/memstr.h>
  39. #include <arch/regutils.h>
  40. #include <interrupt.h>
  41. #include <arch/drivers/gxemul.h>
  42.  
  43. #define PREFETCH_OFFSET     0x8
  44. #define BRANCH_OPCODE       0xea000000
  45. #define LDR_OPCODE      0xe59ff000
  46. #define VALID_BRANCH_MASK   0xff000000
  47. #define EXC_VECTORS_SIZE    0x20
  48. #define EXC_VECTORS     0x8
  49.  
  50.  
  51. #define SAVE_REGS_TO_STACK          \
  52.     asm("stmfd sp!, {r0-r12, sp, lr}");     \
  53.     asm("mrs r14, spsr");           \
  54.     asm("stmfd sp!, {r14}");
  55.  
  56. #define CALL_EXC_DISPATCH(exception)        \
  57.     asm("mov r0, %0" : : "i" (exception));  \
  58.     asm("mov r1, sp");          \
  59.     asm("bl exc_dispatch");    
  60.  
  61. /**Loads registers from the stack and resets SPSR before exitting exception
  62.  * handler.
  63.  */
  64. #define LOAD_REGS_FROM_STACK            \
  65.     asm("ldmfd sp!, {r14}");        \
  66.     asm("msr spsr, r14");           \
  67.     asm("ldmfd sp!, {r0-r12, sp, pc}^");
  68.    
  69. /** General exception handler.
  70.  *  Stores registers, dispatches the exception,
  71.  *  and finally restores registers and returns from exception processing.
  72.  */
  73. #define PROCESS_EXCEPTION(exception)        \
  74.     SAVE_REGS_TO_STACK          \
  75.     CALL_EXC_DISPATCH(exception)        \
  76.     LOAD_REGS_FROM_STACK           
  77.  
  78. /** Updates specified exception vector to jump to given handler.
  79.  * Addresses of handlers are stored in memory following exception vectors.
  80.  */
  81. static void install_handler (unsigned handler_addr, unsigned* vector)
  82. {
  83.     /* relative address (related to exc. vector) of the word
  84.      * where handler's address is stored
  85.     */
  86.     volatile uint32_t handler_address_ptr = EXC_VECTORS_SIZE - PREFETCH_OFFSET;
  87.    
  88.     /* make it LDR instruction and store at exception vector */
  89.     *vector = handler_address_ptr | LDR_OPCODE;
  90.    
  91.     /* store handler's address */
  92.     *(vector + EXC_VECTORS) = handler_addr;
  93. }
  94.  
  95. static void reset_exception_entry()
  96. {
  97.     PROCESS_EXCEPTION(EXC_RESET);
  98. }
  99.  
  100. /** Low-level Software Interrupt Exception handler */
  101. static void swi_exception_entry()
  102. {
  103.     PROCESS_EXCEPTION(EXC_SWI);
  104. }
  105.  
  106. /** Low-level Undefined Instruction Exception handler */
  107. static void undef_instr_exception_entry()
  108. {
  109.     PROCESS_EXCEPTION(EXC_UNDEF_INSTR);
  110. }
  111.  
  112. /** Low-level Fast Interrupt Exception handler */
  113. static void fiq_exception_entry()
  114. {
  115.     PROCESS_EXCEPTION(EXC_FIQ);
  116. }
  117.  
  118. /** Low-level Prefetch Abort Exception handler */
  119. static void prefetch_abort_exception_entry()
  120. {
  121.     asm("sub lr, lr, #4");
  122.     PROCESS_EXCEPTION(EXC_PREFETCH_ABORT);
  123. }
  124.  
  125. /** Low-level Data Abort Exception handler */
  126. static void data_abort_exception_entry()
  127. {
  128.     asm("sub lr, lr, #8");
  129.     PROCESS_EXCEPTION(EXC_DATA_ABORT);
  130. }
  131.  
  132.  
  133. /** Low-level Interrupt Exception handler */
  134. static void irq_exception_entry()
  135. {
  136.     asm("sub lr, lr, #4");
  137.     PROCESS_EXCEPTION(EXC_IRQ);
  138. }
  139.  
  140. static void prefetch_abort_exception(int exc_no, istate_t* istate)
  141. {
  142.     //aux_puts("(PREFETCH|DATA) ABORT exception caught, not processed.\n");
  143. }
  144.  
  145.  
  146. /** Interrupt Exception handler.
  147.  * Determines the sources of interrupt, and calls their handlers.
  148.  */
  149. static void irq_exception(int exc_no, istate_t* istate)
  150. {
  151. // TODO: move somewhere to gxemul.c and use machine_irq_exception (or some similar
  152. // name) to avoid using MACHINE == MACHINE_GXEMUL_TESTARM
  153. #if MACHINE == MACHINE_GXEMUL_TESTARM
  154.     uint32_t sources = gxemul_irqc_get_sources();
  155.     int i = 0;
  156.     for (; i < GXEMUL_IRQC_MAX_IRQ; i++) {
  157.         if (sources & (1 << i)) {
  158.             irq_t *irq = irq_dispatch_and_lock(i);
  159.             if (irq) {
  160.                 /* The IRQ handler was found. */
  161.                 irq->handler(irq, irq->arg);
  162.                 spinlock_unlock(&irq->lock);
  163.             } else {
  164.                 /* Spurious interrupt.*/
  165.                 dprintf("cpu%d: spurious interrupt (inum=%d)\n", CPU->id, i);
  166.             }
  167.         }
  168.     }
  169. #endif
  170. /* TODO remove after testing the above code
  171.             noirq = 0;
  172.             if (i == CONSOLE_IRQ) {
  173.                 char readchar = *(char*)0x10000000;
  174.                 if (readchar == 0) {
  175.                     aux_puts("?");
  176.                 }
  177.                 else {
  178.                     dprintf("%c", readchar);
  179.                 }
  180.                
  181.             }
  182.             else if (i == TIMER_IRQ) {
  183.                 dprintf("\n.\n");
  184.                 //acknowledge
  185.                 *(uint32_t*)0x15000110 = 0;
  186.             }
  187.         }
  188.     }
  189.  
  190.     if (noirq)
  191.     aux_puts("IRQ exception without source\n");*/
  192. }
  193.  
  194. /** Fills exception vectors with appropriate exception handlers.
  195. */
  196. void install_exception_handlers(void)
  197. {
  198.     install_handler((unsigned)reset_exception_entry,
  199.              (unsigned*)EXC_RESET_VEC);
  200.    
  201.     install_handler((unsigned)undef_instr_exception_entry,
  202.              (unsigned*)EXC_UNDEF_INSTR_VEC);
  203.    
  204.     install_handler((unsigned)swi_exception_entry,
  205.              (unsigned*)EXC_SWI_VEC);
  206.    
  207.     install_handler((unsigned)prefetch_abort_exception_entry,
  208.              (unsigned*)EXC_PREFETCH_ABORT_VEC);
  209.    
  210.     install_handler((unsigned)data_abort_exception_entry,
  211.              (unsigned*)EXC_DATA_ABORT_VEC);
  212.    
  213.     install_handler((unsigned)irq_exception_entry,  
  214.              (unsigned*)EXC_IRQ_VEC);
  215.    
  216.     install_handler((unsigned)fiq_exception_entry,
  217.              (unsigned*)EXC_FIQ_VEC);
  218. }
  219.  
  220. /** Activates using high exception vectors addresses. */
  221.  static void high_vectors()
  222. {
  223.     uint32_t control_reg;
  224.    
  225.     asm volatile( "mrc p15, 0, %0, c1, c1": "=r" (control_reg));
  226.    
  227.     //switch on the high vectors bit
  228.     control_reg |= CP15_R1_HIGH_VECTORS_BIT;
  229.    
  230.     asm volatile( "mcr p15, 0, %0, c1, c1" : : "r" (control_reg));
  231. }
  232.  
  233.  
  234. /** Initializes exception handling.
  235.  *
  236.  * Installs low-level exception handlers and then registers
  237.  * exceptions and their handlers to kernel exception dispatcher.
  238.  */
  239. void exception_init(void)
  240. {
  241. #ifdef HIGH_EXCEPTION_VECTORS
  242.     high_vectors();
  243. #endif
  244.  
  245.     install_exception_handlers();
  246.    
  247.     exc_register(EXC_IRQ, "interrupt", (iroutine) irq_exception);
  248.     exc_register(EXC_PREFETCH_ABORT, "prefetch abort", (iroutine) prefetch_abort_exception);
  249.     exc_register(EXC_DATA_ABORT, "data abort", (iroutine) prefetch_abort_exception);
  250.     /* TODO add next */
  251. }
  252.  
  253. /* TODO change soon, temporary hack. */
  254. void setup_exception_stacks()
  255. {
  256.     /* switch to particular mode and set "sp" there */
  257.  
  258.     uint32_t cspr = current_status_reg_read();
  259.  
  260.     /* IRQ stack */
  261.     current_status_reg_control_write(
  262.             (cspr & ~STATUS_REG_MODE_MASK) | IRQ_MODE
  263.     );
  264.     asm("ldr sp, =irq_stack");
  265.  
  266.     /* abort stack */
  267.     current_status_reg_control_write(
  268.             (cspr & ~STATUS_REG_MODE_MASK) | ABORT_MODE
  269.     );
  270.     asm("ldr sp, =abort_stack");
  271.  
  272.     /* TODO if you want to test other exceptions than IRQ,
  273.     make stack analogous to irq_stack (in start.S),
  274.     and then set stack pointer here */
  275.  
  276.     current_status_reg_control_write( cspr);
  277.  
  278. }
  279.  
  280. /** @}
  281.  */
  282.