1/* 2 * Copyright 2016, 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(D61_BSD) 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <assert.h> 17 18#include <refos/vmlayout.h> 19#include <refos/refos.h> 20#include <refos/error.h> 21#include <refos/share.h> 22#include <refos-util/cspace.h> 23#include <refos-util/serv_common.h> 24#include <refos-util/serv_connect.h> 25 26#include <refos-rpc/proc_client.h> 27#include <refos-rpc/proc_client_helper.h> 28#include <refos-rpc/name_client.h> 29#include <refos-rpc/name_client_helper.h> 30 31/* -------------------- Server Default Client Table Handler Helpers ----------------------------- */ 32 33struct srv_client* 34srv_ctable_connect_direct_handler(srv_common_t *srv, srv_msg_t *m, 35 seL4_CPtr liveness, int* _errno) 36{ 37 assert(srv && srv->magic == SRV_MAGIC && m); 38 39 /* Check that the liveness cap passed in correctly. */ 40 if(!srv_check_dispatch_caps(m, 0x00000000, 1)) { 41 SET_ERRNO_PTR(_errno, EINVALIDPARAM); 42 return NULL; 43 } 44 int error = ENOMEM; 45 46 /* Copyout the liveness cap, create session cap cslot. Do not printf before the copyout. */ 47 seL4_CPtr livenessCP = rpc_copyout_cptr(liveness); 48 if (!liveness || !livenessCP) { 49 goto error0; 50 } 51 52 /* Allocate the client structure. */ 53 struct srv_client *c = client_alloc(&srv->clientTable, livenessCP); 54 if (!c) { 55 goto error1; 56 } 57 58 dprintf("Adding new %s client cID = %d. Hi! (:D)\n", srv->config.serverName, c->cID); 59 assert(c->session); 60 61 /* Authenticate the client to the process server, using its liveness cap. */ 62 error = proc_watch_client(c->liveness, srv->notifyClientFaultDeathAsyncEP, &c->deathID); 63 if (error != ESUCCESS) { 64 goto error2; 65 } 66 67 SET_ERRNO_PTR(_errno, ESUCCESS); 68 return c; 69 70 /* Exit stack. */ 71error2: 72 client_queue_delete(&srv->clientTable, c->cID); 73 client_table_postaction(&srv->clientTable); 74error1: 75 seL4_CNode_Delete(REFOS_CSPACE, livenessCP, REFOS_CDEPTH); 76 csfree(livenessCP); 77error0: 78 SET_ERRNO_PTR(_errno, error); 79 return NULL; 80 81} 82 83refos_err_t 84srv_ctable_set_param_buffer_handler(srv_common_t *srv, struct srv_client *c, 85 srv_msg_t *m, seL4_CPtr parambufferDataspace, uint32_t parambufferSize) 86{ 87 assert(srv && srv->magic == SRV_MAGIC); 88 assert(c && m); 89 90 /* Special case: unset the parameter buffer. */ 91 if (!parambufferDataspace && parambufferSize == 0) { 92 seL4_CNode_Revoke(REFOS_CSPACE, c->paramBuffer, REFOS_CDEPTH); 93 seL4_CNode_Delete(REFOS_CSPACE, c->paramBuffer, REFOS_CDEPTH); 94 csfree(c->paramBuffer); 95 c->paramBuffer = 0; 96 c->paramBufferSize = 0; 97 return ESUCCESS; 98 } 99 100 /* Sanity check parameters. */ 101 if (!srv_check_dispatch_caps(m, 0x00000000, 1)) { 102 return EINVALIDPARAM; 103 } 104 if (parambufferSize == 0) { 105 return EINVALIDPARAM; 106 } 107 108 /* Set the parameter buffer by copying out the given dspace cap. 109 Do not printf before copyout. */ 110 c->paramBuffer = rpc_copyout_cptr(parambufferDataspace); 111 if (!c->paramBuffer) { 112 ROS_ERROR("Failed to copyout the cap."); 113 return ENOMEM; 114 } 115 c->paramBufferSize = parambufferSize; 116 dprintf("Set param buffer for client cID = %d...\n", c->cID); 117 118 return ESUCCESS; 119 120} 121 122void 123srv_ctable_disconnect_direct_handler(srv_common_t *srv, struct srv_client *c) 124{ 125 assert(srv && srv->magic == SRV_MAGIC && c); 126 dprintf("Disconnecting %s client cID = %d. Bye! (D:)\n", srv->config.serverName, c->cID); 127 client_queue_delete(&srv->clientTable, c->cID); 128 proc_unwatch_client(c->liveness); 129} 130 131/* ---------------------------------------------------------------------------------------------- */ 132 133int 134srv_common_init(srv_common_t *s, srv_common_config_t config) 135{ 136 assert(s); 137 138 dprintf("Initialising %s common server state...\n", config.serverName); 139 memset(s, 0, sizeof(srv_common_t)); 140 s->config = config; 141 142 /* Create sync anon EP. */ 143 dprintf(" creating %s anon endpoint...\n", config.serverName); 144 s->anonEP = proc_new_endpoint(); 145 if (!s->anonEP) { 146 ROS_ERROR("srv_common_init could not create endpoint for %s.", config.serverName); 147 return ENOMEM; 148 } 149 150 /* Create async EP. */ 151 dprintf(" creating %s async endpoint...\n", config.serverName); 152 s->notifyAsyncEP = proc_new_async_endpoint(); 153 if (!s->notifyAsyncEP) { 154 ROS_ERROR("srv_common_init could not create async endpoint."); 155 return ENOMEM; 156 } 157 158 /* Mint badged async EP. */ 159 dprintf(" creating async death and/or fault notification badged EP...\n"); 160 s->notifyClientFaultDeathAsyncEP = srv_mint(config.faultDeathNotifyBadge, s->notifyAsyncEP); 161 if (!s->notifyClientFaultDeathAsyncEP) { 162 ROS_ERROR("srv_common_init could not create minted async endpoint."); 163 return EINVALID; 164 } 165 166 /* Bind the notification AEP. */ 167 dprintf(" binding notification AEP...\n"); 168 int error = seL4_TCB_BindNotification(REFOS_THREAD_TCB, s->notifyAsyncEP); 169 if (error != seL4_NoError) { 170 ROS_ERROR("srv_common_init could not bind async endpoint."); 171 return EINVALID; 172 } 173 174 /* Register ourselves under our mountpoint name. */ 175 if (config.mountPointPath != NULL) { 176 dprintf(" registering under the mountpoint [%s]...\n", config.mountPointPath); 177 error = nsv_register(config.nameServEP, config.mountPointPath, s->anonEP); 178 if (error != ESUCCESS) { 179 ROS_ERROR("srv_common_init could not register anon ep."); 180 return error; 181 } 182 } 183 184 /* Initialise client table. */ 185 if (config.maxClients > 0) { 186 dprintf(" initialising client table for %s...\n", config.serverName); 187 client_table_init(&s->clientTable, config.maxClients, config.clientBadgeBase, 188 config.clientMagic, s->anonEP); 189 190 dprintf(" initialising client table default handlers for %s...\n", config.serverName); 191 s->ctable_connect_direct_handler = srv_ctable_connect_direct_handler; 192 s->ctable_set_param_buffer_handler = srv_ctable_set_param_buffer_handler; 193 s->ctable_disconnect_direct_handler = srv_ctable_disconnect_direct_handler; 194 } 195 196 /* Set up our server --> process server notification buffer. */ 197 if (config.notificationBufferSize > 0) { 198 199 /* Open and map the notification buffer on our side. */ 200 dprintf(" initialising notification buffer for %s...\n", config.serverName); 201 s->notifyBuffer = data_open_map(REFOS_PROCSERV_EP, "anon", 0, 0, 202 config.notificationBufferSize, -1); 203 if (s->notifyBuffer.err != ESUCCESS) { 204 ROS_ERROR("srv_common_init failed to open & map anon dspace for notifications."); 205 return s->notifyBuffer.err; 206 } 207 208 /* Share and set the notification buffer on the procserv side. */ 209 assert(s->notifyBuffer.dataspace); 210 error = proc_notification_buffer(s->notifyBuffer.dataspace); 211 if (error != ESUCCESS) { 212 ROS_ERROR("srv_common_init failed to set notification buffer."); 213 return error; 214 } 215 216 s->notifyBufferStart = 0; 217 } 218 219 /* Set up our server --> process server parameter buffer. */ 220 if (config.paramBufferSize > 0) { 221 222 dprintf(" initialising procserv param buffer for %s...\n", config.serverName); 223 s->procServParamBuffer = data_open_map(REFOS_PROCSERV_EP, "anon", 0, 0, 224 config.paramBufferSize, -1); 225 if (s->procServParamBuffer.err != ESUCCESS) { 226 ROS_ERROR("srv_common_init failed to open & map anon dspace for param buffer."); 227 return s->procServParamBuffer.err; 228 } 229 error = proc_set_parambuffer(s->procServParamBuffer.dataspace, config.paramBufferSize); 230 if (error != ESUCCESS) { 231 ROS_ERROR("srv_common_init failed to set procserv param buffer."); 232 return error; 233 } 234 } 235 236 s->magic = SRV_MAGIC; 237 return ESUCCESS; 238} 239 240seL4_CPtr 241srv_mint(int badge, seL4_CPtr ep) 242{ 243 assert(ep); 244 seL4_CPtr mintEP = csalloc(); 245 if (!mintEP) { 246 ROS_ERROR("Could not allocate cslot to mint badge."); 247 return 0; 248 } 249 int error = seL4_CNode_Mint ( 250 REFOS_CSPACE, mintEP, REFOS_CDEPTH, 251 REFOS_CSPACE, ep, REFOS_CDEPTH, 252 seL4_NoRead, 253 seL4_CapData_Badge_new(badge) 254 ); 255 if (error != seL4_NoError) { 256 ROS_ERROR("Could not mint badge."); 257 csfree(mintEP); 258 return 0; 259 } 260 return mintEP; 261} 262 263bool 264srv_check_dispatch_caps(srv_msg_t *m, seL4_Word unwrappedMask, int numExtraCaps) 265{ 266 assert(m); 267 if (seL4_MessageInfo_get_capsUnwrapped(m->message) != unwrappedMask || 268 seL4_MessageInfo_get_extraCaps(m->message) != numExtraCaps) { 269 return false; 270 } 271 return true; 272} 273 274int 275srv_dispatch_notification(srv_common_t *srv, srv_common_notify_handler_callbacks_t callbacks) 276{ 277 assert(srv && srv->magic == SRV_MAGIC); 278 279 /* Allocate a notification structure. */ 280 struct proc_notification *notification = malloc(sizeof(struct proc_notification)); 281 if (!notification) { 282 dprintf("Out of memory while creating notification struct.\n"); 283 return DISPATCH_ERROR; 284 } 285 286 dvprintf("%s recieved fault notification!\n", srv->config.serverName); 287 data_mapping_t *nb = &srv->notifyBuffer; 288 uint32_t bytesRead = 0; 289 int error = DISPATCH_PASS; 290 291 while (1) { 292 bytesRead = 0; 293 294 error = refos_share_read ( 295 (char*) notification, sizeof(struct proc_notification), 296 nb->vaddr, nb->size, 297 &srv->notifyBufferStart, &bytesRead 298 ); 299 if (!error && bytesRead == 0) { 300 /* No more notifications to read. */ 301 break; 302 } 303 304 if (error || bytesRead != sizeof(struct proc_notification)) { 305 /* Error during reading notification. */ 306 dprintf("Could not read information from notification buffer!\n"); 307 dprintf(" error = %d\n, read = %d", error, bytesRead); 308 free(notification); 309 return DISPATCH_ERROR; 310 } 311 312 /* Paranoid sanity check here. */ 313 assert(notification->magic == PROCSERV_NOTIFICATION_MAGIC); 314 315 error = DISPATCH_ERROR; 316 switch (notification->label) { 317 case PROCSERV_NOTIFY_FAULT_DELEGATION: 318 if (callbacks.handle_server_fault) { 319 error = callbacks.handle_server_fault(notification); 320 break; 321 } 322 case PROCSERV_NOTIFY_CONTENT_INIT: 323 if (callbacks.handle_server_content_init) { 324 error = callbacks.handle_server_content_init(notification); 325 break; 326 } 327 case PROCSERV_NOTIFY_DEATH: 328 if (callbacks.handle_server_death_notification) { 329 error = callbacks.handle_server_death_notification(notification); 330 break; 331 } 332 default: 333 /* Should never get here. */ 334 ROS_WARNING("Unknown notification.\n"); 335 assert(!"Unknown notification."); 336 break; 337 } 338 } 339 340 if (error) { 341 ROS_WARNING("Notification handling error on %s: %d\n", srv->config.serverName, error); 342 } 343 344 free(notification); 345 return error; 346} 347