/* * Get task coprocessor register */ SYSCALL ER _tk_get_cpr( ID tskid, INT copno, T_COPREGS *pk_copregs ) { ATR copatr = TA_COP0 << copno; TCB *tcb; ER ercd = E_OK; CHECK_INTSK(); CHECK_TSKID(tskid); CHECK_NONSELF(tskid); CHECK_PAR((copatr & available_cop) != 0); tcb = get_tcb(tskid); BEGIN_CRITICAL_SECTION; if ( tcb->state == TS_NONEXIST ) { ercd = E_NOEXS; } else { ercd = mp_check_domain_and_protection(tskid, tcb->tskid, tcb->tskatr); if ( ercd == E_OK ) { if ( (tcb->tskatr & copatr) == 0 ) { ercd = E_PAR; } else if ( is_ctxtsk(tcb) ) { ercd = E_OBJ; } else { /* No coprocessor */ } } } END_CRITICAL_NO_DISPATCH; return ercd; }
/* * Delete rendezvous port */ SYSCALL ER tk_del_por_impl( ID porid ) { PORCB *porcb; ER ercd = E_OK; CHECK_PORID(porid); CHECK_INTSK(); porcb = get_porcb(porid); BEGIN_CRITICAL_SECTION; if ( porcb->porid == 0 ) { ercd = E_NOEXS; } else { /* Release wait state of task (E_DLT) */ knl_wait_delete(&porcb->call_queue); knl_wait_delete(&porcb->accept_queue); /* Return to FreeQue */ QueInsert(&porcb->call_queue, &knl_free_porcb); porcb->porid = 0; } END_CRITICAL_SECTION; return ercd; }
/* * Get task register contents */ SYSCALL ER _tk_get_reg( ID tskid, T_REGS *pk_regs, T_EIT *pk_eit, T_CREGS *pk_cregs ) { TCB *tcb; ER ercd = E_OK; CHECK_INTSK(); CHECK_TSKID(tskid); CHECK_NONSELF(tskid); tcb = get_tcb(tskid); BEGIN_CRITICAL_SECTION; if ( tcb->state == TS_NONEXIST ) { ercd = E_NOEXS; } else { ercd = mp_check_domain_and_protection(tskid, tcb->tskid, tcb->tskatr); if ( ercd == E_OK ) { if ( is_ctxtsk(tcb) ) { ercd = E_OBJ; } else { get_reg(tcb, pk_regs, pk_eit, pk_cregs); } } } END_CRITICAL_NO_DISPATCH; return ercd; }
/* * Unlock mutex */ SYSCALL ER _tk_unl_mtx( ID mtxid ) { MTXCB *mtxcb; TCB *tcb; ER ercd = E_OK; CHECK_MTXID(mtxid); CHECK_INTSK(); mtxcb = get_mtxcb(mtxid); BEGIN_CRITICAL_SECTION; if ( mtxcb->mtxid == 0 ) { ercd = E_NOEXS; goto error_exit; } if ( mtxcb->mtxtsk != ctxtsk ) { ercd = E_ILUSE; /* This is not locked by its own task */ goto error_exit; } /* Delete the mutex from the list, and adjust its own task priority if necessary. */ release_mutex(ctxtsk, mtxcb); if ( mtx_waited(mtxcb) ) { tcb = (TCB*)mtxcb->wait_queue.next; /* Release wait */ wait_release_ok(tcb); /* Change mutex get task */ mtxcb->mtxtsk = tcb; mtxcb->mtxlist = tcb->mtxlist; tcb->mtxlist = mtxcb; if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) { if ( tcb->priority > mtxcb->ceilpri ) { /* Raise the priority of the task that got lock to the highest priority limit */ change_task_priority(tcb, mtxcb->ceilpri); } } } else { /* No wait task */ mtxcb->mtxtsk = NULL; } error_exit: END_CRITICAL_SECTION; return ercd; }
/* * Create rendezvous port */ SYSCALL ID _tk_cre_por( CONST T_CPOR *pk_cpor ) { #if CHK_RSATR const ATR VALID_PORATR = { TA_TPRI |TA_NODISWAI #if USE_OBJECT_NAME |TA_DSNAME #endif }; #endif PORCB *porcb; ID porid; ER ercd; CHECK_RSATR(pk_cpor->poratr, VALID_PORATR); CHECK_PAR(pk_cpor->maxcmsz >= 0); CHECK_PAR(pk_cpor->maxrmsz >= 0); CHECK_INTSK(); BEGIN_CRITICAL_SECTION; /* Get control block from FreeQue */ porcb = (PORCB*)QueRemoveNext(&free_porcb); if ( porcb == NULL ) { ercd = E_LIMIT; } else { porid = ID_POR(porcb - porcb_table); /* Initialize control block */ QueInit(&porcb->call_queue); porcb->porid = porid; porcb->exinf = pk_cpor->exinf; porcb->poratr = pk_cpor->poratr; QueInit(&porcb->accept_queue); porcb->maxcmsz = pk_cpor->maxcmsz; porcb->maxrmsz = pk_cpor->maxrmsz; #if USE_OBJECT_NAME if ( (pk_cpor->poratr & TA_DSNAME) != 0 ) { strncpy((char*)porcb->name, (char*)pk_cpor->dsname, OBJECT_NAME_LENGTH); } #endif ercd = porid; } END_CRITICAL_SECTION; return ercd; }
/* * Get task register contents */ SYSCALL ER tk_get_reg_impl( ID tskid, T_REGS *pk_regs, T_EIT *pk_eit, T_CREGS *pk_cregs ) { TCB *tcb; ER ercd = E_OK; CHECK_INTSK(); CHECK_TSKID(tskid); CHECK_NONSELF(tskid); tcb = get_tcb(tskid); BEGIN_CRITICAL_SECTION; if ( tcb->state == TS_NONEXIST ) { ercd = E_NOEXS; } else { knl_get_reg(tcb, pk_regs, pk_eit, pk_cregs); } END_CRITICAL_SECTION; return ercd; }
/* * Get task coprocessor register */ SYSCALL ER _tk_get_cpr( ID tskid, INT copno, T_COPREGS *pk_copregs ) { ATR copatr = TA_COP0 << copno; TCB *tcb; ER ercd = E_OK; CHECK_INTSK(); CHECK_TSKID(tskid); CHECK_NONSELF(tskid); CHECK_PAR((copatr & available_cop) != 0); tcb = get_tcb(tskid); BEGIN_CRITICAL_NO_DISPATCH; /* Because the state of the task doesn't change. */ if ( tcb->state == TS_NONEXIST ) { ercd = E_NOEXS; } else { ercd = mp_check_domain_and_protection(tskid, tcb->tskid, tcb->tskatr); if ( ercd == E_OK ) { if ( (tcb->tskatr & copatr) == 0 ) { ercd = E_PAR; } else if ( is_ctxtsk(tcb) ) { ercd = E_OBJ; } else { #if USE_SH3_DSP /* Get DSP register */ memcpy(pk_copregs, tcb->isstack, sizeof(T_COP0REGS)); #endif #if TA_FPU /* Get FPU register */ memcpy(pk_copregs, tcb->isstack, sizeof(T_COP0REGS)); #endif } } } END_CRITICAL_NO_DISPATCH; return ercd; }
/* * Reply rendezvous */ SYSCALL ER tk_rpl_rdv_impl( RNO rdvno, VP msg, INT rmsgsz ) { TCB *caltcb; ER ercd = E_OK; CHECK_RDVNO(rdvno); CHECK_PAR(rmsgsz >= 0); CHECK_INTSK(); caltcb = get_tcb(knl_get_tskid_rdvno(rdvno)); BEGIN_CRITICAL_SECTION; if ( (caltcb->state & TS_WAIT) == 0 || caltcb->wspec != &knl_wspec_rdv || rdvno != caltcb->winfo.rdv.rdvno ) { ercd = E_OBJ; goto error_exit; } #if CHK_PAR if ( rmsgsz > caltcb->winfo.rdv.maxrmsz ) { ercd = E_PAR; goto error_exit; } #endif /* Send message */ if ( rmsgsz > 0 ) { memcpy(caltcb->winfo.rdv.msg, msg, (UINT)rmsgsz); } *caltcb->winfo.rdv.p_rmsgsz = rmsgsz; knl_wait_release_ok(caltcb); error_exit: END_CRITICAL_SECTION; return ercd; }
/* * Forward Rendezvous to Other Port */ SYSCALL ER tk_fwd_por_impl( ID porid, UINT calptn, RNO rdvno, VP msg, INT cmsgsz ) { PORCB *porcb; TCB *caltcb, *tcb; QUEUE *queue; RNO new_rdvno; ER ercd = E_OK; CHECK_PORID(porid); CHECK_PAR(calptn != 0); CHECK_RDVNO(rdvno); CHECK_PAR(cmsgsz >= 0); CHECK_INTSK(); porcb = get_porcb(porid); caltcb = get_tcb(knl_get_tskid_rdvno(rdvno)); BEGIN_CRITICAL_SECTION; if ( porcb->porid == 0 ) { ercd = E_NOEXS; goto error_exit; } #if CHK_PAR if ( cmsgsz > porcb->maxcmsz ) { ercd = E_PAR; goto error_exit; } #endif if ( (caltcb->state & TS_WAIT) == 0 || caltcb->wspec != &knl_wspec_rdv || rdvno != caltcb->winfo.rdv.rdvno ) { ercd = E_OBJ; goto error_exit; } if ( porcb->maxrmsz > caltcb->winfo.rdv.maxrmsz ) { ercd = E_OBJ; goto error_exit; } #if CHK_PAR if ( cmsgsz > caltcb->winfo.rdv.maxrmsz ) { ercd = E_PAR; goto error_exit; } #endif /* Search accept wait task */ queue = porcb->accept_queue.next; while ( queue != &porcb->accept_queue ) { tcb = (TCB*)queue; queue = queue->next; if ( (calptn & tcb->winfo.acp.acpptn) == 0 ) { continue; } /* Send message */ new_rdvno = knl_gen_rdvno(caltcb); if ( cmsgsz > 0 ) { memcpy(tcb->winfo.acp.msg, msg, (UINT)cmsgsz); } *tcb->winfo.acp.p_rdvno = new_rdvno; *tcb->winfo.acp.p_cmsgsz = cmsgsz; knl_wait_release_ok(tcb); /* Change rendezvous end wait of the other task */ caltcb->winfo.rdv.rdvno = new_rdvno; caltcb->winfo.rdv.msg = caltcb->winfo.cal.msg; caltcb->winfo.rdv.maxrmsz = porcb->maxrmsz; caltcb->winfo.rdv.p_rmsgsz = caltcb->winfo.cal.p_rmsgsz; goto error_exit; } /* Change the other task to rendezvous call wait */ caltcb->wspec = ( (porcb->poratr & TA_TPRI) != 0 )? &knl_wspec_cal_tpri: &knl_wspec_cal_tfifo; caltcb->wid = porid; caltcb->winfo.cal.calptn = calptn; caltcb->winfo.cal.msg = caltcb->winfo.rdv.msg; caltcb->winfo.cal.cmsgsz = cmsgsz; caltcb->winfo.cal.p_rmsgsz = caltcb->winfo.rdv.p_rmsgsz; knl_timer_insert(&caltcb->wtmeb, TMO_FEVR, (CBACK)knl_wait_release_tmout, caltcb); if ( (porcb->poratr & TA_TPRI) != 0 ) { knl_queue_insert_tpri(caltcb, &porcb->call_queue); } else { QueInsert(&caltcb->tskque, &porcb->call_queue); } if ( cmsgsz > 0 ) { memcpy(caltcb->winfo.cal.msg, msg, (UINT)cmsgsz); } error_exit: END_CRITICAL_SECTION; return ercd; }