1/* 2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <object/reply.h> 8 9void reply_push(tcb_t *tcb_caller, tcb_t *tcb_callee, reply_t *reply, bool_t canDonate) 10{ 11 sched_context_t *sc_donated = tcb_caller->tcbSchedContext; 12 13 assert(tcb_caller != NULL); 14 assert(reply != NULL); 15 assert(reply->replyTCB == NULL); 16 17 assert(call_stack_get_callStackPtr(reply->replyPrev) == 0); 18 assert(call_stack_get_callStackPtr(reply->replyNext) == 0); 19 20 /* tcb caller should not be in a existing call stack */ 21 assert(thread_state_get_replyObject(tcb_caller->tcbState) == 0); 22 23 /* unlink callee and reply - they may not have been linked already, 24 * if this rendesvous is occuring when seL4_Recv is called, 25 * however, no harm in overring 0 with 0 */ 26 thread_state_ptr_set_replyObject(&tcb_callee->tcbState, 0); 27 28 /* link caller and reply */ 29 reply->replyTCB = tcb_caller; 30 thread_state_ptr_set_replyObject(&tcb_caller->tcbState, REPLY_REF(reply)); 31 setThreadState(tcb_caller, ThreadState_BlockedOnReply); 32 33 if (sc_donated != NULL && tcb_callee->tcbSchedContext == NULL && canDonate) { 34 reply_t *old_caller = sc_donated->scReply; 35 36 /* check stack integrity */ 37 assert(old_caller == NULL || 38 SC_PTR(call_stack_get_callStackPtr(old_caller->replyNext)) == sc_donated); 39 40 /* push on to stack */ 41 reply->replyPrev = call_stack_new(REPLY_REF(old_caller), false); 42 if (old_caller) { 43 old_caller->replyNext = call_stack_new(REPLY_REF(reply), false); 44 } 45 reply->replyNext = call_stack_new(SC_REF(sc_donated), true); 46 sc_donated->scReply = reply; 47 48 /* now do the actual donation */ 49 schedContext_donate(sc_donated, tcb_callee); 50 } 51} 52 53/* Pop the head reply from the call stack */ 54void reply_pop(reply_t *reply, tcb_t *tcb) 55{ 56 assert(reply != NULL); 57 assert(thread_state_get_tsType(reply->replyTCB->tcbState) == ThreadState_BlockedOnReply); 58 assert(thread_state_get_replyObject(tcb->tcbState) == REPLY_REF(reply)); 59 assert(reply->replyTCB == tcb); 60 61 /* unlink tcb and reply */ 62 reply_unlink(reply, tcb); 63 64 word_t next_ptr = call_stack_get_callStackPtr(reply->replyNext); 65 word_t prev_ptr = call_stack_get_callStackPtr(reply->replyPrev); 66 67 if (likely(next_ptr != 0)) { 68 assert(call_stack_get_isHead(reply->replyNext)); 69 70 /* give it back */ 71 if (tcb->tcbSchedContext == NULL) { 72 /* only give the SC back if our SC is NULL. This prevents 73 * strange behaviour when a thread is bound to an sc while it is 74 * in the BlockedOnReply state. The semantics in this case are that the 75 * SC cannot go back to the caller if the caller has received another one */ 76 schedContext_donate(SC_PTR(next_ptr), tcb); 77 } 78 79 SC_PTR(next_ptr)->scReply = REPLY_PTR(prev_ptr); 80 if (prev_ptr != 0) { 81 REPLY_PTR(prev_ptr)->replyNext = reply->replyNext; 82 assert(call_stack_get_isHead(REPLY_PTR(prev_ptr)->replyNext)); 83 } 84 85 reply->replyPrev = call_stack_new(0, false); 86 reply->replyNext = call_stack_new(0, false); 87 } 88} 89 90/* Remove a reply from the middle of the call stack */ 91void reply_remove(reply_t *reply, tcb_t *tcb) 92{ 93 assert(reply->replyTCB == tcb); 94 assert(thread_state_get_tsType(tcb->tcbState) == ThreadState_BlockedOnReply); 95 assert(thread_state_get_replyObject(tcb->tcbState) == REPLY_REF(reply)); 96 97 word_t next_ptr = call_stack_get_callStackPtr(reply->replyNext); 98 word_t prev_ptr = call_stack_get_callStackPtr(reply->replyPrev); 99 100 if (likely(next_ptr)) { 101 if (likely(call_stack_get_isHead(reply->replyNext))) { 102 /* head of the call stack -> just pop */ 103 reply_pop(reply, tcb); 104 return; 105 } 106 /* not the head, remove from middle - break the chain */ 107 REPLY_PTR(next_ptr)->replyPrev = call_stack_new(0, false); 108 reply_unlink(REPLY_PTR(reply), tcb); 109 } else { 110 /* removing start of call chain */ 111 reply_unlink(reply, tcb); 112 } 113 114 if (prev_ptr) { 115 REPLY_PTR(prev_ptr)->replyNext = call_stack_new(0, false); 116 } 117 118 reply->replyPrev = call_stack_new(0, false); 119 reply->replyNext = call_stack_new(0, false); 120} 121 122void reply_remove_tcb(tcb_t *tcb) 123{ 124 assert(thread_state_get_tsType(tcb->tcbState) == ThreadState_BlockedOnReply); 125 reply_t *reply = REPLY_PTR(thread_state_get_replyObject(tcb->tcbState)); 126 word_t next_ptr = call_stack_get_callStackPtr(reply->replyNext); 127 word_t prev_ptr = call_stack_get_callStackPtr(reply->replyPrev); 128 129 if (next_ptr) { 130 if (call_stack_get_isHead(reply->replyNext)) { 131 SC_PTR(next_ptr)->scReply = NULL; 132 } else { 133 REPLY_PTR(next_ptr)->replyPrev = call_stack_new(0, false); 134 } 135 } 136 137 if (prev_ptr) { 138 REPLY_PTR(prev_ptr)->replyNext = call_stack_new(0, false); 139 } 140 141 reply->replyPrev = call_stack_new(0, false); 142 reply->replyNext = call_stack_new(0, false); 143 reply_unlink(reply, tcb); 144} 145