Subversion Repositories HelenOS

Rev

Rev 2284 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2007 Pavel Jancik, Michal Kebrt
  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 arm32mm
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34. #include <panic.h>
  35. #include <arch/exception.h>
  36. #include <arch/debug_print/print.h>
  37. #include <arch/mm/page_fault.h>
  38. #include <mm/as.h>
  39. #include <genarch/mm/page_pt.h>
  40. #include <arch.h>
  41. #include <interrupt.h>
  42.  
  43.  
  44. //TODO: remove in final version
  45. static void print_istate(istate_t* istate);
  46. static void print_istate(istate_t* istate) {
  47.     dprintf("\nIstate dump:\n");
  48.     dprintf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
  49.     dprintf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
  50.     dprintf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
  51.     dprintf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
  52.     dprintf("   pc:%X\n", istate->pc);
  53.  
  54. }
  55.  
  56. /**
  57.  * \return Value stored in fault status register
  58.  */
  59. static inline fault_status_t read_fault_status_register() {
  60.         fault_status_union_t tmp;
  61.         asm volatile (
  62.         "mrc p15, 0, %0, c5, c0, 0"
  63.             : "=r"(tmp.dummy)
  64.     );
  65.     return tmp.fsr;
  66. }
  67.  
  68. /**
  69.  * \return Virtual adress. Access on this addres caused exception
  70.  */
  71. static inline uintptr_t read_fault_address_register() {
  72.         uintptr_t tmp;
  73.     // Fault adress is stored in coprocessor15, register 6
  74.     asm volatile (
  75.         "mrc p15, 0, %0, c6, c0, 0"
  76.         : "=r"(tmp)
  77.     );
  78.     return tmp;
  79. };
  80.  
  81. /** Check type of instruction
  82.  * \param i_code Instruction op code
  83.  * \return true if instruction is load or store, false otherwise
  84.  */
  85. static inline bool load_store_instruction(instruction_t i_code) {
  86.  
  87.      // load store immediate offset
  88.     if (i_code.instr_type == 0x2) {
  89.         return true;
  90.     };
  91.  
  92.         // load store register offset
  93.         if (i_code.instr_type == 0x3 && i_code.bit4 == 0) {
  94.         return true;
  95.     };
  96.  
  97.         // load store multiple
  98.         if (i_code.instr_type == 0x4) {
  99.         return true;
  100.     };
  101.  
  102.         // coprocessor load / strore
  103.     if (i_code.instr_type == 0x6) {
  104.         return true;
  105.     };
  106.  
  107.     return false;
  108. }
  109.  
  110. /** Check type of instruction
  111.  * \param i_code Instruction op code
  112.  * \return true if instruction is swap, false otherwise
  113.  */
  114. static inline bool swap_instruction(instruction_t i_code) {
  115.  
  116.     // swap, swapb instruction
  117.     if (i_code.instr_type == 0x0 &&
  118.         (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
  119.         i_code.access == 0x0 && i_code.bits567 == 0x4 &&
  120.         i_code.bit4 == 1) {
  121.         return true;
  122.     };
  123.  
  124.     return false;
  125. }
  126.  
  127.  
  128. /**
  129.  * Decode instruction and decide if try to read or write into memmory.
  130.  *
  131.  * \param instr_addr address of instruction which attempts access into memmory
  132.  * \param badvaddr Virtual address on which instruction tries to access
  133.  * \return type of access into memmory
  134.  *  Note: return PF_ACESS_EXEC if no memmory acess
  135.  */
  136. //TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
  137. static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
  138.         instruction_union_t tmp;
  139.         tmp.ip = instr_addr;
  140.     // get instruction op code
  141.     instruction_t i_code = *(tmp.instr);
  142.  
  143. //         dprintf("get_instruction_memmory_access\n");
  144. //  dprintf(" instr_addr:%X\n",instr_addr);
  145. //  dprintf(" i_code:%X\n",i_code);
  146. //  dprintf(" i_code.condition:%d\n", i_code.condition);
  147. //  dprintf(" i_code.instr_type:%d\n",i_code.instr_type);
  148. //  dprintf(" i_code.opcode:%d\n",i_code.opcode);
  149. //  dprintf(" i_code.acess:%d\n", i_code.access);
  150. //  dprintf(" i_code.dummy:%d\n", i_code.dummy);
  151. //  dprintf(" i_code.bits567%d\n", i_code.bits567);
  152. //  dprintf(" i_code.bit4:%d\n", i_code.bit4);
  153. //  dprintf(" i_code.dummy1:%d\n", i_code.dummy1);
  154.  
  155.  
  156.         // undefined instructions ... (or special instructions)
  157.     if (i_code.condition == 0xf) {
  158.         panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  159.         return PF_ACCESS_EXEC;
  160.     };
  161.  
  162.     // load store instructions
  163.         if (load_store_instruction(i_code)) {
  164.         if ( i_code.access == 1) {
  165.             return PF_ACCESS_READ;
  166.         } else {
  167.             return PF_ACCESS_WRITE;
  168.         }
  169.     };
  170.  
  171.     // swap, swpb instruction
  172.     if (swap_instruction(i_code))
  173.      {
  174.         /* Swap instructions make read and write in one step.
  175.          * Type of access that caused exception have to page tables
  176.          *  and access rights.
  177.          */
  178. //TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
  179. //      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
  180. //  same case as_page_fault .... it's nessesary to solve "stack" problem
  181.                 pte_level1_t* pte = (pte_level1_t*)
  182.             pt_mapping_operations.mapping_find(AS, badvaddr);
  183.  
  184.         ASSERT(pte);
  185.  
  186.                 /* check if read possible
  187.                  * Note: Don't check PTE_READABLE because it returns 1 everytimes */
  188.         if ( !PTE_PRESENT(pte) ) {
  189.                 return PF_ACCESS_READ;
  190.         }
  191.         if ( !PTE_WRITABLE(pte) ) {
  192.             return PF_ACCESS_WRITE;
  193.         }
  194.         else
  195.             // badvaddr is present readable and writeable but error occured ... why?
  196.             panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  197.     }
  198.     panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  199.     return PF_ACCESS_EXEC;
  200. }
  201.  
  202. /**
  203.  * Routine that solves exception data_abourt
  204.  *  ... you try to load or store value into invalid memmory address
  205.  * \param istate State of CPU when data abourt occured
  206.  * \param n number of exception
  207.  */
  208. //TODO: remove debug prints in final tested version
  209. void data_abort(int n, istate_t *istate) {
  210.         fault_status_t fsr = read_fault_status_register();
  211.         uintptr_t  page = read_fault_address_register();
  212.  
  213.     pf_access_t access = get_memmory_access_type( istate->pc, page);
  214.  
  215. //  print_istate(istate);
  216.     dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->pc, page, fsr.status,fsr, access);
  217.  
  218. /* Alf: Will be commented until stack problem will be solved ...
  219.     as_page_fault make consequent page faults*/
  220.  
  221.         int ret = as_page_fault(page, access, istate);
  222.     dprintf(" as_page_fault ret:%d\n", ret);
  223.         if (ret == AS_PF_FAULT) {
  224.         fault_if_from_uspace(istate, "Page fault: %#x", page);
  225.         panic("page fault\n");
  226.         }
  227.  
  228.     // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
  229. //  panic("page fault ... solved\n");
  230.  
  231. }
  232.  
  233. /**
  234.  * Routine that solves exception prefetch_about
  235.  *  ... you try to execute instruction on invalid address
  236.  * \param istate State of CPU when prefetch abourt occured
  237.  * \param n number of exception
  238.  */
  239. void prefetch_abort(int n, istate_t *istate) {
  240.     print_istate(istate);
  241.     dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->pc);
  242.  
  243. /* Alf: Will be commented until stack problem will be solved ...
  244.     as_page_fault make consequent page faults*/
  245.  
  246.     int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate);
  247.     dprintf(" as_page_fault ret:%d\n", ret);
  248.         if (ret == AS_PF_FAULT) {
  249.                 panic("page fault - instruction fetch at addr:%X\n", istate->pc);
  250.         }
  251.  
  252.  
  253. //  panic("Prefetch abourt ... solved");
  254. }
  255.  
  256. /** @}
  257.  */
  258.  
  259.