Rev 2284 | Rev 2304 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 2278 | jancik | 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> |
||
| 2284 | stepan | 41 | #include <interrupt.h> |
| 2278 | jancik | 42 | |
| 43 | |||
| 44 | //TODO: remove in final version |
||
| 45 | static void print_istate(istate_t* istate); |
||
| 46 | static void print_istate(istate_t* istate) { |
||
| 2298 | stepan | 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 | |||
| 2278 | jancik | 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 | |||
| 2284 | stepan | 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); |
||
| 2278 | jancik | 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 | |||
| 2298 | stepan | 213 | pf_access_t access = get_memmory_access_type( istate->pc, page); |
| 2278 | jancik | 214 | |
| 2284 | stepan | 215 | // print_istate(istate); |
| 2298 | stepan | 216 | dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->pc, page, fsr.status,fsr, access); |
| 2278 | jancik | 217 | |
| 218 | /* Alf: Will be commented until stack problem will be solved ... |
||
| 2284 | stepan | 219 | as_page_fault make consequent page faults*/ |
| 2278 | jancik | 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); |
||
| 2298 | stepan | 225 | panic("page fault\n"); |
| 2278 | jancik | 226 | } |
| 2284 | stepan | 227 | |
| 2278 | jancik | 228 | // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures |
| 2298 | stepan | 229 | // panic("page fault ... solved\n"); |
| 2278 | jancik | 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); |
||
| 2298 | stepan | 241 | dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->pc); |
| 2278 | jancik | 242 | |
| 243 | /* Alf: Will be commented until stack problem will be solved ... |
||
| 2284 | stepan | 244 | as_page_fault make consequent page faults*/ |
| 2278 | jancik | 245 | |
| 2298 | stepan | 246 | int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate); |
| 2278 | jancik | 247 | dprintf(" as_page_fault ret:%d\n", ret); |
| 248 | if (ret == AS_PF_FAULT) { |
||
| 2298 | stepan | 249 | panic("page fault - instruction fetch at addr:%X\n", istate->pc); |
| 2278 | jancik | 250 | } |
| 251 | |||
| 2284 | stepan | 252 | |
| 2298 | stepan | 253 | // panic("Prefetch abourt ... solved"); |
| 2278 | jancik | 254 | } |
| 255 | |||
| 256 | /** @} |
||
| 257 | */ |
||
| 258 |