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