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