1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <stdio.h> 14#include <sel4/sel4.h> 15#include <vka/object.h> 16 17#include "../test.h" 18#include "../helpers.h" 19 20#define NUM_BADGED_CLIENTS 32 21 22static int bouncer_func(seL4_CPtr ep, seL4_CPtr reply, seL4_Word arg2, seL4_Word arg3) 23{ 24 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); 25 seL4_Word sender_badge; 26 api_recv(ep, &sender_badge, reply); 27 while (1) { 28 api_reply_recv(ep, tag, &sender_badge, reply); 29 } 30 return 0; 31} 32 33static int call_func(seL4_CPtr ep, seL4_Word msg, volatile seL4_Word *done, seL4_Word arg3) 34{ 35 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1); 36 37 /* Send the given message once. */ 38 seL4_SetMR(0, msg); 39 tag = seL4_Call(ep, tag); 40 test_check(seL4_MessageInfo_get_length(tag) == 1); 41 test_check(seL4_GetMR(0) == ~msg); 42 43 *done = 0; 44 45 /* Send the given message again - should (eventually) fault this time. */ 46 seL4_SetMR(0, msg); 47 tag = seL4_Call(ep, tag); 48 /* The call should fail. */ 49 test_check(seL4_MessageInfo_get_label(tag) == seL4_InvalidCapability); 50 51 *done = 1; 52 53 return sel4test_get_result(); 54} 55 56static int test_ep_cancelBadgedSends(env_t env) 57{ 58 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); 59 struct { 60 helper_thread_t thread; 61 seL4_CPtr badged_ep; 62 seL4_CPtr derived_badged_ep; 63 volatile seL4_Word done; 64 } senders[NUM_BADGED_CLIENTS]; 65 helper_thread_t bouncer; 66 seL4_CPtr bounce_ep; 67 UNUSED int error; 68 seL4_CPtr ep; 69 70 /* Create the master endpoint. */ 71 ep = vka_alloc_endpoint_leaky(&env->vka); 72 73 /* Create N badged endpoints, and derive each of them. */ 74 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 75 senders[i].badged_ep = get_free_slot(env); 76 assert(senders[i].badged_ep != 0); 77 78 senders[i].derived_badged_ep = get_free_slot(env); 79 assert(senders[i].derived_badged_ep != 0); 80 81 error = cnode_mint(env, ep, senders[i].badged_ep, seL4_AllRights, i + 200); 82 assert(!error); 83 84 error = cnode_copy(env, senders[i].badged_ep, senders[i].derived_badged_ep, seL4_AllRights); 85 assert(!error); 86 87 create_helper_thread(env, &senders[i].thread); 88 set_helper_priority(env, &senders[i].thread, 100); 89 90 senders[i].done = -1; 91 } 92 /* Create a bounce thread so we can get lower prio threads to run. */ 93 bounce_ep = vka_alloc_endpoint_leaky(&env->vka); 94 create_helper_thread(env, &bouncer); 95 set_helper_priority(env, &bouncer, 0); 96 start_helper(env, &bouncer, bouncer_func, bounce_ep, get_helper_reply(&bouncer), 0, 0); 97 98 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 99 start_helper(env, &senders[i].thread, (helper_fn_t) call_func, 100 senders[i].derived_badged_ep, i + 100, (seL4_Word) &senders[i].done, 0); 101 } 102 103 /* Let the sender threads run. */ 104 seL4_CPtr reply = vka_alloc_reply_leaky(&env->vka); 105 106 seL4_Call(bounce_ep, tag); 107 /* Receive a message from each endpoint and check the badge. */ 108 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 109 seL4_Word sender_badge; 110 seL4_MessageInfo_ptr_set_length(&tag, 1); 111 tag = api_recv(ep, &sender_badge, reply); 112 assert(seL4_MessageInfo_get_length(tag) == 1); 113 assert(seL4_GetMR(0) == sender_badge - 100); 114 seL4_SetMR(0, ~seL4_GetMR(0)); 115 api_reply(reply, tag); 116 } 117 /* Let the sender threads run. */ 118 seL4_Call(bounce_ep, tag); 119 /* Check none of the threads have failed yet. */ 120 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 121 assert(senders[i].done == 0); 122 } 123 /* cancelBadgedSends each endpoint. */ 124 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 125 error = cnode_revoke(env, senders[i].badged_ep); 126 test_eq(error, seL4_NoError); 127 128 error = cnode_cancelBadgedSends(env, senders[i].badged_ep); 129 assert(!error); 130 131 /* Let thread run. */ 132 seL4_Call(bounce_ep, tag); 133 /* Check that only the intended threads have now aborted. */ 134 for (int j = 0; j < NUM_BADGED_CLIENTS; j++) { 135 if (j <= i) { 136 assert(senders[j].done == 1); 137 } else { 138 assert(senders[j].done == 0); 139 } 140 } 141 } 142 seL4_Call(bounce_ep, tag); 143 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 144 cleanup_helper(env, &senders[i].thread); 145 } 146 cleanup_helper(env, &bouncer); 147 148 return sel4test_get_result(); 149} 150DEFINE_TEST(CANCEL_BADGED_SENDS_0001, "Basic endpoint cancelBadgedSends testing.", test_ep_cancelBadgedSends, true) 151 152static int ep_test_func(seL4_CPtr sync_ep, seL4_CPtr test_ep, volatile seL4_Word *status, seL4_CPtr reply) 153{ 154 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); 155 seL4_Word sender_badge; 156 while (1) { 157 api_recv(sync_ep, &sender_badge, reply); 158 /* Hit up the test end point */ 159 seL4_MessageInfo_t reply_tag = seL4_Call(test_ep, tag); 160 /* See what the status was */ 161 *status = !!(seL4_MessageInfo_get_label(reply_tag) != seL4_InvalidCapability); 162 /* Reply */ 163 api_reply(reply, tag); 164 } 165 return sel4test_get_result(); 166} 167 168/* CANCEL_BADGED_SENDS_0001 only tests if a thread gets its IPC canceled. The IPC 169 * can succeed even if the cap it used got deleted provided the final 170 * capability was not cancelBadgedSendsd (thus causing an IPC cancel to happen) 171 * This means that CANCEL_BADGED_SENDS_0001 will pass even if all the derived badges 172 * are deleted, since deleting them did NOT delete the final capability 173 * or cause a cancelBadgedSends so outstanding IPCs were not canceled */ 174static int test_ep_cancelBadgedSends2(env_t env) 175{ 176 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); 177 struct { 178 helper_thread_t thread; 179 seL4_CPtr sync_ep; 180 seL4_CPtr badged_ep; 181 seL4_CPtr derived_badged_ep; 182 volatile seL4_Word last_status; 183 } helpers[NUM_BADGED_CLIENTS]; 184 seL4_CPtr ep; 185 helper_thread_t reply_thread; 186 UNUSED int error; 187 188 /* Create the main EP we are testing */ 189 ep = vka_alloc_endpoint_leaky(&env->vka); 190 /* spawn a thread to keep replying to any messages on main ep */ 191 create_helper_thread(env, &reply_thread); 192 start_helper(env, &reply_thread, bouncer_func, ep, get_helper_reply(&reply_thread), 0, 0); 193 /* Spawn helper threads each with their own sync ep and a badged copy of the main ep */ 194 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 195 helpers[i].badged_ep = get_free_slot(env); 196 assert(helpers[i].badged_ep != 0); 197 198 helpers[i].derived_badged_ep = get_free_slot(env); 199 assert(helpers[i].derived_badged_ep != 0); 200 201 helpers[i].sync_ep = vka_alloc_endpoint_leaky(&env->vka); 202 203 error = cnode_mint(env, ep, helpers[i].badged_ep, seL4_AllRights, i + 200); 204 assert(!error); 205 206 error = cnode_copy(env, helpers[i].badged_ep, helpers[i].derived_badged_ep, seL4_AllRights); 207 assert(!error); 208 209 helpers[i].last_status = -1; 210 211 create_helper_thread(env, &helpers[i].thread); 212 start_helper(env, &helpers[i].thread, (helper_fn_t) ep_test_func, 213 helpers[i].sync_ep, helpers[i].derived_badged_ep, (seL4_Word) &helpers[i].last_status, 214 get_helper_reply(&helpers[i].thread)); 215 } 216 /* Test that every thread and endpoint is working */ 217 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 218 seL4_Call(helpers[i].sync_ep, tag); 219 } 220 for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { 221 test_assert(helpers[i].last_status); 222 } 223 /* Now start recycling endpoints and make sure the correct endpoints disappear */ 224 for (int i = 0 ; i < NUM_BADGED_CLIENTS; i++) { 225 error = cnode_revoke(env, helpers[i].badged_ep); 226 test_eq(error, seL4_NoError); 227 /* cancelBadgedSends an ep */ 228 error = cnode_cancelBadgedSends(env, helpers[i].badged_ep); 229 assert(!error); 230 /* Now run every thread */ 231 for (int j = 0; j < NUM_BADGED_CLIENTS; j++) { 232 seL4_Call(helpers[j].sync_ep, tag); 233 } 234 for (int j = 0; j < NUM_BADGED_CLIENTS; j++) { 235 if (j <= i) { 236 test_assert(!helpers[j].last_status); 237 } else { 238 test_assert(helpers[j].last_status); 239 } 240 } 241 } 242 return sel4test_get_result(); 243} 244DEFINE_TEST(CANCEL_BADGED_SENDS_0002, "cancelBadgedSends deletes caps", test_ep_cancelBadgedSends2, true) 245