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