// Grow or shrink a file to exactly a specified size. // If growing a file, then fills the new space with zeros. // Returns 0 if successful, or returns -1 and sets errno on error. int fileino_truncate(int ino, off_t newsize) { assert(fileino_isvalid(ino)); assert(newsize >= 0 && newsize <= FILE_MAXSIZE); size_t oldsize = files->fi[ino].size; size_t oldpagelim = ROUNDUP(files->fi[ino].size, PAGESIZE); size_t newpagelim = ROUNDUP(newsize, PAGESIZE); if (newsize > oldsize) { // Grow the file and fill the new space with zeros. sys_get(SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL, FILEDATA(ino) + oldpagelim, newpagelim - oldpagelim); memset(FILEDATA(ino) + oldsize, 0, newsize - oldsize); } else if (newsize > 0) { // Shrink the file, but not all the way to empty. // Would prefer to use SYS_ZERO to free the file content, // but SYS_ZERO isn't guaranteed to work at page granularity. sys_get(SYS_PERM, 0, NULL, NULL, FILEDATA(ino) + newpagelim, FILE_MAXSIZE - newpagelim); } else { // Shrink the file to empty. Use SYS_ZERO to free completely. sys_get(SYS_ZERO, 0, NULL, NULL, FILEDATA(ino), FILE_MAXSIZE); } files->fi[ino].size = newsize; files->fi[ino].ver++; // truncation is always an exclusive change return 0; }
/* * Register application in ctx. As the matter of fact it is normal * to register it in app->ctx, but that depends on what you want. */ int register_app(struct ctx_t *ctx, struct app_t *app) { struct str_t *app_name; log(ctx, 0, "register app: %s\n", app->name); /* Main application */ app_name = sys_get(ctx, "app"); if(NULL == app_name) { app_name = sys_create(ctx, "app", T_STR); if(NULL == app_name) return E_NOMEM; } else log(ctx,1,"already got app [%s]!\n", app_name); app_name->str = app->name; app_name->len = strlen(app->name); if(!add_app(ctx, app)) return E_SYS; return E_NONE; }
/* * Only ints here * Priority funcs are now generic so if you need make your own print */ void print_parsers(struct ctx_t *src) { struct parser_t *p; struct store_t *sys; struct store_t *bs; int i,j; sys = sys_get(src, "parser"); if(NULL == sys) log(ctx,4,"no parsers found\n"); else { log(ctx,4,"found parser array size %d\n", sys->last); for(i = 0; i < sys->last; i++) { bs = store_idx_get(sys, i); for(j = 0; j < bs->last; j++) { p = store_idx_get(bs, j); log(src,4,"%s[%d] ", p->name, p->prio); } log(ctx,4,"\n"); } log(ctx,4,"\n"); } }
void * parser_sys_init(struct ctx_t *dst) { struct store_t *sys; if(NULL == SYS(dst)) return NULL; log(dst, 4, "parser sys init\n"); sys = sys_get(dst, "parser"); if(NULL == sys) { log(dst, 4, "create parser sys\n"); sys = sys_create(dst, "parser", T_STORE); if(NULL == sys) return NULL; store_set(sys, 2, sizeof(struct store_t), parserbscmp); } return sys; }
void app_init_current( t_app *app) { char path[_PATH_]; if( sys_get( "pwd", path, _PATH_)) { s_cp( app->path_current, path, _PATH_); } else { printf("[APP] Error, can't get current directory\n"); } }
intptr_t exec_copyargs(char *const argv[]) { // Give the process a nice big 4MB, zero-filled stack. sys_get(SYS_ZERO | SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL, (void*)VM_SCRATCHLO, PTSIZE); #if SOL >= 4 // How many arguments? int argc; for (argc = 0; argv[argc] != NULL; argc++) ; // Make room for the argv array intptr_t esp = VM_STACKHI; intptr_t scratchofs = VM_SCRATCHLO - (VM_STACKHI-PTSIZE); esp -= (argc+1) * sizeof(intptr_t); // room for arguments plus NULL intptr_t dargv = esp; // Copy the argument strings int i; for (i = 0; i < argc; i++) { int len = strlen(argv[i]); esp -= len+1; strcpy((void*)esp + scratchofs, argv[i]); ((intptr_t*)(dargv + scratchofs))[i] = esp; } esp &= ~3; // get esp word-aligned again // Push the arguments to main() esp -= 4; *(intptr_t*)(esp + scratchofs) = dargv; esp -= 4; *(intptr_t*)(esp + scratchofs) = argc; #else // ! SOL >= 4 // Lab 4: insert your code here to copy our command-line arguments // onto the new process's stack, taking into account the fact that // the stack area is mapped at VM_SCRATCHLO to VM_SCRATCHLO+PTSIZE // in _our_ address space while we're copying the arguments, // but the pointers we're writing into this space will be // interpreted by the newly executed process, // where the stack will be mapped from VM_STACKHI-PTSIZE to VM_STACKHI. warn("exec_copyargs not implemented yet"); intptr_t esp = VM_STACKHI; // no arguments - fix this. #endif // ! SOL >= 4 // Copy the stack into its correct position in child 0. sys_put(SYS_COPY, 0, NULL, (void*)VM_SCRATCHLO, (void*)VM_STACKHI-PTSIZE, PTSIZE); return esp; }
/* * Add app to context * Creates system called app->name and put app in it */ int add_app(struct ctx_t *ctx, struct app_t *app) { struct app_t *sys; sys = sys_get(ctx, app->name); if(NULL == sys) { sys = sys_create(ctx, app->name, T_APP); if(NULL == sys) return E_NOMEM; } else log(ctx,1,"warn: already got [%s] system!\n", app->name); memcpy(sys, app, sizeof(struct app_t)); return E_NONE; }
// Write 'count' data elements each of size 'eltsize' // starting at absolute byte offset 'ofs' within the file in inode 'ino'. // Returns the number of elements actually written, // which should always be equal to the 'count' input parameter // unless an error occurs, in which case this function // returns -1 and sets errno appropriately. // Since PIOS files can be up to only FILE_MAXSIZE bytes in size (4MB), // one particular reason an error might occur is if an application // tries to grow a file beyond this maximum file size, // in which case this function generates the EFBIG error. ssize_t fileino_write(int ino, off_t ofs, const void *buf, size_t eltsize, size_t count) { assert(fileino_isreg(ino)); assert(ofs >= 0); assert(eltsize > 0); fileinode *fi = &files->fi[ino]; assert(fi->size <= FILE_MAXSIZE); #if SOL >= 4 // Return an error if we'd be growing the file too big. size_t len = eltsize * count; size_t lim = ofs + len; if (lim < ofs || lim > FILE_MAXSIZE) { errno = EFBIG; return -1; } // Grow the file as necessary. if (lim > fi->size) { size_t oldpagelim = ROUNDUP(fi->size, PAGESIZE); size_t newpagelim = ROUNDUP(lim, PAGESIZE); if (newpagelim > oldpagelim) sys_get(SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL, FILEDATA(ino) + oldpagelim, newpagelim - oldpagelim); fi->size = lim; } // Write the data. memmove(FILEDATA(ino) + ofs, buf, len); return count; #else // ! SOL >= 4 // Lab 4: insert your file writing code here. warn("fileino_write() not implemented"); errno = EINVAL; return -1; #endif // ! SOL >= 4 }
void app_init_home( t_app *app) { int size = 16; char name[size]; int size_home = _PATH_; char path_home[size_home]; sys_get( "whoami", name, size); s_cp( path_home, "/home/", size_home); s_cat( path_home, name, size); s_cat( path_home, "/.minuit/", size_home); if( !sys_file_exists( path_home)) { printf("Creating minuit home directory: %s\n", path_home); mkdir( path_home, 0777); } s_cp( app->path_home, path_home, _PATH_); }
void * parser_scope_init(struct ctx_t *scope) { struct store_t *sys; if(NULL == SYS(scope)) return NULL; sys = sys_get(scope, "parser"); if(NULL == sys) { sys = sys_create(scope, "parser", T_STORE); if(NULL == sys) return NULL; store_set(sys, 2, sizeof(struct store_t), pbscmp); } return sys; }
void migrate(int node) { cprintf("testmigr: migrating to node %d...\n", node); sys_get(0, (node << 8) | 0, NULL, NULL, NULL, 0); cprintf("testmigr: now on node %d.\n", node); }
void proc_check(void) { // Spawn 2 child processes, executing on statically allocated stacks. cprintf("in proc_check()\n"); int i; for (i = 0; i < 4; i++) { // Setup register state for child uint32_t *esp = (uint32_t*) &child_stack[i][PAGESIZE]; *--esp = i; // push argument to child() function *--esp = 0; // fake return address child_state.tf.eip = (uint32_t) child; child_state.tf.esp = (uint32_t) esp; // Use PUT syscall to create each child, // but only start the first 2 children for now. cprintf("spawning child %d\n", i); sys_put(SYS_REGS | (i < 2 ? SYS_START : 0), i, &child_state, NULL, NULL, 0); } cprintf("proc_check() created childs\n"); // Wait for both children to complete. // This should complete without preemptive scheduling // when we're running on a 2-processor machine. for (i = 0; i < 2; i++) { cprintf("waiting for child %d\n", i); sys_get(SYS_REGS, i, &child_state, NULL, NULL, 0); } cprintf("proc_check() 2-child test succeeded\n"); // (Re)start all four children, and wait for them. // This will require preemptive scheduling to complete // if we have less than 4 CPUs. cprintf("proc_check: spawning 4 children\n"); for (i = 0; i < 4; i++) { cprintf("spawning child %d\n", i); sys_put(SYS_START, i, NULL, NULL, NULL, 0); } // Wait for all 4 children to complete. for (i = 0; i < 4; i++) sys_get(0, i, NULL, NULL, NULL, 0); cprintf("proc_check() 4-child test succeeded\n"); // Now do a trap handling test using all 4 children - // but they'll _think_ they're all child 0! // (We'll lose the register state of the other children.) i = 0; sys_get(SYS_REGS, i, &child_state, NULL, NULL, 0); // get child 0's state assert(recovargs == NULL); do { sys_put(SYS_REGS | SYS_START, i, &child_state, NULL, NULL, 0); sys_get(SYS_REGS, i, &child_state, NULL, NULL, 0); if (recovargs) { // trap recovery needed trap_check_args *args = recovargs; cprintf("recover from trap %d\n", child_state.tf.trapno); child_state.tf.eip = (uint32_t) args->reip; args->trapno = child_state.tf.trapno; } else assert(child_state.tf.trapno == T_SYSCALL); i = (i+1) % 4; // rotate to next child proc } while (child_state.tf.trapno != T_SYSCALL); assert(recovargs == NULL); cprintf("proc_check() trap reflection test succeeded\n"); cprintf("proc_check() succeeded!\n"); }
int exec_readelf(const char *path) { // We'll load the ELF image into a scratch area in our address space. sys_get(SYS_ZERO, 0, NULL, NULL, (void*)VM_SCRATCHLO, EXEMAX); // Open the ELF image to load. filedesc *fd = filedesc_open(NULL, path, O_RDONLY, 0); if (fd == NULL) return -1; void *imgdata = FILEDATA(fd->ino); size_t imgsize = files->fi[fd->ino].size; // Make sure it looks like an ELF image. elfhdr *eh = imgdata; if (imgsize < sizeof(*eh) || eh->e_magic != ELF_MAGIC) { warn("exec_readelf: ELF header not found"); goto err; } // Load each program segment into the scratch area proghdr *ph = imgdata + eh->e_phoff; proghdr *eph = ph + eh->e_phnum; if (imgsize < (void*)eph - imgdata) { warn("exec_readelf: ELF program header truncated"); goto err; } for (; ph < eph; ph++) { if (ph->p_type != ELF_PROG_LOAD) continue; // The executable should fit in the first 4MB of user space. intptr_t valo = ph->p_va; intptr_t vahi = valo + ph->p_memsz; if (valo < VM_USERLO || valo > VM_USERLO+EXEMAX || vahi < valo || vahi > VM_USERLO+EXEMAX) { warn("exec_readelf: executable image too large " "(%d bytes > %d max)", vahi-valo, EXEMAX); goto err; } // Map all pages the segment touches in our scratch region. // They've already been zeroed by the SYS_ZERO above. intptr_t scratchofs = VM_SCRATCHLO - VM_USERLO; intptr_t pagelo = ROUNDDOWN(valo, PAGESIZE); intptr_t pagehi = ROUNDUP(vahi, PAGESIZE); sys_get(SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL, (void*)pagelo + scratchofs, pagehi - pagelo); // Initialize the file-loaded part of the ELF image. // (We could use copy-on-write if SYS_COPY // supports copying at arbitrary page boundaries.) intptr_t filelo = ph->p_offset; intptr_t filehi = filelo + ph->p_filesz; if (filelo < 0 || filelo > imgsize || filehi < filelo || filehi > imgsize) { warn("exec_readelf: loaded section out of bounds"); goto err; } memcpy((void*)valo + scratchofs, imgdata + filelo, filehi - filelo); // Finally, remove write permissions on read-only segments. if (!(ph->p_flags & ELF_PROG_FLAG_WRITE)) sys_get(SYS_PERM | SYS_READ, 0, NULL, NULL, (void*)pagelo + scratchofs, pagehi - pagelo); } // Copy the ELF image into its correct position in child 0. sys_put(SYS_COPY, 0, NULL, (void*)VM_SCRATCHLO, (void*)VM_USERLO, EXEMAX); // The new program should have the same entrypoint as we do! if (eh->e_entry != (intptr_t)start) { warn("exec_readelf: executable has a different start address"); goto err; } filedesc_close(fd); // Done with the ELF file return 0; err: filedesc_close(fd); return -1; }