PS2SDK
PS2 Homebrew Libraries
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 
16 #include "iop_low_memory_globals.h"
17 #include "iop_mmio_hwport.h"
18 
19 extern struct irx_export_table _exp_intrman;
20 
21 #ifdef _IOP
22 IRX_ID("Interrupt_Manager", 1, 1);
23 #endif
24 // Based on the module from SCE SDK 1.3.4.
25 
26 extern int CpuGetICTRL();
27 extern void CpuEnableICTRL();
28 extern int dma_interrupt_handler(void *userdata);
29 
30 extern exception_handler_struct_t exception_interrupt_handler;
31 extern exception_handler_struct_t exception_priority_interrupt_handler;
32 extern exception_handler_struct_t exception_system_handler;
33 
34 static intrman_internals_t intrman_internals;
35 
36 int _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 
98 int 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 
110 intrman_internals_t *GetIntrmanInternalData(void)
111 {
112  return &intrman_internals;
113 }
114 
115 int 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 
157 int ReleaseIntrHandler(int irq)
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 
190 extern int intrman_syscall_04_CpuDisableIntr(void);
191 extern int intrman_syscall_08_CpuEnableIntr(void);
192 extern int intrman_syscall_10(void);
193 extern int intrman_syscall_14(int state);
194 
195 int 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 
217 int 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 
249 int 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 
259 void 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 
336 int 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 
385 int 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 
458 void EnableDispatchIntr(int irq)
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 
484 void DisableDispatchIntr(int irq)
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 
510 void 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
517 static 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
531 static 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 
545 int 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 
697 static void *new_context_stub_cb(void *ctx);
698 static int preempt_stub_cb(int unk);
699 
700 void *ctx_switch_cb = new_context_stub_cb;
701 void *ctx_switch_required_cb = preempt_stub_cb;
702 
703 void SetNewCtxCb(void *cb)
704 {
705  ctx_switch_cb = cb;
706 }
707 
708 void ResetNewCtxCb(void)
709 {
710  ctx_switch_cb = new_context_stub_cb;
711 }
712 
713 void SetShouldPreemptCb(void *cb)
714 {
715  ctx_switch_required_cb = cb;
716 }
717 
718 void ResetShouldPreemptCb(void)
719 {
720  ctx_switch_required_cb = preempt_stub_cb;
721 }
722 
723 u32 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 
1125 static void *new_context_stub_cb(void *ctx)
1126 {
1127  return ctx;
1128 }
1129 
1130 static 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 
1288 extern u32 syscall_handler_00_return_from_exception[];
1289 extern u32 syscall_handler_04_CpuDisableIntr[];
1290 extern u32 syscall_handler_08_CpuEnableIntr[];
1291 extern u32 syscall_handler_0C_CpuInvokeInKmode[];
1292 extern u32 syscall_handler_10[];
1293 extern u32 syscall_handler_14[];
1294 extern u32 syscall_handler_callnext[];
1295 extern u32 syscall_handler_20_threadman[];
1296 
1297 void *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 };
CpuDisableIntr
int CpuDisableIntr()
Definition: intrman.c:228
RegisterIntrHandler
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *arg), void *arg)
Definition: intrman.c:115
SetNewCtxCb
void SetNewCtxCb(void *cb)
Definition: intrman.c:703
ReleaseIntrHandler
int ReleaseIntrHandler(int irq)
Definition: intrman.c:157
CpuEnableIntr
int CpuEnableIntr()
Definition: intrman.c:240
iop_mmio_hwport.h
EnableDispatchIntr
void EnableDispatchIntr(int irq)
Definition: intrman.c:458
DisableIntr
int DisableIntr(int irq, int *res)
Definition: intrman.c:385
QueryIntrContext
int QueryIntrContext(void)
intrman_intr_handler_data_
Definition: intrman.h:80
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
RegisterExceptionHandler
int RegisterExceptionHandler(int exception, exception_handler_t handler)
Definition: excepman.c:70
mipscopaccess.h
DisableDispatchIntr
void DisableDispatchIntr(int irq)
Definition: intrman.c:484
IOP_IRQ_DMA
@ IOP_IRQ_DMA
Definition: intrman.h:31
intrman_internals_
Definition: intrman.h:86
EnableIntr
int EnableIntr(int irq)
Definition: intrman.c:336
irx_export_table
Definition: irx.h:90
_exception_handler_struct_t
Definition: excepman.h:60
IOP_IRQ_DMA_BERR
@ IOP_IRQ_DMA_BERR
Definition: intrman.h:66
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
COP0_REG_PRId
@ COP0_REG_PRId
Definition: mipscopaccess.h:42
intrman.h
iop_low_memory_globals.h
IOP_IRQ_SW2
@ IOP_IRQ_SW2
Definition: intrman.h:77
IOP_IRQ_SW1
@ IOP_IRQ_SW1
Definition: intrman.h:75
kerr.h