void up_assert_code(int errorcode) #endif { #if CONFIG_TASK_NAME_SIZE > 0 _TCB *rtcb = (_TCB*)g_readytorun.head; #endif up_ledon(LED_ASSERTION); #ifdef CONFIG_HAVE_FILENAME #if CONFIG_TASK_NAME_SIZE > 0 lldbg("Assertion failed at file:%s line: %d task: %s error code: %d\n", filename, lineno, rtcb->name, errorcode); #else lldbg("Assertion failed at file:%s line: %d error code: %d\n", filename, lineno, errorcode); #endif #else #if CONFIG_TASK_NAME_SIZE > 0 lldbg("Assertion failed: task: %s error code: %d\n", rtcb->name, errorcode); #else lldbg("Assertion failed: error code: %d\n", errorcode); #endif #endif up_stackdump(); up_registerdump(); _up_assert(errorcode); }
void up_assert(void) #endif { #if CONFIG_TASK_NAME_SIZE > 0 struct tcb_s *rtcb = this_task(); #endif board_autoled_on(LED_ASSERTION); #ifdef CONFIG_HAVE_FILENAME #if CONFIG_TASK_NAME_SIZE > 0 lldbg("Assertion failed at file:%s line: %d task: %s\n", filename, lineno, rtcb->name); #else lldbg("Assertion failed at file:%s line: %d\n", filename, lineno); #endif #else #if CONFIG_TASK_NAME_SIZE > 0 lldbg("Assertion failed: task: %s\n", rtcb->name); #else lldbg("Assertion failed\n"); #endif #endif up_stackdump(); up_registerdump(); #ifdef CONFIG_ARCH_USBDUMP /* Dump USB trace data */ (void)usbtrace_enumerate(assert_tracecallback, NULL); #endif #ifdef CONFIG_BOARD_CRASHDUMP board_crashdump(up_getsp(), this_task(), filename, lineno); #endif _up_assert(EXIT_FAILURE); }
int up_swint0(int irq, FAR void *context) { uint32_t *regs = (uint32_t*)context; uint32_t cause; DEBUGASSERT(regs && regs == current_regs); /* Software interrupt 0 is invoked with REG_A0 (REG_R4) = system call * command and REG_A1-3 and REG_T0-2 (REG_R5-10) = variable number of * arguments depending on the system call. */ #ifdef CONFIG_DEBUG_SYSCALL swidbg("Entry: regs: %p cmd: %d\n", regs, regs[REG_R4]); up_registerdump(regs); #endif /* Handle the SWInt according to the command in $4 */ switch (regs[REG_R4]) { /* R4=SYS_restore_context: This a restore context command: * * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; * * At this point, the following values are saved in context: * * R4 = SYS_restore_context * R5 = restoreregs * * In this case, we simply need to set current_regs to restore register * area referenced in the saved R1. context == current_regs is the normal * exception return. By setting current_regs = context[R1], we force * the return to the saved context referenced in R1. */ case SYS_restore_context: { DEBUGASSERT(regs[REG_A1] != 0); current_regs = (uint32_t*)regs[REG_A1]; } break; /* R4=SYS_switch_context: This a switch context command: * * void up_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); * * At this point, the following values are saved in context: * * R4 = SYS_switch_context * R5 = saveregs * R6 = restoreregs * * In this case, we save the context registers to the save register * area reference by the saved contents of R5 and then set * current_regs to to the save register area referenced by the saved * contents of R6. */ case SYS_switch_context: { DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0); up_copystate((uint32_t*)regs[REG_A1], regs); current_regs = (uint32_t*)regs[REG_A2]; } break; /* R0=SYS_syscall_return: This a switch context command: * * void up_sycall_return(void); * * At this point, the following values are saved in context: * * R0 = SYS_syscall_return * * We need to restore the saved return address and return in * unprivileged thread mode. */ #ifdef CONFIG_BUILD_KERNEL case SYS_syscall_return: { struct tcb_s *rtcb = sched_self(); int index = (int)rtcb->xcp.nsyscalls - 1; /* Make sure that there is a saved syscall return address. */ DEBUGASSERT(index >= 0); /* Setup to return to the saved syscall return address in * the original mode. */ current_regs[REG_EPC] = rtcb->xcp.syscall[index].sysreturn; #error "Missing logic -- need to restore the original mode" rtcb->xcp.nsyscalls = index; } break; #endif /* This is not an architecture-specify system call. If NuttX is built * as a standalone kernel with a system call interface, then all of the * additional system calls must be handled as in the default case. */ default: { #ifdef CONFIG_BUILD_KERNEL FAR struct tcb_s *rtcb = sched_self(); int index = rtcb->xcp.nsyscalls; /* Verify that the SYS call number is within range */ DEBUGASSERT(current_regs[REG_A0] < SYS_maxsyscall); /* Make sure that we got here that there is a no saved syscall * return address. We cannot yet handle nested system calls. */ DEBUGASSERT(index < CONFIG_SYS_NNEST); /* Setup to return to dispatch_syscall in privileged mode. */ rtcb->xcpsyscall[index].sysreturn = regs[REG_EPC]; #error "Missing logic -- Need to save mode" rtcb->xcp.nsyscalls = index + 1; regs[REG_EPC] = (uint32_t)dispatch_syscall; #error "Missing logic -- Need to set privileged mode" /* Offset R0 to account for the reserved values */ current_regs[REG_R0] -= CONFIG_SYS_RESERVED; #else slldbg("ERROR: Bad SYS call: %d\n", regs[REG_A0]); #endif } break; } /* Report what happened. That might difficult in the case of a context switch */ #ifdef CONFIG_DEBUG_SYSCALL if (regs != current_regs) { swidbg("SWInt Return: Context switch!\n"); up_registerdump((const uint32_t*)current_regs); } else { swidbg("SWInt Return: %d\n", regs[REG_V0]); } #endif /* Clear the pending software interrupt 0 in the PIC32 interrupt block */ up_clrpend_irq(PIC32MX_IRQSRC_CS0); /* And reset the software interrupt bit in the MIPS CAUSE register */ cause = cp0_getcause(); cause &= ~CP0_CAUSE_IP0; cp0_putcause(cause); return OK; }
int up_swint0(int irq, FAR void *context) { uint32_t *regs = (uint32_t*)context; DEBUGASSERT(regs && regs == current_regs); /* Software interrupt 0 is invoked with REG_A0 (REG_R4) = system call * command and REG_A1-3 and REG_T0-2 (REG_R5-10) = variable number of * arguments depending on the system call. */ #ifdef DEBUG_SWINT0 swidbg("Entry: regs: %p cmd: %d\n", regs, regs[REG_R4]); up_registerdump(regs); #endif /* Handle the SWInt according to the command in $4 */ switch (regs[REG_R4]) { /* R4=SYS_restore_context: This a restore context command: * * void up_fullcontextrestore(uint32_t *restoreregs) __attribute__ ((noreturn)); * * At this point, the following values are saved in context: * * R4 = SYS_restore_context * R5 = restoreregs * * In this case, we simply need to set current_regs to restore register * area referenced in the saved R1. context == current_regs is the normal * exception return. By setting current_regs = context[R1], we force * the return to the saved context referenced in R1. */ case SYS_restore_context: { DEBUGASSERT(regs[REG_A1] != 0); current_regs = (uint32_t*)regs[REG_A1]; } break; /* R4=SYS_switch_context: This a switch context command: * * void up_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); * * At this point, the following values are saved in context: * * R4 = SYS_switch_context * R5 = saveregs * R6 = restoreregs * * In this case, we save the context registers to the save register * area reference by the saved contents of R5 and then set * current_regs to to the save register area referenced by the saved * contents of R6. */ case SYS_switch_context: { DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0); memcpy((uint32_t*)regs[REG_A1], regs, XCPTCONTEXT_SIZE); current_regs = (uint32_t*)regs[REG_A2]; } break; /* This is not an architecture-specify system call. If NuttX is built * as a standalone kernel with a system call interface, then all of the * additional system calls must be handled as in the default case. */ default: #ifdef CONFIG_NUTTX_KERNEL dispatch_syscall(regs); #else slldbg("ERROR: Bad SYS call: %d\n", regs[REG_A0]); #endif break; } /* Report what happened. That might difficult in the case of a context switch */ #ifdef DEBUG_SWINT0 if (regs != current_regs) { swidbg("SWInt Return: Context switch!\n"); up_registerdump(current_regs); } else { swidbg("SWInt Return: %d\n", regs[REG_V0]); } #endif return OK; }
static void up_dumpstate(void) { struct tcb_s *rtcb = this_task(); uint16_t sp = up_getsp(); uint16_t ustackbase; uint16_t ustacksize; #if CONFIG_ARCH_INTERRUPTSTACK > 3 uint16_t istackbase; uint16_t istacksize; #endif /* Get the limits on the user stack memory */ if (rtcb->pid == 0) { ustackbase = g_idle_topstack - 4; ustacksize = CONFIG_IDLETHREAD_STACKSIZE; } else { ustackbase = (uint16_t)rtcb->adj_stack_ptr; ustacksize = (uint16_t)rtcb->adj_stack_size; } /* Get the limits on the interrupt stack memory */ #if CONFIG_ARCH_INTERRUPTSTACK > 3 istackbase = (uint16_t)&g_intstackbase; istacksize = (CONFIG_ARCH_INTERRUPTSTACK & ~3) - 4; /* Show interrupt stack info */ lldbg("sp: %04x\n", sp); lldbg("IRQ stack:\n"); lldbg(" base: %04x\n", istackbase); lldbg(" size: %04x\n", istacksize); /* Does the current stack pointer lie within the interrupt * stack? */ if (sp <= istackbase && sp > istackbase - istacksize) { /* Yes.. dump the interrupt stack */ up_stackdump(sp, istackbase); /* Extract the user stack pointer which should lie * at the base of the interrupt stack. */ sp = g_intstackbase; lldbg("sp: %04x\n", sp); } /* Show user stack info */ lldbg("User stack:\n"); lldbg(" base: %04x\n", ustackbase); lldbg(" size: %04x\n", ustacksize); #else lldbg("sp: %04x\n", sp); lldbg("stack base: %04x\n", ustackbase); lldbg("stack size: %04x\n", ustacksize); #endif /* Dump the user stack if the stack pointer lies within the allocated user * stack memory. */ if (sp > ustackbase || sp <= ustackbase - ustacksize) { #if !defined(CONFIG_ARCH_INTERRUPTSTACK) || CONFIG_ARCH_INTERRUPTSTACK < 4 lldbg("ERROR: Stack pointer is not within allocated stack\n"); #endif } else { up_stackdump(sp, ustackbase); } /* Then dump the registers (if available) */ up_registerdump(); #ifdef CONFIG_ARCH_USBDUMP /* Dump USB trace data */ (void)usbtrace_enumerate(assert_tracecallback, NULL); #endif }
int lm32_swint(int irq, FAR void *context) { uint32_t *regs = (uint32_t *)context; DEBUGASSERT(g_current_regs == NULL); g_current_regs = regs; /* Software interrupt 0 is invoked with REG_A0 (REG_X10) = system call * command and REG_A1-6 = variable number of * arguments depending on the system call. */ #ifdef CONFIG_DEBUG_SYSCALL_INFO svcinfo("Entry: regs: %p cmd: %d\n", regs, regs[REG_A0]); up_registerdump(regs); #endif /* Handle the SWInt according to the command in $a0 */ switch (regs[REG_A0]) { /* A0=SYS_restore_context: This a restore context command: * * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; * * At this point, the following values are saved in context: * * A0 = SYS_restore_context * A1 = restoreregs * * In this case, we simply need to set g_current_regs to restore register * area referenced in the saved R1. context == g_current_regs is the normal * exception return. By setting g_current_regs = context[R1], we force * the return to the saved context referenced in $a1. */ case SYS_restore_context: { DEBUGASSERT(regs[REG_A1] != 0); g_current_regs = (uint32_t *)regs[REG_A1]; } break; /* A0=SYS_switch_context: This a switch context command: * * void up_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); * * At this point, the following values are saved in context: * * A0 = SYS_switch_context * A1 = saveregs * A2 = restoreregs * * In this case, we save the context registers to the save register * area reference by the saved contents of R5 and then set * g_current_regs to to the save register area referenced by the saved * contents of R6. */ case SYS_switch_context: { DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0); lm32_copystate((uint32_t *)regs[REG_A1], regs); g_current_regs = (uint32_t *)regs[REG_A2]; } break; /* A0=SYS_syscall_return: This a switch context command: * * void up_sycall_return(void); * * At this point, the following values are saved in context: * * A0 = SYS_syscall_return * * We need to restore the saved return address and return in * unprivileged thread mode. */ #ifdef CONFIG_BUILD_KERNEL case SYS_syscall_return: { struct tcb_s *rtcb = sched_self(); int index = (int)rtcb->xcp.nsyscalls - 1; /* Make sure that there is a saved syscall return address. */ DEBUGASSERT(index >= 0); /* Setup to return to the saved syscall return address in * the original mode. */ g_current_regs[REG_EPC] = rtcb->xcp.syscall[index].sysreturn; #error "Missing logic -- need to restore the original mode" rtcb->xcp.nsyscalls = index; } break; #endif /* This is not an architecture-specify system call. If NuttX is built * as a standalone kernel with a system call interface, then all of the * additional system calls must be handled as in the default case. */ default: { #ifdef CONFIG_BUILD_KERNEL FAR struct tcb_s *rtcb = sched_self(); int index = rtcb->xcp.nsyscalls; /* Verify that the SYS call number is within range */ DEBUGASSERT(g_current_regs[REG_A0] < SYS_maxsyscall); /* Make sure that we got here that there is a no saved syscall * return address. We cannot yet handle nested system calls. */ DEBUGASSERT(index < CONFIG_SYS_NNEST); /* Setup to return to dispatch_syscall in privileged mode. */ rtcb->xcpsyscall[index].sysreturn = regs[REG_EPC]; #error "Missing logic -- Need to save mode" rtcb->xcp.nsyscalls = index + 1; regs[REG_EPC] = (uint32_t)dispatch_syscall; #error "Missing logic -- Need to set privileged mode" /* Offset R0 to account for the reserved values */ g_current_regs[REG_A0] -= CONFIG_SYS_RESERVED; #else svcerr("ERROR: Bad SYS call: %d\n", regs[REG_A0]); #endif } break; } /* Report what happened. That might difficult in the case of a context switch */ #ifdef CONFIG_DEBUG_SYSCALL_INFO if (regs != g_current_regs) { svcinfo("SWInt Return: Context switch!\n"); up_registerdump((const uint32_t *)g_current_regs); } else { svcinfo("SWInt Return: %d\n", regs[REG_A0]); } #endif #if defined(CONFIG_ARCH_FPU) || defined(CONFIG_ARCH_ADDRENV) /* Check for a context switch. If a context switch occurred, then * g_current_regs will have a different value than it did on entry. If an * interrupt level context switch has occurred, then restore the floating * point state and the establish the correct address environment before * returning from the interrupt. */ if (regs != g_current_regs) { #ifdef CONFIG_ARCH_FPU /* Restore floating point registers */ up_restorefpu((uint32_t *)g_current_regs); #endif #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new * thread at the head of the ready-to-run list. */ (void)group_addrenv(NULL); #endif } #endif return OK; }