xref: /haiku/src/system/kernel/arch/m68k/arch_int.cpp (revision 9de17be600220db91400c27772b19546284f470f)
1 /*
2  * Copyright 2003-2010, 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  *
10  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
11  * Distributed under the terms of the NewOS License.
12  */
13 
14 
15 #include <int.h>
16 
17 #include <arch_platform.h>
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 #warning M68K: writeme!
34 
35 
36 //#define TRACE_ARCH_INT
37 #ifdef TRACE_ARCH_INT
38 #	define TRACE(x) dprintf x
39 #else
40 #	define TRACE(x) ;
41 #endif
42 
43 typedef void (*m68k_exception_handler)(void);
44 #define M68K_EXCEPTION_VECTOR_COUNT 256
45 #warning M68K: align on 4 ?
46 //m68k_exception_handler gExceptionVectors[M68K_EXCEPTION_VECTOR_COUNT];
47 m68k_exception_handler *gExceptionVectors;
48 
49 // defined in arch_exceptions.S
50 extern "C" void __m68k_exception_noop(void);
51 extern "C" void __m68k_exception_common(void);
52 
53 extern int __irqvec_start;
54 extern int __irqvec_end;
55 
56 extern"C" void m68k_exception_tail(void);
57 
58 // current fault handler
59 addr_t gFaultHandler;
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 // interrupt controller interface (initialized
66 // in arch_int_init_post_device_manager())
67 //static struct interrupt_controller_module_info *sPIC;
68 //static void *sPICCookie;
69 
70 
71 void
72 arch_int_enable_io_interrupt(int irq)
73 {
74 	//if (!sPIC)
75 	//	return;
76 
77 	// TODO: I have no idea, what IRQ type is appropriate.
78 	//sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL);
79 	M68KPlatform::Default()->EnableIOInterrupt(irq);
80 }
81 
82 
83 void
84 arch_int_disable_io_interrupt(int irq)
85 {
86 	//if (!sPIC)
87 	//	return;
88 
89 	//sPIC->disable_io_interrupt(sPICCookie, irq);
90 	M68KPlatform::Default()->DisableIOInterrupt(irq);
91 }
92 
93 
94 /* arch_int_*_interrupts() and friends are in arch_asm.S */
95 
96 
97 static void
98 print_iframe(struct iframe *frame)
99 {
100 	dprintf("iframe at %p:\n", frame);
101 	dprintf("   d0 0x%08lx    d1 0x%08lx    d2 0x%08lx    d3 0x%08lx\n",
102 				frame->d[0], frame->d[1], frame->d[2], frame->d[3]);
103 			kprintf("   d4 0x%08lx    d5 0x%08lx    d6 0x%08lx    d7 0x%08lx\n",
104 				frame->d[4], frame->d[5], frame->d[6], frame->d[7]);
105 			kprintf("   a0 0x%08lx    a1 0x%08lx    a2 0x%08lx    a3 0x%08lx\n",
106 				frame->a[0], frame->a[1], frame->a[2], frame->a[3]);
107 			kprintf("   a4 0x%08lx    a5 0x%08lx    a6 0x%08lx    "/*"a7 0x%08lx (sp)"*/"\n",
108 				frame->a[4], frame->a[5], frame->a[6]/*, frame->a[7]*/);
109 
110 			/*kprintf("   pc 0x%08lx   ccr 0x%02x\n",
111 			  frame->pc, frame->ccr);*/
112 			kprintf("   pc 0x%08lx        sr 0x%04x\n",
113 				frame->cpu.pc, frame->cpu.sr);
114 #if 0
115 	dprintf("r0-r3:   0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d0, frame->d1, frame->d2, frame->d3);
116 	dprintf("r4-r7:   0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d4, frame->d5, frame->d6, frame->d7);
117 	dprintf("r8-r11:  0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a0, frame->a1, frame->a2, frame->a3);
118 	dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a4, frame->a5, frame->a6, frame->a7);
119 	dprintf("      pc 0x%08lx         sr 0x%08lx\n", frame->pc, frame->sr);
120 #endif
121 }
122 
123 
124 static addr_t
125 fault_address(struct iframe *iframe)
126 {
127 	switch (iframe->cpu.type) {
128 		case 0x0:
129 		case 0x1:
130 			return 0;
131 		case 0x2:
132 			return iframe->cpu.type_2.instruction_address;
133 		case 0x3:
134 			return iframe->cpu.type_3.effective_address;
135 		case 0x7:
136 			return iframe->cpu.type_7.effective_address;
137 		case 0x9:
138 			return iframe->cpu.type_9.instruction_address;
139 		case 0xa:
140 			return iframe->cpu.type_a.fault_address;
141 		case 0xb:
142 			return iframe->cpu.type_b.fault_address;
143 		default:
144 			return 0;
145 	}
146 }
147 
148 
149 static bool
150 fault_was_write(struct iframe *iframe)
151 {
152 	switch (iframe->cpu.type) {
153 		case 0x7:
154 			return !iframe->cpu.type_7.ssw.rw;
155 		case 0xa:
156 			return !iframe->cpu.type_a.ssw.rw;
157 		case 0xb:
158 			return !iframe->cpu.type_b.ssw.rw;
159 		default:
160 			panic("can't determine r/w from iframe type %d\n",
161 				iframe->cpu.type);
162 			return false;
163 	}
164 }
165 
166 
167 extern "C" void m68k_exception_entry(struct iframe *iframe);
168 void
169 m68k_exception_entry(struct iframe *iframe)
170 {
171 	int vector = iframe->cpu.vector >> 2;
172 	bool hardwareInterrupt = false;
173 
174 	if (vector != -1) {
175 		dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, "
176 			"pc: %p\n", system_time(), vector, iframe, (void*)iframe->cpu.pc);
177 	}
178 
179 	struct thread *thread = thread_get_current_thread();
180 
181 	// push iframe
182 	if (thread)
183 		m68k_push_iframe(&thread->arch_info.iframes, iframe);
184 	else
185 		m68k_push_iframe(&gBootFrameStack, iframe);
186 
187 	switch (vector) {
188 		case 0: // system reset
189 			panic("system reset exception\n");
190 			break;
191 		case 2: // bus error
192 		case 3: // address error
193 		{
194 			bool kernelDebugger = debug_debugger_running();
195 
196 			if (kernelDebugger) {
197 				// if this thread has a fault handler, we're allowed to be here
198 				if (thread && thread->fault_handler != 0) {
199 					iframe->cpu.pc = thread->fault_handler;
200 					break;
201 				}
202 
203 
204 				// otherwise, not really
205 				panic("page fault in debugger without fault handler! Touching "
206 					"address %p from ip %p\n", (void *)fault_address(iframe),
207 					(void *)iframe->cpu.pc);
208 				break;
209 			} else if ((iframe->cpu.sr & SR_IP_MASK) != 0) {
210 				// interrupts disabled
211 
212 				// If a page fault handler is installed, we're allowed to be here.
213 				// TODO: Now we are generally allowing user_memcpy() with interrupts
214 				// disabled, which in most cases is a bug. We should add some thread
215 				// flag allowing to explicitly indicate that this handling is desired.
216 				if (thread && thread->fault_handler != 0) {
217 					iframe->cpu.pc = thread->fault_handler;
218 						return;
219 				}
220 
221 				// if the interrupts were disabled, and we are not running the
222 				// kernel startup the page fault was not allowed to happen and
223 				// we must panic
224 				panic("page fault, but interrupts were disabled. Touching "
225 					"address %p from ip %p\n", (void *)fault_address(iframe),
226 					(void *)iframe->cpu.pc);
227 				break;
228 			} else if (thread != NULL && thread->page_faults_allowed < 1) {
229 				panic("page fault not allowed at this place. Touching address "
230 					"%p from ip %p\n", (void *)fault_address(iframe),
231 					(void *)iframe->cpu.pc);
232 			}
233 
234 			enable_interrupts();
235 
236 			addr_t newip;
237 
238 			vm_page_fault(fault_address(iframe), iframe->cpu.pc,
239 				fault_was_write(iframe), // store or load
240 				iframe->cpu.sr & SR_S, // was the system in user or supervisor
241 				&newip);
242 			if (newip != 0) {
243 				// the page fault handler wants us to modify the iframe to set the
244 				// IP the cpu will return to to be this ip
245 				iframe->cpu.pc = newip;
246 			}
247  			break;
248 		}
249 
250 		case 24: // spurious interrupt
251 			dprintf("spurious interrupt\n");
252 			break;
253 		case 25: // autovector interrupt
254 		case 26: // autovector interrupt
255 		case 27: // autovector interrupt
256 		case 28: // autovector interrupt
257 		case 29: // autovector interrupt
258 		case 30: // autovector interrupt
259 		case 31: // autovector interrupt
260 		{
261 #if 0
262 			if (!sPIC) {
263 				panic("m68k_exception_entry(): external interrupt although we "
264 					"don't have a PIC driver!");
265 				break;
266 			}
267 #endif
268 			M68KPlatform::Default()->AcknowledgeIOInterrupt(vector);
269 
270 dprintf("handling I/O interrupts...\n");
271 			int_io_interrupt_handler(vector, true);
272 #if 0
273 			while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) {
274 // TODO: correctly pass level-triggered vs. edge-triggered to the handler!
275 				int_io_interrupt_handler(irq, true);
276 			}
277 #endif
278 dprintf("handling I/O interrupts done\n");
279 			hardwareInterrupt = true;
280 			break;
281 		}
282 
283 		case 9: // trace
284 		default:
285 			// vectors >= 64 are user defined vectors, used for IRQ
286 			if (vector >= 64) {
287 				if (M68KPlatform::Default()->AcknowledgeIOInterrupt(vector)) {
288 					int_io_interrupt_handler(vector, true);
289 					break;
290 				}
291 			}
292 			dprintf("unhandled exception type 0x%x\n", vector);
293 			print_iframe(iframe);
294 			panic("unhandled exception type\n");
295 	}
296 
297 	int state = disable_interrupts();
298 	if (thread->cpu->invoke_scheduler) {
299 		GRAB_THREAD_LOCK();
300 		scheduler_reschedule();
301 		RELEASE_THREAD_LOCK();
302 		restore_interrupts(state);
303 	} else if (hardwareInterrupt && thread->post_interrupt_callback != NULL) {
304 		restore_interrupts(state);
305 		void (*callback)(void*) = thread->post_interrupt_callback;
306 		void* data = thread->post_interrupt_data;
307 
308 		thread->post_interrupt_callback = NULL;
309 		thread->post_interrupt_data = NULL;
310 
311 		callback(data);
312 	}
313 
314 	// pop iframe
315 	if (thread)
316 		m68k_pop_iframe(&thread->arch_info.iframes);
317 	else
318 		m68k_pop_iframe(&gBootFrameStack);
319 }
320 
321 
322 status_t
323 arch_int_init(kernel_args *args)
324 {
325 	status_t err;
326 	addr_t vbr;
327 	int i;
328 
329 	gExceptionVectors = (m68k_exception_handler *)args->arch_args.vir_vbr;
330 
331 	/* fill in the vector table */
332 	for (i = 0; i < M68K_EXCEPTION_VECTOR_COUNT; i++)
333 		gExceptionVectors[i] = &__m68k_exception_common;
334 
335 	vbr = args->arch_args.phys_vbr;
336 	/* point VBR to the new table */
337 	asm volatile  ("movec %0,%%vbr" : : "r"(vbr):);
338 
339 	return B_OK;
340 }
341 
342 
343 status_t
344 arch_int_init_post_vm(kernel_args *args)
345 {
346 	status_t err;
347 	err = M68KPlatform::Default()->InitPIC(args);
348 	return err;
349 }
350 
351 
352 status_t
353 arch_int_init_io(kernel_args* args)
354 {
355 	return B_OK;
356 }
357 
358 
359 #if 0 /* PIC modules */
360 template<typename ModuleInfo>
361 struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > {
362 	Module(ModuleInfo *module)
363 		: module(module)
364 	{
365 	}
366 
367 	~Module()
368 	{
369 		if (module)
370 			put_module(((module_info*)module)->name);
371 	}
372 
373 	ModuleInfo	*module;
374 };
375 
376 typedef Module<interrupt_controller_module_info> PICModule;
377 
378 struct PICModuleList : DoublyLinkedList<PICModule> {
379 	~PICModuleList()
380 	{
381 		while (PICModule *module = First()) {
382 			Remove(module);
383 			delete module;
384 		}
385 	}
386 };
387 
388 
389 class DeviceTreeIterator {
390 public:
391 	DeviceTreeIterator(device_manager_info *deviceManager)
392 		: fDeviceManager(deviceManager),
393 		  fNode(NULL),
394 		  fParent(NULL)
395 	{
396 		Rewind();
397 	}
398 
399 	~DeviceTreeIterator()
400 	{
401 		if (fParent != NULL)
402 			fDeviceManager->put_device_node(fParent);
403 		if (fNode != NULL)
404 			fDeviceManager->put_device_node(fNode);
405 	}
406 
407 	void Rewind()
408 	{
409 		fNode = fDeviceManager->get_root();
410 	}
411 
412 	bool HasNext() const
413 	{
414 		return (fNode != NULL);
415 	}
416 
417 	device_node_handle Next()
418 	{
419 		if (fNode == NULL)
420 			return NULL;
421 
422 		device_node_handle foundNode = fNode;
423 
424 		// get first child
425 		device_node_handle child = NULL;
426 		if (fDeviceManager->get_next_child_device(fNode, &child, NULL)
427 				== B_OK) {
428 			// move to the child node
429 			if (fParent != NULL)
430 				fDeviceManager->put_device_node(fParent);
431 			fParent = fNode;
432 			fNode = child;
433 
434 		// no more children; backtrack to find the next sibling
435 		} else {
436 			while (fParent != NULL) {
437 				if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL)
438 						== B_OK) {
439 						// get_next_child_device() always puts the node
440 					break;
441 				}
442 				fNode = fParent;
443 				fParent = fDeviceManager->get_parent(fNode);
444 			}
445 
446 			// if we hit the root node again, we're done
447 			if (fParent == NULL) {
448 				fDeviceManager->put_device_node(fNode);
449 				fNode = NULL;
450 			}
451 		}
452 
453 		return foundNode;
454 	}
455 
456 private:
457 	device_manager_info *fDeviceManager;
458 	device_node_handle	fNode;
459 	device_node_handle	fParent;
460 };
461 
462 
463 static void
464 get_interrupt_controller_modules(PICModuleList &list)
465 {
466 	const char *namePrefix = "interrupt_controllers/";
467 	size_t namePrefixLen = strlen(namePrefix);
468 
469 	char name[B_PATH_NAME_LENGTH];
470 	size_t length;
471 	uint32 cookie = 0;
472 	while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name)))
473 			== B_OK) {
474 		// an interrupt controller module?
475 		if (length <= namePrefixLen
476 			|| strncmp(name, namePrefix, namePrefixLen) != 0) {
477 			continue;
478 		}
479 
480 		// get the module
481 		interrupt_controller_module_info *moduleInfo;
482 		if (get_module(name, (module_info**)&moduleInfo) != B_OK)
483 			continue;
484 
485 		// add it to the list
486 		PICModule *module = new(nothrow) PICModule(moduleInfo);
487 		if (!module) {
488 			put_module(((module_info*)moduleInfo)->name);
489 			continue;
490 		}
491 		list.Add(module);
492 	}
493 }
494 
495 
496 static bool
497 probe_pic_device(device_node_handle node, PICModuleList &picModules)
498 {
499 	for (PICModule *module = picModules.Head();
500 		 module;
501 		 module = picModules.GetNext(module)) {
502 		bool noConnection;
503 		if (module->module->info.supports_device(node, &noConnection) > 0) {
504 			if (module->module->info.register_device(node) == B_OK)
505 				return true;
506 		}
507 	}
508 
509 	return false;
510 }
511 #endif /* PIC modules */
512 
513 status_t
514 arch_int_init_post_device_manager(struct kernel_args *args)
515 {
516 #if 0 /* PIC modules */
517 	// get the interrupt controller driver modules
518 	PICModuleList picModules;
519 	get_interrupt_controller_modules(picModules);
520 	if (picModules.IsEmpty()) {
521 		panic("arch_int_init_post_device_manager(): Found no PIC modules!");
522 		return B_ENTRY_NOT_FOUND;
523 	}
524 
525 	// get the device manager module
526 	device_manager_info *deviceManager;
527 	status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME,
528 		(module_info**)&deviceManager);
529 	if (error != B_OK) {
530 		panic("arch_int_init_post_device_manager(): Failed to get device "
531 			"manager: %s", strerror(error));
532 		return error;
533 	}
534 	Module<device_manager_info> _deviceManager(deviceManager);	// auto put
535 
536 	// iterate through the device tree and probe the interrupt controllers
537 	DeviceTreeIterator iterator(deviceManager);
538 	while (device_node_handle node = iterator.Next())
539 		probe_pic_device(node, picModules);
540 
541 	// iterate through the tree again and get an interrupt controller node
542 	iterator.Rewind();
543 	while (device_node_handle node = iterator.Next()) {
544 		char *deviceType;
545 		if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE,
546 				&deviceType, false) == B_OK) {
547 			bool isPIC
548 				= (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0);
549 			free(deviceType);
550 
551 			if (isPIC) {
552 				driver_module_info *driver;
553 				void *driverCookie;
554 				error = deviceManager->init_driver(node, NULL, &driver,
555 					&driverCookie);
556 				if (error == B_OK) {
557 					sPIC = (interrupt_controller_module_info *)driver;
558 					sPICCookie = driverCookie;
559 					return B_OK;
560 				}
561 			}
562 		}
563 	}
564 
565 #endif /* PIC modules */
566 
567 	// no PIC found
568 	panic("arch_int_init_post_device_manager(): Found no supported PIC!");
569 
570 	return B_ENTRY_NOT_FOUND;
571 }
572 
573 
574 #if 0//PPC
575 // #pragma mark -
576 
577 struct m68k_cpu_exception_context *
578 m68k_get_cpu_exception_context(int cpu)
579 {
580 	return sCPUExceptionContexts + cpu;
581 }
582 
583 
584 void
585 m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context *context)
586 {
587 	// translate to physical address
588 	addr_t physicalPage;
589 	addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1);
590 	status_t error = vm_get_page_mapping(VMAddressSpace::KernelID(),
591 		(addr_t)context - inPageOffset, &physicalPage);
592 	if (error != B_OK) {
593 		panic("m68k_set_current_cpu_exception_context(): Failed to get physical "
594 			"address!");
595 		return;
596 	}
597 
598 	asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset));
599 }
600 
601 #endif
602