#define _GNU_SOURCE #include "kloadcore.h" #include "kexcepman.h" #include "kintrman.h" #include "err.h" #define ICFG (*(volatile int*)0xbf801450) #define IREG (*(volatile int*)0xbf801070) #define IMASK (*(volatile int*)0xbf801074) #define ICTRL (*(volatile int*)0xbf801078) #define DMA_ICR (*(volatile int*)0xbf8010F4) #define DMA_ICR2 (*(volatile int*)0xbf801574) #define EXCEP_CAUSE (*(volatile int*)0x40C) int debug=1; #define _dprintf(fmt, args...) \ if (debug > 0) __printf("intrman: " fmt, ## args) struct intrHandler { u32 handler; void *arg; }; func context_switch_required_handler; func context_switch_handler; // Additional interrupt mask applied after IMASK u32 soft_hw_intr_mask; int unknown2[4]; //0x1280 up #define INTR_STACK_SIZE 0x800 unsigned char tempstack[INTR_STACK_SIZE]; u32 *extable; struct intrHandler *intrtable; extern struct export export_stub; int _start(); int IntrHandler(); void intrman_retonly(); /////////////////////////////syscalls////////////////////////////////// __inline void syscall_0(); void syscall_1_CpuDisableIntr(); void syscall_2_CpuEnableIntr(); void syscall_3_intrman_call14(); void syscall_4_intrman_call17_19(); void syscall_5_intrman_call18_20(); void goto_EXCEP_Sys_handler(); void syscall_8_threadman(); func syscall[] = { (func)syscall_0, /* (func)syscall_1_CpuDisableIntr, (func)syscall_2_CpuEnableIntr, (func)syscall_3_intrman_call14, (func)syscall_4_intrman_call17_19, (func)syscall_5_intrman_call18_20, (func)goto_EXCEP_Sys_handler, (func)goto_EXCEP_Sys_handler, (func)syscall_8_threadman, (func)goto_EXCEP_Sys_handler, (func)goto_EXCEP_Sys_handler, (func)goto_EXCEP_Sys_handler, (func)goto_EXCEP_Sys_handler, (func)goto_EXCEP_Sys_handler, (func)goto_EXCEP_Sys_handler, (func)goto_EXCEP_Sys_handler*/ }; /////////////////////////////////////////////////////////////////////// int intrmanDeinit() { return 0; } /////////////////////////////////////////////////////////////////////// int intrman_call2() { IMASK = 0x00; DMA_ICR = 0x00; DMA_ICR2 = 0x00; return 0; } /////////////////////////////////////////////////////////////////////// int intrman_call3(){ return (int)&unknown2; } /////////////////////////////////////////////////////////////////////// // // interrupt values 0x2E - 0x3F are equivalent to 0x1E - 0x2F with a mode set // interrupt values 0x20 - 0x2D have their mode forced to zero // // mode specifies what registers to save around the call // 0 = don't save anything, handler will not change anything // 1 = save t0 - t9, gp and fp // 2 = save t0 - t9, gp, fp and s0 - s7 // // arg is the value passed to the interrupt handler when it is called // int RegisterIntrHandler(int interrupt, int mode, intrh_func handler, void *arg) { u32 ictrl; _dprintf("%s interrupt=%x, mode=%x\n", __FUNCTION__, interrupt, mode); if (QueryIntrContext()){ // cannot be called from within an interrupt _dprintf("%s ERROR_INTR_CONTEXT\n", __FUNCTION__); return ERROR_INTR_CONTEXT; } CpuSuspendIntr(&ictrl); if (interrupt < 0 || interrupt > 0x3F) { CpuResumeIntr(ictrl); _dprintf("%s ERROR_ILLEGAL_INTRCODE\n", __FUNCTION__); return ERROR_ILLEGAL_INTRCODE; } int real_interrupt = interrupt; int real_mode = mode; if (interrupt >= 0x2E){ real_interrupt -= 0x10; } else if (interrupt >= 0x20){ real_mode = 0; } if (intrtable[real_interrupt].handler){ CpuResumeIntr(ictrl); _dprintf("%s ERROR_DOES_EXIST\n", __FUNCTION__); return ERROR_DOES_EXIST; } intrtable[real_interrupt].handler = (mode & 0x03) | (u32)handler; intrtable[real_interrupt].arg = arg; CpuResumeIntr(ictrl); return 0; } /////////////////////////////////////////////////////////////////////// int ReleaseIntrHandler(int interrupt) { u32 ictrl; if (QueryIntrContext()){ // Cannot be called from within an interrupt return ERROR_INTR_CONTEXT; } CpuSuspendIntr(&ictrl); if (interrupt < 0 || interrupt >= 0x40) { CpuResumeIntr(ictrl); return ERROR_ILLEGAL_INTRCODE; } if (interrupt >= 0x2E){ interrupt -= 0x10; } if (intrtable[interrupt].handler){ intrtable[interrupt].handler = 0; CpuResumeIntr(ictrl); return 0; } CpuResumeIntr(ictrl); return ERROR_DOES_EXIST; } /////////////////////////////////////////////////////////////////////// int CpuSuspendIntr(u32 *ictrl) { u32 rval = ICTRL; if (ictrl) *ictrl = rval; if (rval == 0) return ERROR_CPUDI; return 0; } /////////////////////////////////////////////////////////////////////// int CpuResumeIntr(u32 ictrl) { ICTRL = ictrl; return 0; } /////////////////////////////////////////////////////////////////////// int CpuDisableIntr() { if (ICTRL) return 0; return ERROR_CPUDI; } /////////////////////////////////////////////////////////////////////// int CpuEnableIntr() { //_dprintf("%s\n", __FUNCTION__); // intrman_syscall_08(); // _dprintf("syscall ok\n"); CpuEnableICTRL(); return 0; } /////////////////////////////////////////////////////////////////////// int CpuGetICTRL() { return ICTRL; } /////////////////////////////////////////////////////////////////////// int CpuEnableICTRL() { ICTRL = 1; return 1; } /////////////////////////////////////////////////////////////////////// void intrman_syscall_04() { __asm__ ( "li $3, 4\n" "syscall\n" ); } /////////////////////////////////////////////////////////////////////// void intrman_syscall_08() { __asm__ ( "li $3, 8\n" "syscall\n" ); } /////////////////////////////////////////////////////////////////////// void intrman_syscall_10() { __asm__ ( "li $3, 16\n" "syscall\n" ); } /////////////////////////////////////////////////////////////////////// void intrman_syscall_14() { __asm__ ( "li $3, 20\n" "syscall\n" ); } /////////////////////////////////////////////////////////////////////// void intrman_syscall_0C() { __asm__ ( "li $3, 12\n" "syscall\n" ); } /////////////////////////////////////////////////////////////////////// // // Interrupt: // 0 - 0x1F normal interrupt // 0x20 - 0x26 // 0x27 - 0x2D // // Return 0 for success, -101 for invalid interrupt number // #define ERROR_BAD_NUMBER -101 #define INUM_DMA_0 0x20 #define INUM_DMA_BERR 0x27 #define INUM_DMA_7 0x28 #define IMODE_DMA_IRM 0x100 #define IMODE_DMA_IQE 0x200 #define INUM_DMA 3 int EnableIntr(int interrupt) { int retval = 0; u32 low_irq = interrupt & 0xFF; u32 high_irq = interrupt & 0xFFFFFF00; u32 ictrl; CpuSuspendIntr(&ictrl); if( interrupt < 0 ) { retval = ERROR_BAD_NUMBER; } else if (low_irq < INUM_DMA_0){ IMASK |= (1 << low_irq); } else if (low_irq < INUM_DMA_BERR){ DMA_ICR = (DMA_ICR & ((~(1<<(low_irq-INUM_DMA_0)))&0x00FFFFFF)) | (1 << (INUM_DMA_BERR-INUM_DMA_0 + 16)) | (1<<(low_irq-INUM_DMA_0+0x10)) | ((high_irq & IMODE_DMA_IRM) ? (1<<(low_irq-INUM_DMA_0)) : 0); DMA_ICR2 = (DMA_ICR2 & ((~(1<<(low_irq-INUM_DMA_0)))&0x00FFFFFF)) | ((high_irq & IMODE_DMA_IQE) ? (1<<(low_irq-0x10)) : 0); IMASK |= 1<>(low_irq-0x20)) & 0x01) stat = low_irq | 0x100; if (DMA_ICR2 & (1<<(low_irq-0x20))) stat |= 0x200; DMA_ICR2 &= ~(1<<(low_irq-0x20)) & 0xFFFFFF; goto end; } ret = -103; goto end; } if (low_irq<0x2E) { if (DMA_ICR2 & 0xFFFFFF & (1<<(low_irq-0x18))) { stat = low_irq; if (((DMA_ICR2 & 0xFFFFFF)>>(low_irq-0x21))&0x01) stat |= 0x200; DMA_ICR2 &= ~(1<<(low_irq-0x18)) & 0xFFFFFF; goto end; } ret = -103; goto end; } end: if (oldstat) *(volatile int*)oldstat = stat; CpuResumeIntr(ictrl); return ret; } /////////////////////////////////////////////////////////////////////// // Enable void intrman_call16(int interrupt) { u32 ictrl; CpuSuspendIntr(&ictrl); interrupt &= 0xFF; if (interrupt < 0x20){ soft_hw_intr_mask |= (1 << interrupt); } else if (interrupt < 0x28){ unknown2[1] |= 1 << (interrupt-0x08); } else if (interrupt < 0x2E){ unknown2[2] |= 1 << (interrupt-0x10); } CpuResumeIntr(ictrl); } /////////////////////////////////////////////////////////////////////// // Disable void intrman_call15(int interrupt) { u32 ictrl; CpuSuspendIntr(&ictrl); interrupt &= 0xFF; if (interrupt < 0x20){ soft_hw_intr_mask &= ~(1 << interrupt); } else if (interrupt < 0x28){ unknown2[1] &= ~(1 << (interrupt-0x08)); } else if (interrupt < 0x2E){ unknown2[2] &= ~(1 << (interrupt-0x10)); } CpuResumeIntr(ictrl); } /////////////////////////////////////////////////////////////////////// void intrman_call27(int arg0) { unknown2[3]=arg0; } /////////////////////////////////////////////////////////////////////// // int IntrHandler() { u32 masked_icr = DMA_ICR & unknown2[1]; _dprintf("%s\n", __FUNCTION__); while (masked_icr & 0x7F008000){ int i; if (masked_icr & 0x00008000){ // Int 0x25 func int_func = (func)(intrtable[0x25].handler & 0xFFFFFFFC); DMA_ICR &= 0x00FF7FFF; if (int_func){ int_func(intrtable[0x25].arg); } } // Check each DMA interrupt // The bits 24 - 30 are set for DMA channels 0 - 6 (ints 0x20 - 0x26 respectively) // The bits 16 - 23 are the corresponding mask bits - the interrupt is only generated if the mask bit is set. for (i=0; i < 7; ++i){ u32 ibit = 0x01000000 << i; if (masked_icr & ibit){ func int_func = (func)(intrtable[0x20+i].handler & 0xFFFFFFFC); DMA_ICR &= (ibit | 0x00FFFFFF); if (int_func){ if (!int_func(intrtable[0x20+i].arg)){ // Disable / mask the interrupt if it was not handled DMA_ICR &= (~(0x00010000 << i) & 0x00FFFFFF); } } } } } DMA_ICR &= 0x007FFFFF; while (DMA_ICR & 0x00800000){ // do nothing } { u32 temp_icr = DMA_ICR; temp_icr &= 0x007FFFFF; temp_icr |= 0x00800000; DMA_ICR = temp_icr; } return 1; } /////////////////////////////////////////////////////////////////////// // // Default context switch handler - does not switch context. // int default_ctx_switch_handler(u32 sp_in) { return sp_in; } /////////////////////////////////////////////////////////////////////// // // Default routine to request a context switch. Does not request one. // int default_ctx_switch_required_handler() { return 0; } void SetCtxSwitchHandler(func handler){ context_switch_handler = handler; } void* ResetCtxSwitchHandler() { context_switch_handler = default_ctx_switch_handler; return &context_switch_handler; } void SetCtxSwitchReqHandler(func handler) { context_switch_required_handler = handler; } int ResetCtxSwitchReqHandler() { context_switch_required_handler = default_ctx_switch_required_handler; } /////////////////////////////////////////////////////////////////////// // Return non-zero if sp is in an interrupt context int QueryIntrStack(unsigned char* sp) { int retval = 0; if ( (sp < tempstack + INTR_STACK_SIZE) && (sp > tempstack) ){ retval = 1; } return retval; } /////////////////////////////////////////////////////////////////////// // Return non-zero is we're currently in a interrupt context int QueryIntrContext() { unsigned char* sp; __asm__ ("move %0, $29\n" : "=r"(sp) :); return QueryIntrStack(sp); } /////////////////////////////////////////////////////////////////////// // int iCatchMultiIntr() { unsigned char* sp; __asm__ ("move %0, $29\n" : "=r"(sp) :); if (QueryIntrStack(sp)){ if (sp >= tempstack + 0x160){ u32 SR; __asm__ ("mfc0 %0, $12\n" : "=r"(SR)); if (SR & 1 == 0){ u32 set_SR = SR | 1; __asm__ volatile ( "mtc0 %0, $12\n" "nop\n" "nop\n" "mtc0 %1, $12\n" : : "r"(set_SR), "r" (SR) ); } return SR; } } return 0; } /////////////////////////////////////////////////////////////////////// // called by EXCEP_Sys_handler void EXCEP_Sys_8() { _dprintf("%s\n", __FUNCTION__); } /////////////////////////////////////////////////////////////////////// //not finished void syscall_3_intrman_call14(){ } /////////////////////////////////////////////////////////////////////// //not finished void syscall_4_intrman_call17_19(){ } /////////////////////////////////////////////////////////////////////// __inline void syscall_0(){ func funct; funct=(func)((*(volatile int*)(0x404))+4); __asm__ ( "jr %0\n" "rfe\n" : "=r" (funct) ); } /////////////////////////////////////////////////////////////////////// void retonly(){} u32 callContextSwitchRequiredHandler() { if (NULL != context_switch_required_handler){ return context_switch_required_handler(); } else { return 0; } } //////////////////////////////entrypoint/////////////////////////////// struct export export_stub={ 0x41C00000, 0, VER(1, 2), // 1.2 => 0x102 0, "intrman", (func)_start, // entrypoint (func)intrmanDeinit, (func)intrman_call2, (func)intrman_call3, (func)RegisterIntrHandler, (func)ReleaseIntrHandler, (func)EnableIntr, (func)DisableIntr, (func)CpuDisableIntr, (func)CpuEnableIntr, (func)intrman_syscall_04, // 0x0A (func)intrman_syscall_08, (func)CpuGetICTRL, (func)CpuEnableICTRL, (func)intrman_syscall_0C, // 0x0E (func)intrman_call15, (func)intrman_call16, // 0x10 (func)CpuSuspendIntr, (func)CpuResumeIntr, (func)CpuSuspendIntr, (func)CpuResumeIntr, (func)intrman_syscall_10, (func)intrman_syscall_14, (func)QueryIntrContext, // 0x17 (func)QueryIntrStack, (func)iCatchMultiIntr, (func)retonly, (func)intrman_call27, (func)SetCtxSwitchHandler, // 0x1C (called by threadman) (func)ResetCtxSwitchHandler, (func)SetCtxSwitchReqHandler, // 0x1E (called by threadman) (func)ResetCtxSwitchReqHandler, 0 }; extern struct exHandler EXCEP_Int_priority_exception_handler; extern struct exHandler EXCEP_Int_handler; extern struct exHandler EXCEP_Sys_handler; //////////////////////////////entrypoint/////////////////////////////// int _start(){ int i; intrtable = (struct intrHandler*)(GetExHandlersTable() + 0x40); IMASK = 0x00; DMA_ICR = 0x00; DMA_ICR2 = 0x00; for (i=0; i < 0x2F; i++) { intrtable[i].handler = 0; intrtable[i].arg = 0; } soft_hw_intr_mask = 0xFFFFFFFF; unknown2[1] = -1; unknown2[2] = -1; unknown2[0] = (int)intrtable; RegisterExceptionHandler(0, &EXCEP_Int_handler); RegisterPriorityExceptionHandler(0, 3, &EXCEP_Int_priority_exception_handler); RegisterExceptionHandler(8, &EXCEP_Sys_handler); RegisterIntrHandler(3, 1, &IntrHandler, 0); RegisterLibraryEntries(&export_stub); return 0; } void ijb_ping1() { _dprintf("%s\n", __FUNCTION__); unsigned char* x = tempstack; } void ijb_trace3(u32 a0, u32 a1, u32 a2, u32 a3) { __printf("trace3: 0x%x, 0x%x, 0x%x\n", a0, a1, a2); while (1){} }