1 /* 2 * Copyright 2003-2023, 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=%08x R01=%08x R02=%08x R03=%08x\n" 108 "R04=%08x R05=%08x R06=%08x R07=%08x\n", 109 frame->r0, frame->r1, frame->r2, frame->r3, 110 frame->r4, frame->r5, frame->r6, frame->r7); 111 dprintf("R08=%08x R09=%08x R10=%08x R11=%08x\n" 112 "R12=%08x SPs=%08x LRs=%08x PC =%08x\n", 113 frame->r8, frame->r9, frame->r10, frame->r11, 114 frame->r12, frame->svc_sp, frame->svc_lr, frame->pc); 115 dprintf(" SPu=%08x LRu=%08x CPSR=%08x\n", 116 frame->usr_sp, frame->usr_lr, frame->spsr); 117 } 118 119 120 status_t 121 arch_int_init(kernel_args *args) 122 { 123 return B_OK; 124 } 125 126 127 extern "C" void arm_vector_init(void); 128 129 130 status_t 131 arch_int_init_post_vm(kernel_args *args) 132 { 133 // create a read/write kernel area 134 sVectorPageArea = create_area("vectorpage", (void **)&sVectorPageAddress, 135 B_ANY_ADDRESS, VECTORPAGE_SIZE, B_FULL_LOCK, 136 B_KERNEL_WRITE_AREA | B_KERNEL_READ_AREA); 137 if (sVectorPageArea < 0) 138 panic("vector page could not be created!"); 139 140 // clone it at a fixed address with user read/only permissions 141 sUserVectorPageAddress = (addr_t*)USER_VECTOR_ADDR_HIGH; 142 sUserVectorPageArea = clone_area("user_vectorpage", 143 (void **)&sUserVectorPageAddress, B_EXACT_ADDRESS, 144 B_READ_AREA | B_EXECUTE_AREA, sVectorPageArea); 145 146 if (sUserVectorPageArea < 0) 147 panic("user vector page @ %p could not be created (%x)!", 148 sVectorPageAddress, sUserVectorPageArea); 149 150 // copy vectors into the newly created area 151 memcpy(sVectorPageAddress, &_vectors_start, VECTORPAGE_SIZE); 152 153 arm_vector_init(); 154 155 // see if high vectors are enabled 156 if ((mmu_read_c1() & (1 << 13)) != 0) 157 dprintf("High vectors already enabled\n"); 158 else { 159 mmu_write_c1(mmu_read_c1() | (1 << 13)); 160 161 if ((mmu_read_c1() & (1 << 13)) == 0) 162 dprintf("Unable to enable high vectors!\n"); 163 else 164 dprintf("Enabled high vectors\n"); 165 } 166 167 if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_GICV2, 168 sizeof(args->arch_args.interrupt_controller.kind)) == 0) { 169 InterruptController *ic = new(std::nothrow) GICv2InterruptController( 170 args->arch_args.interrupt_controller.regs1.start, 171 args->arch_args.interrupt_controller.regs2.start); 172 if (ic == NULL) 173 return B_NO_MEMORY; 174 } else if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_OMAP3, 175 sizeof(args->arch_args.interrupt_controller.kind)) == 0) { 176 InterruptController *ic = new(std::nothrow) OMAP3InterruptController( 177 args->arch_args.interrupt_controller.regs1.start); 178 if (ic == NULL) 179 return B_NO_MEMORY; 180 } else if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_PXA, 181 sizeof(args->arch_args.interrupt_controller.kind)) == 0) { 182 InterruptController *ic = new(std::nothrow) PXAInterruptController( 183 args->arch_args.interrupt_controller.regs1.start); 184 if (ic == NULL) 185 return B_NO_MEMORY; 186 } else if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_SUN4I, 187 sizeof(args->arch_args.interrupt_controller.kind)) == 0) { 188 InterruptController *ic = new(std::nothrow) Sun4iInterruptController( 189 args->arch_args.interrupt_controller.regs1.start); 190 if (ic == NULL) 191 return B_NO_MEMORY; 192 } else { 193 panic("No interrupt controllers found!\n"); 194 } 195 196 return B_OK; 197 } 198 199 200 status_t 201 arch_int_init_io(kernel_args* args) 202 { 203 return B_OK; 204 } 205 206 207 status_t 208 arch_int_init_post_device_manager(struct kernel_args *args) 209 { 210 return B_ENTRY_NOT_FOUND; 211 } 212 213 214 // Little helper class for handling the 215 // iframe stack as used by KDL. 216 class IFrameScope { 217 public: 218 IFrameScope(struct iframe *iframe) { 219 fThread = thread_get_current_thread(); 220 if (fThread) 221 arm_push_iframe(&fThread->arch_info.iframes, iframe); 222 else 223 arm_push_iframe(&gBootFrameStack, iframe); 224 } 225 226 virtual ~IFrameScope() { 227 // pop iframe 228 if (fThread) 229 arm_pop_iframe(&fThread->arch_info.iframes); 230 else 231 arm_pop_iframe(&gBootFrameStack); 232 } 233 private: 234 Thread* fThread; 235 }; 236 237 238 extern "C" void 239 arch_arm_undefined(struct iframe *iframe) 240 { 241 print_iframe("Undefined Instruction", iframe); 242 IFrameScope scope(iframe); // push/pop iframe 243 244 panic("not handled!"); 245 } 246 247 248 extern "C" void 249 arch_arm_syscall(struct iframe *iframe) 250 { 251 #ifdef TRACE_ARCH_INT 252 print_iframe("Software interrupt", iframe); 253 #endif 254 255 IFrameScope scope(iframe); 256 257 uint32_t syscall = *(uint32_t *)(iframe->pc-4) & 0x00ffffff; 258 TRACE("syscall number: %d\n", syscall); 259 260 uint32_t args[20]; 261 if (syscall < kSyscallCount) { 262 TRACE("syscall(%s,%d)\n", 263 kExtendedSyscallInfos[syscall].name, 264 kExtendedSyscallInfos[syscall].parameter_count); 265 266 int argSize = kSyscallInfos[syscall].parameter_size; 267 memcpy(args, &iframe->r0, std::min<int>(argSize, 4 * sizeof(uint32))); 268 if (argSize > 4 * sizeof(uint32)) { 269 status_t res = user_memcpy(&args[4], (void *)iframe->usr_sp, 270 (argSize - 4 * sizeof(uint32))); 271 if (res < B_OK) { 272 dprintf("can't read syscall arguments on user stack\n"); 273 iframe->r0 = res; 274 return; 275 } 276 } 277 } 278 279 thread_get_current_thread()->arch_info.userFrame = iframe; 280 thread_get_current_thread()->arch_info.oldR0 = iframe->r0; 281 thread_at_kernel_entry(system_time()); 282 283 enable_interrupts(); 284 285 uint64 returnValue = 0; 286 syscall_dispatcher(syscall, (void*)args, &returnValue); 287 288 TRACE("returning %" B_PRId64 "\n", returnValue); 289 iframe->r0 = returnValue; 290 291 disable_interrupts(); 292 atomic_and(&thread_get_current_thread()->flags, ~THREAD_FLAGS_SYSCALL_RESTARTED); 293 if ((thread_get_current_thread()->flags & (THREAD_FLAGS_SIGNALS_PENDING 294 | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_TRAP_FOR_CORE_DUMP)) != 0) { 295 enable_interrupts(); 296 thread_at_kernel_exit(); 297 } else { 298 thread_at_kernel_exit_no_signals(); 299 } 300 if ((thread_get_current_thread()->flags & THREAD_FLAGS_RESTART_SYSCALL) != 0) { 301 atomic_and(&thread_get_current_thread()->flags, ~THREAD_FLAGS_RESTART_SYSCALL); 302 atomic_or(&thread_get_current_thread()->flags, THREAD_FLAGS_SYSCALL_RESTARTED); 303 iframe->r0 = thread_get_current_thread()->arch_info.oldR0; 304 iframe->pc -= 4; 305 } 306 307 thread_get_current_thread()->arch_info.userFrame = NULL; 308 } 309 310 311 static void 312 arch_arm_page_fault(struct iframe *frame, addr_t far, uint32 fsr, bool isWrite, bool isExec) 313 { 314 Thread *thread = thread_get_current_thread(); 315 bool isUser = (frame->spsr & CPSR_MODE_MASK) == CPSR_MODE_USR; 316 addr_t newip = 0; 317 318 #ifdef TRACE_ARCH_INT 319 print_iframe("Page Fault", frame); 320 dprintf("FAR: %08lx, FSR: %08x, isUser: %d, isWrite: %d, isExec: %d, thread: %s\n", far, fsr, isUser, isWrite, isExec, thread->name); 321 #endif 322 323 IFrameScope scope(frame); 324 325 if (debug_debugger_running()) { 326 // If this CPU or this thread has a fault handler, we're allowed to be 327 // here. 328 if (thread != NULL) { 329 cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; 330 331 if (cpu->fault_handler != 0) { 332 debug_set_page_fault_info(far, frame->pc, 333 isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); 334 frame->svc_sp = cpu->fault_handler_stack_pointer; 335 frame->pc = cpu->fault_handler; 336 return; 337 } 338 339 if (thread->fault_handler != 0) { 340 kprintf("ERROR: thread::fault_handler used in kernel " 341 "debugger!\n"); 342 debug_set_page_fault_info(far, frame->pc, 343 isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); 344 frame->pc = reinterpret_cast<uintptr_t>(thread->fault_handler); 345 return; 346 } 347 } 348 349 // otherwise, not really 350 panic("page fault in debugger without fault handler! Touching " 351 "address %p from pc %p\n", (void *)far, (void *)frame->pc); 352 return; 353 } else if (isExec && !isUser && (far < KERNEL_BASE) && 354 (((fsr & 0x060f) == FSR_FS_PERMISSION_FAULT_L1) || ((fsr & 0x060f) == FSR_FS_PERMISSION_FAULT_L2))) { 355 panic("PXN violation trying to execute user-mapped address 0x%08" B_PRIxADDR " from kernel mode\n", 356 far); 357 } else if (!isExec && ((fsr & 0x060f) == FSR_FS_ALIGNMENT_FAULT)) { 358 panic("unhandled alignment exception\n"); 359 } else if ((frame->spsr & CPSR_I) != 0) { 360 // interrupts disabled 361 362 // If a page fault handler is installed, we're allowed to be here. 363 // TODO: Now we are generally allowing user_memcpy() with interrupts 364 // disabled, which in most cases is a bug. We should add some thread 365 // flag allowing to explicitly indicate that this handling is desired. 366 uintptr_t handler = reinterpret_cast<uintptr_t>(thread->fault_handler); 367 if (thread && thread->fault_handler != 0) { 368 if (frame->pc != handler) { 369 frame->pc = handler; 370 return; 371 } 372 373 // The fault happened at the fault handler address. This is a 374 // certain infinite loop. 375 panic("page fault, interrupts disabled, fault handler loop. " 376 "Touching address %p from pc %p\n", (void*)far, 377 (void*)frame->pc); 378 } 379 380 // If we are not running the kernel startup the page fault was not 381 // allowed to happen and we must panic. 382 panic("page fault, but interrupts were disabled. Touching address " 383 "%p from pc %p\n", (void *)far, (void *)frame->pc); 384 return; 385 } else if (thread != NULL && thread->page_faults_allowed < 1) { 386 panic("page fault not allowed at this place. Touching address " 387 "%p from pc %p\n", (void *)far, (void *)frame->pc); 388 return; 389 } 390 391 enable_interrupts(); 392 393 vm_page_fault(far, frame->pc, isWrite, isExec, isUser, &newip); 394 395 if (newip != 0) { 396 // the page fault handler wants us to modify the iframe to set the 397 // IP the cpu will return to to be this ip 398 frame->pc = newip; 399 } 400 } 401 402 403 extern "C" void 404 arch_arm_data_abort(struct iframe *frame) 405 { 406 addr_t dfar = arm_get_dfar(); 407 uint32 dfsr = arm_get_dfsr(); 408 bool isWrite = (dfsr & FSR_WNR) == FSR_WNR; 409 410 arch_arm_page_fault(frame, dfar, dfsr, isWrite, false); 411 } 412 413 414 extern "C" void 415 arch_arm_prefetch_abort(struct iframe *frame) 416 { 417 addr_t ifar = arm_get_ifar(); 418 uint32 ifsr = arm_get_ifsr(); 419 420 arch_arm_page_fault(frame, ifar, ifsr, false, true); 421 } 422 423 424 extern "C" void 425 arch_arm_irq(struct iframe *iframe) 426 { 427 IFrameScope scope(iframe); 428 429 InterruptController *ic = InterruptController::Get(); 430 if (ic != NULL) 431 ic->HandleInterrupt(); 432 433 Thread* thread = thread_get_current_thread(); 434 cpu_status state = disable_interrupts(); 435 if (thread->cpu->invoke_scheduler) { 436 SpinLocker schedulerLocker(thread->scheduler_lock); 437 scheduler_reschedule(B_THREAD_READY); 438 schedulerLocker.Unlock(); 439 restore_interrupts(state); 440 } else if (thread->post_interrupt_callback != NULL) { 441 void (*callback)(void*) = thread->post_interrupt_callback; 442 void* data = thread->post_interrupt_data; 443 444 thread->post_interrupt_callback = NULL; 445 thread->post_interrupt_data = NULL; 446 447 restore_interrupts(state); 448 449 callback(data); 450 } 451 } 452 453 454 extern "C" void 455 arch_arm_fiq(struct iframe *iframe) 456 { 457 IFrameScope scope(iframe); 458 459 panic("FIQ not implemented yet!"); 460 } 461