1 /* 2 * Copyright 2003-2021, 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/AutoLock.h> 27 #include <util/DoublyLinkedList.h> 28 #include <util/kernel_cpp.h> 29 #include <vm/vm.h> 30 #include <vm/vm_priv.h> 31 #include <vm/VMAddressSpace.h> 32 #include <string.h> 33 34 #include <drivers/bus/FDT.h> 35 #include "arch_int_gicv2.h" 36 #include "soc.h" 37 38 #include "soc_pxa.h" 39 #include "soc_omap3.h" 40 41 #define TRACE_ARCH_INT 42 #ifdef TRACE_ARCH_INT 43 # define TRACE(x) dprintf x 44 #else 45 # define TRACE(x) ; 46 #endif 47 48 #define VECTORPAGE_SIZE 64 49 #define USER_VECTOR_ADDR_LOW 0x00000000 50 #define USER_VECTOR_ADDR_HIGH 0xffff0000 51 52 extern int _vectors_start; 53 extern int _vectors_end; 54 55 static area_id sVectorPageArea; 56 static void *sVectorPageAddress; 57 static area_id sUserVectorPageArea; 58 static void *sUserVectorPageAddress; 59 //static fdt_module_info *sFdtModule; 60 61 // An iframe stack used in the early boot process when we don't have 62 // threads yet. 63 struct iframe_stack gBootFrameStack; 64 65 66 void 67 arch_int_enable_io_interrupt(int irq) 68 { 69 TRACE(("arch_int_enable_io_interrupt(%d)\n", irq)); 70 InterruptController *ic = InterruptController::Get(); 71 if (ic != NULL) 72 ic->EnableInterrupt(irq); 73 } 74 75 76 void 77 arch_int_disable_io_interrupt(int irq) 78 { 79 TRACE(("arch_int_disable_io_interrupt(%d)\n", irq)); 80 InterruptController *ic = InterruptController::Get(); 81 if (ic != NULL) 82 ic->DisableInterrupt(irq); 83 } 84 85 86 /* arch_int_*_interrupts() and friends are in arch_asm.S */ 87 88 int32 89 arch_int_assign_to_cpu(int32 irq, int32 cpu) 90 { 91 // Not yet supported. 92 return 0; 93 } 94 95 96 static void 97 print_iframe(const char *event, struct iframe *frame) 98 { 99 if (event) 100 dprintf("Exception: %s\n", event); 101 102 dprintf("R00=%08lx R01=%08lx R02=%08lx R03=%08lx\n" 103 "R04=%08lx R05=%08lx R06=%08lx R07=%08lx\n", 104 frame->r0, frame->r1, frame->r2, frame->r3, 105 frame->r4, frame->r5, frame->r6, frame->r7); 106 dprintf("R08=%08lx R09=%08lx R10=%08lx R11=%08lx\n" 107 "R12=%08lx SP=%08lx LR=%08lx PC=%08lx CPSR=%08lx\n", 108 frame->r8, frame->r9, frame->r10, frame->r11, 109 frame->r12, frame->svc_sp, frame->svc_lr, frame->pc, frame->spsr); 110 } 111 112 113 status_t 114 arch_int_init(kernel_args *args) 115 { 116 return B_OK; 117 } 118 119 120 extern "C" void arm_vector_init(void); 121 122 123 status_t 124 arch_int_init_post_vm(kernel_args *args) 125 { 126 // create a read/write kernel area 127 sVectorPageArea = create_area("vectorpage", (void **)&sVectorPageAddress, 128 B_ANY_ADDRESS, VECTORPAGE_SIZE, B_FULL_LOCK, 129 B_KERNEL_WRITE_AREA | B_KERNEL_READ_AREA); 130 if (sVectorPageArea < 0) 131 panic("vector page could not be created!"); 132 133 // clone it at a fixed address with user read/only permissions 134 sUserVectorPageAddress = (addr_t*)USER_VECTOR_ADDR_HIGH; 135 sUserVectorPageArea = clone_area("user_vectorpage", 136 (void **)&sUserVectorPageAddress, B_EXACT_ADDRESS, 137 B_READ_AREA | B_EXECUTE_AREA, sVectorPageArea); 138 139 if (sUserVectorPageArea < 0) 140 panic("user vector page @ %p could not be created (%lx)!", 141 sVectorPageAddress, sUserVectorPageArea); 142 143 // copy vectors into the newly created area 144 memcpy(sVectorPageAddress, &_vectors_start, VECTORPAGE_SIZE); 145 146 arm_vector_init(); 147 148 // see if high vectors are enabled 149 if ((mmu_read_c1() & (1 << 13)) != 0) 150 dprintf("High vectors already enabled\n"); 151 else { 152 mmu_write_c1(mmu_read_c1() | (1 << 13)); 153 154 if ((mmu_read_c1() & (1 << 13)) == 0) 155 dprintf("Unable to enable high vectors!\n"); 156 else 157 dprintf("Enabled high vectors\n"); 158 } 159 160 if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_GICV2, 161 sizeof(args->arch_args.interrupt_controller.kind)) == 0) { 162 InterruptController *ic = new(std::nothrow) GICv2InterruptController( 163 args->arch_args.interrupt_controller.regs1.start, 164 args->arch_args.interrupt_controller.regs2.start); 165 if (ic == NULL) 166 return B_NO_MEMORY; 167 } else if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_OMAP3, 168 sizeof(args->arch_args.interrupt_controller.kind)) == 0) { 169 InterruptController *ic = new(std::nothrow) OMAP3InterruptController( 170 args->arch_args.interrupt_controller.regs1.start); 171 if (ic == NULL) 172 return B_NO_MEMORY; 173 } else if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_PXA, 174 sizeof(args->arch_args.interrupt_controller.kind)) == 0) { 175 InterruptController *ic = new(std::nothrow) PXAInterruptController( 176 args->arch_args.interrupt_controller.regs1.start); 177 if (ic == NULL) 178 return B_NO_MEMORY; 179 } else { 180 panic("No interrupt controllers found!\n"); 181 } 182 183 return B_OK; 184 } 185 186 187 status_t 188 arch_int_init_io(kernel_args* args) 189 { 190 return B_OK; 191 } 192 193 194 status_t 195 arch_int_init_post_device_manager(struct kernel_args *args) 196 { 197 return B_ENTRY_NOT_FOUND; 198 } 199 200 201 // Little helper class for handling the 202 // iframe stack as used by KDL. 203 class IFrameScope { 204 public: 205 IFrameScope(struct iframe *iframe) { 206 fThread = thread_get_current_thread(); 207 if (fThread) 208 arm_push_iframe(&fThread->arch_info.iframes, iframe); 209 else 210 arm_push_iframe(&gBootFrameStack, iframe); 211 } 212 213 virtual ~IFrameScope() { 214 // pop iframe 215 if (fThread) 216 arm_pop_iframe(&fThread->arch_info.iframes); 217 else 218 arm_pop_iframe(&gBootFrameStack); 219 } 220 private: 221 Thread* fThread; 222 }; 223 224 225 extern "C" void 226 arch_arm_undefined(struct iframe *iframe) 227 { 228 print_iframe("Undefined Instruction", iframe); 229 IFrameScope scope(iframe); // push/pop iframe 230 231 panic("not handled!"); 232 } 233 234 235 extern "C" void 236 arch_arm_syscall(struct iframe *iframe) 237 { 238 print_iframe("Software interrupt", iframe); 239 IFrameScope scope(iframe); // push/pop iframe 240 } 241 242 243 extern "C" void 244 arch_arm_data_abort(struct iframe *frame) 245 { 246 Thread *thread = thread_get_current_thread(); 247 bool isUser = (frame->spsr & 0x1f) == 0x10; 248 addr_t far = arm_get_far(); 249 bool isWrite = true; 250 addr_t newip = 0; 251 252 #ifdef TRACE_ARCH_INT 253 print_iframe("Data Abort", frame); 254 dprintf("FAR: %08lx, thread: %s\n", far, thread->name); 255 #endif 256 257 IFrameScope scope(frame); 258 259 if (debug_debugger_running()) { 260 // If this CPU or this thread has a fault handler, we're allowed to be 261 // here. 262 if (thread != NULL) { 263 cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; 264 265 if (cpu->fault_handler != 0) { 266 debug_set_page_fault_info(far, frame->pc, 267 isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); 268 frame->svc_sp = cpu->fault_handler_stack_pointer; 269 frame->pc = cpu->fault_handler; 270 return; 271 } 272 273 if (thread->fault_handler != 0) { 274 kprintf("ERROR: thread::fault_handler used in kernel " 275 "debugger!\n"); 276 debug_set_page_fault_info(far, frame->pc, 277 isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); 278 frame->pc = reinterpret_cast<uintptr_t>(thread->fault_handler); 279 return; 280 } 281 } 282 283 // otherwise, not really 284 panic("page fault in debugger without fault handler! Touching " 285 "address %p from pc %p\n", (void *)far, (void *)frame->pc); 286 return; 287 } else if ((frame->spsr & (1 << 7)) != 0) { 288 // interrupts disabled 289 290 // If a page fault handler is installed, we're allowed to be here. 291 // TODO: Now we are generally allowing user_memcpy() with interrupts 292 // disabled, which in most cases is a bug. We should add some thread 293 // flag allowing to explicitly indicate that this handling is desired. 294 uintptr_t handler = reinterpret_cast<uintptr_t>(thread->fault_handler); 295 if (thread && thread->fault_handler != 0) { 296 if (frame->pc != handler) { 297 frame->pc = handler; 298 return; 299 } 300 301 // The fault happened at the fault handler address. This is a 302 // certain infinite loop. 303 panic("page fault, interrupts disabled, fault handler loop. " 304 "Touching address %p from pc %p\n", (void*)far, 305 (void*)frame->pc); 306 } 307 308 // If we are not running the kernel startup the page fault was not 309 // allowed to happen and we must panic. 310 panic("page fault, but interrupts were disabled. Touching address " 311 "%p from pc %p\n", (void *)far, (void *)frame->pc); 312 return; 313 } else if (thread != NULL && thread->page_faults_allowed < 1) { 314 panic("page fault not allowed at this place. Touching address " 315 "%p from pc %p\n", (void *)far, (void *)frame->pc); 316 return; 317 } 318 319 enable_interrupts(); 320 321 vm_page_fault(far, frame->pc, isWrite, false, isUser, &newip); 322 323 if (newip != 0) { 324 // the page fault handler wants us to modify the iframe to set the 325 // IP the cpu will return to to be this ip 326 frame->pc = newip; 327 } 328 } 329 330 331 extern "C" void 332 arch_arm_prefetch_abort(struct iframe *iframe) 333 { 334 print_iframe("Prefetch Abort", iframe); 335 IFrameScope scope(iframe); 336 337 panic("not handled!"); 338 } 339 340 341 extern "C" void 342 arch_arm_irq(struct iframe *iframe) 343 { 344 IFrameScope scope(iframe); 345 346 InterruptController *ic = InterruptController::Get(); 347 if (ic != NULL) 348 ic->HandleInterrupt(); 349 350 Thread* thread = thread_get_current_thread(); 351 cpu_status state = disable_interrupts(); 352 if (thread->cpu->invoke_scheduler) { 353 SpinLocker schedulerLocker(thread->scheduler_lock); 354 scheduler_reschedule(B_THREAD_READY); 355 schedulerLocker.Unlock(); 356 restore_interrupts(state); 357 } else if (thread->post_interrupt_callback != NULL) { 358 void (*callback)(void*) = thread->post_interrupt_callback; 359 void* data = thread->post_interrupt_data; 360 361 thread->post_interrupt_callback = NULL; 362 thread->post_interrupt_data = NULL; 363 364 restore_interrupts(state); 365 366 callback(data); 367 } 368 } 369 370 371 extern "C" void 372 arch_arm_fiq(struct iframe *iframe) 373 { 374 IFrameScope scope(iframe); 375 376 panic("FIQ not implemented yet!"); 377 } 378