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 <sel4/sel4.h> 14#include "data_syscall.h" 15#include <refos-rpc/data_server.h> 16#include <refos/refos.h> 17 18#include "../system/memserv/window.h" 19#include "../system/memserv/dataspace.h" 20#include "../system/memserv/ringbuffer.h" 21#include "../system/process/process.h" 22#include "../system/process/pid.h" 23 24/*! @file 25 @brief Process server anon dataspace syscall handler. 26 27 This module is reponsible for implementing the dataspace interface in the generated 28 <refos-rpc/data_server.h>, for anon dataspaces. 29*/ 30 31seL4_CPtr 32data_open_handler(void *rpc_userptr , char* rpc_name , int rpc_flags , int rpc_mode , int rpc_size , 33 int* rpc_errno) 34{ 35 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 36 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 37 38 (void) pcb; 39 (void) rpc_mode; 40 41 if (rpc_size <= 0) { 42 SET_ERRNO_PTR(rpc_errno, EINVALIDPARAM); 43 return 0; 44 } 45 46 /* Name must either be NULL, empty string or anon. */ 47 if (rpc_name != NULL) { 48 if (strlen(rpc_name) > 0 && strcmp(rpc_name, "anon") != 0) { 49 SET_ERRNO_PTR(rpc_errno, EFILENOTFOUND); 50 return 0; 51 } 52 } 53 54 /* Create a ram dataspace of the given size. */ 55 struct ram_dspace *newDataspace = ram_dspace_create(&procServ.dspaceList, rpc_size); 56 if (!newDataspace) { 57 ROS_ERROR("Failed to create new_dataspace.\n"); 58 SET_ERRNO_PTR(rpc_errno, ENOMEM); 59 return 0; 60 } 61 62 /* Set physical address mode, if required. */ 63 if ((rpc_flags & PROCSERV_DSPACE_FLAG_DEVICE_PADDR) != 0) { 64 int error = EACCESSDENIED; 65 if (pcb->systemCapabilitiesMask & PROCESS_PERMISSION_DEVICE_MAP) { 66 error = ram_dspace_set_to_paddr(newDataspace, (uint32_t) rpc_mode); 67 } 68 if (error) { 69 ram_dspace_unref(&procServ.dspaceList, newDataspace->ID); 70 SET_ERRNO_PTR(rpc_errno, error); 71 return 0; 72 } 73 } 74 75 SET_ERRNO_PTR(rpc_errno, ESUCCESS); 76 assert(newDataspace->magic == RAM_DATASPACE_MAGIC); 77 return newDataspace->capability.capPtr; 78} 79 80refos_err_t 81data_close_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd) 82{ 83 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 84 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 85 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 86 87 if (!check_dispatch_caps(m, 0x00000001, 1)) { 88 ROS_ERROR("data_close EINVALIDPARAM: bad dataspace capability.\n"); 89 return EINVALIDWINDOW; 90 } 91 92 /* Verify and find the RAM dataspace. */ 93 if (!dispatcher_badge_dspace(rpc_dspace_fd)) { 94 ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n"); 95 return EINVALIDPARAM; 96 } 97 struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd); 98 if (!dspace) { 99 ROS_ERROR("EINVALIDPARAM: dataspace not found.\n"); 100 return EINVALIDPARAM; 101 } 102 103 /* Purge the dataspace from all windows, unmapping every instance of it. */ 104 w_purge_dspace(&procServ.windowList, dspace); 105 106 /* Purge the dataspace from all notification buffers and ring buffers. */ 107 pid_iterate(&procServ.PIDList, proc_dspace_delete_callback, (void*) dspace); 108 109 /* Check that this is the last reference to the dataspace. */ 110 if (dspace->ref != 1) { 111 ROS_WARNING("Dataspace reference is %d and not 1.", dspace->ref); 112 ROS_WARNING("This is either a book-keeping bug or corruption."); 113 } 114 115 /* And finally destroy the RAM dataspace. */ 116 ram_dspace_unref(&procServ.dspaceList, dspace->ID); 117 return ESUCCESS; 118} 119 120int 121data_getc_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , int rpc_block) 122{ 123 (void) rpc_userptr; 124 (void) rpc_dspace_fd; 125 return EUNIMPLEMENTED; 126} 127 128off_t 129data_lseek_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , off_t rpc_offset , 130 int rpc_whence) 131{ 132 (void) rpc_userptr; 133 (void) rpc_dspace_fd; 134 (void) rpc_offset; 135 (void) rpc_whence; 136 return EUNIMPLEMENTED; 137} 138 139uint32_t 140data_get_size_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd) 141{ 142 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 143 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 144 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 145 146 if (!check_dispatch_caps(m, 0x00000001, 1)) { 147 ROS_ERROR("bad dspace capability.\n"); 148 return 0; 149 } 150 151 /* Verify and find the RAM dataspace. */ 152 if (!dispatcher_badge_dspace(rpc_dspace_fd)) { 153 ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n"); 154 return EINVALIDPARAM; 155 } 156 struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd); 157 if (!dspace) { 158 ROS_ERROR("EINVALIDPARAM: dataspace not found.\n"); 159 return EINVALIDPARAM; 160 } 161 162 return dspace->npages * REFOS_PAGE_SIZE; 163} 164 165refos_err_t 166data_expand_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , uint32_t rpc_size) 167{ 168 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 169 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 170 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 171 172 if (!check_dispatch_caps(m, 0x00000001, 1)) { 173 return EINVALIDPARAM; 174 } 175 176 /* Verify and find the RAM dataspace. */ 177 if (!dispatcher_badge_dspace(rpc_dspace_fd)) { 178 ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n"); 179 return EINVALIDPARAM; 180 } 181 struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd); 182 if (!dspace) { 183 ROS_ERROR("EINVALIDPARAM: dataspace not found.\n"); 184 return EINVALIDPARAM; 185 } 186 187 return ram_dspace_expand(dspace, rpc_size); 188} 189 190/*! \brief Maps the given dataspace to the given memory window. */ 191refos_err_t 192data_datamap_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , seL4_CPtr rpc_memoryWindow, 193 uint32_t rpc_offset) 194{ 195 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 196 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 197 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 198 199 if (!check_dispatch_caps(m, 0x00000003, 2)) { 200 return EINVALIDPARAM; 201 } 202 203 /* Retrieve and validate window badge. */ 204 if (!dispatcher_badge_window(rpc_memoryWindow)) { 205 return EINVALIDWINDOW; 206 } 207 struct w_window *window = w_get_window(&procServ.windowList, rpc_memoryWindow - W_BADGE_BASE); 208 if (!window) { 209 return EINVALIDWINDOW; 210 } 211 212 /* Verify and find the RAM dataspace. */ 213 if (!dispatcher_badge_dspace(rpc_dspace_fd)) { 214 ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n"); 215 return EINVALIDPARAM; 216 } 217 struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd); 218 if (!dspace) { 219 ROS_ERROR("EINVALIDPARAM: dataspace not found.\n"); 220 return EINVALIDPARAM; 221 } 222 223 /* Check that the offset is sane. */ 224 if (rpc_offset > (dspace->npages * REFOS_PAGE_SIZE)) { 225 return EINVALIDPARAM; 226 } 227 228 /* Associate the dataspace with the window. This will release whatever the window was associated 229 with beforehand. */ 230 w_set_anon_dspace(window, dspace, rpc_offset); 231 return ESUCCESS; 232} 233 234refos_err_t 235data_dataunmap_handler(void *rpc_userptr , seL4_CPtr rpc_memoryWindow) 236{ 237 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 238 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 239 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 240 241 if (!check_dispatch_caps(m, 0x00000001, 1)) { 242 return EINVALIDPARAM; 243 } 244 245 /* Retrieve and validate window badge. */ 246 if (!dispatcher_badge_window(rpc_memoryWindow)) { 247 return EINVALIDWINDOW; 248 } 249 struct w_window *window = w_get_window(&procServ.windowList, rpc_memoryWindow - W_BADGE_BASE); 250 if (!window) { 251 return EINVALIDWINDOW; 252 } 253 254 /* If window is already empty, then there's nothing to do here. */ 255 if (window->mode == W_MODE_EMPTY) { 256 return ESUCCESS; 257 } 258 259 /* If window is mapped to something else, the un-do operation should not be data_unmap. */ 260 if (window->mode != W_MODE_ANONYMOUS) { 261 return EINVALIDPARAM; 262 } 263 264 /* Reset the window back to empty. */ 265 w_set_anon_dspace(window, NULL, 0); 266 return ESUCCESS; 267} 268 269 270refos_err_t 271data_init_data_handler(void *rpc_userptr , seL4_CPtr rpc_destDataspace , 272 seL4_CPtr rpc_srcDataspace , uint32_t rpc_srcDataspaceOffset) 273{ 274 (void) rpc_userptr; 275 (void) rpc_destDataspace; 276 (void) rpc_srcDataspace; 277 (void) rpc_srcDataspaceOffset; 278 279 /* Process server doesn't support init_data syscall. 280 Who on earth would want to initialise another dataspace by anonymous memory? */ 281 282 return EUNIMPLEMENTED; 283} 284 285/*! \brief Call from external dataserver asking to be the content initialiser for this dataspace. */ 286refos_err_t 287data_have_data_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , seL4_CPtr rpc_faultNotifyEP , 288 uint32_t* rpc_dataID) 289{ 290 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 291 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 292 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 293 294 if (!(check_dispatch_caps(m, 0x00000001, 2) || check_dispatch_caps(m, 0x00000001, 1))) { 295 return EINVALIDPARAM; 296 } 297 298 if (rpc_dataID) { 299 (*rpc_dataID) = 0; 300 } 301 302 /* Verify and find the RAM dataspace. */ 303 if (!dispatcher_badge_dspace(rpc_dspace_fd)) { 304 ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n"); 305 return EINVALIDPARAM; 306 } 307 struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd); 308 if (!dspace) { 309 ROS_ERROR("EINVALIDPARAM: dataspace not found.\n"); 310 return EINVALIDPARAM; 311 } 312 313 /* Special case - no fault notify EP, means unset content-init mode. */ 314 if (!rpc_faultNotifyEP) { 315 cspacepath_t path; 316 vka_cspace_make_path(&procServ.vka, 0, &path); 317 return ram_dspace_content_init(dspace, path, PID_NULL); 318 } 319 320 /* Copyout the content-init fault notify EP. */ 321 seL4_CPtr faultNotifyEP = dispatcher_copyout_cptr(rpc_faultNotifyEP); 322 if (!faultNotifyEP) { 323 dvprintf("could not copy out faultNotifyEP."); 324 return EINVALIDPARAM; 325 } 326 cspacepath_t path; 327 vka_cspace_make_path(&procServ.vka, faultNotifyEP, &path); 328 329 /* Initialise the dataspace content with given dataserver EP. */ 330 int error = ram_dspace_content_init(dspace, path, pcb->pid); 331 if (error != ESUCCESS) { 332 dispatcher_release_copyout_cptr(faultNotifyEP); 333 return error; 334 } 335 336 if (rpc_dataID) { 337 (*rpc_dataID) = dspace->ID; 338 } 339 return ESUCCESS; 340} 341 342refos_err_t 343data_unhave_data_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd) 344{ 345 return data_have_data_handler(rpc_userptr, rpc_dspace_fd, 0, NULL); 346} 347 348/*! \brief Reply from another dataserver to provide the process server with content, in reply to a 349 notification the process server has sent it which asked for content. 350*/ 351refos_err_t 352data_provide_data_from_parambuffer_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , 353 uint32_t rpc_offset , uint32_t rpc_contentSize) 354{ 355 struct proc_pcb *pcb = (struct proc_pcb*) rpc_userptr; 356 struct procserv_msg *m = (struct procserv_msg*) pcb->rpcClient.userptr; 357 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 358 359 if (!check_dispatch_caps(m, 0x00000001, 1)) { 360 return EINVALIDPARAM; 361 } 362 363 /* Verify and find the RAM dataspace. */ 364 if (!dispatcher_badge_dspace(rpc_dspace_fd)) { 365 ROS_ERROR("EINVALIDPARAM: invalid RAM dataspace badge..\n"); 366 return EINVALIDPARAM; 367 } 368 struct ram_dspace *dspace = ram_dspace_get_badge(&procServ.dspaceList, rpc_dspace_fd); 369 if (!dspace) { 370 ROS_ERROR("EINVALIDPARAM: dataspace not found.\n"); 371 return EINVALIDPARAM; 372 } 373 374 char *initContentBuffer = dispatcher_read_param(pcb, rpc_contentSize); 375 if (!initContentBuffer) { 376 ROS_WARNING("data_provide_data_from_parambuffer_handler: failed to read from paramBuffer."); 377 return ENOPARAMBUFFER; 378 } 379 380 /* Initialise the page of the ram dataspace with these contents. */ 381 int error = ram_dspace_write(initContentBuffer, rpc_contentSize, dspace, rpc_offset); 382 if (error != ESUCCESS) { 383 return error; 384 } 385 386 /* Set the bit that says this page has been provided, and notify all waiters blocking on it. */ 387 rpc_offset = REFOS_PAGE_ALIGN(rpc_offset); 388 int npages = (rpc_contentSize / REFOS_PAGE_SIZE) + (rpc_contentSize % REFOS_PAGE_SIZE ? 1 : 0); 389 for (vaddr_t i = 0; i < npages; i++) { 390 vaddr_t offset = rpc_offset + (i * REFOS_PAGE_SIZE); 391 ram_dspace_set_content_init_provided(dspace, offset); 392 ram_dspace_content_init_reply_waiters(dspace, offset); 393 } 394 395 return ESUCCESS; 396} 397 398int 399check_dispatch_dataspace(struct procserv_msg *m, void **userptr) 400{ 401 return check_dispatch_interface(m, userptr, RPC_DATA_LABEL_MIN, RPC_DATA_LABEL_MAX); 402} 403 404