Changeset 03362fbd in mainline for kernel/arch/arm32/src/mm/page_fault.c
- Timestamp:
- 2013-02-09T23:14:45Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/fix-logger-deadlock, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 22dfd38
- Parents:
- b5d2e57 (diff), 005b765 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
kernel/arch/arm32/src/mm/page_fault.c (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/arm32/src/mm/page_fault.c
rb5d2e57 r03362fbd 34 34 */ 35 35 #include <panic.h> 36 #include <arch/cp15.h> 36 37 #include <arch/exception.h> 37 38 #include <arch/mm/page_fault.h> … … 42 43 #include <print.h> 43 44 44 /** Returns value stored in fault status register. 45 * 46 * @return Value stored in CP15 fault status register (FSR). 47 */ 48 static inline fault_status_t read_fault_status_register(void) 49 { 50 fault_status_union_t fsu; 51 52 /* fault status is stored in CP15 register 5 */ 53 asm volatile ( 54 "mrc p15, 0, %[dummy], c5, c0, 0" 55 : [dummy] "=r" (fsu.dummy) 56 ); 57 58 return fsu.fs; 59 } 60 61 /** Returns FAR (fault address register) content. 62 * 63 * @return FAR (fault address register) content (address that caused a page 64 * fault) 65 */ 66 static inline uintptr_t read_fault_address_register(void) 67 { 68 uintptr_t ret; 69 70 /* fault adress is stored in CP15 register 6 */ 71 asm volatile ( 72 "mrc p15, 0, %[ret], c6, c0, 0" 73 : [ret] "=r" (ret) 74 ); 75 76 return ret; 77 } 78 79 /** Decides whether the instruction is load/store or not. 80 * 81 * @param instr Instruction 82 * 83 * @return true when instruction is load/store, false otherwise 84 * 85 */ 86 static inline bool is_load_store_instruction(instruction_t instr) 87 { 88 /* load store immediate offset */ 89 if (instr.type == 0x2) 90 return true; 91 92 /* load store register offset */ 93 if ((instr.type == 0x3) && (instr.bit4 == 0)) 94 return true; 95 96 /* load store multiple */ 97 if (instr.type == 0x4) 98 return true; 99 100 /* oprocessor load/store */ 101 if (instr.type == 0x6) 102 return true; 103 104 return false; 105 } 106 107 /** Decides whether the instruction is swap or not. 108 * 109 * @param instr Instruction 110 * 111 * @return true when instruction is swap, false otherwise 112 */ 113 static inline bool is_swap_instruction(instruction_t instr) 114 { 115 /* swap, swapb instruction */ 116 if ((instr.type == 0x0) && 117 ((instr.opcode == 0x8) || (instr.opcode == 0xa)) && 118 (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1)) 119 return true; 120 121 return false; 122 } 123 45 46 /** 47 * FSR encoding ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition. 48 * 49 * B3.13.3 page B3-1406 (PDF page 1406) 50 */ 51 typedef enum { 52 DFSR_SOURCE_ALIGN = 0x0001, 53 DFSR_SOURCE_CACHE_MAINTENANCE = 0x0004, 54 DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L1 = 0x000c, 55 DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L2 = 0x000e, 56 DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L1 = 0x040c, 57 DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L2 = 0x040e, 58 DFSR_SOURCE_TRANSLATION_L1 = 0x0005, 59 DFSR_SOURCE_TRANSLATION_L2 = 0x0007, 60 DFSR_SOURCE_ACCESS_FLAG_L1 = 0x0003, /**< @note: This used to be alignment enc. */ 61 DFSR_SOURCE_ACCESS_FLAG_L2 = 0x0006, 62 DFSR_SOURCE_DOMAIN_L1 = 0x0009, 63 DFSR_SOURCE_DOMAIN_L2 = 0x000b, 64 DFSR_SOURCE_PERMISSION_L1 = 0x000d, 65 DFSR_SOURCE_PERMISSION_L2 = 0x000f, 66 DFSR_SOURCE_DEBUG = 0x0002, 67 DFSR_SOURCE_SYNC_EXTERNAL = 0x0008, 68 DFSR_SOURCE_TLB_CONFLICT = 0x0400, 69 DFSR_SOURCE_LOCKDOWN = 0x0404, /**< @note: Implementation defined */ 70 DFSR_SOURCE_COPROCESSOR = 0x040a, /**< @note Implementation defined */ 71 DFSR_SOURCE_SYNC_PARITY = 0x0409, 72 DFSR_SOURCE_ASYNC_EXTERNAL = 0x0406, 73 DFSR_SOURCE_ASYNC_PARITY = 0x0408, 74 DFSR_SOURCE_MASK = 0x0000040f, 75 } dfsr_source_t; 76 77 static inline const char * dfsr_source_to_str(dfsr_source_t source) 78 { 79 switch (source) { 80 case DFSR_SOURCE_TRANSLATION_L1: 81 return "Translation fault L1"; 82 case DFSR_SOURCE_TRANSLATION_L2: 83 return "Translation fault L2"; 84 case DFSR_SOURCE_PERMISSION_L1: 85 return "Permission fault L1"; 86 case DFSR_SOURCE_PERMISSION_L2: 87 return "Permission fault L2"; 88 case DFSR_SOURCE_ALIGN: 89 return "Alignment fault"; 90 case DFSR_SOURCE_CACHE_MAINTENANCE: 91 return "Instruction cache maintenance fault"; 92 case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L1: 93 return "Synchronous external abort on translation table walk level 1"; 94 case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L2: 95 return "Synchronous external abort on translation table walk level 2"; 96 case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L1: 97 return "Synchronous parity error on translation table walk level 1"; 98 case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L2: 99 return "Synchronous parity error on translation table walk level 2"; 100 case DFSR_SOURCE_ACCESS_FLAG_L1: 101 return "Access flag fault L1"; 102 case DFSR_SOURCE_ACCESS_FLAG_L2: 103 return "Access flag fault L2"; 104 case DFSR_SOURCE_DOMAIN_L1: 105 return "Domain fault L1"; 106 case DFSR_SOURCE_DOMAIN_L2: 107 return "Domain flault L2"; 108 case DFSR_SOURCE_DEBUG: 109 return "Debug event"; 110 case DFSR_SOURCE_SYNC_EXTERNAL: 111 return "Synchronous external abort"; 112 case DFSR_SOURCE_TLB_CONFLICT: 113 return "TLB conflict abort"; 114 case DFSR_SOURCE_LOCKDOWN: 115 return "Lockdown (Implementation defined)"; 116 case DFSR_SOURCE_COPROCESSOR: 117 return "Coprocessor abort (Implementation defined)"; 118 case DFSR_SOURCE_SYNC_PARITY: 119 return "Synchronous parity error on memory access"; 120 case DFSR_SOURCE_ASYNC_EXTERNAL: 121 return "Asynchronous external abort"; 122 case DFSR_SOURCE_ASYNC_PARITY: 123 return "Asynchronous parity error on memory access"; 124 case DFSR_SOURCE_MASK: 125 break; 126 } 127 return "Unknown data abort"; 128 } 129 130 #if defined(PROCESSOR_ARCH_armv4) | defined(PROCESSOR_ARCH_armv5) 124 131 /** Decides whether read or write into memory is requested. 125 132 * … … 128 135 * 129 136 * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is 130 * requested.137 * requested. 131 138 */ 132 139 static pf_access_t get_memory_access_type(uint32_t instr_addr, … … 142 149 panic("page_fault - instruction does not access memory " 143 150 "(instr_code: %#0" PRIx32 ", badvaddr:%p).", 144 instr_union.pc, (void *) badvaddr);151 *(uint32_t*)instr_union.instr, (void *) badvaddr); 145 152 return PF_ACCESS_EXEC; 146 153 } 147 154 148 /* load store instructions */ 149 if (is_load_store_instruction(instr)) { 150 if (instr.access == 1) { 151 return PF_ACCESS_READ; 152 } else { 153 return PF_ACCESS_WRITE; 155 /* See ARM Architecture reference manual ARMv7-A and ARMV7-R edition 156 * A5.3 (PDF p. 206) */ 157 static const struct { 158 uint32_t mask; 159 uint32_t value; 160 pf_access_t access; 161 } ls_inst[] = { 162 /* Store word/byte */ 163 { 0x0e100000, 0x04000000, PF_ACCESS_WRITE }, /*STR(B) imm*/ 164 { 0x0e100010, 0x06000000, PF_ACCESS_WRITE }, /*STR(B) reg*/ 165 /* Load word/byte */ 166 { 0x0e100000, 0x04100000, PF_ACCESS_READ }, /*LDR(B) imm*/ 167 { 0x0e100010, 0x06100000, PF_ACCESS_READ }, /*LDR(B) reg*/ 168 /* Store half-word/dual A5.2.8 */ 169 { 0x0e1000b0, 0x000000b0, PF_ACCESS_WRITE }, /*STRH imm reg*/ 170 /* Load half-word/dual A5.2.8 */ 171 { 0x0e0000f0, 0x000000d0, PF_ACCESS_READ }, /*LDRH imm reg*/ 172 { 0x0e1000b0, 0x001000b0, PF_ACCESS_READ }, /*LDRH imm reg*/ 173 /* Block data transfer, Store */ 174 { 0x0e100000, 0x08000000, PF_ACCESS_WRITE }, /* STM variants */ 175 { 0x0e100000, 0x08100000, PF_ACCESS_READ }, /* LDM variants */ 176 /* Swap */ 177 { 0x0fb00000, 0x01000000, PF_ACCESS_WRITE }, 178 }; 179 const uint32_t inst = *(uint32_t*)instr_addr; 180 for (unsigned i = 0; i < sizeof(ls_inst) / sizeof(ls_inst[0]); ++i) { 181 if ((inst & ls_inst[i].mask) == ls_inst[i].value) { 182 return ls_inst[i].access; 154 183 } 155 }156 157 /* swap, swpb instruction */158 if (is_swap_instruction(instr)) {159 return PF_ACCESS_WRITE;160 184 } 161 185 162 186 panic("page_fault - instruction doesn't access memory " 163 187 "(instr_code: %#0" PRIx32 ", badvaddr:%p).", 164 instr_union.pc, (void *) badvaddr); 165 166 return PF_ACCESS_EXEC; 167 } 188 inst, (void *) badvaddr); 189 } 190 #endif 168 191 169 192 /** Handles "data abort" exception (load or store at invalid address). … … 175 198 void data_abort(unsigned int exc_no, istate_t *istate) 176 199 { 177 fault_status_t fsr __attribute__ ((unused)) = 178 read_fault_status_register(); 179 uintptr_t badvaddr = read_fault_address_register(); 180 181 pf_access_t access = get_memory_access_type(istate->pc, badvaddr); 182 183 int ret = as_page_fault(badvaddr, access, istate); 184 185 if (ret == AS_PF_FAULT) { 186 fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr); 187 panic_memtrap(istate, access, badvaddr, NULL); 188 } 200 const uintptr_t badvaddr = DFAR_read(); 201 const fault_status_t fsr = { .raw = DFSR_read() }; 202 const dfsr_source_t source = fsr.raw & DFSR_SOURCE_MASK; 203 204 switch (source) { 205 case DFSR_SOURCE_TRANSLATION_L1: 206 case DFSR_SOURCE_TRANSLATION_L2: 207 case DFSR_SOURCE_PERMISSION_L1: 208 case DFSR_SOURCE_PERMISSION_L2: 209 /* Page fault is handled further down */ 210 break; 211 case DFSR_SOURCE_ALIGN: 212 case DFSR_SOURCE_CACHE_MAINTENANCE: 213 case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L1: 214 case DFSR_SOURCE_SYNC_EXTERNAL_TRANSLATION_L2: 215 case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L1: 216 case DFSR_SOURCE_SYNC_PARITY_TRANSLATION_L2: 217 case DFSR_SOURCE_ACCESS_FLAG_L1: 218 case DFSR_SOURCE_ACCESS_FLAG_L2: 219 case DFSR_SOURCE_DOMAIN_L1: 220 case DFSR_SOURCE_DOMAIN_L2: 221 case DFSR_SOURCE_DEBUG: 222 case DFSR_SOURCE_SYNC_EXTERNAL: 223 case DFSR_SOURCE_TLB_CONFLICT: 224 case DFSR_SOURCE_LOCKDOWN: 225 case DFSR_SOURCE_COPROCESSOR: 226 case DFSR_SOURCE_SYNC_PARITY: 227 case DFSR_SOURCE_ASYNC_EXTERNAL: 228 case DFSR_SOURCE_ASYNC_PARITY: 229 case DFSR_SOURCE_MASK: 230 /* Weird abort stuff */ 231 fault_if_from_uspace(istate, "Unhandled abort %s at address: " 232 "%#x.", dfsr_source_to_str(source), badvaddr); 233 panic("Unhandled abort %s at address: %#x.", 234 dfsr_source_to_str(source), badvaddr); 235 } 236 237 #if defined(PROCESSOR_ARCH_armv6) | defined(PROCESSOR_ARCH_armv7_a) 238 const pf_access_t access = 239 fsr.data.wr ? PF_ACCESS_WRITE : PF_ACCESS_READ; 240 #elif defined(PROCESSOR_ARCH_armv4) | defined(PROCESSOR_ARCH_armv5) 241 const pf_access_t access = get_memory_access_type(istate->pc, badvaddr); 242 #else 243 #error "Unsupported architecture" 244 #endif 245 as_page_fault(badvaddr, access, istate); 189 246 } 190 247 … … 197 254 void prefetch_abort(unsigned int exc_no, istate_t *istate) 198 255 { 199 int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate); 200 201 if (ret == AS_PF_FAULT) { 202 fault_if_from_uspace(istate, 203 "Page fault - prefetch_abort: %#x.", istate->pc); 204 panic_memtrap(istate, PF_ACCESS_EXEC, istate->pc, NULL); 205 } 256 as_page_fault(istate->pc, PF_ACCESS_EXEC, istate); 206 257 } 207 258
Note:
See TracChangeset
for help on using the changeset viewer.
