sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
intrman.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include "intrman.h"
12#include "irx_imports.h"
13#include "kerr.h"
14#include <mipscopaccess.h>
15
17#include "iop_mmio_hwport.h"
18
19extern struct irx_export_table _exp_intrman;
20
21#ifdef _IOP
22IRX_ID("Interrupt_Manager", 1, 1);
23#endif
24// Based on the module from SCE SDK 1.3.4.
25
26extern int CpuGetICTRL();
27extern void CpuEnableICTRL();
28extern int dma_interrupt_handler(void *userdata);
29
30extern exception_handler_struct_t exception_interrupt_handler;
31extern exception_handler_struct_t exception_priority_interrupt_handler;
32extern exception_handler_struct_t exception_system_handler;
33
34static intrman_internals_t intrman_internals;
35
36int _start(int ac, char **av)
37{
38 s32 prid;
39 int i;
40 USE_IOP_MMIO_HWPORT();
41 USE_IOP_LOW_MEMORY_GLOBALS();
42
43 (void)ac;
44 (void)av;
45
46 prid = get_mips_cop_reg(0, COP0_REG_PRId);
47
48#ifdef BUILDING_INTRMANP
49 if ( prid >= 16 )
50 {
51 if ( (iop_mmio_hwport->iop_sbus_ctrl[0] & 8) == 0 )
52 {
53 return MODULE_NO_RESIDENT_END;
54 }
55 }
56#else
57 if ( prid < 16 )
58 {
59 return MODULE_NO_RESIDENT_END;
60 }
61
62 if ( (iop_mmio_hwport->iop_sbus_ctrl[0] & 8) != 0 )
63 {
64 return MODULE_NO_RESIDENT_END;
65 }
66#endif
67
68#pragma GCC diagnostic push
69#pragma GCC diagnostic ignored "-Warray-bounds"
70 iop_low_memory_globals->dispatch_interrupt_state = -1;
71#pragma GCC diagnostic pop
72 iop_mmio_hwport->imask = 0;
73 iop_mmio_hwport->dmac1.dicr1 = 0;
74#ifndef BUILDING_INTRMANP
75 iop_mmio_hwport->dmac2.dicr2 = 0;
76#endif
77 intrman_internals.masked_icr_1 = -1;
78 intrman_internals.masked_icr_2 = -1;
79 intrman_internals.interrupt_handler_table = &(iop_low_memory_globals->intr_handlers[0]);
80 // Unofficial: The upper bound was changed from 0x40 because it is not actually used
81 for ( i = 0; i < 0x30; i += 1 )
82 {
83#pragma GCC diagnostic push
84#pragma GCC diagnostic ignored "-Warray-bounds"
85 intrman_internals.interrupt_handler_table[i].handler = NULL;
86 intrman_internals.interrupt_handler_table[i].userdata = NULL;
87#pragma GCC diagnostic pop
88 }
89 RegisterExceptionHandler(0, &exception_interrupt_handler);
90 RegisterPriorityExceptionHandler(0, 3, &exception_priority_interrupt_handler);
91 RegisterExceptionHandler(8, &exception_system_handler);
92 // Unofficial: pass internal structure
93 RegisterIntrHandler(IOP_IRQ_DMA, 1, dma_interrupt_handler, (void *)&intrman_internals);
94 RegisterLibraryEntries(&_exp_intrman);
95 return 0;
96}
97
98int intrman_deinit(void)
99{
100 USE_IOP_MMIO_HWPORT();
101
102 iop_mmio_hwport->imask = 0;
103 iop_mmio_hwport->dmac1.dicr1 = 0;
104#ifndef BUILDING_INTRMANP
105 iop_mmio_hwport->dmac2.dicr2 = 0;
106#endif
107 return 0;
108}
109
110intrman_internals_t *GetIntrmanInternalData(void)
111{
112 return &intrman_internals;
113}
114
115int RegisterIntrHandler(int irq, int mode, int (*handler)(void *arg), void *arg)
116{
117 int intr_handler_offset;
118 int state;
119
120 if ( QueryIntrContext() != 0 )
121 {
122 return KE_ILLEGAL_CONTEXT;
123 }
124 CpuSuspendIntr(&state);
125 if ( irq >= IOP_IRQ_VBLANK && irq <= IOP_IRQ_DMA_SIO2_OUT )
126 {
127 intr_handler_offset = irq;
128 }
129 else if ( irq >= IOP_IRQ_SW1 && IOP_IRQ_SW1 <= IOP_IRQ_SW2 )
130 {
131 intr_handler_offset = irq - 0x10;
132 }
133 else
134 {
135 CpuResumeIntr(state);
136 return KE_ILLEGAL_INTRCODE;
137 }
138 if ( intrman_internals.interrupt_handler_table[intr_handler_offset].handler )
139 {
140 CpuResumeIntr(state);
141 return KE_FOUND_HANDLER;
142 }
143 if ( irq < IOP_IRQ_DMA_MDEC_IN || irq > IOP_IRQ_DMA_SIO2_OUT )
144 {
145 intrman_internals.interrupt_handler_table[intr_handler_offset].handler =
146 (int (*)(void *arg))((uiptr)handler | (mode & 3));
147 }
148 else
149 {
150 intrman_internals.interrupt_handler_table[intr_handler_offset].handler = handler;
151 }
152 intrman_internals.interrupt_handler_table[intr_handler_offset].userdata = arg;
153 CpuResumeIntr(state);
154 return 0;
155}
156
158{
159 int intr_handler_offset;
160 int state;
161
162 if ( QueryIntrContext() != 0 )
163 {
164 return KE_ILLEGAL_CONTEXT;
165 }
166 CpuSuspendIntr(&state);
167 if ( irq >= IOP_IRQ_VBLANK && irq <= IOP_IRQ_DMA_SIO2_OUT )
168 {
169 intr_handler_offset = irq;
170 }
171 else if ( irq >= IOP_IRQ_SW1 && IOP_IRQ_SW1 <= IOP_IRQ_SW2 )
172 {
173 intr_handler_offset = irq - 0x10;
174 }
175 else
176 {
177 CpuResumeIntr(state);
178 return KE_ILLEGAL_INTRCODE;
179 }
180 if ( !intrman_internals.interrupt_handler_table[intr_handler_offset].handler )
181 {
182 CpuResumeIntr(state);
183 return KE_NOTFOUND_HANDLER;
184 }
185 intrman_internals.interrupt_handler_table[intr_handler_offset].handler = NULL;
186 CpuResumeIntr(state);
187 return 0;
188}
189
190extern int intrman_syscall_04_CpuDisableIntr(void);
191extern int intrman_syscall_08_CpuEnableIntr(void);
192extern int intrman_syscall_10(void);
193extern int intrman_syscall_14(int state);
194
195int CpuSuspendIntr(int *state)
196{
197 int intrstate;
198
199#ifdef BUILDING_INTRMANP
200 intrstate = intrman_syscall_10();
201#else
202 USE_IOP_MMIO_HWPORT();
203 intrstate = iop_mmio_hwport->iop_sbus_info;
204#endif
205 if ( state )
206 *state = intrstate;
207#ifdef BUILDING_INTRMANP
208 if ( (intrstate & 0x404) != 0x404 )
209 return KE_CPUDI;
210#else
211 if ( !intrstate )
212 return KE_CPUDI;
213#endif
214 return 0;
215}
216
217int CpuResumeIntr(int state)
218{
219#ifdef BUILDING_INTRMANP
220 intrman_syscall_14(state);
221#else
222 USE_IOP_MMIO_HWPORT();
223 iop_mmio_hwport->iop_sbus_info = state;
224#endif
225 return 0;
226}
227
229{
230#ifdef BUILDING_INTRMANP
231 if ( intrman_syscall_04_CpuDisableIntr() == 0 )
232 return KE_CPUDI;
233#else
234 if ( CpuGetICTRL() == 0 )
235 return KE_CPUDI;
236#endif
237 return 0;
238}
239
241{
242 intrman_syscall_08_CpuEnableIntr();
243#ifndef BUILDING_INTRMANP
244 CpuEnableICTRL();
245#endif
246 return 0;
247}
248
249int CpuGetICTRL()
250{
251#ifdef BUILDING_INTRMANP
252 return intrman_syscall_04_CpuDisableIntr();
253#else
254 USE_IOP_MMIO_HWPORT();
255 return iop_mmio_hwport->iop_sbus_info;
256#endif
257}
258
259void CpuEnableICTRL()
260{
261#ifdef BUILDING_INTRMANP
262 intrman_syscall_08_CpuEnableIntr();
263#else
264 USE_IOP_MMIO_HWPORT();
265 iop_mmio_hwport->iop_sbus_info = 1;
266#endif
267}
268
269// clang-format off
270__asm__ (
271 "\t" ".set push" "\n"
272 "\t" ".set noat" "\n"
273 "\t" ".set noreorder" "\n"
274 "\t" ".global intrman_syscall_04_CpuDisableIntr" "\n"
275 "\t" "intrman_syscall_04_CpuDisableIntr:" "\n"
276 "\t" " addiu $v0, $zero, 0x04" "\n"
277 "\t" " syscall 0" "\n"
278 "\t" " jr $ra" "\n"
279 "\t" " nop" "\n"
280 "\t" ".set pop" "\n"
281);
282
283__asm__ (
284 "\t" ".set push" "\n"
285 "\t" ".set noat" "\n"
286 "\t" ".set noreorder" "\n"
287 "\t" ".global intrman_syscall_08_CpuEnableIntr" "\n"
288 "\t" "intrman_syscall_08_CpuEnableIntr:" "\n"
289 "\t" " addiu $v0, $zero, 0x08" "\n"
290 "\t" " syscall 0" "\n"
291 "\t" " jr $ra" "\n"
292 "\t" " nop" "\n"
293 "\t" ".set pop" "\n"
294);
295
296__asm__ (
297 "\t" ".set push" "\n"
298 "\t" ".set noat" "\n"
299 "\t" ".set noreorder" "\n"
300 "\t" ".global intrman_syscall_10" "\n"
301 "\t" "intrman_syscall_10:" "\n"
302 "\t" " addiu $v0, $zero, 0x10" "\n"
303 "\t" " syscall 0" "\n"
304 "\t" " jr $ra" "\n"
305 "\t" " nop" "\n"
306 "\t" ".set pop" "\n"
307);
308
309__asm__ (
310 "\t" ".set push" "\n"
311 "\t" ".set noat" "\n"
312 "\t" ".set noreorder" "\n"
313 "\t" ".global intrman_syscall_14" "\n"
314 "\t" "intrman_syscall_14:" "\n"
315 "\t" " addiu $v0, $zero, 0x14" "\n"
316 "\t" " syscall 0" "\n"
317 "\t" " jr $ra" "\n"
318 "\t" " nop" "\n"
319 "\t" ".set pop" "\n"
320);
321
322__asm__ (
323 "\t" ".set push" "\n"
324 "\t" ".set noat" "\n"
325 "\t" ".set noreorder" "\n"
326 "\t" ".global CpuInvokeInKmode" "\n"
327 "\t" "CpuInvokeInKmode:" "\n"
328 "\t" " addiu $v0, $zero, 0x0C" "\n"
329 "\t" " syscall 0" "\n"
330 "\t" " jr $ra" "\n"
331 "\t" " nop" "\n"
332 "\t" ".set pop" "\n"
333);
334// clang-format on
335
336int EnableIntr(int irq)
337{
338 int ret;
339 int irq_index;
340 int state;
341 USE_IOP_MMIO_HWPORT();
342
343 ret = 0;
344 irq_index = irq & 0xFF;
345 CpuSuspendIntr(&state);
346 if ( irq_index < IOP_IRQ_DMA_MDEC_IN )
347 {
348 iop_mmio_hwport->imask |= (1 << irq_index);
349 }
350 else if ( (irq_index >= IOP_IRQ_DMA_MDEC_IN) && (irq_index <= IOP_IRQ_DMA_GPU_OTC) )
351 {
352 iop_mmio_hwport->dmac1.dicr1 = (iop_mmio_hwport->dmac1.dicr1 & (~(1 << (irq_index - 32)) & 0xFFFFFF))
353 | (((((irq & 0xFF00) >> 8) & 0x1) != 0) ? (1 << (irq_index - 32)) : 0)
354 | (1 << (irq_index - 32 + 16)) | 0x800000;
355#ifndef BUILDING_INTRMANP
356 iop_mmio_hwport->dmac2.dicr2 = (iop_mmio_hwport->dmac2.dicr2 & (~(1 << (irq_index - 32)) & 0xFFFFFF))
357 | (((((irq & 0xFF00) >> 8) & 0x2) != 0) ? (1 << (irq_index - 32)) : 0);
358#endif
359 iop_mmio_hwport->imask |= 8;
360#if 0
361 /* The following was in the original. */
362#ifdef BUILDING_INTRMANP
363 ret = KE_ILLEGAL_INTRCODE;
364#endif
365#endif
366 }
367#ifndef BUILDING_INTRMANP
368 else if ( (irq_index >= IOP_IRQ_DMA_SPU2) && (irq_index <= IOP_IRQ_DMA_SIO2_OUT) )
369 {
370 iop_mmio_hwport->dmac2.dicr2 = (iop_mmio_hwport->dmac2.dicr2 & (~(1 << (irq_index - 40 + 7)) & 0xFFFFFF))
371 | (((((irq & 0xFF00) >> 8) & 0x2) != 0) ? (1 << (irq_index - 33)) : 0)
372 | (1 << (irq_index - 40 + 16));
373 iop_mmio_hwport->dmac1.dicr1 = (iop_mmio_hwport->dmac1.dicr1 & 0x7FFFFF) | 0x800000;
374 iop_mmio_hwport->imask |= 8;
375 }
376#endif
377 else
378 {
379 ret = KE_ILLEGAL_INTRCODE;
380 }
381 CpuResumeIntr(state);
382 return ret;
383}
384
385int DisableIntr(int irq, int *res)
386{
387 int ret;
388 int res_temp;
389 int irq_index;
390 u32 imask;
391 int dicr_tmp;
392 int state;
393 USE_IOP_MMIO_HWPORT();
394
395 ret = 0;
396 res_temp = KE_INTRDISABLE;
397 irq_index = irq & 0xFF;
398 CpuSuspendIntr(&state);
399 if ( irq_index < IOP_IRQ_DMA_MDEC_IN )
400 {
401 imask = iop_mmio_hwport->imask;
402 iop_mmio_hwport->imask = imask & ~(1 << irq_index);
403 if ( (imask & (1 << irq_index)) != 0 )
404 {
405 res_temp = irq_index;
406 }
407 else
408 {
409 ret = KE_INTRDISABLE;
410 }
411 }
412 else if ( (irq_index >= IOP_IRQ_DMA_MDEC_IN) && (irq_index <= IOP_IRQ_DMA_GPU_OTC) )
413 {
414 dicr_tmp = iop_mmio_hwport->dmac1.dicr1 & 0xFFFFFF;
415 if ( (dicr_tmp & (1 << (irq_index - 16))) != 0 )
416 {
417 res_temp = irq_index;
418 if ( ((dicr_tmp >> (irq_index - 32)) & 1) != 0 )
419 res_temp |= 0x100;
420#ifndef BUILDING_INTRMANP
421 if ( iop_mmio_hwport->dmac2.dicr2 & (1 << (irq_index - 32)) )
422 res_temp |= 0x200;
423#endif
424 iop_mmio_hwport->dmac1.dicr1 = dicr_tmp & ~(1 << (irq_index - 16));
425 }
426 else
427 {
428 ret = KE_INTRDISABLE;
429 }
430 }
431#ifndef BUILDING_INTRMANP
432 else if ( (irq_index >= IOP_IRQ_DMA_SPU2) && (irq_index <= IOP_IRQ_DMA_SIO2_OUT) )
433 {
434 dicr_tmp = iop_mmio_hwport->dmac2.dicr2 & 0xFFFFFF;
435 if ( (dicr_tmp & (1 << (irq_index - 24))) != 0 )
436 {
437 res_temp = irq_index;
438 if ( (dicr_tmp >> (irq_index - 33)) & 1 )
439 res_temp |= 0x200;
440 iop_mmio_hwport->dmac2.dicr2 = dicr_tmp & ~(1 << (irq_index - 24));
441 }
442 else
443 {
444 ret = KE_INTRDISABLE;
445 }
446 }
447#endif
448 else
449 {
450 ret = KE_ILLEGAL_INTRCODE;
451 }
452 if ( res )
453 *res = res_temp;
454 CpuResumeIntr(state);
455 return ret;
456}
457
459{
460 int irq_index;
461 int state;
462 USE_IOP_LOW_MEMORY_GLOBALS();
463
464 irq_index = irq & 0xFF;
465 CpuSuspendIntr(&state);
466 if ( irq_index < IOP_IRQ_DMA_MDEC_IN )
467 {
468#pragma GCC diagnostic push
469#pragma GCC diagnostic ignored "-Warray-bounds"
470 iop_low_memory_globals->dispatch_interrupt_state |= 1 << irq_index;
471#pragma GCC diagnostic pop
472 }
473 else if ( (irq_index >= IOP_IRQ_DMA_MDEC_IN) && (irq_index <= IOP_IRQ_DMA_BERR) )
474 {
475 intrman_internals.masked_icr_1 |= 1 << (irq_index - 8);
476 }
477 else if ( (irq_index >= IOP_IRQ_DMA_SPU2) && (irq_index <= IOP_IRQ_DMA_SIO2_OUT) )
478 {
479 intrman_internals.masked_icr_2 |= 1 << (irq_index - 16);
480 }
481 CpuResumeIntr(state);
482}
483
485{
486 int irq_index;
487 int state;
488 USE_IOP_LOW_MEMORY_GLOBALS();
489
490 irq_index = irq & 0xFF;
491 CpuSuspendIntr(&state);
492 if ( irq_index < IOP_IRQ_DMA_MDEC_IN )
493 {
494#pragma GCC diagnostic push
495#pragma GCC diagnostic ignored "-Warray-bounds"
496 iop_low_memory_globals->dispatch_interrupt_state &= ~(1 << irq_index);
497#pragma GCC diagnostic pop
498 }
499 else if ( (irq_index >= IOP_IRQ_DMA_MDEC_IN) && (irq_index <= IOP_IRQ_DMA_BERR) )
500 {
501 intrman_internals.masked_icr_1 &= ~(1 << (irq_index - 8));
502 }
503 else if ( (irq_index >= IOP_IRQ_DMA_SPU2) && (irq_index <= IOP_IRQ_DMA_SIO2_OUT) )
504 {
505 intrman_internals.masked_icr_2 &= ~(1 << (irq_index - 16));
506 }
507 CpuResumeIntr(state);
508}
509
510void intrman_set_dmac2_interrupt_handler_mask(int mask)
511{
512 intrman_internals.dmac2_interrupt_handler_mask = mask;
513}
514
515#ifndef BUILDING_INTRMANP
516// Unofficial: reference relative to internal structure
517static void dmac2_enable_set(const intrman_internals_t *p_intrman_internals, int mask)
518{
519 USE_IOP_MMIO_HWPORT();
520
521 if ( (p_intrman_internals->dmac2_interrupt_handler_mask & mask) != 0 )
522 {
523 while ( iop_mmio_hwport->dmac2.dmacen != 1 )
524 {
525 iop_mmio_hwport->dmac2.dmacen = 1;
526 }
527 }
528}
529
530// Unofficial: reference relative to internal structure
531static void dmac2_enable_unset(const intrman_internals_t *p_intrman_internals, int mask)
532{
533 USE_IOP_MMIO_HWPORT();
534
535 if ( (p_intrman_internals->dmac2_interrupt_handler_mask & mask) != 0 )
536 {
537 while ( iop_mmio_hwport->dmac2.dmacen != 0 )
538 {
539 iop_mmio_hwport->dmac2.dmacen = 0;
540 }
541 }
542}
543#endif
544
545int dma_interrupt_handler(void *userdata)
546{
547#ifndef BUILDING_INTRMANP
548 u32 dma2_intr_flags;
549#endif
550 u32 dma1_intr_flags_tmp;
551 u32 dma1_intr_flags;
552 int bus_error_intr_flag;
553 int i;
554 int masked_icr_1_tmp;
555#ifndef BUILDING_INTRMANP
556 int masked_icr_2_tmp;
557#endif
558 intrman_internals_t *p_intrman_internals;
559 intrman_intr_handler_data_t *interrupt_handler_table;
560 USE_IOP_MMIO_HWPORT();
561
562 // Unofficial: reference relative to internal structure
563 p_intrman_internals = (intrman_internals_t *)userdata;
564 interrupt_handler_table = p_intrman_internals->interrupt_handler_table;
565 masked_icr_1_tmp = p_intrman_internals->masked_icr_1;
566#ifndef BUILDING_INTRMANP
567 masked_icr_2_tmp = p_intrman_internals->masked_icr_2;
568#endif
569#ifndef BUILDING_INTRMANP
570 dmac2_enable_unset(p_intrman_internals, 1);
571#endif
572 while ( 1 )
573 {
574#ifndef BUILDING_INTRMANP
575 dmac2_enable_unset(p_intrman_internals, 2);
576#endif
577#ifndef BUILDING_INTRMANP
578 dma2_intr_flags = ((iop_mmio_hwport->dmac2.dicr2 & masked_icr_2_tmp) >> 24) & 0x3F;
579#endif
580 dma1_intr_flags_tmp = iop_mmio_hwport->dmac1.dicr1 & masked_icr_1_tmp;
581 dma1_intr_flags = ((dma1_intr_flags_tmp & 0xFF00) >> 8) & 0x7F;
582 bus_error_intr_flag = (dma1_intr_flags_tmp >> 15) & 1;
583#ifndef BUILDING_INTRMANP
584 dmac2_enable_set(p_intrman_internals, 2);
585#endif
586#ifdef BUILDING_INTRMANP
587 if ( !(dma1_intr_flags | bus_error_intr_flag) )
588 break;
589#else
590 if ( !(dma1_intr_flags | dma2_intr_flags | bus_error_intr_flag) )
591 break;
592#endif
593 if ( bus_error_intr_flag )
594 {
595#ifndef BUILDING_INTRMANP
596 dmac2_enable_unset(p_intrman_internals, 2);
597#endif
598 iop_mmio_hwport->dmac1.dicr1 &= 0xFF7FFF;
599#ifndef BUILDING_INTRMANP
600 dmac2_enable_set(p_intrman_internals, 2);
601#endif
602 if ( interrupt_handler_table[IOP_IRQ_DMA_BERR].handler )
603 {
604 interrupt_handler_table[IOP_IRQ_DMA_BERR].handler(interrupt_handler_table[IOP_IRQ_DMA_BERR].userdata);
605 }
606 }
607 if ( dma1_intr_flags )
608 {
609 for ( i = 0; i < 7; i += 1 )
610 {
611 if ( (dma1_intr_flags & 1) != 0 )
612 {
613#ifndef BUILDING_INTRMANP
614 dmac2_enable_unset(p_intrman_internals, 2);
615#endif
616 iop_mmio_hwport->dmac1.dicr1 &= ((1 << (i + 24)) | 0xFFFFFF);
617 if ( interrupt_handler_table[i + IOP_IRQ_DMA_MDEC_IN].handler )
618 {
619#ifndef BUILDING_INTRMANP
620 dmac2_enable_set(p_intrman_internals, 4);
621#endif
622 if ( !interrupt_handler_table[i + IOP_IRQ_DMA_MDEC_IN].handler(
623 interrupt_handler_table[i + IOP_IRQ_DMA_MDEC_IN].userdata) )
624 {
625#ifndef BUILDING_INTRMANP
626 dmac2_enable_unset(p_intrman_internals, 4);
627#endif
628 iop_mmio_hwport->dmac1.dicr1 &= 0xFFFFFF & ~(1 << (i + 16));
629 }
630#ifndef BUILDING_INTRMANP
631 dmac2_enable_unset(p_intrman_internals, 4);
632#endif
633 }
634 else
635 {
636 iop_mmio_hwport->dmac1.dicr1 &= 0xFFFFFF & ~(1 << (i + 16));
637 }
638#ifndef BUILDING_INTRMANP
639 dmac2_enable_set(p_intrman_internals, 2);
640#endif
641 }
642 dma1_intr_flags >>= 1;
643 if ( !dma1_intr_flags )
644 break;
645 }
646 }
647#ifndef BUILDING_INTRMANP
648 if ( dma2_intr_flags )
649 {
650 for ( i = 0; i < 6; i += 1 )
651 {
652 if ( (dma2_intr_flags & 1) != 0 )
653 {
654 dmac2_enable_unset(p_intrman_internals, 2);
655 iop_mmio_hwport->dmac2.dicr2 &= (1 << (i + 24)) | 0xFFFFFF;
656 if ( interrupt_handler_table[i + IOP_IRQ_DMA_SPU2].handler )
657 {
658 dmac2_enable_set(p_intrman_internals, 4);
659 if ( !(interrupt_handler_table[i + IOP_IRQ_DMA_SPU2].handler(
660 interrupt_handler_table[i + IOP_IRQ_DMA_SPU2].userdata)) )
661 {
662 dmac2_enable_unset(p_intrman_internals, 4);
663 iop_mmio_hwport->dmac2.dicr2 &= 0xFFFFFF & ~(1 << (i + 16));
664 }
665 dmac2_enable_unset(p_intrman_internals, 4);
666 }
667 else
668 {
669 iop_mmio_hwport->dmac2.dicr2 &= 0xFFFFFF & ~(1 << (i + 16));
670 }
671 dmac2_enable_set(p_intrman_internals, 2);
672 }
673 dma2_intr_flags >>= 1;
674 if ( !dma2_intr_flags )
675 break;
676 }
677 }
678#endif
679 }
680#ifndef BUILDING_INTRMANP
681 dmac2_enable_unset(p_intrman_internals, 2);
682#endif
683 {
684 u32 dicr1x;
685
686 dicr1x = iop_mmio_hwport->dmac1.dicr1;
687 iop_mmio_hwport->dmac1.dicr1 = (dicr1x & 0x7FFFFF);
688 iop_mmio_hwport->dmac1.dicr1 = (dicr1x & 0x7FFFFF) | 0x800000;
689 }
690#ifndef BUILDING_INTRMANP
691 dmac2_enable_set(p_intrman_internals, 2);
692 dmac2_enable_set(p_intrman_internals, 1);
693#endif
694 return 1;
695}
696
697static void *new_context_stub_cb(void *ctx);
698static int preempt_stub_cb(int unk);
699
700void *ctx_switch_cb = new_context_stub_cb;
701void *ctx_switch_required_cb = preempt_stub_cb;
702
703void SetNewCtxCb(void *cb)
704{
705 ctx_switch_cb = cb;
706}
707
708void ResetNewCtxCb(void)
709{
710 ctx_switch_cb = new_context_stub_cb;
711}
712
713void SetShouldPreemptCb(void *cb)
714{
715 ctx_switch_required_cb = cb;
716}
717
718void ResetShouldPreemptCb(void)
719{
720 ctx_switch_required_cb = preempt_stub_cb;
721}
722
723u32 tempstack[0x200];
724
725// clang-format off
726__asm__ (
727 "\t" ".set push" "\n"
728 "\t" ".set noat" "\n"
729 "\t" ".set noreorder" "\n"
730 "\t" ".global QueryIntrContext" "\n"
731 "\t" "QueryIntrContext:" "\n"
732 "\t" " addu $a0, $sp, $zero" "\n"
733 "\t" ".global QueryIntrStack" "\n"
734 "\t" "QueryIntrStack:" "\n"
735 "\t" " lui $v1, %hi(tempstack + 0x800)" "\n"
736 "\t" " addiu $v1, $v1, %lo(tempstack + 0x800)" "\n" // sizeof(tempstack)
737 "\t" " sltu $v0, $a0, $v1" "\n"
738 "\t" " beqz $v0, 9f" "\n"
739 "\t" " nop" "\n"
740 "\t" " addiu $v1, $v1, -0x800" "\n"
741 "\t" " sltu $v0, $v1, $a0" "\n"
742 "\t" "9:" "\n"
743 "\t" " jr $ra" "\n"
744 "\t" " nop" "\n"
745 "\t" ".set pop" "\n"
746);
747
748__asm__ (
749 "\t" ".set push" "\n"
750 "\t" ".set noat" "\n"
751 "\t" ".set noreorder" "\n"
752 "\t" ".global iCatchMultiIntr" "\n"
753 "\t" "iCatchMultiIntr:" "\n"
754 "\t" " lui $v1, %hi(tempstack + 0x800)" "\n"
755 "\t" " addiu $v1, $v1, %lo(tempstack + 0x800)" "\n" // sizeof(tempstack)
756 "\t" " sltu $v0, $sp, $v1" "\n"
757 "\t" " beqz $v0, 1f" "\n"
758 "\t" " nop" "\n"
759 "\t" " addiu $v1, $v1, -0x800" "\n"
760 "\t" " sltu $v0, $v1, $sp" "\n"
761 "\t" " beqz $v0, 2f" "\n"
762 "\t" " nop" "\n"
763 "\t" " addiu $v1, $v1, 0x160" "\n"
764 "\t" " sltu $v0, $v1, $sp" "\n"
765 "\t" " beqz $v0, 1f" "\n"
766 "\t" " nop" "\n"
767 "\t" " mfc0 $v0, $12" "\n"
768 "\t" " nop" "\n"
769 "\t" " andi $v1, $v0, 0x1" "\n"
770 "\t" " bnez $v1, 1f" "\n"
771 "\t" " ori $v1, $v0, 0x1" "\n"
772 "\t" " mtc0 $v1, $12" "\n"
773 "\t" " nop" "\n"
774 "\t" " nop" "\n"
775 "\t" " mtc0 $v0, $12" "\n"
776 "\t" "1:" "\n"
777 "\t" " jr $ra" "\n"
778 "\t" " nop" "\n"
779 "\t" "2:" "\n"
780 "\t" " break 2" "\n"
781 "\t" " jr $ra" "\n"
782 "\t" " nop" "\n"
783 "\t" ".set pop" "\n"
784);
785
786__asm__ (
787 "\t" ".set push" "\n"
788 "\t" ".set noat" "\n"
789 "\t" ".set noreorder" "\n"
790 "\t" "exception_interrupt_handler:" "\n"
791 "\t" " .word 0" "\n"
792 "\t" " .word 0" "\n"
793
794 "\t" "exception_interrupt_handler_code:" "\n"
795 "\t" " addiu $sp, $sp, -0x98" "\n"
796 "\t" " lw $at, 0x400($zero)" "\n"
797 "\t" " sw $ra, 0x7C($sp)" "\n"
798 "\t" " sw $at, 0x4($sp)" "\n"
799 "\t" " sw $v0, 0x8($sp)" "\n"
800 "\t" " sw $v1, 0xC($sp)" "\n"
801 "\t" " sw $a0, 0x10($sp)" "\n"
802 "\t" " sw $a1, 0x14($sp)" "\n"
803 "\t" " sw $a2, 0x18($sp)" "\n"
804 "\t" " sw $a3, 0x1C($sp)" "\n"
805 "\t" " addiu $v0, $sp, 0x98" "\n"
806 "\t" " sw $v0, 0x74($sp)" "\n"
807 "\t" " mfhi $v0" "\n"
808 "\t" " mflo $v1" "\n"
809 "\t" " sw $v0, 0x80($sp)" "\n"
810 "\t" " sw $v1, 0x84($sp)" "\n"
811 "\t" " lw $v0, 0x408($zero)" "\n"
812 "\t" " lw $v1, 0x404($zero)" "\n"
813 "\t" " sw $v0, 0x88($sp)" "\n"
814 "\t" " sw $v1, 0x8C($sp)" "\n"
815#ifndef BUILDING_INTRMANP
816 "\t" " lui $v0, (0xBF801078 >> 16)" "\n"
817 "\t" " ori $v0, $v0, (0xBF801078 & 0xFFFF)" "\n"
818 "\t" " lw $v1, 0x0($v0)" "\n"
819 "\t" " addiu $a0, $zero, 0x1" "\n"
820 "\t" " sw $v1, 0x90($sp)" "\n"
821 "\t" " sw $a0, 0x0($v0)" "\n"
822#endif
823 "\t" " lui $v0, (0xAC0000FE >> 16)" "\n"
824 "\t" " ori $v0, $v0, (0xAC0000FE & 0xFFFF)" "\n"
825 "\t" " sw $v0, 0x0($sp)" "\n"
826 "\t" " jal QueryIntrContext" "\n"
827 "\t" " nop" "\n"
828 "\t" " beqz $v0, .Lexception_interrupt_handler_code_1" "\n"
829 "\t" " nop" "\n"
830 "\t" " addu $v0, $sp, $zero" "\n"
831 "\t" " addiu $sp, $sp, -0x18" "\n"
832 "\t" " b .Lexception_interrupt_handler_code_2" "\n"
833 "\t" " sw $v0, 0x14($sp)" "\n"
834 "\t" ".Lexception_interrupt_handler_code_1:" "\n"
835 "\t" " addu $v0, $sp, $zero" "\n"
836 "\t" " lui $sp, %hi(tempstack + 0x7E0)" "\n"
837 "\t" " addiu $sp, $sp, %lo(tempstack + 0x7E0)" "\n"
838 "\t" " sw $v0, 0x14($sp)" "\n"
839 "\t" ".Lexception_interrupt_handler_code_2:" "\n"
840 "\t" " lw $a0, 0x40C($zero)" "\n"
841 "\t" " nop" "\n"
842 "\t" " sll $a0, $a0, 22" "\n"
843 "\t" " srl $a0, $a0, 30" "\n"
844 "\t" " bne $zero, $a0, .Lexception_interrupt_handler_code_5" "\n"
845 "\t" " nop" "\n"
846 "\t" " lui $k0, (0xBF801070 >> 16)" "\n"
847 "\t" " ori $k0, $k0, (0xBF801070 & 0xFFFF)" "\n"
848 "\t" " lw $k1, 0x4($k0)" "\n"
849 "\t" " lw $a0, 0x0($k0)" "\n"
850 "\t" " lw $a1, 0x41C($zero)" "\n"
851 "\t" " and $a0, $a0, $k1" "\n"
852 "\t" " and $a0, $a0, $a1" "\n"
853 "\t" " beq $zero, $a0, .Lexception_interrupt_handler_code_4" "\n"
854 "\t" " nop" "\n"
855 "\t" " addiu $v0, $zero, -0x4" "\n"
856 "\t" ".Lexception_interrupt_handler_code_3:" "\n"
857 "\t" " sll $a2, $a0, 28" "\n"
858 "\t" " srl $a0, $a0, 4" "\n"
859 "\t" " beqz $a2, .Lexception_interrupt_handler_code_3" "\n"
860 "\t" " addi $v0, $v0, 0x4" "\n"
861 "\t" " srl $a0, $a2, 26" "\n"
862 "\t" " andi $a0, $a0, 0x1C" "\n"
863 "\t" " lui $a2, (0x1020103 >> 16)" "\n"
864 "\t" " ori $a2, $a2, (0x1020103 & 0xFFFF)" "\n"
865 "\t" " srlv $a2, $a2, $a0" "\n"
866 "\t" " andi $a2, $a2, 0xF" "\n"
867 "\t" " add $v0, $v0, $a2" "\n"
868 "\t" " addiu $a2, $zero, 0x1" "\n"
869 "\t" " sllv $a2, $a2, $v0" "\n"
870 "\t" " sw $a2, 0x10($sp)" "\n"
871 "\t" " not $a2, $a2" "\n"
872 "\t" " and $a3, $a2, $k1" "\n"
873 "\t" " sw $a3, 0x4($k0)" "\n"
874 "\t" " sw $a2, 0x0($k0)" "\n"
875 "\t" " sll $a2, $v0, 3" "\n"
876 "\t" " lw $a3, 0x480($a2)" "\n"
877 "\t" " lw $a0, 0x484($a2)" "\n"
878 "\t" " bne $zero, $a3, .Lexception_interrupt_handler_code_7" "\n"
879 "\t" " nop" "\n"
880 "\t" ".Lexception_interrupt_handler_code_4:" "\n"
881 "\t" " lw $sp, 0x14($sp)" "\n"
882 "\t" " nop" "\n"
883 "\t" " lw $ra, 0x7C($sp)" "\n"
884 "\t" " lw $at, 0x4($sp)" "\n"
885 "\t" " lw $v0, 0x8($sp)" "\n"
886 "\t" " lw $v1, 0xC($sp)" "\n"
887 "\t" " lw $a0, 0x10($sp)" "\n"
888 "\t" " lw $a1, 0x14($sp)" "\n"
889 "\t" " lw $a2, 0x18($sp)" "\n"
890 "\t" " lw $a3, 0x1C($sp)" "\n"
891 "\t" " addiu $sp, $sp, 0x98" "\n"
892 "\t" " lui $k0, %hi(exception_interrupt_handler)" "\n"
893 "\t" " lw $k0, %lo(exception_interrupt_handler)($k0)" "\n"
894 "\t" " nop" "\n"
895 "\t" " jr $k0" "\n"
896 "\t" " nop" "\n"
897 "\t" ".Lexception_interrupt_handler_code_5:" "\n"
898 "\t" " sw $zero, 0x10($sp)" "\n"
899 "\t" " andi $a0, $a0, 0x1" "\n"
900 "\t" " bnez $a0, .Lexception_interrupt_handler_code_6" "\n"
901 "\t" " addiu $v0, $zero, 0x0" "\n"
902 "\t" " addiu $v0, $zero, 0x1" "\n"
903 "\t" ".Lexception_interrupt_handler_code_6:" "\n"
904 "\t" " addiu $a2, $zero, 0x100" "\n"
905 "\t" " sllv $a2, $a2, $v0" "\n"
906 "\t" " mfc0 $a0, $13" "\n"
907 "\t" " not $a2, $a2" "\n"
908 "\t" " and $a0, $a0, $a2" "\n"
909 "\t" " mtc0 $a0, $13" "\n"
910 "\t" " sll $a2, $v0, 3" "\n"
911 "\t" " lw $a3, 0x5F0($a2)" "\n"
912 "\t" " lw $a0, 0x5F4($a2)" "\n"
913 "\t" " beq $zero, $a3, .Lexception_interrupt_handler_code_4" "\n"
914 "\t" " nop" "\n"
915 "\t" ".Lexception_interrupt_handler_code_7:" "\n"
916 "\t" " sll $a2, $a3, 30" "\n"
917 "\t" " bnez $a2, .Lexception_interrupt_handler_code_8" "\n"
918 "\t" " nop" "\n"
919 "\t" " srl $a3, $a3, 2" "\n"
920 "\t" " sll $a3, $a3, 2" "\n"
921 "\t" " jalr $a3" "\n"
922 "\t" " nop" "\n"
923 "\t" " b .Lexception_interrupt_handler_code_10" "\n"
924 "\t" " nop" "\n"
925 "\t" ".Lexception_interrupt_handler_code_8:" "\n"
926 "\t" " lw $v0, 0x14($sp)" "\n"
927 "\t" " nop" "\n"
928 "\t" " sw $t0, 0x20($v0)" "\n"
929 "\t" " sw $t1, 0x24($v0)" "\n"
930 "\t" " sw $t2, 0x28($v0)" "\n"
931 "\t" " sw $t3, 0x2C($v0)" "\n"
932 "\t" " sw $t4, 0x30($v0)" "\n"
933 "\t" " sw $t5, 0x34($v0)" "\n"
934 "\t" " sw $t6, 0x38($v0)" "\n"
935 "\t" " sw $t7, 0x3C($v0)" "\n"
936 "\t" " sw $t8, 0x60($v0)" "\n"
937 "\t" " sw $t9, 0x64($v0)" "\n"
938 "\t" " sw $gp, 0x70($v0)" "\n"
939 "\t" " sw $fp, 0x78($v0)" "\n"
940 "\t" " lui $t0, (0xFF00FFFE >> 16)" "\n"
941 "\t" " ori $t0, $t0, (0xFF00FFFE & 0xFFFF)" "\n"
942 "\t" " sw $t0, 0x0($v0)" "\n"
943 "\t" " lui $gp, (0xFFFF0000 >> 16)" "\n"
944 "\t" " sll $a2, $a2, 1" "\n"
945 "\t" " beqz $a2, .Lexception_interrupt_handler_code_9" "\n"
946 "\t" " nop" "\n"
947 "\t" " srl $a3, $a3, 2" "\n"
948 "\t" " sll $a3, $a3, 2" "\n"
949 "\t" " jalr $a3" "\n"
950 "\t" " nop" "\n"
951 "\t" " b .Lexception_interrupt_handler_code_10" "\n"
952 "\t" " nop" "\n"
953 "\t" ".Lexception_interrupt_handler_code_9:" "\n"
954 "\t" " lw $v0, 0x14($sp)" "\n"
955 "\t" " nop" "\n"
956 "\t" " sw $s0, 0x40($v0)" "\n"
957 "\t" " sw $s1, 0x44($v0)" "\n"
958 "\t" " sw $s2, 0x48($v0)" "\n"
959 "\t" " sw $s3, 0x4C($v0)" "\n"
960 "\t" " sw $s4, 0x50($v0)" "\n"
961 "\t" " sw $s5, 0x54($v0)" "\n"
962 "\t" " sw $s6, 0x58($v0)" "\n"
963 "\t" " sw $s7, 0x5C($v0)" "\n"
964 "\t" " addiu $t0, $zero, -0x2" "\n"
965 "\t" " sw $t0, 0x0($v0)" "\n"
966 "\t" " srl $a3, $a3, 2" "\n"
967 "\t" " sll $a3, $a3, 2" "\n"
968 "\t" " jalr $a3" "\n"
969 "\t" " nop" "\n"
970 "\t" ".Lexception_interrupt_handler_code_10:" "\n"
971 "\t" " lw $a3, 0x10($sp)" "\n"
972 "\t" " mtc0 $zero, $12" "\n"
973 "\t" " lui $a0, (0xBF801074 >> 16)" "\n"
974 "\t" " beq $zero, $v0, .Lexception_interrupt_handler_code_11" "\n"
975 "\t" " ori $a0, $a0, (0xBF801074 & 0xFFFF)" "\n"
976 "\t" " lw $a2, 0x0($a0)" "\n"
977 "\t" " nop" "\n"
978 "\t" " or $a3, $a3, $a2" "\n"
979 "\t" " sw $a3, 0x0($a0)" "\n"
980 "\t" ".Lexception_interrupt_handler_code_11:" "\n"
981 "\t" " lw $a0, 0x14($sp)" "\n"
982 "\t" " jal QueryIntrStack" "\n"
983 "\t" " nop" "\n"
984 "\t" " bnez $v0, .Lexception_interrupt_handler_code_14" "\n"
985 "\t" " nop" "\n"
986 "\t" " lui $v1, %hi(ctx_switch_required_cb)" "\n"
987 "\t" " lw $v1, %lo(ctx_switch_required_cb)($v1)" "\n"
988 "\t" " nop" "\n"
989 "\t" " jalr $v1" "\n"
990 "\t" " nop" "\n"
991 "\t" " lw $a0, 0x14($sp)" "\n"
992 "\t" " beqz $v0, .Lexception_interrupt_handler_code_14" "\n"
993 "\t" " nop" "\n"
994 "\t" " lw $v0, 0x0($a0)" "\n"
995 "\t" " addiu $a1, $zero, -0x2" "\n"
996 "\t" " beq $v0, $a1, intrman_perform_context_switch" "\n"
997 "\t" " nop" "\n"
998 "\t" " lui $a1, (0xFF00FFFE >> 16)" "\n"
999 "\t" " ori $a1, $a1, (0xFF00FFFE & 0xFFFF)" "\n"
1000 "\t" " beq $v0, $a1, .Lexception_interrupt_handler_code_12" "\n"
1001 "\t" " nop" "\n"
1002 "\t" " sw $t0, 0x20($a0)" "\n"
1003 "\t" " sw $t1, 0x24($a0)" "\n"
1004 "\t" " sw $t2, 0x28($a0)" "\n"
1005 "\t" " sw $t3, 0x2C($a0)" "\n"
1006 "\t" " sw $t4, 0x30($a0)" "\n"
1007 "\t" " sw $t5, 0x34($a0)" "\n"
1008 "\t" " sw $t6, 0x38($a0)" "\n"
1009 "\t" " sw $t7, 0x3C($a0)" "\n"
1010 "\t" " sw $t8, 0x60($a0)" "\n"
1011 "\t" " sw $t9, 0x64($a0)" "\n"
1012 "\t" " sw $gp, 0x70($a0)" "\n"
1013 "\t" " sw $fp, 0x78($a0)" "\n"
1014 "\t" ".Lexception_interrupt_handler_code_12:" "\n"
1015 "\t" " sw $s0, 0x40($a0)" "\n"
1016 "\t" " sw $s1, 0x44($a0)" "\n"
1017 "\t" " sw $s2, 0x48($a0)" "\n"
1018 "\t" " sw $s3, 0x4C($a0)" "\n"
1019 "\t" " sw $s4, 0x50($a0)" "\n"
1020 "\t" " sw $s5, 0x54($a0)" "\n"
1021 "\t" " sw $s6, 0x58($a0)" "\n"
1022 "\t" " sw $s7, 0x5C($a0)" "\n"
1023 "\t" " addiu $v0, $zero, -0x2" "\n"
1024 "\t" " sw $v0, 0x0($a0)" "\n"
1025 "\t" "intrman_perform_context_switch:" "\n"
1026 "\t" " lui $v1, %hi(ctx_switch_cb)" "\n"
1027 "\t" " lw $v1, %lo(ctx_switch_cb)($v1)" "\n"
1028 "\t" " nop" "\n"
1029 "\t" " jalr $v1" "\n"
1030 "\t" " nop" "\n"
1031 "\t" " addu $a0, $v0, $zero" "\n"
1032 "\t" ".Lexception_interrupt_handler_code_14:" "\n"
1033 "\t" " addu $sp, $a0, $zero" "\n"
1034 "\t" " lw $a0, 0x0($sp)" "\n"
1035 "\t" " lui $a1, (0xF0FF000C >> 16)" "\n"
1036 "\t" " ori $a1, $a1, (0xF0FF000C & 0xFFFF)" "\n"
1037 "\t" " beq $a0, $a1, .Lintrman_perform_context_switch_4" "\n"
1038 "\t" " lui $a1, (0xAC0000FE >> 16)" "\n"
1039 "\t" " ori $a1, $a1, (0xAC0000FE & 0xFFFF)" "\n"
1040 "\t" " beq $a0, $a1, .Lintrman_perform_context_switch_2" "\n"
1041 "\t" " lui $a1, (0xFF00FFFE >> 16)" "\n"
1042 "\t" " ori $a1, $a1, (0xFF00FFFE & 0xFFFF)" "\n"
1043 "\t" " beq $a0, $a1, .Lintrman_perform_context_switch_1" "\n"
1044 "\t" " nop" "\n"
1045 "\t" " lw $s0, 0x40($sp)" "\n"
1046 "\t" " lw $s1, 0x44($sp)" "\n"
1047 "\t" " lw $s2, 0x48($sp)" "\n"
1048 "\t" " lw $s3, 0x4C($sp)" "\n"
1049 "\t" " lw $s4, 0x50($sp)" "\n"
1050 "\t" " lw $s5, 0x54($sp)" "\n"
1051 "\t" " lw $s6, 0x58($sp)" "\n"
1052 "\t" " lw $s7, 0x5C($sp)" "\n"
1053 "\t" ".Lintrman_perform_context_switch_1:" "\n"
1054 "\t" " lw $t0, 0x20($sp)" "\n"
1055 "\t" " lw $t1, 0x24($sp)" "\n"
1056 "\t" " lw $t2, 0x28($sp)" "\n"
1057 "\t" " lw $t3, 0x2C($sp)" "\n"
1058 "\t" " lw $t4, 0x30($sp)" "\n"
1059 "\t" " lw $t5, 0x34($sp)" "\n"
1060 "\t" " lw $t6, 0x38($sp)" "\n"
1061 "\t" " lw $t7, 0x3C($sp)" "\n"
1062 "\t" " lw $t8, 0x60($sp)" "\n"
1063 "\t" " lw $t9, 0x64($sp)" "\n"
1064 "\t" " lw $gp, 0x70($sp)" "\n"
1065 "\t" " lw $fp, 0x78($sp)" "\n"
1066 "\t" ".Lintrman_perform_context_switch_2:" "\n"
1067#ifndef BUILDING_INTRMANP
1068 "\t" " lw $v1, 0x90($sp)" "\n"
1069 "\t" " lui $v0, (0xBF801078 >> 16)" "\n"
1070 "\t" " ori $v0, $v0, (0xBF801078 & 0xFFFF)" "\n"
1071 "\t" " sw $v1, 0x0($v0)" "\n"
1072#endif
1073 "\t" " lw $v0, 0x80($sp)" "\n"
1074 "\t" " lw $v1, 0x84($sp)" "\n"
1075 "\t" " mthi $v0" "\n"
1076 "\t" " mtlo $v1" "\n"
1077 "\t" " lw $a0, 0x88($sp)" "\n"
1078 "\t" " lw $ra, 0x7C($sp)" "\n"
1079 "\t" " srl $a0, $a0, 1" "\n"
1080 "\t" " sll $a0, $a0, 1" "\n"
1081 "\t" " mtc0 $a0, $12" "\n"
1082 "\t" " lw $at, 0x4($sp)" "\n"
1083 "\t" " lw $v0, 0x8($sp)" "\n"
1084 "\t" " lw $v1, 0xC($sp)" "\n"
1085 "\t" " lw $a0, 0x10($sp)" "\n"
1086 "\t" " lw $a1, 0x14($sp)" "\n"
1087 "\t" " lw $a2, 0x18($sp)" "\n"
1088 "\t" " lw $a3, 0x1C($sp)" "\n"
1089 "\t" ".Lintrman_perform_context_switch_3:" "\n"
1090 "\t" " lw $k0, 0x8C($sp)" "\n"
1091 "\t" " lw $sp, 0x74($sp)" "\n"
1092 "\t" " jr $k0" "\n"
1093 "\t" " .word 0x42000010" "\n" // cop0 0x10 # return from exception
1094 "\t" " nop" "\n"
1095 "\t" ".Lintrman_perform_context_switch_4:" "\n"
1096#ifndef BUILDING_INTRMANP
1097 "\t" " lw $v1, 0x90($sp)" "\n"
1098 "\t" " lui $v0, (0xBF801078 >> 16)" "\n"
1099 "\t" " ori $v0, $v0, (0xBF801078 & 0xFFFF)" "\n"
1100 "\t" " sw $v1, 0x0($v0)" "\n"
1101#endif
1102 "\t" " lw $s0, 0x40($sp)" "\n"
1103 "\t" " lw $s1, 0x44($sp)" "\n"
1104 "\t" " lw $s2, 0x48($sp)" "\n"
1105 "\t" " lw $s3, 0x4C($sp)" "\n"
1106 "\t" " lw $s4, 0x50($sp)" "\n"
1107 "\t" " lw $s5, 0x54($sp)" "\n"
1108 "\t" " lw $s6, 0x58($sp)" "\n"
1109 "\t" " lw $s7, 0x5C($sp)" "\n"
1110 "\t" " lw $v0, 0x8($sp)" "\n"
1111 "\t" " lw $v1, 0xC($sp)" "\n"
1112 "\t" " lw $gp, 0x70($sp)" "\n"
1113 "\t" " lw $fp, 0x78($sp)" "\n"
1114 "\t" " lw $a0, 0x88($sp)" "\n"
1115 "\t" " lw $ra, 0x7C($sp)" "\n"
1116 "\t" " srl $a0, $a0, 1" "\n"
1117 "\t" " sll $a0, $a0, 1" "\n"
1118 "\t" " mtc0 $a0, $12" "\n"
1119 "\t" " b .Lintrman_perform_context_switch_3" "\n"
1120 "\t" " nop" "\n"
1121 "\t" ".set pop" "\n"
1122);
1123// clang-format on
1124
1125static void *new_context_stub_cb(void *ctx)
1126{
1127 return ctx;
1128}
1129
1130static int preempt_stub_cb(int unk)
1131{
1132 (void)unk;
1133
1134 return 0;
1135}
1136
1137// clang-format off
1138__asm__ (
1139 "\t" ".set push" "\n"
1140 "\t" ".set noat" "\n"
1141 "\t" ".set noreorder" "\n"
1142 "\t" "exception_priority_interrupt_handler:" "\n"
1143 "\t" " .word 0" "\n"
1144 "\t" " .word 0" "\n"
1145
1146 "\t" "exception_priority_interrupt_handler_code:" "\n"
1147 "\t" " lw $k0, 0x408($zero)" "\n"
1148 "\t" " lw $at, 0x400($zero)" "\n"
1149 "\t" " mtc0 $k0, $12" "\n"
1150 "\t" " lw $k0, 0x404($zero)" "\n"
1151 "\t" " nop" "\n"
1152 "\t" " jr $k0" "\n"
1153 "\t" " .word 0x42000010" "\n" // cop0 0x10 # return from exception
1154 "\t" ".set pop" "\n"
1155);
1156
1157__asm__ (
1158 "\t" ".set push" "\n"
1159 "\t" ".set noat" "\n"
1160 "\t" ".set noreorder" "\n"
1161 "\t" "exception_system_handler:" "\n"
1162 "\t" " .word 0" "\n"
1163 "\t" " .word 0" "\n"
1164
1165 "\t" "exception_system_handler_code:" "\n"
1166 "\t" " andi $k0, $v0, 0x3" "\n"
1167 "\t" " beqz $k0, syscall_handler_dispatch" "\n"
1168
1169 "\t" "syscall_handler_callnext:" "\n"
1170 "\t" " lui $k0, %hi(exception_system_handler)" "\n"
1171 "\t" " lw $k0, %lo(exception_system_handler)($k0)" "\n"
1172 "\t" " nop" "\n"
1173 "\t" " jr $k0" "\n"
1174 "\t" " nop" "\n"
1175
1176 "\t" "syscall_handler_dispatch:" "\n"
1177 "\t" " lui $k0, %hi(syscall_dsp)" "\n"
1178 "\t" " addiu $k0, $k0, %lo(syscall_dsp)" "\n"
1179 "\t" " addu $k0, $k0, $v0" "\n"
1180 "\t" " lw $k0, 0x0($k0)" "\n"
1181 "\t" " nop" "\n"
1182 "\t" " jr $k0" "\n"
1183 "\t" " nop" "\n"
1184
1185 "\t" "syscall_handler_0C_CpuInvokeInKmode:" "\n"
1186 "\t" " lw $t0, 0x404($zero)" "\n"
1187 "\t" " lw $t1, 0x408($zero)" "\n"
1188 "\t" " addiu $sp, $sp, -0x1C" "\n"
1189 "\t" " sw $ra, 0x10($sp)" "\n"
1190 "\t" " sw $t0, 0x14($sp)" "\n"
1191 "\t" " sw $t1, 0x18($sp)" "\n"
1192 "\t" " addu $t0, $a0, $zero" "\n"
1193 "\t" " addu $a0, $a1, $zero" "\n"
1194 "\t" " addu $a1, $a2, $zero" "\n"
1195 "\t" " addu $a2, $a3, $zero" "\n"
1196 "\t" " jalr $t0" "\n"
1197 "\t" " nop" "\n"
1198 "\t" " lw $ra, 0x10($sp)" "\n"
1199 "\t" " lw $t0, 0x14($sp)" "\n"
1200 "\t" " lw $t1, 0x18($sp)" "\n"
1201 "\t" " addiu $sp, $sp, 0x1C" "\n"
1202 "\t" " mtc0 $t1, $12" "\n"
1203 "\t" " addiu $t0, $t0, 0x4" "\n"
1204 "\t" " jr $t0" "\n"
1205 "\t" " .word 0x42000010" "\n" // cop0 0x10 # return from exception
1206
1207 "\t" "syscall_handler_10:" "\n"
1208 "\t" " lw $t0, 0x408($zero)" "\n"
1209 "\t" " addiu $t1, $zero, 0x414" "\n"
1210 "\t" " and $v0, $t0, $t1" "\n"
1211 "\t" " addiu $at, $zero, -0x405" "\n"
1212 "\t" " b do_set_status_register" "\n"
1213 "\t" " and $t0, $t0, $at" "\n"
1214
1215 "\t" "syscall_handler_14:" "\n"
1216 "\t" " lw $t0, 0x408($zero)" "\n"
1217 "\t" " addiu $t1, $zero, -0x415" "\n"
1218 "\t" " and $t0, $t0, $t1" "\n"
1219 "\t" " b do_set_status_register" "\n"
1220 "\t" " or $t0, $t0, $a0" "\n"
1221
1222 "\t" "syscall_handler_08_CpuEnableIntr:" "\n"
1223 "\t" " lw $t0, 0x408($zero)" "\n"
1224 "\t" " b do_set_status_register" "\n"
1225 "\t" " ori $t0, $t0, 0x404" "\n"
1226
1227 "\t" "syscall_handler_04_CpuDisableIntr:" "\n"
1228 "\t" " lw $t0, 0x408($zero)" "\n"
1229 "\t" " addiu $t1, $zero, 0x404" "\n"
1230 "\t" " and $v0, $t0, $t1" "\n"
1231 "\t" " beq $v0, $t1, 9f" "\n"
1232 "\t" " nop" "\n"
1233 "\t" " addiu $v0, $zero, 0x0" "\n"
1234 "\t" "9:" "\n"
1235 "\t" " addiu $at, $zero, -0x405" "\n"
1236 "\t" " and $t0, $t0, $at" "\n"
1237 "\t" "do_set_status_register:" "\n"
1238 "\t" " mtc0 $t0, $12" "\n" // $12
1239
1240 "\t" "syscall_handler_00_return_from_exception:" "\n"
1241 "\t" " lw $a0, 0x404($zero)" "\n"
1242 "\t" " nop" "\n"
1243 "\t" " addiu $a0, $a0, 0x4" "\n"
1244 "\t" " jr $a0" "\n"
1245 "\t" " .word 0x42000010" "\n" // cop0 0x10 # return from exception
1246
1247 "\t" "syscall_handler_20_threadman:" "\n"
1248 "\t" " addiu $sp, $sp, -0x98" "\n"
1249#ifndef BUILDING_INTRMANP
1250 "\t" " sw $a2, 0x90($sp)" "\n"
1251#endif
1252 "\t" " lw $t0, 0x408($zero)" "\n"
1253#ifdef BUILDING_INTRMANP
1254 "\t" " addiu $t1, $zero, -0x415" "\n"
1255 "\t" " and $t0, $t0, $t1" "\n"
1256 "\t" " or $t0, $t0, $a2" "\n"
1257#endif
1258 "\t" " lw $t1, 0x404($zero)" "\n"
1259 "\t" " sw $t0, 0x88($sp)" "\n"
1260 "\t" " addiu $t1, $t1, 0x4" "\n"
1261 "\t" " sw $t1, 0x8C($sp)" "\n"
1262 "\t" " sw $s0, 0x40($sp)" "\n"
1263 "\t" " sw $s1, 0x44($sp)" "\n"
1264 "\t" " sw $s2, 0x48($sp)" "\n"
1265 "\t" " sw $s3, 0x4C($sp)" "\n"
1266 "\t" " sw $s4, 0x50($sp)" "\n"
1267 "\t" " sw $s5, 0x54($sp)" "\n"
1268 "\t" " sw $s6, 0x58($sp)" "\n"
1269 "\t" " sw $s7, 0x5C($sp)" "\n"
1270 "\t" " sw $a0, 0x8($sp)" "\n"
1271 "\t" " sw $a1, 0xC($sp)" "\n"
1272 "\t" " sw $gp, 0x70($sp)" "\n"
1273 "\t" " sw $fp, 0x78($sp)" "\n"
1274 "\t" " sw $ra, 0x7C($sp)" "\n"
1275 "\t" " addiu $t0, $sp, 0x98" "\n"
1276 "\t" " sw $t0, 0x74($sp)" "\n"
1277 "\t" " lui $t0, (0xF0FF000C >> 16)" "\n"
1278 "\t" " ori $t0, $t0, (0xF0FF000C & 0xFFFF)" "\n"
1279 "\t" " sw $t0, 0x0($sp)" "\n"
1280 "\t" " addu $a0, $sp, $zero" "\n"
1281 "\t" " addiu $sp, $sp, -0x10" "\n"
1282 "\t" " j intrman_perform_context_switch" "\n"
1283 "\t" " nop" "\n"
1284 "\t" ".set pop" "\n"
1285);
1286// clang-format on
1287
1288extern u32 syscall_handler_00_return_from_exception[];
1289extern u32 syscall_handler_04_CpuDisableIntr[];
1290extern u32 syscall_handler_08_CpuEnableIntr[];
1291extern u32 syscall_handler_0C_CpuInvokeInKmode[];
1292extern u32 syscall_handler_10[];
1293extern u32 syscall_handler_14[];
1294extern u32 syscall_handler_callnext[];
1295extern u32 syscall_handler_20_threadman[];
1296
1297void *syscall_dsp[] = {
1298 &syscall_handler_00_return_from_exception,
1299 &syscall_handler_04_CpuDisableIntr,
1300 &syscall_handler_08_CpuEnableIntr,
1301 &syscall_handler_0C_CpuInvokeInKmode,
1302 &syscall_handler_10,
1303 &syscall_handler_14,
1304 &syscall_handler_callnext,
1305 &syscall_handler_callnext,
1306 &syscall_handler_20_threadman,
1307 &syscall_handler_callnext,
1308 &syscall_handler_callnext,
1309 &syscall_handler_callnext,
1310 &syscall_handler_callnext,
1311 &syscall_handler_callnext,
1312 &syscall_handler_callnext,
1313 &syscall_handler_callnext,
1314};
int RegisterExceptionHandler(int exception, exception_handler_t handler)
Definition excepman.c:70
int CpuEnableIntr()
Definition intrman.c:240
int CpuResumeIntr(int state)
Definition intrman.c:217
void DisableDispatchIntr(int irq)
Definition intrman.c:484
int ReleaseIntrHandler(int irq)
Definition intrman.c:157
void SetNewCtxCb(void *cb)
Definition intrman.c:703
int CpuDisableIntr()
Definition intrman.c:228
void EnableDispatchIntr(int irq)
Definition intrman.c:458
int QueryIntrContext(void)
int DisableIntr(int irq, int *res)
Definition intrman.c:385
int CpuSuspendIntr(int *state)
Definition intrman.c:195
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *arg), void *arg)
Definition intrman.c:115
@ IOP_IRQ_DMA
Definition intrman.h:32
@ IOP_IRQ_SW1
Definition intrman.h:76
@ IOP_IRQ_SW2
Definition intrman.h:78
@ IOP_IRQ_DMA_BERR
Definition intrman.h:67
int EnableIntr(int irq)
Definition intrman.c:336
#define COP0_REG_PRId