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 <assert.h> 14#include <stdio.h> 15#include <stdint.h> 16#include <stdlib.h> 17#include <string.h> 18#include <sel4/sel4.h> 19 20#include <refos/refos.h> 21#include <refos/error.h> 22#include <refos-io/filetable.h> 23#include <refos-io/internal_state.h> 24#include <refos-rpc/serv_client.h> 25#include <refos-rpc/serv_client_helper.h> 26#include <refos-util/dprintf.h> 27 28#define FD_TABLE_DEFAULT_SIZE 1024 29#define FD_TABLE_ENTRY_TYPE_NONE 0 30#define FD_TABLE_ENTRY_TYPE_DATASPACE 1 31 32#define FD_TABLE_ENTRY_DATASPACE_MAGIC 0x4E6CC517 33#define FD_TABLE_DATASPACE_IPC_MAXLEN 32 34 35typedef struct fd_table_entry_dataspace_s { 36 char type; /* FD_TABLE_ENTRY_TYPE. Inherited, must be first. */ 37 int magic; 38 int fd; 39 40 serv_connection_t connection; 41 seL4_CPtr dspace; 42 int32_t dspacePos; 43 uint32_t dspaceSize; 44} fd_table_entry_dataspace_t; 45 46/* ----------------------------- Filetable OAT functions ---------------------------------------- */ 47 48static cvector_item_t 49filetable_oat_create(coat_t *oat, int id, uint32_t arg[COAT_ARGS]) 50{ 51 char type = (char) arg[0]; 52 cvector_item_t item = NULL; 53 54 fd_table_entry_dataspace_t *e = NULL; 55 56 switch (type) { 57 case FD_TABLE_ENTRY_TYPE_DATASPACE: 58 /* Allocate and set a new dataspace FD entry struct. */ 59 e = (fd_table_entry_dataspace_t*) malloc(sizeof(fd_table_entry_dataspace_t)); 60 if (e){ 61 memset(e, 0, sizeof(fd_table_entry_dataspace_t)); 62 e->type = type; 63 e->magic = FD_TABLE_ENTRY_DATASPACE_MAGIC; 64 e->fd = id; 65 } 66 item = (cvector_item_t) e; 67 break; 68 default: 69 printf("filetable_oat_create error: Unknown type.\n"); 70 break; 71 } 72 73 if (!item) { 74 printf("filetable_oat_create error: Could not allocate structure.\n"); 75 return NULL; 76 } 77 78 return item; 79} 80 81static void 82filetable_oat_delete(coat_t *oat, cvector_item_t *obj) 83{ 84 char type = *((char*) obj); 85 fd_table_entry_dataspace_t *e = NULL; 86 87 switch(type) { 88 case FD_TABLE_ENTRY_TYPE_DATASPACE: 89 e = (fd_table_entry_dataspace_t*) obj; 90 assert(e->type == FD_TABLE_ENTRY_TYPE_DATASPACE); 91 assert(e->magic == FD_TABLE_ENTRY_DATASPACE_MAGIC); 92 93 /* Delete dataspace. */ 94 if (e->connection.serverSession && e->dspace) { 95 refos_err_t error = data_close(e->connection.serverSession, e->dspace); 96 if (error != ESUCCESS) { 97 printf("filetable_oat_delete error: couldn't close dspace.\n"); 98 return; 99 } 100 csfree_delete(e->dspace); 101 e->dspace = 0; 102 } 103 104 /* Disconnect from server. */ 105 if (e->connection.serverSession) { 106 serv_disconnect(&e->connection); 107 e->connection.serverSession = 0; 108 } 109 110 e->magic = 0x0; 111 free(e); 112 break; 113 default: 114 printf("filetable_oat_delete error: Unknown type.\n"); 115 break; 116 } 117 118 return; 119} 120 121/* -------------------------- Filetable interface functions ------------------------------------- */ 122 123void 124filetable_init(fd_table_t *fdt, uint32_t tableSize) 125{ 126 assert(fdt); 127 fdt->magic = FD_TABLE_MAGIC; 128 fdt->tableSize = tableSize; 129 130 /* Initialise FD allocation table. */ 131 memset(&fdt->table, 0, sizeof(coat_t)); 132 fdt->table.oat_create = filetable_oat_create; 133 fdt->table.oat_delete = filetable_oat_delete; 134 coat_init(&fdt->table, FD_TABLE_BASE, tableSize); 135} 136 137void 138filetable_release(fd_table_t *fdt) 139{ 140 assert(fdt && fdt->magic == FD_TABLE_MAGIC); 141 coat_release(&fdt->table); 142 fdt->magic = 0x0; 143} 144 145int 146filetable_dspace_open(fd_table_t *fdt, char* filePath, int flags, int mode, int size) 147{ 148 assert(fdt && fdt->magic == FD_TABLE_MAGIC); 149 if (!filePath) { 150 return -EFILENOTFOUND; 151 } 152 153 int error = -EINVALID; 154 fd_table_entry_dataspace_t* e = NULL; 155 uint32_t arg[COAT_ARGS]; 156 arg[0] = FD_TABLE_ENTRY_TYPE_DATASPACE; 157 158 /* Allocate an ID, and the FD entry structure associated with it. */ 159 coat_alloc(&fdt->table, arg, (cvector_item_t *) &e); 160 if (!e) { 161 printf("filetable_open out of memory.\n"); 162 return -ENOMEM; 163 } 164 165 /* Connect to the dataspace server. */ 166 assert(e->magic == FD_TABLE_ENTRY_DATASPACE_MAGIC); 167 e->connection = serv_connect_no_pbuffer(filePath); 168 if (e->connection.error != ESUCCESS || !e->connection.serverSession) { 169 error = -ESERVERNOTFOUND; 170 goto exit1; 171 } 172 173 /* Open the dataspace on the server. */ 174 e->dspace = data_open(e->connection.serverSession, 175 e->connection.serverMountPoint.dspaceName, flags, mode, size, &error); 176 if (error || !e->dspace) { 177 error = -EFILENOTFOUND; 178 goto exit2; 179 } 180 181 e->dspaceSize = data_get_size(e->connection.serverSession, e->dspace); 182 e->dspacePos = 0; 183 return e->fd; 184 185 /* Exit stack. */ 186exit2: 187 serv_disconnect(&e->connection); 188exit1: 189 assert(e && e->fd); 190 coat_free(&fdt->table, e->fd); 191 assert(error < 0); 192 return error; 193} 194 195int 196filetable_close(fd_table_t *fdt, int fd) 197{ 198 assert(fdt && fdt->magic == FD_TABLE_MAGIC); 199 if (fd < FD_TABLE_BASE || fd >= fdt->tableSize) { 200 return -EFILENOTFOUND; 201 } 202 coat_free(&fdt->table, fd); 203 return ESUCCESS; 204} 205 206refos_err_t 207filetable_lseek(fd_table_t *fdt, int fd, int *offset, int whence) 208{ 209 /* because muslc can now call seek when closing a file, 210 fdt->magic may now be 0 here as well as FD_TABLE_MAGIC */ 211 assert(fdt && (fdt->magic == FD_TABLE_MAGIC || fdt->magic == 0)); 212 if (!offset) { 213 printf("filetable_lseek - NULL parameter.\n"); 214 return EINVALIDPARAM; 215 } 216 if (fd < FD_TABLE_BASE || fd >= fdt->tableSize) { 217 return EFILENOTFOUND; 218 } 219 220 /* Retrieve the file descr entry. */ 221 cvector_item_t entry = coat_get(&fdt->table, fd); 222 if (!entry) { 223 return EFILENOTFOUND; 224 } 225 char type = *((char*) entry); 226 227 /* lseek only support for dataspace entries. */ 228 if (type != FD_TABLE_ENTRY_TYPE_DATASPACE) { 229 assert(!"lseek for this type unimplemented."); 230 return EUNIMPLEMENTED; 231 } 232 233 fd_table_entry_dataspace_t *fdEntry = (fd_table_entry_dataspace_t*) entry; 234 assert(fdEntry->magic == FD_TABLE_ENTRY_DATASPACE_MAGIC); 235 236 switch(whence) { 237 case SEEK_SET: 238 fdEntry->dspacePos = (*offset); 239 break; 240 case SEEK_CUR: 241 fdEntry->dspacePos += (*offset); 242 break; 243 case SEEK_END: 244 fdEntry->dspacePos = fdEntry->dspaceSize + (*offset); 245 break; 246 default: 247 return EINVALIDPARAM; 248 } 249 250 if (fdEntry->dspacePos < 0) { 251 fdEntry->dspacePos = 0; 252 } 253 if (fdEntry->dspacePos > fdEntry->dspaceSize) { 254 fdEntry->dspacePos = fdEntry->dspaceSize; 255 } 256 257 (*offset) = fdEntry->dspacePos; 258 return ESUCCESS; 259} 260 261static int 262filetable_internal_read_write(fd_table_t *fdt, int fd, char *buffer, int bufferLen, bool read) 263{ 264 assert(fdt && fdt->magic == FD_TABLE_MAGIC); 265 if (!buffer || !bufferLen) { 266 ROS_SET_ERRNO(ESUCCESS); 267 return 0; 268 } 269 if (fd < FD_TABLE_BASE || fd >= fdt->tableSize) { 270 ROS_SET_ERRNO(EFILENOTFOUND); 271 return -EFILENOTFOUND; 272 } 273 274 /* Retrieve the file descr entry. */ 275 cvector_item_t entry = coat_get(&fdt->table, fd); 276 if (!entry) { 277 ROS_SET_ERRNO(EFILENOTFOUND); 278 return -EFILENOTFOUND; 279 } 280 char type = *((char*) entry); 281 282 /* Read / write only supported for dataspace entries. */ 283 if (type != FD_TABLE_ENTRY_TYPE_DATASPACE) { 284 assert(!"read / write for this type unimplemented."); 285 ROS_SET_ERRNO(EUNIMPLEMENTED); 286 return -EUNIMPLEMENTED; 287 } 288 289 fd_table_entry_dataspace_t *fdEntry = (fd_table_entry_dataspace_t*) entry; 290 assert(fdEntry->magic == FD_TABLE_ENTRY_DATASPACE_MAGIC); 291 292 /* Cap length so we don't overrun IPC buffer. 293 Currently read / write is implemented over IPC, and this is inefficient and somewhat hacky. 294 In the future, file read / write using mapped shared memory should be implemented. 295 */ 296 if (bufferLen > FD_TABLE_DATASPACE_IPC_MAXLEN) { 297 bufferLen = FD_TABLE_DATASPACE_IPC_MAXLEN; 298 } 299 300 /* Perform the actual dataspace read / write operation. */ 301 assert(fdEntry->dspace); 302 int nr = -EINVALID; 303 if (read) { 304 nr = data_read(fdEntry->connection.serverSession, fdEntry->dspace, fdEntry->dspacePos, 305 buffer, bufferLen); 306 } else { 307 nr = data_write(fdEntry->connection.serverSession, fdEntry->dspace, fdEntry->dspacePos, 308 buffer, bufferLen); 309 } 310 if (nr < 0) { 311 ROS_SET_ERRNO(-nr); 312 return nr; 313 } 314 315 /* Shift the dataspace position offset. */ 316 fdEntry->dspacePos += nr; 317 if (fdEntry->dspacePos < 0) { 318 fdEntry->dspacePos = 0; 319 } 320 if (read) { 321 if (fdEntry->dspacePos > fdEntry->dspaceSize) { 322 fdEntry->dspacePos = fdEntry->dspaceSize; 323 } 324 } else { 325 fdEntry->dspaceSize = data_get_size(fdEntry->connection.serverSession, fdEntry->dspace); 326 } 327 328 ROS_SET_ERRNO(ESUCCESS); 329 return nr; 330} 331 332int 333filetable_read(fd_table_t *fdt, int fd, char *bufferDest, int bufferLen) 334{ 335 return filetable_internal_read_write(fdt, fd, bufferDest, bufferLen, true); 336} 337 338int 339filetable_write(fd_table_t *fdt, int fd, char *bufferSrc, int bufferLen) 340{ 341 return filetable_internal_read_write(fdt, fd, bufferSrc, bufferLen, false); 342} 343 344seL4_CPtr 345filetable_dspace_get(fd_table_t *fdt, int fd) 346{ 347 assert(fdt && fdt->magic == FD_TABLE_MAGIC); 348 if (fd < FD_TABLE_BASE || fd >= fdt->tableSize) { 349 ROS_SET_ERRNO(EFILENOTFOUND); 350 return -EFILENOTFOUND; 351 } 352 353 /* Retrieve the file descr entry. */ 354 cvector_item_t entry = coat_get(&fdt->table, fd); 355 if (!entry) { 356 ROS_SET_ERRNO(EFILENOTFOUND); 357 return -EFILENOTFOUND; 358 } 359 char type = *((char*) entry); 360 361 /* Read / write only supported for dataspace entries. */ 362 if (type != FD_TABLE_ENTRY_TYPE_DATASPACE) { 363 assert(!"dspace_get for this type unsupported."); 364 ROS_SET_ERRNO(EUNIMPLEMENTED); 365 return -EUNIMPLEMENTED; 366 } 367 368 fd_table_entry_dataspace_t *fdEntry = (fd_table_entry_dataspace_t*) entry; 369 assert(fdEntry->magic == FD_TABLE_ENTRY_DATASPACE_MAGIC); 370 return fdEntry->dspace; 371} 372 373/* ----------------------- Refos IO default filetable functions --------------------------------- */ 374 375void 376filetable_init_default(void) 377{ 378 filetable_init(&refosIOState.fdTable, FD_TABLE_DEFAULT_SIZE); 379} 380 381void 382filetable_deinit_default(void) 383{ 384 filetable_release(&refosIOState.fdTable); 385} 386