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 "dispatch.h" 14#include "serv_dispatch.h" 15#include "../state.h" 16#include "../badge.h" 17#include <sys/types.h> 18#include <sys/stat.h> 19#include <utils/arith.h> 20#include <fcntl.h> 21#include <refos/error.h> 22#include <refos-rpc/data_server.h> 23#include <refos-rpc/data_client.h> 24#include <refos-util/serv_connect.h> 25#include <refos-util/serv_common.h> 26 27/*! @file 28 @brief Handles CPIO file server dataspace calls. 29 30 This file contains the handlers for dataspace interface syscalls, and exposes the file server's 31 CPIO contents through this interface. The methods here should implement the methods declared in 32 refos-rpc/data_server.h. 33*/ 34 35#define CPIO_RAMFS_MAX_CREATED_FILES 64 36#define CPIO_RAMFS_MAX_FILESSIZE 40960 37#define CPIO_RAMFS_MAX_FILENAME 32 38 39/*! @brief Forward declaration of the CPIO archive. 40 41 The CPIO archive is a simple format file archive stored inside a parent program's ELF section. 42 This is a similar idea to something like creating a 43 > const char data[] = { 0x3F, 0xFF, 0x23 ...etc} 44*/ 45extern char _cpio_archive[]; 46 47/*! @brief Rather hacky minimal ramfs created files. 48 49 This is a rather terrible hack to allow creation of writable files in CPIO fileserver as a sort 50 of minimal crude RamFS. The functionality is nice for portability, although in the future a 51 much better way to do this should be implemented. 52*/ 53static char _ramfs_archive[CPIO_RAMFS_MAX_CREATED_FILES][CPIO_RAMFS_MAX_FILESSIZE]; 54static char _ramfs_filename[CPIO_RAMFS_MAX_CREATED_FILES][CPIO_RAMFS_MAX_FILENAME]; 55static int _ramfs_filesz[CPIO_RAMFS_MAX_CREATED_FILES]; 56static int _ramfs_curfile = 0; /* Incrementally allocated files. */ 57 58seL4_CPtr 59data_open_handler(void *rpc_userptr , char* rpc_name , int rpc_flags , int rpc_mode , int rpc_size , 60 int* rpc_errno) 61{ 62 struct srv_client *c = (struct srv_client *) rpc_userptr; 63 assert(c->magic == FS_CLIENT_MAGIC); 64 65 if (!rpc_name) { 66 SET_ERRNO_PTR(rpc_errno, EINVALIDPARAM); 67 return 0; 68 } 69 70 /* Find file data in CPIO. */ 71 dprintf("Opening %s...\n", rpc_name); 72 unsigned long fileDataSize = 0; 73 char *fileData = cpio_get_file(_cpio_archive, rpc_name, &fileDataSize); 74 bool fileCreated = false; 75 76 if (fileData && (rpc_flags & O_ACCMODE) != O_RDONLY) { 77 /* CPIO dataspaces require read only. */ 78 SET_ERRNO_PTR(rpc_errno, EACCESSDENIED); 79 return 0; 80 } 81 82 if (!fileData) { 83 for (int i = 0; i < _ramfs_curfile; i++) { 84 if (!strcmp(rpc_name, _ramfs_filename[i])) { 85 if ((rpc_flags & O_CREAT)) { 86 /* Re-create this file. */ 87 memset(_ramfs_archive[i], 0, CPIO_RAMFS_MAX_FILESSIZE); 88 _ramfs_filesz[i] = 0; 89 } 90 fileData = _ramfs_archive[i]; 91 fileDataSize = _ramfs_filesz[i]; 92 fileCreated = true; 93 break; 94 } 95 } 96 } 97 98 if (!fileData) { 99 if ((rpc_flags & O_CREAT) == 0) { 100 dprintf("File %s not found!\n", rpc_name); 101 SET_ERRNO_PTR(rpc_errno, EFILENOTFOUND); 102 return 0; 103 } 104 /* Assign new blank RAMFS file. */ 105 if (_ramfs_curfile >= CPIO_RAMFS_MAX_CREATED_FILES) { 106 SET_ERRNO_PTR(rpc_errno, EACCESSDENIED); 107 return 0; 108 } 109 dvprintf("Creating new file %s...\n", rpc_name); 110 strncpy(_ramfs_filename[_ramfs_curfile], rpc_name, CPIO_RAMFS_MAX_FILENAME); 111 fileData = _ramfs_archive[_ramfs_curfile++]; 112 fileDataSize = 0; 113 fileCreated = true; 114 } 115 116 /* Allocate new dataspace structure. */ 117 struct fs_dataspace* nds = dspace_alloc(&fileServ.dspaceTable, c->deathID, fileData, 118 (size_t) fileDataSize, O_RDONLY); 119 if (!nds) { 120 ROS_ERROR("data_open_handler failed to allocate dataspace."); 121 SET_ERRNO_PTR(rpc_errno, ENOMEM); 122 return 0; 123 } 124 nds->fileCreated = fileCreated; 125 126 dvprintf("%s file %s OK ID %d...\n", fileCreated ? "Created" : "Opened", rpc_name, nds->dID); 127 SET_ERRNO_PTR(rpc_errno, ESUCCESS); 128 assert(nds->dataspaceCap); 129 return nds->dataspaceCap; 130} 131 132refos_err_t 133data_close_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd) 134{ 135 struct srv_client *c = (struct srv_client *) rpc_userptr; 136 srv_msg_t *m = (srv_msg_t *) c->rpcClient.userptr; 137 assert(c->magic == FS_CLIENT_MAGIC); 138 139 /* Sanity check the dataspace cap. */ 140 if (seL4_MessageInfo_get_capsUnwrapped(m->message) != 0x00000001 || 141 seL4_MessageInfo_get_extraCaps(m->message) != 1) { 142 dprintf("data_close_handler EINVALIDPARAM: bad caps.\n"); 143 return EINVALIDPARAM; 144 } 145 146 if (!dspace_get_badge(&fileServ.dspaceTable, rpc_dspace_fd)) { 147 ROS_WARNING("data_close_handler: no such dataspace."); 148 return EINVALIDPARAM; 149 } 150 151 dprintf("Closing dataspace ID %d...\n", rpc_dspace_fd- FS_DSPACE_BADGE_BASE); 152 153 dspace_delete(&fileServ.dspaceTable, rpc_dspace_fd - FS_DSPACE_BADGE_BASE); 154 return ESUCCESS; 155} 156 157int 158data_read_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , uint32_t rpc_offset , 159 rpc_buffer_t rpc_buf , uint32_t rpc_count) 160{ 161 struct srv_client *c = (struct srv_client *) rpc_userptr; 162 srv_msg_t *m = (srv_msg_t *) c->rpcClient.userptr; 163 assert(c->magic == FS_CLIENT_MAGIC); 164 165 /* Sanity check the dataspace cap. */ 166 if (seL4_MessageInfo_get_capsUnwrapped(m->message) != 0x00000001 || 167 seL4_MessageInfo_get_extraCaps(m->message) != 1) { 168 dprintf("data_read_handler EINVALIDPARAM: bad caps.\n"); 169 return EINVALIDPARAM; 170 } 171 172 struct fs_dataspace* dspace = dspace_get_badge(&fileServ.dspaceTable, rpc_dspace_fd); 173 if (!dspace) { 174 ROS_WARNING("data_read_handler: no such dataspace."); 175 return 0; 176 } 177 assert(dspace->magic == FS_DATASPACE_MAGIC); 178 assert(dspace->fileData); 179 180 if (rpc_offset >= dspace->fileDataSize) { 181 return 0; 182 } 183 uint32_t count = MIN(dspace->fileDataSize - rpc_offset, rpc_buf.count); 184 memcpy(rpc_buf.data, dspace->fileData + rpc_offset, count); 185 return count; 186} 187 188int 189data_write_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , uint32_t rpc_offset , 190 rpc_buffer_t rpc_buf , uint32_t rpc_count) 191{ 192 struct srv_client *c = (struct srv_client *) rpc_userptr; 193 srv_msg_t *m = (srv_msg_t *) c->rpcClient.userptr; 194 assert(c->magic == FS_CLIENT_MAGIC); 195 196 /* Sanity check the dataspace cap. */ 197 if (seL4_MessageInfo_get_capsUnwrapped(m->message) != 0x00000001 || 198 seL4_MessageInfo_get_extraCaps(m->message) != 1) { 199 dprintf("data_write_handler EINVALIDPARAM: bad caps.\n"); 200 return -EINVALIDPARAM; 201 } 202 203 struct fs_dataspace* dspace = dspace_get_badge(&fileServ.dspaceTable, rpc_dspace_fd); 204 if (!dspace) { 205 ROS_WARNING("data_write_handler: no such dataspace."); 206 return 0; 207 } 208 assert(dspace->magic == FS_DATASPACE_MAGIC); 209 assert(dspace->fileData); 210 211 if (!dspace->fileCreated) { 212 /* Tried to write to a read only CPIO file. */ 213 ROS_WARNING("data_write_handler: Tried to write to a read only CPIO file %d.", dspace->dID); 214 return -EACCESSDENIED; 215 } 216 217 if (rpc_offset + rpc_buf.count > dspace->fileDataSize) { 218 if (rpc_offset + rpc_buf.count > CPIO_RAMFS_MAX_FILESSIZE) { 219 assert(!"File maxsize overflow."); 220 return -ENOMEM; 221 } 222 dspace->fileDataSize = rpc_offset + rpc_buf.count; 223 } 224 for (int i = 0; i < _ramfs_curfile; i++) { 225 if (_ramfs_archive[i] == dspace->fileData) { 226 _ramfs_filesz[i] = dspace->fileDataSize; 227 break; 228 } 229 } 230 memcpy(dspace->fileData + rpc_offset, rpc_buf.data, rpc_buf.count); 231 return rpc_buf.count; 232} 233 234int 235data_getc_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , int rpc_block) 236{ 237 assert(!"data_getc_handler not implemented"); 238 return EUNIMPLEMENTED; 239} 240 241off_t 242data_lseek_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , off_t rpc_offset , int rpc_whence) 243{ 244 assert(!"data_lseek_handler not implemented"); 245 return 0; 246} 247 248uint32_t 249data_get_size_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd) 250{ 251 struct srv_client *c = (struct srv_client *) rpc_userptr; 252 srv_msg_t *m = (srv_msg_t *) c->rpcClient.userptr; 253 assert(c->magic == FS_CLIENT_MAGIC); 254 255 /* Sanity check the dataspace cap. */ 256 if (seL4_MessageInfo_get_capsUnwrapped(m->message) != 0x00000001 || 257 seL4_MessageInfo_get_extraCaps(m->message) != 1) { 258 dprintf("data_get_size_handler EINVALIDPARAM: bad caps.\n"); 259 return 0; 260 } 261 262 struct fs_dataspace* dspace = dspace_get_badge(&fileServ.dspaceTable, rpc_dspace_fd); 263 if (!dspace) { 264 ROS_WARNING("data_get_size_handler: no such dataspace."); 265 return 0; 266 } 267 assert(dspace->magic == FS_DATASPACE_MAGIC); 268 269 return (uint32_t) dspace->fileDataSize; 270} 271 272refos_err_t 273data_expand_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , uint32_t rpc_size) 274{ 275 return EUNIMPLEMENTED; 276} 277 278refos_err_t 279data_datamap_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , seL4_CPtr rpc_memoryWindow , 280 uint32_t rpc_offset) 281{ 282 struct srv_client *c = (struct srv_client *) rpc_userptr; 283 srv_msg_t *m = (srv_msg_t *) c->rpcClient.userptr; 284 assert(c->magic == FS_CLIENT_MAGIC); 285 286 if (seL4_MessageInfo_get_extraCaps(m->message) != 2 || 287 !(seL4_MessageInfo_get_capsUnwrapped(m->message) & 0x00000001)) { 288 return EINVALIDPARAM; 289 } 290 291 /* Retrieve and validate dataspace badge. */ 292 seL4_Word dataspaceBadge = seL4_CapData_Badge_get_Badge(seL4_GetBadge(0)); 293 assert(dataspaceBadge == rpc_dspace_fd); 294 struct fs_dataspace* dspace = dspace_get_badge(&fileServ.dspaceTable, dataspaceBadge); 295 if (!dspace) { 296 ROS_ERROR("data_datamap_handler error: no such dataspace."); 297 return EINVALIDPARAM; 298 } 299 300 /* Copy out the memory window cap. Do not printf before the copyout. */ 301 seL4_CPtr memoryWindow = rpc_copyout_cptr(rpc_memoryWindow); 302 if (!memoryWindow) { 303 ROS_ERROR("data_datamap_handler error: invalid memory window."); 304 return EINVALIDPARAM; 305 } 306 307 /* Ask the process server to be the pager for this window. */ 308 seL4_Word winID; 309 int error = proc_register_as_pager(memoryWindow, fileServCommon->notifyClientFaultDeathAsyncEP, 310 &winID); 311 if (error != ESUCCESS) { 312 csfree(memoryWindow); 313 ROS_ERROR("data_datamap_handler error: failed to register as pager."); 314 return EINVALID; 315 } 316 317 /* Set up fileserver window ID bookkeeping. */ 318 dprintf("Associating dataspace %d --> windowID %d\n", dspace->dID, winID); 319 error = dspace_window_associate(&fileServ.dspaceTable, winID, dspace->dID, rpc_offset, 320 memoryWindow); 321 if (error != ESUCCESS) { 322 // TODO: proc_unregister_as_pager 323 csfree(memoryWindow); 324 return error; 325 } 326 327 return ESUCCESS; 328} 329 330refos_err_t 331data_dataunmap_handler(void *rpc_userptr , seL4_CPtr rpc_memoryWindow) 332{ 333 struct srv_client *c = (struct srv_client *) rpc_userptr; 334 srv_msg_t *m = (srv_msg_t *) c->rpcClient.userptr; 335 assert(c->magic == FS_CLIENT_MAGIC); 336 337 if (seL4_MessageInfo_get_extraCaps(m->message) != 1 || 338 !(seL4_MessageInfo_get_capsUnwrapped(m->message) & 0x00000001)) { 339 return EINVALIDPARAM; 340 } 341 342 /* Copy out the memory window cap. Do not printf before the copyout. */ 343 seL4_CPtr memoryWindow = rpc_copyout_cptr(rpc_memoryWindow); 344 if (!memoryWindow) { 345 ROS_ERROR("data_datamap_handler error: invalid memory window."); 346 return EINVALIDPARAM; 347 } 348 349 int winID = proc_window_getID(memoryWindow); 350 if (winID < 0) { 351 ROS_ERROR("data_datamap_handler error: invalid memory window ID."); 352 csfree(memoryWindow); 353 return EINVALIDPARAM; 354 } 355 356 // TODO: proc_unregister_as_pager 357 358 /* Clear any fileserver window ID bookkeeping. */ 359 dspace_window_unassociate(&fileServ.dspaceTable, winID); 360 csfree(memoryWindow); 361 return ESUCCESS; 362} 363 364refos_err_t 365data_init_data_handler(void *rpc_userptr , seL4_CPtr rpc_destDataspace , 366 seL4_CPtr rpc_srcDataspace , uint32_t rpc_srcDataspaceOffset) 367{ 368 struct srv_client *c = (struct srv_client *) rpc_userptr; 369 srv_msg_t *m = (srv_msg_t *) c->rpcClient.userptr; 370 assert(c->magic == FS_CLIENT_MAGIC); 371 372 if (seL4_MessageInfo_get_extraCaps(m->message) != 2 || 373 seL4_MessageInfo_get_capsUnwrapped(m->message) != 0x00000002) { 374 dvprintf("data_init_data_handler: invalid cap parameters: %d 0x%x !\n", 375 seL4_MessageInfo_get_extraCaps(m->message), 376 seL4_MessageInfo_get_capsUnwrapped(m->message)); 377 dvprintf("rpc_destDataspace %d rpc_srcDataspace %d\n", rpc_destDataspace, rpc_srcDataspace) 378 return EINVALIDPARAM; 379 } 380 381 /* Retrieve and validate dataspace badge. */ 382 struct fs_dataspace* dspace = dspace_get_badge(&fileServ.dspaceTable, rpc_srcDataspace); 383 if (!dspace) { 384 ROS_ERROR("data_init_data_handler error: no such dest dataspace."); 385 return EINVALIDPARAM; 386 } 387 388 /* Copyout the source dataspace cap. Do not printf before the copyout. */ 389 seL4_CPtr destDataspace = rpc_copyout_cptr(rpc_destDataspace); 390 if (!destDataspace) { 391 ROS_ERROR("data_init_data_handler error: could not copyout src dspace cap."); 392 return ENOMEM; 393 } 394 395 /* Notify process server that we want to provide data for this dataspace. */ 396 uint32_t dataID = (uint32_t) -1; 397 int error = data_have_data(REFOS_PROCSERV_EP, destDataspace, fileServCommon->notifyClientFaultDeathAsyncEP, &dataID); 398 if (error != ESUCCESS || dataID == -1) { 399 csfree_delete(destDataspace); 400 ROS_ERROR("data_init_data_handler error: data_have_data failed."); 401 return EINVALID; 402 } 403 404 /* Set up fileserver dataspace ID bookkeeping. */ 405 dprintf("Associating dataspace %d --> external dataspace %d\n", dspace->dID, dataID); 406 error = dspace_external_associate(&fileServ.dspaceTable, dataID, dspace->dID, 407 rpc_srcDataspaceOffset, destDataspace); 408 if (error != ESUCCESS) { 409 ROS_ERROR("Failed to associate dataspace."); 410 data_unhave_data(REFOS_PROCSERV_EP, destDataspace); 411 csfree_delete(destDataspace); 412 return error; 413 } 414 415 return ESUCCESS; 416} 417 418refos_err_t 419data_have_data_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , seL4_CPtr rpc_faultNotifyEP , 420 uint32_t* rpc_dataID) 421{ 422 ROS_WARNING("CPIO Fileserver does not support data_have_data!"); 423 return EUNIMPLEMENTED; 424} 425 426refos_err_t 427data_unhave_data_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd) 428{ 429 ROS_WARNING("CPIO Fileserver does not support data_unhave_data!"); 430 return EUNIMPLEMENTED; 431} 432 433refos_err_t 434data_provide_data_from_parambuffer_handler(void *rpc_userptr , seL4_CPtr rpc_dspace_fd , 435 uint32_t rpc_offset , uint32_t rpc_contentSize) 436{ 437 ROS_WARNING("CPIO Fileserver does not support data_provide_data!"); 438 return EUNIMPLEMENTED; 439} 440 441int 442check_dispatch_data(srv_msg_t *m, void **userptr) 443{ 444 if (m->badge == SRV_UNBADGED) { 445 return DISPATCH_PASS; 446 } 447 return check_dispatch_interface(m, userptr, RPC_DATA_LABEL_MIN, RPC_DATA_LABEL_MAX); 448} 449