1 /* 2 * Copyright 2003-2012, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler <axeld@pinc-software.de> 7 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 8 * François Revol <revol@free.fr> 9 * Ithamar R. Adema <ithamar@upgrade-android.com> 10 * 11 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 12 * Distributed under the terms of the NewOS License. 13 */ 14 15 16 #include <int.h> 17 18 #include <arch/smp.h> 19 #include <boot/kernel_args.h> 20 #include <device_manager.h> 21 #include <kscheduler.h> 22 #include <interrupt_controller.h> 23 #include <smp.h> 24 #include <thread.h> 25 #include <timer.h> 26 #include <util/DoublyLinkedList.h> 27 #include <util/kernel_cpp.h> 28 #include <vm/vm.h> 29 #include <vm/vm_priv.h> 30 #include <vm/VMAddressSpace.h> 31 #include <string.h> 32 33 34 #define TRACE_ARCH_INT 35 #ifdef TRACE_ARCH_INT 36 # define TRACE(x) dprintf x 37 #else 38 # define TRACE(x) ; 39 #endif 40 41 #define VECTORPAGE_SIZE 64 42 #define USER_VECTOR_ADDR_LOW 0x00000000 43 #define USER_VECTOR_ADDR_HIGH 0xffff0000 44 45 #define PXA_INTERRUPT_PHYS_BASE 0x40D00000 46 #define PXA_INTERRUPT_SIZE 0x00000034 47 48 #define PXA_ICIP 0x00 49 #define PXA_ICMR 0x01 50 #define PXA_ICFP 0x03 51 #define PXA_ICMR2 0x28 52 53 static area_id sPxaInterruptArea; 54 static uint32 *sPxaInterruptBase; 55 56 extern int _vectors_start; 57 extern int _vectors_end; 58 59 static area_id sVectorPageArea; 60 static void *sVectorPageAddress; 61 static area_id sUserVectorPageArea; 62 static void *sUserVectorPageAddress; 63 64 // An iframe stack used in the early boot process when we don't have 65 // threads yet. 66 struct iframe_stack gBootFrameStack; 67 68 69 void 70 arch_int_enable_io_interrupt(int irq) 71 { 72 TRACE(("arch_int_enable_io_interrupt(%d)\n", irq)); 73 74 if (irq <= 31) { 75 sPxaInterruptBase[PXA_ICMR] |= 1 << irq; 76 return; 77 } 78 79 sPxaInterruptBase[PXA_ICMR2] |= 1 << (irq - 32); 80 } 81 82 83 void 84 arch_int_disable_io_interrupt(int irq) 85 { 86 TRACE(("arch_int_disable_io_interrupt(%d)\n", irq)); 87 88 if (irq <= 31) { 89 sPxaInterruptBase[PXA_ICMR] &= ~(1 << irq); 90 return; 91 } 92 93 sPxaInterruptBase[PXA_ICMR2] &= ~(1 << (irq - 32)); 94 } 95 96 97 /* arch_int_*_interrupts() and friends are in arch_asm.S */ 98 99 void 100 arch_int_assign_to_cpu(int32 irq, int32 cpu) 101 { 102 // intentionally left blank; no SMP support (yet) 103 } 104 105 static void 106 print_iframe(const char *event, struct iframe *frame) 107 { 108 if (event) 109 dprintf("Exception: %s\n", event); 110 111 dprintf("R00=%08lx R01=%08lx R02=%08lx R03=%08lx\n" 112 "R04=%08lx R05=%08lx R06=%08lx R07=%08lx\n", 113 frame->r0, frame->r1, frame->r2, frame->r3, 114 frame->r4, frame->r5, frame->r6, frame->r7); 115 dprintf("R08=%08lx R09=%08lx R10=%08lx R11=%08lx\n" 116 "R12=%08lx SP=%08lx LR=%08lx PC=%08lx CPSR=%08lx\n", 117 frame->r8, frame->r9, frame->r10, frame->r11, 118 frame->r12, frame->svc_sp, frame->svc_lr, frame->pc, frame->spsr); 119 } 120 121 122 status_t 123 arch_int_init(kernel_args *args) 124 { 125 return B_OK; 126 } 127 128 129 extern "C" void arm_vector_init(void); 130 131 132 status_t 133 arch_int_init_post_vm(kernel_args *args) 134 { 135 // create a read/write kernel area 136 sVectorPageArea = create_area("vectorpage", (void **)&sVectorPageAddress, 137 B_ANY_ADDRESS, VECTORPAGE_SIZE, B_FULL_LOCK, 138 B_KERNEL_WRITE_AREA | B_KERNEL_READ_AREA); 139 140 if (sVectorPageArea < 0) 141 panic("vector page could not be created!"); 142 143 // clone it at a fixed address with user read/only permissions 144 sUserVectorPageAddress = (addr_t*)USER_VECTOR_ADDR_HIGH; 145 sUserVectorPageArea = clone_area("user_vectorpage", 146 (void **)&sUserVectorPageAddress, B_EXACT_ADDRESS, 147 B_READ_AREA | B_EXECUTE_AREA, sVectorPageArea); 148 149 if (sUserVectorPageArea < 0) 150 panic("user vector page @ %p could not be created (%lx)!", sVectorPageAddress, sUserVectorPageArea); 151 152 // copy vectors into the newly created area 153 memcpy(sVectorPageAddress, &_vectors_start, VECTORPAGE_SIZE); 154 155 arm_vector_init(); 156 157 // see if high vectors are enabled 158 if ((mmu_read_c1() & (1 << 13)) != 0) 159 dprintf("High vectors already enabled\n"); 160 else { 161 mmu_write_c1(mmu_read_c1() | (1 << 13)); 162 163 if ((mmu_read_c1() & (1 << 13)) == 0) 164 dprintf("Unable to enable high vectors!\n"); 165 else 166 dprintf("Enabled high vectors\n"); 167 } 168 169 sPxaInterruptArea = map_physical_memory("pxa_intc", PXA_INTERRUPT_PHYS_BASE, 170 PXA_INTERRUPT_SIZE, 0, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&sPxaInterruptBase); 171 172 if (sPxaInterruptArea < 0) 173 return sPxaInterruptArea; 174 175 sPxaInterruptBase[PXA_ICMR] = 0; 176 sPxaInterruptBase[PXA_ICMR2] = 0; 177 178 return B_OK; 179 } 180 181 182 status_t 183 arch_int_init_io(kernel_args* args) 184 { 185 return B_OK; 186 } 187 188 189 status_t 190 arch_int_init_post_device_manager(struct kernel_args *args) 191 { 192 return B_ENTRY_NOT_FOUND; 193 } 194 195 196 // Little helper class for handling the 197 // iframe stack as used by KDL. 198 class IFrameScope { 199 public: 200 IFrameScope(struct iframe *iframe) { 201 fThread = thread_get_current_thread(); 202 if (fThread) 203 arm_push_iframe(&fThread->arch_info.iframes, iframe); 204 else 205 arm_push_iframe(&gBootFrameStack, iframe); 206 } 207 208 virtual ~IFrameScope() { 209 // pop iframe 210 if (fThread) 211 arm_pop_iframe(&fThread->arch_info.iframes); 212 else 213 arm_pop_iframe(&gBootFrameStack); 214 } 215 private: 216 Thread* fThread; 217 }; 218 219 220 extern "C" void 221 arch_arm_undefined(struct iframe *iframe) 222 { 223 print_iframe("Undefined Instruction", iframe); 224 IFrameScope scope(iframe); // push/pop iframe 225 226 panic("not handled!"); 227 } 228 229 230 extern "C" void 231 arch_arm_syscall(struct iframe *iframe) 232 { 233 print_iframe("Software interrupt", iframe); 234 IFrameScope scope(iframe); // push/pop iframe 235 } 236 237 238 extern "C" void 239 arch_arm_data_abort(struct iframe *frame) 240 { 241 Thread *thread = thread_get_current_thread(); 242 bool isUser = (frame->spsr & 0x1f) == 0x10; 243 addr_t far = arm_get_far(); 244 bool isWrite = true; 245 addr_t newip = 0; 246 247 #ifdef TRACE_ARCH_INT 248 print_iframe("Data Abort", frame); 249 dprintf("FAR: %08lx, thread: %s\n", far, thread->name); 250 #endif 251 252 IFrameScope scope(frame); 253 254 if (debug_debugger_running()) { 255 // If this CPU or this thread has a fault handler, we're allowed to be 256 // here. 257 if (thread != NULL) { 258 cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; 259 260 if (cpu->fault_handler != 0) { 261 debug_set_page_fault_info(far, frame->pc, 262 isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); 263 frame->svc_sp = cpu->fault_handler_stack_pointer; 264 frame->pc = cpu->fault_handler; 265 return; 266 } 267 268 if (thread->fault_handler != 0) { 269 kprintf("ERROR: thread::fault_handler used in kernel " 270 "debugger!\n"); 271 debug_set_page_fault_info(far, frame->pc, 272 isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); 273 frame->pc = thread->fault_handler; 274 return; 275 } 276 } 277 278 // otherwise, not really 279 panic("page fault in debugger without fault handler! Touching " 280 "address %p from pc %p\n", (void *)far, (void *)frame->pc); 281 return; 282 } else if ((frame->spsr & (1 << 7)) != 0) { 283 // interrupts disabled 284 285 // If a page fault handler is installed, we're allowed to be here. 286 // TODO: Now we are generally allowing user_memcpy() with interrupts 287 // disabled, which in most cases is a bug. We should add some thread 288 // flag allowing to explicitly indicate that this handling is desired. 289 if (thread && thread->fault_handler != 0) { 290 if (frame->pc != thread->fault_handler) { 291 frame->pc = thread->fault_handler; 292 return; 293 } 294 295 // The fault happened at the fault handler address. This is a 296 // certain infinite loop. 297 panic("page fault, interrupts disabled, fault handler loop. " 298 "Touching address %p from pc %p\n", (void*)far, 299 (void*)frame->pc); 300 } 301 302 // If we are not running the kernel startup the page fault was not 303 // allowed to happen and we must panic. 304 panic("page fault, but interrupts were disabled. Touching address " 305 "%p from pc %p\n", (void *)far, (void *)frame->pc); 306 return; 307 } else if (thread != NULL && thread->page_faults_allowed < 1) { 308 panic("page fault not allowed at this place. Touching address " 309 "%p from pc %p\n", (void *)far, (void *)frame->pc); 310 return; 311 } 312 313 enable_interrupts(); 314 315 vm_page_fault(far, frame->pc, isWrite, false, isUser, &newip); 316 317 if (newip != 0) { 318 // the page fault handler wants us to modify the iframe to set the 319 // IP the cpu will return to to be this ip 320 frame->pc = newip; 321 } 322 } 323 324 325 extern "C" void 326 arch_arm_prefetch_abort(struct iframe *iframe) 327 { 328 print_iframe("Prefetch Abort", iframe); 329 IFrameScope scope(iframe); 330 331 panic("not handled!"); 332 } 333 334 335 extern "C" void 336 arch_arm_irq(struct iframe *iframe) 337 { 338 IFrameScope scope(iframe); 339 340 for (int i=0; i < 32; i++) { 341 if (sPxaInterruptBase[PXA_ICIP] & (1 << i)) 342 int_io_interrupt_handler(i, true); 343 } 344 } 345 346 347 extern "C" void 348 arch_arm_fiq(struct iframe *iframe) 349 { 350 IFrameScope scope(iframe); 351 352 for (int i=0; i < 32; i++) { 353 if (sPxaInterruptBase[PXA_ICIP] & (1 << i)) { 354 dprintf("arch_arm_fiq: help me, FIQ %d was triggered but no " 355 "FIQ support!\n", i); 356 } 357 } 358 } 359