Subversion Repositories HelenOS

Rev

Rev 2179 | Rev 2245 | 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 "aux_print/printf.h"
  38. #include <arch/memstr.h>
  39. #include <arch/regutils.h>
  40. #include <interrupt.h>
  41.  
  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. /* GXEmul interrupt controller macros
  51. TODO might go to drivers/ together with servicing functions
  52. */
  53. /* IRQ Controller device is added in a special premium gxemul
  54.  * edition at www.ms.mff.cuni.cz/~stepp3am/mygxemul-0.4.4.1.tar.gz
  55.  * :)
  56.  */
  57. #define IRQ_CONTROLLER_CAUSE    0x0000000016000000
  58. #define IRQ_CONTROLLER_MAX_IRQ  8
  59.  
  60. /* IRQs */
  61. #define CONSOLE_IRQ     2
  62. #define TIMER_IRQ       4
  63.  
  64.  
  65. #define SAVE_REGS_TO_STACK          \
  66.     asm("stmfd sp!, {r0-r12, sp, lr}");     \
  67.     asm("mrs r14, spsr");           \
  68.     asm("stmfd sp!, {r14}");
  69.  
  70. #define CALL_EXC_DISPATCH(exception)        \
  71.     asm("mov r0, %0" : : "i" (exception));  \
  72.     asm("mov r1, sp");          \
  73.     asm("bl exc_dispatch");    
  74.  
  75. /**Loads registers from the stack and resets SPSR before exitting exception
  76.  * handler.
  77.  */
  78. #define LOAD_REGS_FROM_STACK            \
  79.     asm("ldmfd sp!, {r14}");        \
  80.     asm("msr spsr, r14");           \
  81.     asm("ldmfd sp!, {r0-r12, sp, pc}^");
  82.    
  83. /** General exception handler.
  84.  *  Stores registers, dispatches the exception,
  85.  *  and finally restores registers and returns from exception processing.
  86.  */
  87. #define PROCESS_EXCEPTION(exception)        \
  88.     SAVE_REGS_TO_STACK          \
  89.     CALL_EXC_DISPATCH(exception)        \
  90.     LOAD_REGS_FROM_STACK           
  91.  
  92. /** Updates specified exception vector to jump to given handler.
  93.  * Addresses of handlers are stored in memory following exception vectors.
  94.  */
  95. static void install_handler (unsigned handler_addr, unsigned* vector)
  96. {
  97.     /* relative address (related to exc. vector) of the word
  98.      * where handler's address is stored
  99.     */
  100.     volatile uint32_t handler_address_ptr = EXC_VECTORS_SIZE - PREFETCH_OFFSET;
  101.    
  102.     /* make it LDR instruction and store at exception vector */
  103.     *vector = handler_address_ptr | LDR_OPCODE;
  104.    
  105.     /* store handler's address */
  106.     *(vector + EXC_VECTORS) = handler_addr;
  107. }
  108.  
  109. static void reset_exception_entry()
  110. {
  111.     PROCESS_EXCEPTION(EXC_RESET);
  112. }
  113.  
  114. /** Low-level Software Interrupt Exception handler */
  115. static void swi_exception_entry()
  116. {
  117.     PROCESS_EXCEPTION(EXC_SWI);
  118. }
  119.  
  120. /** Low-level Undefined Instruction Exception handler */
  121. static void undef_instr_exception_entry()
  122. {
  123.     PROCESS_EXCEPTION(EXC_UNDEF_INSTR);
  124. }
  125.  
  126. /** Low-level Fast Interrupt Exception handler */
  127. static void fiq_exception_entry()
  128. {
  129.     PROCESS_EXCEPTION(EXC_FIQ);
  130. }
  131.  
  132. /** Low-level Prefetch Abort Exception handler */
  133. static void prefetch_abort_exception_entry()
  134. {
  135.     asm("sub lr, lr, #4");
  136.     PROCESS_EXCEPTION(EXC_PREFETCH_ABORT);
  137. }
  138.  
  139. /** Low-level Data Abort Exception handler */
  140. static void data_abort_exception_entry()
  141. {
  142.     asm("sub lr, lr, #8");
  143.     PROCESS_EXCEPTION(EXC_DATA_ABORT);
  144. }
  145.  
  146.  
  147. /** Low-level Interrupt Exception handler */
  148. static void irq_exception_entry()
  149. {
  150.     asm("sub lr, lr, #4");
  151.     PROCESS_EXCEPTION(EXC_IRQ);
  152. }
  153.  
  154.  
  155. /** Interrupt Exception handler.
  156.  * Determines the sources of interrupt, and calls their handlers.
  157.  */
  158. static void irq_exception(int exc_no, istate_t* istate)
  159. {
  160.     /* TODO this will call interrupt dispatching routine
  161.      *
  162.      */
  163.  
  164.     uint32_t sources = *(uint32_t*) IRQ_CONTROLLER_CAUSE;
  165.     int i = 0;
  166.     int noirq = 1;
  167.     for (; i < IRQ_CONTROLLER_MAX_IRQ; i++) {
  168.         if (sources & (1 << i)) {
  169.             noirq = 0;
  170.             if (i == CONSOLE_IRQ) {
  171.                 char readchar = *(char*)0x10000000;
  172.                 if (readchar == 0) {
  173.                     aux_puts("?");
  174.                 }
  175.                 else {
  176.                     aux_printf("%c", readchar);
  177.                 }
  178.                
  179.             }
  180.             else if (i == TIMER_IRQ) {
  181.                 aux_printf("\n.\n");
  182.                 /* acknowledge  */
  183.                 *(uint32_t*)0x15000110 = 0;
  184.             }
  185.         }
  186.     }
  187.  
  188.     if (noirq)
  189.         aux_puts("IRQ exception without source\n");
  190. }
  191.  
  192. /** Fills exception vectors with appropriate exception handlers.
  193. */
  194. void install_exception_handlers(void)
  195. {
  196.     install_handler((unsigned)reset_exception_entry,
  197.              (unsigned*)EXC_RESET_VEC);
  198.    
  199.     install_handler((unsigned)undef_instr_exception_entry,
  200.              (unsigned*)EXC_UNDEF_INSTR_VEC);
  201.    
  202.     install_handler((unsigned)swi_exception_entry,
  203.              (unsigned*)EXC_SWI_VEC);
  204.    
  205.     install_handler((unsigned)prefetch_abort_exception_entry,
  206.              (unsigned*)EXC_PREFETCH_ABORT_VEC);
  207.    
  208.     install_handler((unsigned)data_abort_exception_entry,
  209.              (unsigned*)EXC_DATA_ABORT_VEC);
  210.    
  211.     install_handler((unsigned)irq_exception_entry,  
  212.              (unsigned*)EXC_IRQ_VEC);
  213.    
  214.     install_handler((unsigned)fiq_exception_entry,
  215.              (unsigned*)EXC_FIQ_VEC);
  216. }
  217.  
  218. /** Registers exceptions and their handlers to kernel exception dispatcher. */
  219. void exception_init(void)
  220. {
  221.     exc_register(EXC_IRQ, "interrupt", (iroutine) irq_exception);
  222.     /* TODO add next */
  223. }
  224.  
  225. /* TODO change soon, temporary hack. */
  226. void setup_exception_stacks()
  227. {
  228.     /* switch to particular mode and set "sp" there */
  229.     uint32_t cspr = current_status_reg_read();
  230.     current_status_reg_control_write(
  231.             (cspr & ~STATUS_REG_MODE_MASK) | IRQ_MODE
  232.     );
  233.     asm("ldr sp, =irq_stack");
  234.     current_status_reg_control_write( cspr);
  235. }
  236.  
  237. /** @}
  238.  */
  239.