SNSS_RETURN_CODE SNSS_CloseFile (SNSS_FILE **snssFile) { int prevLoc; SNSS_RETURN_CODE code; /* file was never open, so this should indicate success- kinda. */ if (NULL == *snssFile) return SNSS_OK; if (SNSS_OPEN_WRITE == (*snssFile)->mode) { prevLoc = vfs_tell((*snssFile)->fp); vfs_seek((*snssFile)->fp, 0, VFS_SEEK_SET); /* write the header again to get block count correct */ if (SNSS_OK != (code = SNSS_WriteFileHeader(*snssFile))) return SNSS_CLOSE_FAILED; vfs_seek((*snssFile)->fp, prevLoc, VFS_SEEK_SET); } vfs_close ((*snssFile)->fp); NES_FREE(*snssFile); *snssFile = NULL; return SNSS_OK; }
///////////////////////////////////////////////////////////////////// // Mapper 20 bool NES_mapper20::initialize (NES *parent, NES_PPU *ppu) { hfile_t fp = NULL; uint8 header[16]; if (!(NES_mapper::initialize (parent, ppu))) goto error; fp = vfs_open (parent->disksys_rom_filename, VFS_READ); if (!fp) { ERROR("no disksys.rom"); ERROR(parent->disksys_rom_filename); goto error; } if (vfs_read(header, sizeof(header), 1, fp) != sizeof(header)) goto error; if (!NES_MEMCMP (header, "NES", 3)) vfs_seek(fp, 0x6010, VFS_SEEK_SET); else vfs_seek(fp, 0, VFS_SEEK_SET); if (vfs_read(bios, 0x2000, 1, fp) != 0x2000) goto error; vfs_close(fp); return true; error: if (fp) vfs_close(fp); return false; }
struct VFS_HANDLE * vfs_open( char * filename, int mode ) { struct VFS_HANDLE * handle; struct VFS_MOUNTPOINT * mount; char name[VFS_MAXFILENAME], * name_ptr; // copy the name so we can modify it name_ptr = (char *)&name; strcpy( name_ptr, filename ); // find the correct mountpoint for this file mount = vfs_file2mountpoint( name_ptr ); if( mount == NULL ) return NULL; // advance the filname past the mount point name_ptr = (char *)( name_ptr + strlen(mount->mountpoint) ); // call the file system driver to open if( mount->fs->calltable.open == NULL ) return NULL; // create the new virtual file handle handle = (struct VFS_HANDLE *)mm_kmalloc( sizeof(struct VFS_HANDLE) ); handle->mount = mount; handle->mode = mode; // try to open the file on the mounted file system if( mount->fs->calltable.open( handle, name_ptr ) != NULL ) { // set the file position to the end of the file if in append mode if( (handle->mode & VFS_MODE_APPEND) == VFS_MODE_APPEND ) vfs_seek( handle, 0, VFS_SEEK_END ); return handle; } else { // if we fail to open the file but are in create mode, we can create the file // TO-DO: test the failed open() result for a value like FILE_NOT_FOUND // otherwise we could end up in an infinite recurive loop if( (handle->mode & VFS_MODE_CREATE) == VFS_MODE_CREATE ) { if( mount->fs->calltable.create != NULL ) { // try to create it name_ptr = (char *)&name; strcpy( name_ptr, filename ); name_ptr = (char *)( name_ptr + strlen(mount->mountpoint) ); if( mount->fs->calltable.create( mount, name_ptr ) != FAIL ) { if( mount->fs->calltable.open( handle, name_ptr ) != NULL ) { if( (handle->mode & VFS_MODE_APPEND) == VFS_MODE_APPEND ) vfs_seek( handle, 0, VFS_SEEK_END ); return handle; } } } } } // if we fail, free the handle and return NULL mm_kfree( handle ); return NULL; }
// Kludge to push changes in VFS memobj back out to disk errval_t memobj_flush_vfs(struct memobj *memobj, struct vregion *vregion) { errval_t err; assert(memobj->type == MEMOBJ_VFS); struct memobj_vfs *mv = (struct memobj_vfs *)memobj; struct vspace *vspace = vregion_get_vspace(vregion); struct pmap *pmap = vspace_get_pmap(vspace); genvaddr_t vregion_base = vregion_get_base_addr(vregion); lvaddr_t vregion_lbase = vspace_genvaddr_to_lvaddr(vregion_base); genvaddr_t vregion_off = vregion_get_offset(vregion); assert(vregion_off == 0); // not sure if we handle this correctly /* TODO: mv->size instead of BASE_PAGE_SIZE?*/ for (genvaddr_t off = 0; off < mv->filesize ; off += BASE_PAGE_SIZE){ genvaddr_t retvaddr; size_t retsize; vregion_flags_t retflags; // For each page check if it's in memory err = pmap->f.lookup(pmap, vregion_base + off, &retvaddr, &retsize, NULL, NULL, &retflags); if (err_is_fail(err)) { continue; // Page not in memory #if 0 /* this optimisation may not be correct if flags were changed -AB */ } else if ((retflags & VREGION_FLAGS_WRITE) == 0) { continue; // Not writable #endif } //TRACE("Flushing page at address: %lx\n", vregion_base + off); // seek file handle err = vfs_seek(mv->vh, VFS_SEEK_SET, off + mv->offset); if (err_is_fail(err)) { return err; } // write contents to file size_t rsize, pos = 0; size_t nbytes = mv->filesize - off; if (nbytes > BASE_PAGE_SIZE) { nbytes = BASE_PAGE_SIZE; } do { err = vfs_write(mv->vh, (char *)vregion_lbase + off + pos, nbytes - pos, &rsize); if (err_is_fail(err)) { return err; } pos += rsize; } while(rsize > 0 && pos < nbytes); assert(pos==nbytes); } return SYS_ERR_OK; }
SNSS_RETURN_CODE SNSS_SkipNextBlock (SNSS_FILE *snssFile) { SnssBlockHeader header; if (SNSS_ReadBlockHeader (&header, snssFile) != SNSS_OK) return SNSS_READ_FAILED; vfs_seek (snssFile->fp, header.blockLength, VFS_SEEK_CUR); return SNSS_OK; }
SNSS_RETURN_CODE SNSS_GetNextBlockType (SNSS_BLOCK_TYPE *blockType, SNSS_FILE *snssFile) { char tagBuffer[TAG_LENGTH + 1]; int pos = vfs_tell(snssFile->fp); if (vfs_read (tagBuffer, TAG_LENGTH, 1, snssFile->fp) != TAG_LENGTH) return SNSS_READ_FAILED; tagBuffer[TAG_LENGTH] = '\0'; /* reset the file pointer to the start of the block */ vfs_seek (snssFile->fp, -TAG_LENGTH, VFS_SEEK_CUR); if (pos != vfs_tell(snssFile->fp)) return SNSS_READ_FAILED; /* figure out which type of block it is */ if (strcmp (tagBuffer, "BASR") == 0) { *blockType = SNSS_BASR; return SNSS_OK; } else if (strcmp (tagBuffer, "VRAM") == 0) { *blockType = SNSS_VRAM; return SNSS_OK; } else if (strcmp (tagBuffer, "SRAM") == 0) { *blockType = SNSS_SRAM; return SNSS_OK; } else if (strcmp (tagBuffer, "MPRD") == 0) { *blockType = SNSS_MPRD; return SNSS_OK; } else if (strcmp (tagBuffer, "CNTR") == 0) { *blockType = SNSS_CNTR; return SNSS_OK; } else if (strcmp (tagBuffer, "SOUN") == 0) { *blockType = SNSS_SOUN; return SNSS_OK; } else { *blockType = SNSS_UNKNOWN_BLOCK; return SNSS_OK; } }
off_t vfsfd_lseek(int fd, off_t offset, int whence) { struct fdtab_entry *e = fdtab_get(fd); switch(e->type) { case FDTAB_TYPE_FILE: { enum vfs_seekpos vfs_whence; errval_t err; size_t retpos; switch(whence) { case SEEK_SET: vfs_whence = VFS_SEEK_SET; break; case SEEK_CUR: vfs_whence = VFS_SEEK_CUR; break; case SEEK_END: vfs_whence = VFS_SEEK_END; break; default: return -1; } err = vfs_seek((vfs_handle_t)e->handle, vfs_whence, offset); if(err_is_fail(err)) { DEBUG_ERR(err, "vfs_seek"); return -1; } err = vfs_tell((vfs_handle_t)e->handle, &retpos); if(err_is_fail(err)) { DEBUG_ERR(err, "vfs_tell"); return -1; } VFSFD_DEBUG("lseek(%d, %lld, %d) = %lu\n", fd, offset, whence, retpos); return retpos; } break; default: return -1; } }
int syscall_seek(openfile_t file, int position) { int result = vfs_seek(file - 2, position); if (result < 0) { switch(result) { case VFS_UNUSABLE: kprintf("Error seeking in file. File system unusable.\n"); break; case VFS_INVALID_PARAMS: kprintf("Error seeking in file: Invalid params\n"); break; case VFS_NOT_OPEN: kprintf("Error seeking in file: File not open\n"); break; default: kprintf("Error seeking in file: unknown error\n"); break; } } return result; }
int vfs_write( struct VFS_HANDLE * handle, BYTE * buffer, DWORD size ) { int ret; if( handle == NULL ) return FAIL; // test if the file ha been opened in read mode first if( (handle->mode & VFS_MODE_WRITE) != VFS_MODE_WRITE ) return FAIL; // try to call the file system driver to write if( handle->mount->fs->calltable.write != NULL ) { ret = handle->mount->fs->calltable.write( handle, buffer, size ); if( ret != FAIL ) { // set the file position to the end of the file if in append mode if( (handle->mode & VFS_MODE_APPEND) == VFS_MODE_APPEND ) vfs_seek( handle, 0, VFS_SEEK_END ); // return the write result return ret; } } // if we get here we have failed return FAIL; }
//-------------------------------------------------------------------------------------------- pip_t * load_one_pip_file_vfs( const char *szLoadName, pip_t * ppip ) { /// @details ZZ@> This function loads a particle template, returning bfalse if the file wasn't /// found vfs_FILE* fileread; IDSZ idsz; char cTmp; fileread = vfs_openRead( szLoadName ); if ( NULL == fileread ) { return NULL; } pip_init( ppip ); // set up the EGO_PROFILE_STUFF strncpy( ppip->name, szLoadName, SDL_arraysize( ppip->name ) ); ppip->loaded = btrue; // read the 1 line comment at the top of the file vfs_gets( ppip->comment, SDL_arraysize( ppip->comment ) - 1, fileread ); // rewind the file vfs_seek( fileread, 0 ); // General data ppip->force = fget_next_bool( fileread ); cTmp = fget_next_char( fileread ); if ( 'L' == toupper( cTmp ) ) ppip->type = SPRITE_LIGHT; else if ( 'S' == toupper( cTmp ) ) ppip->type = SPRITE_SOLID; else if ( 'T' == toupper( cTmp ) ) ppip->type = SPRITE_ALPHA; ppip->image_base = fget_next_int( fileread ); ppip->numframes = fget_next_int( fileread ); ppip->image_add.base = fget_next_int( fileread ); ppip->image_add.rand = fget_next_int( fileread ); ppip->rotate_pair.base = fget_next_int( fileread ); ppip->rotate_pair.rand = fget_next_int( fileread ); ppip->rotate_add = fget_next_int( fileread ); ppip->size_base = fget_next_int( fileread ); ppip->size_add = fget_next_int( fileread ); ppip->spdlimit = fget_next_float( fileread ); ppip->facingadd = fget_next_int( fileread ); // override the base rotation if ( ppip->image_base < 256 && prt_u != prt_direction[ ppip->image_base ] ) { ppip->rotate_pair.base = prt_direction[ ppip->image_base ]; }; // Ending conditions ppip->end_water = fget_next_bool( fileread ); ppip->end_bump = fget_next_bool( fileread ); ppip->end_ground = fget_next_bool( fileread ); ppip->end_lastframe = fget_next_bool( fileread ); ppip->end_time = fget_next_int( fileread ); // Collision data ppip->dampen = fget_next_float( fileread ); ppip->bump_money = fget_next_int( fileread ); ppip->bump_size = fget_next_int( fileread ); ppip->bump_height = fget_next_int( fileread ); fget_next_range( fileread, &( ppip->damage ) ); ppip->damagetype = fget_next_damage_type( fileread ); // Lighting data cTmp = fget_next_char( fileread ); if ( 'T' == toupper( cTmp ) ) ppip->dynalight.mode = DYNA_MODE_ON; else if ( 'L' == toupper( cTmp ) ) ppip->dynalight.mode = DYNA_MODE_LOCAL; else ppip->dynalight.mode = DYNA_MODE_OFF; ppip->dynalight.level = fget_next_float( fileread ); ppip->dynalight.falloff = fget_next_int( fileread ); // Initial spawning of this particle ppip->facing_pair.base = fget_next_int( fileread ); ppip->facing_pair.rand = fget_next_int( fileread ); ppip->spacing_hrz_pair.base = fget_next_int( fileread ); ppip->spacing_hrz_pair.rand = fget_next_int( fileread ); ppip->spacing_vrt_pair.base = fget_next_int( fileread ); ppip->spacing_vrt_pair.rand = fget_next_int( fileread ); ppip->vel_hrz_pair.base = fget_next_int( fileread ); ppip->vel_hrz_pair.rand = fget_next_int( fileread ); ppip->vel_vrt_pair.base = fget_next_int( fileread ); ppip->vel_vrt_pair.rand = fget_next_int( fileread ); // Continuous spawning of other particles ppip->contspawn_delay = fget_next_int( fileread ); ppip->contspawn_amount = fget_next_int( fileread ); ppip->contspawn_facingadd = fget_next_int( fileread ); ppip->contspawn_lpip = fget_next_int( fileread ); // End spawning of other particles ppip->endspawn_amount = fget_next_int( fileread ); ppip->endspawn_facingadd = fget_next_int( fileread ); ppip->endspawn_lpip = fget_next_int( fileread ); // Bump spawning of attached particles ppip->bumpspawn_amount = fget_next_int( fileread ); ppip->bumpspawn_lpip = fget_next_int( fileread ); // Random stuff !!!BAD!!! Not complete ppip->daze_time = fget_next_int( fileread ); ppip->grog_time = fget_next_int( fileread ); ppip->spawnenchant = fget_next_bool( fileread ); ppip->cause_roll = fget_next_bool( fileread ); // !!Cause roll ppip->cause_pancake = fget_next_bool( fileread ); ppip->needtarget = fget_next_bool( fileread ); ppip->targetcaster = fget_next_bool( fileread ); ppip->startontarget = fget_next_bool( fileread ); ppip->onlydamagefriendly = fget_next_bool( fileread ); ppip->soundspawn = fget_next_int( fileread ); ppip->end_sound = fget_next_int( fileread ); ppip->friendlyfire = fget_next_bool( fileread ); ppip->hateonly = fget_next_bool( fileread ); ppip->newtargetonspawn = fget_next_bool( fileread ); ppip->targetangle = fget_next_int( fileread ) >> 1; ppip->homing = fget_next_bool( fileread ); ppip->homingfriction = fget_next_float( fileread ); ppip->homingaccel = fget_next_float( fileread ); ppip->rotatetoface = fget_next_bool( fileread ); goto_colon( NULL, fileread, bfalse ); // !!Respawn on hit is unused ppip->manadrain = fget_next_int( fileread ) * 256; ppip->lifedrain = fget_next_int( fileread ) * 256; // assume default end_wall ppip->end_wall = ppip->end_ground; // assume default damfx if ( ppip->homing ) ppip->damfx = DAMFX_NONE; // Read expansions while ( goto_colon( NULL, fileread, btrue ) ) { idsz = fget_idsz( fileread ); if ( idsz == MAKE_IDSZ( 'T', 'U', 'R', 'N' ) ) SET_BIT( ppip->damfx, DAMFX_NONE ); //ZF> This line doesnt do anything? else if ( idsz == MAKE_IDSZ( 'A', 'R', 'M', 'O' ) ) SET_BIT( ppip->damfx, DAMFX_ARMO ); else if ( idsz == MAKE_IDSZ( 'B', 'L', 'O', 'C' ) ) SET_BIT( ppip->damfx, DAMFX_NBLOC ); else if ( idsz == MAKE_IDSZ( 'A', 'R', 'R', 'O' ) ) SET_BIT( ppip->damfx, DAMFX_ARRO ); else if ( idsz == MAKE_IDSZ( 'T', 'I', 'M', 'E' ) ) SET_BIT( ppip->damfx, DAMFX_TIME ); else if ( idsz == MAKE_IDSZ( 'Z', 'S', 'P', 'D' ) ) ppip->zaimspd = fget_float( fileread ); else if ( idsz == MAKE_IDSZ( 'F', 'S', 'N', 'D' ) ) ppip->end_sound_floor = fget_int( fileread ); else if ( idsz == MAKE_IDSZ( 'W', 'S', 'N', 'D' ) ) ppip->end_sound_wall = fget_int( fileread ); else if ( idsz == MAKE_IDSZ( 'W', 'E', 'N', 'D' ) ) ppip->end_wall = ( 0 != fget_int( fileread ) ); else if ( idsz == MAKE_IDSZ( 'P', 'U', 'S', 'H' ) ) ppip->allowpush = ( 0 != fget_int( fileread ) ); else if ( idsz == MAKE_IDSZ( 'D', 'L', 'E', 'V' ) ) ppip->dynalight.level_add = fget_int( fileread ) / 1000.0f; else if ( idsz == MAKE_IDSZ( 'D', 'R', 'A', 'D' ) ) ppip->dynalight.falloff_add = fget_int( fileread ) / 1000.0f; else if ( idsz == MAKE_IDSZ( 'I', 'D', 'A', 'M' ) ) ppip->intdamagebonus = ( 0 != fget_int( fileread ) ); else if ( idsz == MAKE_IDSZ( 'W', 'D', 'A', 'M' ) ) ppip->wisdamagebonus = ( 0 != fget_int( fileread ) ); else if ( idsz == MAKE_IDSZ( 'O', 'R', 'N', 'T' ) ) { char cTmp = fget_first_letter( fileread ); switch ( toupper( cTmp ) ) { case 'X': ppip->orientation = ORIENTATION_X; break; // put particle up along the world or body-fixed x-axis case 'Y': ppip->orientation = ORIENTATION_Y; break; // put particle up along the world or body-fixed y-axis case 'Z': ppip->orientation = ORIENTATION_Z; break; // put particle up along the world or body-fixed z-axis case 'V': ppip->orientation = ORIENTATION_V; break; // vertical, like a candle case 'H': ppip->orientation = ORIENTATION_H; break; // horizontal, like a plate case 'B': ppip->orientation = ORIENTATION_B; break; // billboard } } } vfs_close( fileread ); return ppip; }
static int rand_bench_time(char *target, uint8_t *buffer, size_t filesize, size_t blocksize, size_t count, size_t randval, struct bench_res *result) { size_t randbit; size_t rsize = 0; size_t wsize = 0; int ret = 0; #define RAND_NEXT do {\ randbit = ((randval >> 0) ^ (randval >> 3)) & 1;\ randval = (randval >> 1) | (randbit << (sizeof(size_t) * CHAR_BIT - 1));\ } while (0) #define RAND_BLOCK ((randval % (filesize / blocksize)) * blocksize) if (filesize % blocksize != 0) { printf("Please spcifiy the filesize as a multiple of blocksize\n"); return 0; } errval_t err; vfs_handle_t f = NULL; char *path = vfs_path_mkabsolute(cwd, target); err = vfs_open(path, &f); if (err_is_fail(err)) { printf("%s: %s\n", path, err_getstring(err)); return 1; } #if defined(__x86_64__) || defined(__i386__) uint64_t tscperms; err = sys_debug_get_tsc_per_ms(&tscperms); assert(err_is_ok(err)); //printf("ticks per millisec: %" PRIu64 "\n", tscperms); uint64_t start = rdtsc(); #endif size_t count2 = count; while (count2--) { RAND_NEXT; vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK); err = vfs_read(f, buffer, blocksize, &rsize); if (err_is_fail(err)) { DEBUG_ERR(err, "error reading file"); ret = 1; goto out; } assert(rsize == blocksize); } #if defined(__x86_64__) || defined(__i386__) uint64_t stop = rdtsc(); uint64_t elapsed_msecs = ((stop - start) / tscperms); double elapsed_secs = (double)elapsed_msecs/1000.0; result->read = elapsed_secs; start = rdtsc(); #endif count2 = count; while(count2--) { RAND_NEXT; vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK); err = vfs_write(f, buffer, blocksize, &wsize); if (err_is_fail(err) || wsize == 0) { DEBUG_ERR(err, "error writing file"); ret = 1; goto out; } assert(wsize == blocksize); vfs_flush(f); } #if defined(__x86_64__) || defined(__i386__) stop = rdtsc(); elapsed_msecs = ((stop - start) / tscperms); elapsed_secs = (double)elapsed_msecs/1000.0; result->write = elapsed_secs; #endif out: if (f != NULL) { err = vfs_close(f); if (err_is_fail(err)) { DEBUG_ERR(err, "in vfs_close"); } } return ret; }
static int shuffle_file(int argc, char *argv[]) { if (argc != 6) { printf("Usage: %s <file> <filesize> <blocksize> <count> <seed>\n", argv[0]); return 0; } size_t filesize = atoi(argv[2]); size_t blocksize = atoi(argv[3]); size_t count = atoi(argv[4]); size_t randval = atoi(argv[5]); size_t randbit; char * filename = argv[1]; size_t rsize = 0; size_t wsize = 0; int ret = 0; #define RAND_NEXT do {\ randbit = ((randval >> 0) ^ (randval >> 3)) & 1;\ randval = (randval >> 1) | (randbit << (sizeof(size_t) * CHAR_BIT - 1));\ } while (0) #define RAND_BLOCK ((randval % (filesize / blocksize)) * blocksize) if (filesize % blocksize != 0) { printf("Please spcifiy the filesize as a multiple of blocksize\n"); return 0; } uint8_t * buffer = malloc(blocksize); if (buffer == NULL) { printf("failed to allocate buffer of size %zd\n", blocksize); return 1; } errval_t err; vfs_handle_t f = NULL; char *path = vfs_path_mkabsolute(cwd, filename); err = vfs_open(path, &f); if (err_is_fail(err)) { printf("%s: %s\n", path, err_getstring(err)); return 1; } #if defined(__x86_64__) || defined(__i386__) uint64_t tscperms; err = sys_debug_get_tsc_per_ms(&tscperms); assert(err_is_ok(err)); //printf("ticks per millisec: %" PRIu64 "\n", tscperms); uint64_t start = rdtsc(); #endif size_t count2 = count; while (count2--) { RAND_NEXT; vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK); err = vfs_read(f, buffer, blocksize, &rsize); if (err_is_fail(err)) { DEBUG_ERR(err, "error reading file"); ret = 1; goto out; } assert(rsize == blocksize); RAND_NEXT; vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK); err = vfs_write(f, buffer, blocksize, &wsize); if (err_is_fail(err) || wsize == 0) { DEBUG_ERR(err, "error writing file"); ret = 1; goto out; } assert(wsize == blocksize); } #if defined(__x86_64__) || defined(__i386__) uint64_t stop = rdtsc(); uint64_t elapsed_msecs = ((stop - start) / tscperms); double elapsed_secs = (double)elapsed_msecs/1000.0; printf("start: %" PRIu64 " stop: %" PRIu64 "\n", start, stop); double kbps = ((double)(count * blocksize) / 1024.0) / elapsed_secs; printf("%zu bytes read. %zu bytes written. %f s, %f kB/s\n", count * blocksize, count * blocksize, elapsed_secs, kbps); #endif out: if (buffer != NULL) free(buffer); if (f != NULL) { err = vfs_close(f); if (err_is_fail(err)) { DEBUG_ERR(err, "in vfs_close"); } } return ret; }
static errval_t fill_bench(char *target, uint8_t *buffer, size_t blocksize, size_t count, struct bench_res *result) { vfs_handle_t target_vh = NULL; size_t blocks_written = 0; size_t blocks_read = 0; size_t total_bytes_read = 0; size_t total_bytes_written = 0; uint64_t start = 0, stop = 0; errval_t err; #if defined(__x86_64__) || defined(__i386__) uint64_t tscperms; err = sys_debug_get_tsc_per_ms(&tscperms); assert(err_is_ok(err)); #endif errval_t ret = 0; err = vfs_open(target, &target_vh); if (err_is_fail(err)) { printf("%s: %s (%ld)\n", target, err_getstring(err), err); return err; } #if defined(__x86_64__) || defined(__i386__) start = rdtsc(); #endif if (buffer == NULL) { ret = -2; printf("failed to allocate buffer of size %zd\n", blocksize); goto out; } size_t wsize; do { // initialize buffer for (size_t i = 0; i < blocksize; i += sizeof(size_t)) *((size_t *)(buffer + i)) = blocks_written; // write to file size_t wpos = 0; while (wpos < blocksize) { if (wpos > 0) printf("was unable to write the whole chunk of size %zd. Now at pos: %zd of buffer\n", blocksize, wpos); err = vfs_write(target_vh, &buffer[wpos], blocksize - wpos, &wsize); if (err_is_fail(err) || wsize == 0) { DEBUG_ERR(err, "error writing file"); ret = err; goto out; } wpos += wsize; total_bytes_written += wsize; } blocks_written++; } while (blocksize > 0 && !(count > 0 && blocks_written >= count)); err = vfs_close(target_vh); if (err_is_fail(err)) { DEBUG_ERR(err, "in vfs_close"); goto out; } #if defined(__x86_64__) || defined(__i386__) stop = rdtsc(); { uint64_t elapsed_msecs = ((stop - start) / tscperms); double elapsed_secs = (double)elapsed_msecs/1000.0; result->write = ((double)total_bytes_written / 1024.0) / elapsed_secs; printf("%lf\n", result->write); } #endif err = vfs_open(target, &target_vh); if (err_is_fail(err)) { printf("%s: %s (%ld)\n", target, err_getstring(err), err); goto out; } err = vfs_seek(target_vh, VFS_SEEK_SET, 0); if (err_is_fail(err)) { DEBUG_ERR(err, "seeking failed"); ret = err; goto out; } #if defined(__x86_64__) || defined(__i386__) start = rdtsc(); #endif size_t rsize; do { // read size_t rpos = 0; while (rpos < blocksize) { if (rpos > 0) printf("was unable to read whole chunk of size %zd. Now at pos: %zd of buffer\n", blocksize, rpos); err = vfs_read(target_vh, &buffer[rpos], blocksize - rpos, &rsize); if (err_is_fail(err) || wsize == 0) { DEBUG_ERR(err, "error reading file"); ret = err; goto out; } rpos += rsize; total_bytes_read += rsize; } // verify data for (size_t i = 0; i < blocksize; i += sizeof(size_t)) { if (*((size_t *)(buffer + i)) != blocks_read) { printf("Verification failed! Block %zd, value %zd\n", blocks_read, *((size_t *)(buffer + i)) ); ret = err; goto out; } } blocks_read++; } while (blocksize > 0 && !(count > 0 && blocks_read >= count)); out: if (target_vh != NULL) { err = vfs_close(target_vh); if (err_is_fail(err)) { DEBUG_ERR(err, "in vfs_close"); ret = err; } } #if defined(__x86_64__) || defined(__i386__) stop = rdtsc(); { uint64_t elapsed_msecs = ((stop - start) / tscperms); double elapsed_secs = (double)elapsed_msecs/1000.0; result->read = ((double)total_bytes_read / 1024.0) / elapsed_secs; printf("%lf\n", result->read); } #endif return ret; }
/** * Parse useful information from a given ELF file into the ELF info * structure. * * @param file The ELF file * * @param elf Information found in the file is returned in this * structure. In case of error this structure may contain arbitrary * values. * * @return 0 on failure, other values indicate success. */ int elf_parse_header(elf_info_t *elf, openfile_t file) { Elf32_Ehdr elf_hdr; Elf64_Ehdr elf_hdr64; Elf32_Phdr program_hdr; Elf64_Phdr program_hdr64; uint8_t use64 = 0; int i; int current_position; int segs = 0; #define SEG_RO 1 #define SEG_RW 2 /* Read the ELF header into the 32 bit, but size of 64 */ if (vfs_read(file, &elf_hdr64, sizeof(elf_hdr64)) != sizeof(elf_hdr64)) { return -1; } /* Nasty hack */ memcopy(sizeof(elf_hdr), &elf_hdr, &elf_hdr64); /* Check that the ELF magic is correct. */ if (from_big_endian32(elf_hdr.e_ident.i) != ELF_MAGIC) { return -2; } /* Not an executable file */ if (elf_hdr.e_type != ET_EXEC) { return -3; } /* Now, check architecture */ if (elf_hdr.e_ident.c[EI_CLASS] & ELFCLASS64) { use64 = 1; } /* No program headers */ if (use64) { if (elf_hdr64.e_phnum == 0) { return -4; } } else { if (elf_hdr.e_phnum == 0) { return -4; } } /* Zero the return structure. Uninitialized data is bad(TM). */ memoryset(elf, 0, sizeof(*elf)); /* Get the entry point */ if (use64) elf->entry_point = (uint32_t)elf_hdr64.e_entry; else elf->entry_point = elf_hdr.e_entry; /* Seek to the program header table */ if (use64) current_position = (uint32_t)elf_hdr64.e_phoff; else current_position = elf_hdr.e_phoff; vfs_seek(file, current_position); /* Read the program headers. */ if (use64) { for (i = 0; i < elf_hdr64.e_phnum; i++) { if (vfs_read(file, &program_hdr64, sizeof(program_hdr64)) != sizeof(program_hdr64)) { return -6; } switch (program_hdr64.p_type) { case PT_NULL: case PT_NOTE: case PT_PHDR: /* These program headers can be ignored */ break; case PT_LOAD: /* These are the ones we are looking for */ /* The RW segment */ if (program_hdr64.p_flags & PF_W) { if (segs & SEG_RW) { /* already have an RW segment*/ return -7; } segs |= SEG_RW; elf->rw_location = program_hdr64.p_offset; elf->rw_size = program_hdr64.p_filesz; elf->rw_vaddr = program_hdr64.p_vaddr; /* memory size rounded up to the page boundary, in pages */ elf->rw_pages = (program_hdr64.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; /* The RO segment */ } else { if (segs & SEG_RO) { /* already have an RO segment*/ return -8; } segs |= SEG_RO; elf->ro_location = program_hdr64.p_offset; elf->ro_size = program_hdr64.p_filesz; elf->ro_vaddr = program_hdr64.p_vaddr; /* memory size rounded up to the page boundary, in pages */ elf->ro_pages = (program_hdr64.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; } break; /* Other program headers indicate an incompatible file *or* a file with extra headers. Just ignore. */ } /* In case the program header size is non-standard: */ current_position += sizeof(program_hdr64); vfs_seek(file, current_position); } } else { for (i = 0; i < elf_hdr.e_phnum; i++) { if (vfs_read(file, &program_hdr, sizeof(program_hdr)) != sizeof(program_hdr)) { return -6; } switch (program_hdr.p_type) { case PT_NULL: case PT_NOTE: case PT_PHDR: /* These program headers can be ignored */ break; case PT_LOAD: /* These are the ones we are looking for */ /* The RW segment */ if (program_hdr.p_flags & PF_W) { if (segs & SEG_RW) { /* already have an RW segment*/ return -7; } segs |= SEG_RW; elf->rw_location = program_hdr.p_offset; elf->rw_size = program_hdr.p_filesz; elf->rw_vaddr = program_hdr.p_vaddr; /* memory size rounded up to the page boundary, in pages */ elf->rw_pages = (program_hdr.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; /* The RO segment */ } else { if (segs & SEG_RO) { /* already have an RO segment*/ return -8; } segs |= SEG_RO; elf->ro_location = program_hdr.p_offset; elf->ro_size = program_hdr.p_filesz; elf->ro_vaddr = program_hdr.p_vaddr; /* memory size rounded up to the page boundary, in pages */ elf->ro_pages = (program_hdr.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; } break; /* Other program headers indicate an incompatible file *or* a file with extra headers. Just ignore. */ } /* In case the program header size is non-standard: */ current_position += sizeof(program_hdr); vfs_seek(file, current_position); } } /* Make sure either RW or RO segment is present: */ return (segs > 0); }
/** * Starts one userland process. The thread calling this function will * be used to run the process and will therefore never return from * this function. This function asserts that no errors occur in * process startup (the executable file exists and is a valid ecoff * file, enough memory is available, file operations succeed...). * Therefore this function is not suitable to allow startup of * arbitrary processes. * * @executable The name of the executable to be run in the userland * process */ void process_start(uint32_t pid) { thread_table_t *my_entry; pagetable_t *pagetable; uint32_t phys_page; context_t user_context; uint32_t stack_bottom; elf_info_t elf; openfile_t file; const char* executable; int i; interrupt_status_t intr_status; my_entry = thread_get_current_thread_entry(); my_entry->process_id = pid; executable = process_table[pid].executable; /* If the pagetable of this thread is not NULL, we are trying to run a userland process for a second time in the same thread. This is not possible. */ KERNEL_ASSERT(my_entry->pagetable == NULL); pagetable = vm_create_pagetable(thread_get_current_thread()); KERNEL_ASSERT(pagetable != NULL); intr_status = _interrupt_disable(); my_entry->pagetable = pagetable; _interrupt_set_state(intr_status); file = vfs_open((char *)executable); /* Make sure the file existed and was a valid ELF file */ KERNEL_ASSERT(file >= 0); KERNEL_ASSERT(elf_parse_header(&elf, file)); /* Trivial and naive sanity check for entry point: */ KERNEL_ASSERT(elf.entry_point >= PAGE_SIZE); /* Calculate the number of pages needed by the whole process (including userland stack). Since we don't have proper tlb handling code, all these pages must fit into TLB. */ KERNEL_ASSERT(elf.ro_pages + elf.rw_pages + CONFIG_USERLAND_STACK_SIZE <= _tlb_get_maxindex() + 1); /* Allocate and map stack */ for(i = 0; i < CONFIG_USERLAND_STACK_SIZE; i++) { phys_page = pagepool_get_phys_page(); KERNEL_ASSERT(phys_page != 0); vm_map(my_entry->pagetable, phys_page, (USERLAND_STACK_TOP & PAGE_SIZE_MASK) - i*PAGE_SIZE, 1); } /* Allocate and map pages for the segments. We assume that segments begin at page boundary. (The linker script in tests directory creates this kind of segments) */ for(i = 0; i < (int)elf.ro_pages; i++) { phys_page = pagepool_get_phys_page(); KERNEL_ASSERT(phys_page != 0); vm_map(my_entry->pagetable, phys_page, elf.ro_vaddr + i*PAGE_SIZE, 1); } for(i = 0; i < (int)elf.rw_pages; i++) { phys_page = pagepool_get_phys_page(); KERNEL_ASSERT(phys_page != 0); vm_map(my_entry->pagetable, phys_page, elf.rw_vaddr + i*PAGE_SIZE, 1); } /* Put the mapped pages into TLB. Here we again assume that the pages fit into the TLB. After writing proper TLB exception handling this call should be skipped. */ //intr_status = _interrupt_disable(); //tlb_fill(my_entry->pagetable); //_interrupt_set_state(intr_status); /* Now we may use the virtual addresses of the segments. */ /* Zero the pages. */ memoryset((void *)elf.ro_vaddr, 0, elf.ro_pages*PAGE_SIZE); memoryset((void *)elf.rw_vaddr, 0, elf.rw_pages*PAGE_SIZE); stack_bottom = (USERLAND_STACK_TOP & PAGE_SIZE_MASK) - (CONFIG_USERLAND_STACK_SIZE-1)*PAGE_SIZE; memoryset((void *)stack_bottom, 0, CONFIG_USERLAND_STACK_SIZE*PAGE_SIZE); /* Copy segments */ if (elf.ro_size > 0) { /* Make sure that the segment is in proper place. */ KERNEL_ASSERT(elf.ro_vaddr >= PAGE_SIZE); KERNEL_ASSERT(vfs_seek(file, elf.ro_location) == VFS_OK); KERNEL_ASSERT(vfs_read(file, (void *)elf.ro_vaddr, elf.ro_size) == (int)elf.ro_size); } if (elf.rw_size > 0) { /* Make sure that the segment is in proper place. */ KERNEL_ASSERT(elf.rw_vaddr >= PAGE_SIZE); KERNEL_ASSERT(vfs_seek(file, elf.rw_location) == VFS_OK); KERNEL_ASSERT(vfs_read(file, (void *)elf.rw_vaddr, elf.rw_size) == (int)elf.rw_size); } /* Set the dirty bit to zero (read-only) on read-only pages. */ for(i = 0; i < (int)elf.ro_pages; i++) { vm_set_dirty(my_entry->pagetable, elf.ro_vaddr + i*PAGE_SIZE, 0); } /* Insert page mappings again to TLB to take read-only bits into use */ //intr_status = _interrupt_disable(); //tlb_fill(my_entry->pagetable); //_interrupt_set_state(intr_status); /* Initialize the user context. (Status register is handled by thread_goto_userland) */ memoryset(&user_context, 0, sizeof(user_context)); user_context.cpu_regs[MIPS_REGISTER_SP] = USERLAND_STACK_TOP; user_context.pc = elf.entry_point; vfs_close(file); thread_goto_userland(&user_context); KERNEL_PANIC("thread_goto_userland failed."); }
static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { bool cont = true; /* * The connection was opened via the IPC_CONNECT_ME_TO call. * This call needs to be answered. */ async_answer_0(iid, EOK); while (cont) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) break; switch (IPC_GET_IMETHOD(call)) { case VFS_IN_REGISTER: vfs_register(callid, &call); cont = false; break; case VFS_IN_MOUNT: vfs_mount(callid, &call); break; case VFS_IN_UNMOUNT: vfs_unmount(callid, &call); break; case VFS_IN_OPEN: vfs_open(callid, &call); break; case VFS_IN_CLOSE: vfs_close(callid, &call); break; case VFS_IN_READ: vfs_read(callid, &call); break; case VFS_IN_WRITE: vfs_write(callid, &call); break; case VFS_IN_SEEK: vfs_seek(callid, &call); break; case VFS_IN_TRUNCATE: vfs_truncate(callid, &call); break; case VFS_IN_FSTAT: vfs_fstat(callid, &call); break; case VFS_IN_STAT: vfs_stat(callid, &call); break; case VFS_IN_MKDIR: vfs_mkdir(callid, &call); break; case VFS_IN_UNLINK: vfs_unlink(callid, &call); break; case VFS_IN_RENAME: vfs_rename(callid, &call); break; case VFS_IN_SYNC: vfs_sync(callid, &call); break; case VFS_IN_DUP: vfs_dup(callid, &call); break; case VFS_IN_WAIT_HANDLE: vfs_wait_handle(callid, &call); break; case VFS_IN_MTAB_GET: vfs_get_mtab(callid, &call); break; default: async_answer_0(callid, ENOTSUP); break; } } /* * Open files for this client will be cleaned up when its last * connection fibril terminates. */ }
/* Set the reading or writing position of the open file represented by filehandle to the indicated absolute offset (in bytes from the beginning). Returns 0 on success, a negative number on error. Seeking beyond the end of the file sets the position to the end and produces an error return value. */ int syscall_seek(int filehandle, int offset){ return vfs_seek((openfile_t)filehandle, offset); }
/* Return non-zero on error. */ int setup_new_process(TID_t thread, const char *executable, const char **argv_src, virtaddr_t *entry_point, virtaddr_t *stack_top) { pagetable_t *pagetable; elf_info_t elf; openfile_t file; uintptr_t phys_page; int i, res; thread_table_t *thread_entry = thread_get_thread_entry(thread); int argc = 1; virtaddr_t argv_begin; virtaddr_t argv_dst; int argv_elem_size; virtaddr_t argv_elem_dst; file = vfs_open((char *)executable); /* Make sure the file existed and was a valid ELF file */ if (file < 0) { return -1; } res = elf_parse_header(&elf, file); if (res < 0) { return -1; } /* Trivial and naive sanity check for entry point: */ if (elf.entry_point < PAGE_SIZE) { return -1; } *entry_point = elf.entry_point; pagetable = vm_create_pagetable(thread); thread_entry->pagetable = pagetable; /* Allocate and map stack */ for(i = 0; i < CONFIG_USERLAND_STACK_SIZE; i++) { phys_page = physmem_allocblock(); KERNEL_ASSERT(phys_page != 0); /* Zero the page */ memoryset((void*)ADDR_PHYS_TO_KERNEL(phys_page), 0, PAGE_SIZE); vm_map(pagetable, phys_page, (USERLAND_STACK_TOP & PAGE_SIZE_MASK) - i*PAGE_SIZE, 1); } /* Allocate and map pages for the segments. We assume that segments begin at page boundary. (The linker script in tests directory creates this kind of segments) */ for(i = 0; i < (int)elf.ro_pages; i++) { int left_to_read = elf.ro_size - i*PAGE_SIZE; phys_page = physmem_allocblock(); KERNEL_ASSERT(phys_page != 0); /* Zero the page */ memoryset((void*)ADDR_PHYS_TO_KERNEL(phys_page), 0, PAGE_SIZE); /* Fill the page from ro segment */ if (left_to_read > 0) { KERNEL_ASSERT(vfs_seek(file, elf.ro_location + i*PAGE_SIZE) == VFS_OK); KERNEL_ASSERT(vfs_read(file, (void*)ADDR_PHYS_TO_KERNEL(phys_page), MIN(PAGE_SIZE, left_to_read)) == (int) MIN(PAGE_SIZE, left_to_read)); } vm_map(pagetable, phys_page, elf.ro_vaddr + i*PAGE_SIZE, 0); } for(i = 0; i < (int)elf.rw_pages; i++) { int left_to_read = elf.rw_size - i*PAGE_SIZE; phys_page = physmem_allocblock(); KERNEL_ASSERT(phys_page != 0); /* Zero the page */ memoryset((void*)ADDR_PHYS_TO_KERNEL(phys_page), 0, PAGE_SIZE); /* Fill the page from rw segment */ if (left_to_read > 0) { KERNEL_ASSERT(vfs_seek(file, elf.rw_location + i*PAGE_SIZE) == VFS_OK); KERNEL_ASSERT(vfs_read(file, (void*)ADDR_PHYS_TO_KERNEL(phys_page), MIN(PAGE_SIZE, left_to_read)) == (int) MIN(PAGE_SIZE, left_to_read)); } vm_map(pagetable, phys_page, elf.rw_vaddr + i*PAGE_SIZE, 1); } /* Set up argc and argv on the stack. */ /* Start by preparing ancillary information for the new process argv. */ if (argv_src != NULL) for (i = 0; argv_src[i] != NULL; i++) { argc++; } argv_begin = USERLAND_STACK_TOP - (argc * sizeof(virtaddr_t)); argv_dst = argv_begin; /* Prepare for copying executable. */ argv_elem_size = strlen(executable) + 1; argv_elem_dst = argv_dst - wordpad(argv_elem_size); /* Copy executable to argv[0] location. */ vm_memwrite(pagetable, argv_elem_size, argv_elem_dst, executable); /* Set argv[i] */ vm_memwrite(pagetable, sizeof(virtaddr_t), argv_dst, &argv_elem_dst); /* Move argv_dst to &argv[1]. */ argv_dst += sizeof(virtaddr_t); if (argv_src != NULL) { for (i = 0; argv_src[i] != NULL; i++) { /* Compute the size of argv[i+1] */ argv_elem_size = strlen(argv_src[i]) + 1; argv_elem_dst -= wordpad(argv_elem_size); /* Write the 'i+1'th element of argv */ vm_memwrite(pagetable, argv_elem_size, argv_elem_dst, argv_src[i]); /* Write argv[i+1] */ vm_memwrite(pagetable, sizeof(virtaddr_t), argv_dst, &argv_elem_dst); /* Move argv_dst to next element of argv. */ argv_dst += sizeof(virtaddr_t); } } /* Write argc to the stack. */ vm_memwrite(pagetable, sizeof(int), argv_elem_dst - sizeof(int), &argc); /* Write argv to the stack. */ vm_memwrite(pagetable, sizeof(virtaddr_t), argv_elem_dst - sizeof(int) - sizeof(virtaddr_t), &argv_begin); /* Stack pointer points at argv. */ *stack_top = argv_elem_dst - sizeof(int) - sizeof(virtaddr_t); return 0; }
int io_seek(openfile_t file, int offset) { file -= 3; if (!process_has_open_file(file)) return VFS_NOT_OPEN_IN_PROCESS; return vfs_seek(file, offset); }
/** * Parse useful information from a given ELF file into the ELF info * structure. * * @param file The ELF file * * @param elf Information found in the file is returned in this * structure. In case of error this structure may contain arbitrary * values. * * @return 0 on failure, other values indicate success. */ int elf_parse_header(elf_info_t *elf, openfile_t file) { Elf32_Ehdr elf_hdr; Elf32_Phdr program_hdr; int i; int current_position; int segs = 0; #define SEG_RO 1 #define SEG_RW 2 /* Read the ELF header */ if (vfs_read(file, &elf_hdr, sizeof(elf_hdr)) != sizeof(elf_hdr)) { return 0; } /* Check that the ELF magic is correct. */ if (EI_MAGIC(elf_hdr.e_ident) != ELF_MAGIC) { return 0; } /* File data is not MIPS 32 bit big-endian */ if (elf_hdr.e_ident[EI_CLASS] != ELFCLASS32 || elf_hdr.e_ident[EI_DATA] != ELFDATA2MSB || elf_hdr.e_machine != EM_MIPS) { return 0; } /* Invalid ELF version */ if (elf_hdr.e_version != EV_CURRENT || elf_hdr.e_ident[EI_VERSION] != EV_CURRENT) { return 0; } /* Not an executable file */ if (elf_hdr.e_type != ET_EXEC) { return 0; } /* No program headers */ if (elf_hdr.e_phnum == 0) { return 0; } /* Zero the return structure. Uninitialized data is bad(TM). */ memoryset(elf, 0, sizeof(*elf)); /* Get the entry point */ elf->entry_point = elf_hdr.e_entry; /* Seek to the program header table */ current_position = elf_hdr.e_phoff; vfs_seek(file, current_position); /* Read the program headers. */ for (i = 0; i < elf_hdr.e_phnum; i++) { if (vfs_read(file, &program_hdr, sizeof(program_hdr)) != sizeof(program_hdr)) { return 0; } switch (program_hdr.p_type) { case PT_NULL: case PT_NOTE: case PT_PHDR: /* These program headers can be ignored */ break; case PT_LOAD: /* These are the ones we are looking for */ /* The RW segment */ if (program_hdr.p_flags & PF_W) { if (segs & SEG_RW) { /* already have an RW segment*/ return 0; } segs |= SEG_RW; elf->rw_location = program_hdr.p_offset; elf->rw_size = program_hdr.p_filesz; elf->rw_vaddr = program_hdr.p_vaddr; /* memory size rounded up to the page boundary, in pages */ elf->rw_pages = (program_hdr.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; /* The RO segment */ } else { if (segs & SEG_RO) { /* already have an RO segment*/ return 0; } segs |= SEG_RO; elf->ro_location = program_hdr.p_offset; elf->ro_size = program_hdr.p_filesz; elf->ro_vaddr = program_hdr.p_vaddr; /* memory size rounded up to the page boundary, in pages */ elf->ro_pages = (program_hdr.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; } break; default: /* Other program headers indicate an incompatible file */ return 0; } /* In case the program header size is non-standard: */ current_position += sizeof(program_hdr); vfs_seek(file, current_position); } /* Make sure either RW or RO segment is present: */ return (segs > 0); }
/** * \brief Page fault handler * * \param memobj The memory object * \param region The associated vregion * \param offset Offset into memory object of the page fault * \param type The fault type */ static errval_t pagefault(struct memobj *memobj, struct vregion *vregion, genvaddr_t offset, vm_fault_type_t type) { errval_t err; assert(memobj->type == MEMOBJ_VFS); struct memobj_vfs *mv = (struct memobj_vfs *)memobj; struct memobj_anon *anon = &mv->anon; struct vspace *vspace = vregion_get_vspace(vregion); struct pmap *pmap = vspace_get_pmap(vspace); genvaddr_t vregion_base = vregion_get_base_addr(vregion); genvaddr_t vregion_off = vregion_get_offset(vregion); assert(vregion_off == 0); // not sure if we handle this correctly // Walk the ordered list to find the matching frame, but don't map it yet struct memobj_frame_list *walk = anon->frame_list; while (walk) { if (offset >= walk->offset && offset < walk->offset + walk->size) { break; } walk = walk->next; } if (walk == NULL) { return LIB_ERR_MEMOBJ_WRONG_OFFSET; } genvaddr_t map_offset = vregion_off + walk->offset; size_t nbytes = walk->size; // how much do we need to read from the file? if (map_offset >= mv->filesize) { // nothing goto do_map; } else if (map_offset + nbytes > mv->filesize) { // limit size of read to maximum mapping (rest is zero-filled) nbytes = mv->filesize - map_offset; } #if 0 debug_printf("fault at offset %lx, mapping at %lx-%lx from file data %lx-%lx\n", offset, vregion_base + map_offset, vregion_base + map_offset + walk->size, map_offset + mv->offset, map_offset + mv->offset + nbytes); #endif // map frame writable at temporary location so that we can safely fill it void *buf; struct memobj *tmp_memobj = NULL; struct vregion *tmp_vregion = NULL; err = vspace_map_one_frame(&buf, walk->size, walk->frame, &tmp_memobj, &tmp_vregion); if (err_is_fail(err)) { DEBUG_ERR(err, "error setting up temp mapping in mmap pagefault handler\n"); return err; // XXX } // seek file handle err = vfs_seek(mv->vh, VFS_SEEK_SET, map_offset + mv->offset); if (err_is_fail(err)) { return err; } // read contents into frame size_t rsize, pos = 0; do { err = vfs_read(mv->vh, (char *)buf + pos, nbytes - pos, &rsize); if (err_is_fail(err)) { break; } pos += rsize; } while(rsize > 0 && pos < nbytes); // destroy temp mappings // FIXME: the API for tearing down mappings is really unclear! is this sufficient? err = vregion_destroy(tmp_vregion); assert(err_is_ok(err)); err = memobj_destroy_one_frame(tmp_memobj); assert(err_is_ok(err)); //free(tmp_vregion); //free(tmp_memobj); do_map: // map at target address with appropriate flags err = pmap->f.map(pmap, vregion_base + map_offset, walk->frame, 0, walk->size, vregion_get_flags(vregion), NULL, NULL); if (err_is_fail(err)) { return err_push(err, LIB_ERR_PMAP_MAP); } return SYS_ERR_OK; }