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