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 "proc_syscall.h" 14 15#include <vka/kobject_t.h> 16#include <refos-rpc/proc_common.h> 17#include <refos-rpc/proc_server.h> 18 19#include "../system/process/pid.h" 20#include "../system/process/process.h" 21#include "../system/process/proc_client_watch.h" 22#include "../system/addrspace/vspace.h" 23#include "../system/memserv/window.h" 24#include "../system/memserv/dataspace.h" 25#include "../system/memserv/ringbuffer.h" 26 27/*! @file 28 @brief Dispatcher for the procserv syscalls. 29 30 Handles calls to process server syscall interface. The process server interface provides process 31 abstraction, simple naming, server registration, memory windows...etc. (For more details, refer 32 to the protocol design document.). The methods here implement the functions in the generated 33 header file <refos-rpc/proc_server.h>. 34 35 The memory related process server syscalls resides in mem_syscall.c and mem_syscall.h. 36*/ 37 38/* ---------------------------- Proc Server syscall helper functions ---------------------------- */ 39 40/*! @brief Creates a kernel endpoint object for the given process. 41 42 Creates a kernel endpoint object for the given process. Also does the book-keeping underneath so 43 that the created objects can be destroyed when the process exits. 44 45 @param pcb Handle to the process to create the object for. (no ownership) 46 @param type The kernel endpoint object type to create for the process; sync or async. 47 @return Handle to the created object if successful (no ownership), NULL if there was an 48 error. (eg. ran out of heap or untyped memory). 49 */ 50static seL4_CPtr 51proc_syscall_allocate_endpoint(struct proc_pcb *pcb, kobject_t type) 52{ 53 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 54 55 /* Allocate the kernel object. */ 56 vka_object_t endpoint; 57 int error = -1; 58 if (type == KOBJECT_ENDPOINT) { 59 error = vka_alloc_endpoint(&procServ.vka, &endpoint); 60 } else if (type == KOBJECT_NOTIFICATION) { 61 error = vka_alloc_notification(&procServ.vka, &endpoint); 62 } else { 63 assert(!"Invalid endpoint type."); 64 } 65 if (error || endpoint.cptr == 0) { 66 ROS_ERROR("failed to allocate endpoint for process. Procserv out of memory.\n"); 67 return 0; 68 } 69 70 /* Track this allocation, so it may be freed along with the process vspace. */ 71 vs_track_obj(&pcb->vspace, endpoint); 72 return endpoint.cptr; 73} 74 75/* -------------------------------- Proc Server syscall handlers -------------------------------- */ 76 77/*! @brief Handles ping syscalls. */ 78refos_err_t 79proc_ping_handler(void *rpc_userptr) { 80 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 81 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 82 assert(pcb->magic == REFOS_PCB_MAGIC); 83 84 (void) pcb; 85 (void) m; 86 87 dprintf(COLOUR_G "PROCESS SERVER RECIEVED PING!!! HELLO THERE! (����������)������" COLOUR_RESET "\n"); 88 return ESUCCESS; 89} 90 91/*! @brief Handles sync endpoint creation syscalls. */ 92seL4_CPtr 93proc_new_endpoint_internal_handler(void *rpc_userptr , refos_err_t* rpc_errno) 94{ 95 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 96 assert(pcb->magic == REFOS_PCB_MAGIC); 97 dprintf("Process server creating endpoint!\n"); 98 seL4_CPtr ep = proc_syscall_allocate_endpoint(pcb, KOBJECT_ENDPOINT); 99 if (!ep) { 100 SET_ERRNO_PTR(rpc_errno, ENOMEM); 101 return 0; 102 } 103 SET_ERRNO_PTR(rpc_errno, ESUCCESS); 104 return ep; 105} 106 107/*! @brief Handles async endpoint creation syscalls. */ 108seL4_CPtr 109proc_new_async_endpoint_internal_handler(void *rpc_userptr , refos_err_t* rpc_errno) 110{ 111 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 112 assert(pcb->magic == REFOS_PCB_MAGIC); 113 dprintf("Process server creating async endpoint!\n"); 114 seL4_CPtr ep = proc_syscall_allocate_endpoint(pcb, KOBJECT_NOTIFICATION); 115 if (!ep) { 116 SET_ERRNO_PTR(rpc_errno, ENOMEM); 117 return 0; 118 } 119 SET_ERRNO_PTR(rpc_errno, ESUCCESS); 120 return ep; 121} 122 123/*! @brief Handles client watching syscalls. 124 125 Most servers would need to call this in order to be notified of client death in order to be able 126 to delete any internal book-keeping for the dead client. 127 */ 128refos_err_t 129proc_watch_client_handler(void *rpc_userptr , seL4_CPtr rpc_liveness , seL4_CPtr rpc_deathEP , 130 int32_t* rpc_deathID) 131{ 132 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 133 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 134 assert(pcb->magic == REFOS_PCB_MAGIC); 135 136 if (!check_dispatch_caps(m, 0x00000001, 2)) { 137 return EINVALIDPARAM; 138 } 139 140 /* Retrieve the corresponding client's ASID unwrapped from its liveness cap. */ 141 if (!dispatcher_badge_liveness(rpc_liveness)) { 142 return EINVALIDPARAM; 143 } 144 145 /* Verify the corresponding client. */ 146 struct proc_pcb *client = pid_get_pcb(&procServ.PIDList, 147 rpc_liveness - PID_LIVENESS_BADGE_BASE); 148 if (!client) { 149 return EINVALIDPARAM; 150 } 151 assert(client->magic == REFOS_PCB_MAGIC); 152 153 /* Copy out the death notification endpoint. */ 154 seL4_CPtr deathNotifyEP = dispatcher_copyout_cptr(rpc_deathEP); 155 if (!deathNotifyEP) { 156 ROS_ERROR("could not copy out deathNotifyEP."); 157 return ENOMEM; 158 } 159 160 /* Add the new client to the watch list of the calling process. */ 161 int error = client_watch(&pcb->clientWatchList, client->pid, deathNotifyEP); 162 if (error) { 163 ROS_ERROR("failed to add to watch list. Procserv possibly out of memory."); 164 dispatcher_release_copyout_cptr(deathNotifyEP); 165 return error; 166 } 167 if (rpc_deathID) { 168 (*rpc_deathID) = client->pid; 169 } 170 171 return ESUCCESS; 172} 173 174 175/*! @brief Handles client un-watching syscalls. */ 176refos_err_t 177proc_unwatch_client_handler(void *rpc_userptr , seL4_CPtr rpc_liveness) 178{ 179 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 180 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 181 assert(pcb->magic == REFOS_PCB_MAGIC); 182 183 if (!check_dispatch_caps(m, 0x00000001, 1)) { 184 return EINVALIDPARAM; 185 } 186 187 /* Retrieve the corresponding client's ASID unwrapped from its liveness cap. */ 188 if (!dispatcher_badge_liveness(rpc_liveness)) { 189 return EINVALIDPARAM; 190 } 191 192 /* Verify the corresponding client. */ 193 struct proc_pcb *client = pid_get_pcb(&procServ.PIDList, 194 rpc_liveness - PID_LIVENESS_BADGE_BASE); 195 if (!client) { 196 return EINVALIDPARAM; 197 } 198 assert(client->magic == REFOS_PCB_MAGIC); 199 200 /* Remove the given client PID from the watch list. */ 201 client_unwatch(&pcb->clientWatchList, client->pid); 202 return ESUCCESS; 203} 204 205/*! @brief Sets the process's parameter buffer. 206 207 Sets the process's parameter buffer to the given RAM dataspace. Only support a RAM dataspace 208 which orginated from the process server's own dataspace implementation, does not support 209 an external dataspace. 210*/ 211refos_err_t 212proc_set_parambuffer_handler(void *rpc_userptr , seL4_CPtr rpc_dataspace , uint32_t rpc_size) 213{ 214 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 215 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 216 assert(pcb->magic == REFOS_PCB_MAGIC); 217 struct ram_dspace *dataspace; 218 219 /* Special case zero size and NULL parameter buffer - means unset the parameter buffer. */ 220 if (rpc_size == 0 && rpc_dataspace == 0) { 221 proc_set_parambuffer(pcb, NULL); 222 return ESUCCESS; 223 } 224 225 if (!check_dispatch_caps(m, 0x00000001, 1)) { 226 return EINVALIDPARAM; 227 } 228 229 /* Check if the given badge is a RAM dataspace. */ 230 if (!dispatcher_badge_dspace(rpc_dataspace)) { 231 return EINVALIDPARAM; 232 } 233 234 /* Retrieve RAM dataspace structure. */ 235 dataspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dataspace); 236 if (!dataspace) { 237 dvprintf("No such dataspace!.\n"); 238 return EINVALID; 239 } 240 241 /* Set new parameter buffer. */ 242 proc_set_parambuffer(pcb, dataspace); 243 return ESUCCESS; 244} 245 246 247/*! @brief Starts a new process. */ 248refos_err_t 249proc_new_proc_handler(void *rpc_userptr , char* rpc_name , char* rpc_params , bool rpc_block , 250 int32_t rpc_priority , int32_t* rpc_status) 251{ 252 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 253 assert(pcb->magic == REFOS_PCB_MAGIC); 254 255 if (!rpc_name) { 256 return EINVALIDPARAM; 257 } 258 259 /* Kick off an instance of selfloader, which will do the actual process loading work. */ 260 int error = proc_load_direct("selfloader", rpc_priority, rpc_name, pcb->pid, 0x0); 261 if (error != ESUCCESS) { 262 ROS_WARNING("failed to run selfloader for new process [%s].", rpc_name); 263 return error; 264 } 265 266 /* Optionally block parent process until child process has finished. */ 267 if (rpc_block) { 268 /* Save the reply endpoint. */ 269 proc_save_caller(pcb); 270 pcb->parentWaiting = true; 271 pcb->rpcClient.skip_reply = true; 272 return ESUCCESS; 273 } 274 275 /* Immediately resume the parent process. */ 276 return ESUCCESS; 277} 278 279/*! @brief Exits and deletes the process which made this call. */ 280refos_err_t 281proc_exit_handler(void *rpc_userptr , int32_t rpc_status) 282{ 283 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 284 assert(pcb->magic == REFOS_PCB_MAGIC); 285 dprintf("Process PID %u exiting with status %d !!!\n", pcb->pid, rpc_status); 286 pcb->exitStatus = rpc_status; 287 pcb->rpcClient.skip_reply = true; 288 proc_queue_release(pcb); 289 return ESUCCESS; 290} 291 292int 293proc_clone_internal_handler(void *rpc_userptr , seL4_Word rpc_entryPoint , seL4_Word rpc_childStack 294 , int rpc_flags , seL4_Word rpc_arg , refos_err_t* rpc_errno) 295{ 296 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 297 assert(pcb->magic == REFOS_PCB_MAGIC); 298 299 int threadID = -1; 300 int error = proc_clone(pcb, &threadID, (vaddr_t) rpc_childStack, (vaddr_t) rpc_entryPoint); 301 SET_ERRNO_PTR(rpc_errno, error); 302 return threadID; 303} 304 305refos_err_t 306proc_nice_handler(void *rpc_userptr , int rpc_threadID , int rpc_priority) 307{ 308 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 309 assert(pcb->magic == REFOS_PCB_MAGIC); 310 return proc_nice(pcb, rpc_threadID, rpc_priority); 311} 312 313seL4_CPtr 314proc_get_irq_handler_handler(void *rpc_userptr , int rpc_irq) 315{ 316 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 317 assert(pcb->magic == REFOS_PCB_MAGIC); 318 if ((pcb->systemCapabilitiesMask & PROCESS_PERMISSION_DEVICE_IRQ) == 0) { 319 return 0; 320 } 321 dprintf("Process %d (%s) getting IRQ number %d...\n", pcb->pid, pcb->debugProcessName, rpc_irq); 322 return procserv_get_irq_handler(rpc_irq); 323} 324 325 326/* ------------------------------------ Dispatcher functions ------------------------------------ */ 327 328int 329check_dispatch_syscall(struct procserv_msg *m, void **userptr) { 330 return check_dispatch_interface(m, userptr, RPC_PROC_LABEL_MIN, RPC_PROC_LABEL_MAX); 331} 332