void do_ipc(tcb_t* from, tcb_t* to) { ipc_msg_tag_t tag; ipc_typed_item typed_item; int untyped_idx, typed_idx, typed_item_idx; int typed_last, untyped_last; uint32_t typed_data; /* typed item extra word*/ /*Copy tag of message*/ tag.raw = ipc_read_mr(from, 0); untyped_last = tag.s.n_untyped + 1; typed_last = untyped_last + tag.s.n_typed; if(typed_last > IPC_MR_COUNT) { set_user_error(from, UE_IPC_MSG_OVERFLOW | UE_IPC_PHASE_SEND); set_user_error(to, UE_IPC_MSG_OVERFLOW | UE_IPC_PHASE_RECV); return; } ipc_write_mr(to, 0, tag.s.label << 16); /*Copy untyped words*/ for(untyped_idx = 1; untyped_idx < untyped_last; ++untyped_idx) { ipc_write_mr(to, untyped_idx, ipc_read_mr(from, untyped_idx)); } typed_item_idx = -1; /* Copy typed words * FSM: j - number of byte*/ for(typed_idx = untyped_idx; typed_idx < typed_last; ++typed_idx) { if(typed_item_idx == -1) { /*If typed_item_idx == -1 - read ti's tag*/ typed_item.raw = ipc_read_mr(from, typed_idx); ++typed_item_idx; } else if(typed_item.s.header & IPC_TI_MAP_GRANT) { /* MapItem / GrantItem have 1xxx in header */ typed_data = ipc_read_mr(from, typed_idx); map_area(from->as, to->as, typed_item.raw & 0xFFFFFFC0, typed_data & 0xFFFFFFC0, (typed_item.s.header & IPC_TI_GRANT)? GRANT : MAP, thread_ispriviliged(from)); typed_item_idx = -1; } /*TODO: StringItem support*/ } to->utcb->sender = from->t_globalid; to->state = T_RUNNABLE; to->ipc_from = L4_NILTHREAD; from->state = T_RUNNABLE; /*Dispatch communicating threads*/ sched_slot_dispatch(SSI_NORMAL_THREAD, from); sched_slot_dispatch(SSI_IPC_THREAD, to); dbg_printf(DL_IPC, "IPC: %t to %t\n", caller->t_globalid, to->t_globalid); }
void sys_ipc(uint32_t *param1) { /* TODO: Checking of recv-mask */ tcb_t *to_thr = NULL; l4_thread_t to_tid = param1[REG_R0], from_tid = param1[REG_R1]; if (to_tid != L4_NILTHREAD) { to_thr = thread_by_globalid(to_tid); if (to_tid == TID_TO_GLOBALID(THREAD_LOG)) { user_log(caller); caller->state = T_RUNNABLE; } else if ((to_thr && to_thr->state == T_RECV_BLOCKED) || to_tid == caller->t_globalid) { /* To thread who is waiting for us or sends to myself */ do_ipc(caller, to_thr); } else if (to_thr && to_thr->state == T_INACTIVE && GLOBALID_TO_TID(to_thr->utcb->t_pager) == GLOBALID_TO_TID(caller->t_globalid)) { if (ipc_read_mr(caller, 0) == 0x00000003) { /* thread start protocol */ memptr_t sp = ipc_read_mr(caller, 2); size_t stack_size = ipc_read_mr(caller, 3); dbg_printf(DL_IPC, "IPC: %t thread start\n", to_tid); to_thr->stack_base = sp - stack_size; to_thr->stack_size = stack_size; thread_init_ctx((void *) sp, (void *) ipc_read_mr(caller, 1), to_thr); caller->state = T_RUNNABLE; /* Start thread */ to_thr->state = T_RUNNABLE; } else { do_ipc(caller, to_thr); to_thr->state = T_INACTIVE; } } else { /* No waiting, block myself */ caller->state = T_SEND_BLOCKED; caller->utcb->intended_receiver = to_tid; dbg_printf(DL_IPC, "IPC: %t sending\n", caller->t_globalid); return; } } if (from_tid != L4_NILTHREAD) { /* Only receive phases, simply lock myself */ caller->state = T_RECV_BLOCKED; caller->ipc_from = from_tid; dbg_printf(DL_IPC, "IPC: %t receiving\n", caller->t_globalid); } }
void sys_ipc(uint32_t* param1) { /*TODO: Checking of recv-mask*/ tcb_t *to_thr = NULL; l4_thread_t to_tid = param1[REG_R0], from_tid = param1[REG_R1]; if(to_tid != L4_NILTHREAD) { to_thr = thread_by_globalid(to_tid); if((to_thr && to_thr->state == T_RECV_BLOCKED) || to_tid == caller->t_globalid ) { /* To thread who waiting us or send myself*/ do_ipc(caller, to_thr); } else if(to_thr && to_thr->state == T_INACTIVE && GLOBALID_TO_TID(to_thr->utcb->t_pager) == GLOBALID_TO_TID(caller->t_globalid)) { /* That is thread start protocol */ dbg_printf(DL_IPC, "IPC: %t thread start\n", to_tid); thread_init_ctx((void*) ipc_read_mr(caller, 2), (void*) ipc_read_mr(caller, 1), to_thr); caller->state = T_RUNNABLE; /*Start thread*/ to_thr->state = T_RUNNABLE; } else { /*No waiting, block myself*/ caller->state = T_SEND_BLOCKED; caller->utcb->intended_receiver = to_tid; dbg_printf(DL_IPC, "IPC: %t sending\n", caller->t_globalid); } } if(from_tid != L4_NILTHREAD) { /*Only receive phases, simply lock myself*/ caller->state = T_RECV_BLOCKED; caller->ipc_from = from_tid; dbg_printf(DL_IPC, "IPC: %t receiving\n", caller->t_globalid); } }
static void user_ipc_error(tcb_t *thr, enum user_error_t error) { ipc_msg_tag_t tag; /* Set ipc unsuccessful */ tag.raw = ipc_read_mr(thr, 0); tag.s.flags |= 0x8; ipc_write_mr(thr, 0, tag.raw); set_user_error(thr, error); }
static void do_ipc(tcb_t *from, tcb_t *to) { ipc_msg_tag_t tag; ipc_typed_item typed_item; int untyped_idx, typed_idx, typed_item_idx; int typed_last, untyped_last; uint32_t typed_data; /* typed item extra word */ l4_thread_t from_recv_tid; /* Clear timeout event when ipc is established. */ from->timeout_event = 0; to->timeout_event = 0; /* Copy tag of message */ tag.raw = ipc_read_mr(from, 0); untyped_last = tag.s.n_untyped + 1; typed_last = untyped_last + tag.s.n_typed; if (typed_last > IPC_MR_COUNT) { do_ipc_error(from, to, UE_IPC_MSG_OVERFLOW | UE_IPC_PHASE_SEND, UE_IPC_MSG_OVERFLOW | UE_IPC_PHASE_RECV, T_RUNNABLE, T_RUNNABLE); return; } ipc_write_mr(to, 0, tag.raw); /* Copy untyped words */ for (untyped_idx = 1; untyped_idx < untyped_last; ++untyped_idx) { ipc_write_mr(to, untyped_idx, ipc_read_mr(from, untyped_idx)); } typed_item_idx = -1; /* Copy typed words * FSM: j - number of byte */ for (typed_idx = untyped_idx; typed_idx < typed_last; ++typed_idx) { uint32_t mr_data = ipc_read_mr(from, typed_idx); /* Write typed mr data to 'to' thread */ ipc_write_mr(to, typed_idx, mr_data); if (typed_item_idx == -1) { /* If typed_item_idx == -1 - read typed item's tag */ typed_item.raw = mr_data; ++typed_item_idx; } else if (typed_item.s.header & IPC_TI_MAP_GRANT) { /* MapItem / GrantItem have 1xxx in header */ int ret; typed_data = mr_data; ret = map_area(from->as, to->as, typed_item.raw & 0xFFFFFFC0, typed_data & 0xFFFFFFC0, (typed_item.s.header & IPC_TI_GRANT) ? GRANT : MAP, thread_ispriviliged(from)); typed_item_idx = -1; if (ret < 0) { do_ipc_error(from, to, UE_IPC_ABORTED | UE_IPC_PHASE_SEND, UE_IPC_ABORTED | UE_IPC_PHASE_RECV, T_RUNNABLE, T_RUNNABLE); return; } } /* TODO: StringItem support */ } if (!to->ctx.sp || !from->ctx.sp) { do_ipc_error(from, to, UE_IPC_ABORTED | UE_IPC_PHASE_SEND, UE_IPC_ABORTED | UE_IPC_PHASE_RECV, T_RUNNABLE, T_RUNNABLE); return; } to->utcb->sender = from->t_globalid; to->state = T_RUNNABLE; to->ipc_from = L4_NILTHREAD; ((uint32_t*)to->ctx.sp)[REG_R0] = from->t_globalid; /* If from has receive phases, lock myself */ from_recv_tid = ((uint32_t*)from->ctx.sp)[REG_R1]; if (from_recv_tid == L4_NILTHREAD) { from->state = T_RUNNABLE; } else { from->state = T_RECV_BLOCKED; from->ipc_from = from_recv_tid; dbg_printf(DL_IPC, "IPC: %t receiving\n", from->t_globalid); } /* Dispatch communicating threads */ sched_slot_dispatch(SSI_NORMAL_THREAD, from); sched_slot_dispatch(SSI_IPC_THREAD, to); dbg_printf(DL_IPC, "IPC: %t to %t\n", caller->t_globalid, to->t_globalid); }
void sys_ipc(uint32_t *param1) { /* TODO: Checking of recv-mask */ tcb_t *to_thr = NULL; l4_thread_t to_tid = param1[REG_R0], from_tid = param1[REG_R1]; uint32_t timeout = param1[REG_R2]; if (to_tid == L4_NILTHREAD && from_tid == L4_NILTHREAD) { caller->state = T_INACTIVE; if (timeout) sys_ipc_timeout(timeout); return; } if (to_tid != L4_NILTHREAD) { to_thr = thread_by_globalid(to_tid); if (to_tid == TID_TO_GLOBALID(THREAD_LOG)) { user_log(caller); caller->state = T_RUNNABLE; return; } else if (to_tid == TID_TO_GLOBALID(THREAD_IRQ_REQUEST)) { user_interrupt_config(caller); caller->state = T_RUNNABLE; return; } else if ((to_thr && to_thr->state == T_RECV_BLOCKED) || to_tid == caller->t_globalid) { /* To thread who is waiting for us or sends to myself */ do_ipc(caller, to_thr); return; } else if (to_thr && to_thr->state == T_INACTIVE && GLOBALID_TO_TID(to_thr->utcb->t_pager) == GLOBALID_TO_TID(caller->t_globalid)) { if (ipc_read_mr(caller, 0) == 0x00000005) { /* mr1: thread func, mr2: stack addr, mr3: stack size*/ /* mr4: thread entry, mr5: thread args */ /* thread start protocol */ memptr_t sp = ipc_read_mr(caller, 2); size_t stack_size = ipc_read_mr(caller, 3); uint32_t regs[4]; /* r0, r1, r2, r3 */ dbg_printf(DL_IPC, "IPC: %t thread start\n", to_tid); to_thr->stack_base = sp - stack_size; to_thr->stack_size = stack_size; regs[REG_R0] = (uint32_t)&kip; regs[REG_R1] = (uint32_t)to_thr->utcb; regs[REG_R2] = ipc_read_mr(caller, 4); regs[REG_R3] = ipc_read_mr(caller, 5); thread_init_ctx((void *) sp, (void *) ipc_read_mr(caller, 1), regs, to_thr); caller->state = T_RUNNABLE; /* Start thread */ to_thr->state = T_RUNNABLE; return; } else { do_ipc(caller, to_thr); to_thr->state = T_INACTIVE; return; } } else { /* No waiting, block myself */ caller->state = T_SEND_BLOCKED; caller->utcb->intended_receiver = to_tid; dbg_printf(DL_IPC, "IPC: %t sending\n", caller->t_globalid); if (timeout) sys_ipc_timeout(timeout); return; } } if (from_tid != L4_NILTHREAD) { tcb_t *thr = NULL; if (from_tid == L4_ANYTHREAD) { int i; /* Find out if there is any sending thread waiting for caller */ for (i = 1; i < thread_count; ++i) { thr = thread_map[i]; if (thr->state == T_SEND_BLOCKED && thr->utcb->intended_receiver == caller->t_globalid) { do_ipc(thr, caller); return; } } } else if (from_tid != TID_TO_GLOBALID(THREAD_INTERRUPT)) { thr = thread_by_globalid(from_tid); if (thr->state == T_SEND_BLOCKED && thr->utcb->intended_receiver == caller->t_globalid) { do_ipc(thr, caller); return; } } /* Only receive phases, simply lock myself */ caller->state = T_RECV_BLOCKED; caller->ipc_from = from_tid; if (from_tid == TID_TO_GLOBALID(THREAD_INTERRUPT)) { /* Threaded interrupt is ready */ user_interrupt_handler_update(caller); } if (timeout) sys_ipc_timeout(timeout); dbg_printf(DL_IPC, "IPC: %t receiving\n", caller->t_globalid); return; } caller->state = T_SEND_BLOCKED; }