示例#1
0
// Spawn a child process from a program image loaded from the file system.
// prog: the pathname of the program to run.
// argv: pointer to null-terminated array of pointers to strings,
// 	 which will be passed to the child as its command-line arguments.
// Returns child envid on success, < 0 on failure.
int
spawn(const char *prog, const char **argv)
{
	unsigned char elf_buf[512];
	struct Trapframe child_tf;
	envid_t child;

	// Insert your code, following approximately this procedure:
	//
	//   - Open the program file.
	//
	//   - Read the ELF header, as you have before, and sanity check its
	//     magic number.  (Check out your load_icode!)
	//
	//   - Use sys_exofork() to create a new environment.
	//
	//   - Set child_tf to an initial struct Trapframe for the child.
	//     Hint: The sys_exofork() system call has already created
	//     a good basis, in envs[ENVX(child)].env_tf.
	//     Hint: You must do something with the program's entry point.
	//     What?  (See load_icode!)
	//
	//   - Call the init_stack() function above to set up
	//     the initial stack page for the child environment.
	//
	//   - Map all of the program's segments that are of p_type
	//     ELF_PROG_LOAD into the new environment's address space.
	//     Use the p_flags field in the Proghdr for each segment
	//     to determine how to map the segment:
	//
	//	* If the ELF flags do not include ELF_PROG_FLAG_WRITE,
	//	  then the segment contains text and read-only data.
	//	  Use read_map() to read the contents of this segment,
	//	  and map the pages it returns directly into the child
	//        so that multiple instances of the same program
	//	  will share the same copy of the program text.
	//        Be sure to map the program text read-only in the child.
	//        Read_map is like read but returns a pointer to the data in
	//        *blk rather than copying the data into another buffer.
	//
	//	* If the ELF segment flags DO include ELF_PROG_FLAG_WRITE,
	//	  then the segment contains read/write data and bss.
	//	  As with load_icode() in Lab 3, such an ELF segment
	//	  occupies p_memsz bytes in memory, but only the FIRST
	//	  p_filesz bytes of the segment are actually loaded
	//	  from the executable file - you must clear the rest to zero.
	//        For each page to be mapped for a read/write segment,
	//        allocate a page in the parent temporarily at UTEMP,
	//        read() the appropriate portion of the file into that page
	//	  and/or use memset() to zero non-loaded portions.
	//	  (You can avoid calling memset(), if you like, if
	//	  page_alloc() returns zeroed pages already.)
	//        Then insert the page mapping into the child.
	//        Look at init_stack() for inspiration.
	//        Be sure you understand why you can't use read_map() here.
	//
	//     Note: None of the segment addresses or lengths above
	//     are guaranteed to be page-aligned, so you must deal with
	//     these non-page-aligned values appropriately.
	//     The ELF linker does, however, guarantee that no two segments
	//     will overlap on the same page; and it guarantees that
	//     PGOFF(ph->p_offset) == PGOFF(ph->p_va).
	//
	//   - Call sys_env_set_trapframe(child, &child_tf) to set up the
	//     correct initial eip and esp values in the child.
	//
	//   - Start the child process running with sys_env_set_status().

	// LAB 5: Your code here.
	
	(void) child;
	//panic("spawn unimplemented!");
	int r;
	int i;
	int fdnum;
	void *blk;
	uintptr_t init_esp;
	uint32_t readsize;
	uintptr_t va;
	uint32_t pdex;
	uint32_t ptex;
	uint32_t pn;

	struct Elf *elf;
	struct Proghdr *ph, *eph;

	if ((fdnum=open(prog, O_RDONLY)) < 0)
		return fdnum;
	if ((r=read(fdnum, (void *)elf_buf, 512)) < 0)
		return r;
	elf = (struct Elf*) elf_buf;

	if (elf->e_magic != ELF_MAGIC)
		return -E_NOT_EXEC;
	if ((child=sys_exofork()) < 0)
		return child;

	// return point of child
	if (child == 0) {
		env = &envs[ENVX(sys_getenvid())];
		return 0;
	}

	child_tf = envs[ENVX(child)].env_tf;
	child_tf.tf_eip = elf->e_entry;

	if ((r=init_stack(child, argv, &init_esp)) < 0)
		return r;

	child_tf.tf_esp = init_esp;

	ph = (struct Proghdr *) (elf_buf+elf->e_phoff);
	eph = ph + elf->e_phnum;
	for (; ph != eph; ph++) {
		if (ph->p_type == ELF_PROG_LOAD) {

			// sigh, remember to carefully read the instr above!!!!!!!!
			// make ph->p_va && p_offset page-aligned
			uint32_t aligned_va = ROUNDDOWN(ph->p_va, PGSIZE);
			uint32_t aligned_offset = ROUNDDOWN(ph->p_offset, PGSIZE);

			if (ph->p_flags & ELF_PROG_FLAG_WRITE) {

				for (i = 0; i < ph->p_memsz; i += PGSIZE) {
					if ((r=sys_page_alloc(0, (void *) UTEMP, PTE_U|PTE_P|PTE_W)) < 0)
						return r;
					
					if (i < ph->p_filesz) {
						/*seek(fdnum, ph->p_offset+i);*/
						seek(fdnum,aligned_offset+i);

						readsize = (ph->p_filesz-i >= PGSIZE) ? PGSIZE:(ph->p_filesz-i);

						read(fdnum,(void *) UTEMP, readsize);

						// if the segment can full-fill the page, set tail section to 0x0
						if (readsize < PGSIZE)
							memset((void *) (UTEMP+readsize), 0x0, PGSIZE-readsize);

					} else {
						memset((void *) UTEMP, 0x0, PGSIZE);
					}

					sys_page_map(0, UTEMP, child, (void *) (aligned_va+i), PTE_U|PTE_W|PTE_P);
					sys_page_unmap(0, UTEMP);
				}

			} else {
				for (i = 0; i < ph->p_memsz; i+=PGSIZE) {
					if ((r=read_map(fdnum, aligned_offset+i, &blk)) < 0)
						return r;
					if ((r=sys_page_map(0, blk, child, (void *) (aligned_va+i), PTE_U|PTE_P)) < 0)
						return r;
				}
			}
		}
	}

	close(fdnum);

	if ((r=sys_env_set_trapframe(child, &child_tf)) < 0)
		return r;

	if ((r=sys_env_set_status(child, ENV_RUNNABLE)) < 0)
		return r;

	for (pdex = PDX(0); pdex < PDX(UTOP); pdex++) {
		if (vpd[pdex] & PTE_P) {
			for ( ptex = 0; ptex < NPTENTRIES; ptex++) {
				pn = (pdex << 10) + ptex;

				if ((vpt[pn] & PTE_P) && (vpt[pn] & PTE_SHARE)) {
					va = (uintptr_t) PGADDR(pdex, ptex, 0);
					if ((r=sys_page_map(0, (void *) va, child, (void *) va, vpt[pn] & PTE_USER)) < 0)
						return r;
				}
			}
		}
	}


	return child;
}
示例#2
0
// Challenge!
int
sfork(void)
{

	//panic("sfork not implemented");
	envid_t envid=-1;
	pte_t ptentry=0, ptable=0, page_num=0;
	pde_t pdentry=0;
	uintptr_t addr=0;
	int pdindex = 0, pte_perm=0, pte_loop=0;
	int r=-1;

	set_pgfault_handler(pgfault);
	if((envid=sys_exofork())<0)
		panic("\nCannot create a child process:%e\n",envid);
	//cprintf("\nenvid of newly created child:%x\n",envid);
	if (envid == 0) {
		// We're the child.
		// The copied value of the global variable 'thisenv'
		// is no longer valid (it refers to the parent!).
		// Fix it and return 0.
		thisenv = &envs[ENVX(sys_getenvid())];
		set_pgfault_handler(pgfault);
		return 0;
	}
	//Incrementing by PGSIZE in loop because 1 page of pgsize corresponds to 1 page taable entry
	//Incrementing the address by 4MB because uvpd has no entry means 1 uvpd->4 MB region so need to skip it.
	while(addr<(USTACKTOP-PGSIZE))
	{
		//cprintf("parent address:%x",addr);
		if(uvpd[PDX(addr)] & PTE_P)
		{
			if(uvpt[PGNUM(addr)] & PTE_P)
			{
				//cprintf("\ncalling duppgae for address %x\n",addr);
				s_duppage(envid, PGNUM(addr));
			}
			addr += PGSIZE;
		}
		else
		{
			addr = addr + PTSIZE;
		}
	}

	sf_stack_duppage(envid, (void *)USTACKTOP-PGSIZE);
	/*addr = USTACKTOP-2*PGSIZE;
	if(uvpd[PDX(addr)] & PTE_P)
	{
		if(uvpt[PGNUM(addr)] & PTE_P)
		{
				//cprintf("\ncalling duppgae for address %x\n",addr);
			s_duppage(envid, PGNUM(addr));
		}
		addr += PGSIZE;
	}*/

	if ((r = sys_page_alloc(envid,(void *)UXSTACKTOP-PGSIZE, PTE_P|PTE_U|PTE_W)) < 0)
		panic("sys_page_alloc: %e", r);

	
	if ((r = sys_env_set_pgfault_upcall(envid, _pgfault_upcall)) < 0)
		panic("pagefault upcall setup error: %e", r);
	sys_env_set_status(envid, ENV_RUNNABLE);
	return envid;

}
示例#3
0
//
// User-level fork with copy-on-write.
// Set up our page fault handler appropriately.
// Create a child.
// Copy our address space and page fault handler setup to the child.
// Then mark the child as runnable and return.
//
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
// It is also OK to panic on error.
//
// Hint:
//   Use uvpd, uvpt, and duppage.
//   Remember to fix "thisenv" in the child process.
//   Neither user exception stack should ever be marked copy-on-write,
//   so you must allocate a new page for the child's user exception stack.
//
envid_t
fork(void)
{
	envid_t child;
	unsigned pagenum;
	int i;

	// First set up the page fault handler
	set_pgfault_handler(pgfault);

	// Create a new child environment and store its id. Return the error
	//  on failure
	child = sys_exofork();
	if(child < 0) {
		// There was some error, return the error
		return child;
	} else if(child == 0) {
		// This is the child, thisenv needs to be fixed
		thisenv = &envs[ENVX(sys_getenvid())];
		return child;
	}

	// Map every page under UTOP using duppage.  Writable pages will
	//  be mapped to a COW page, and non-writable pages will be mapped
	//  to read-only pages.  Very simple.
	//
	// The only exception is the exception stack (located at UXSTACKTOP-
	//  PGSIZE).  A new page should be allocated in the child for this.
	for(pagenum = 0; pagenum < PGNUM(UTOP); pagenum++) {
		// Check to see if the page directory entry and page table
		//  entry for this page exist.
		if((uvpd[PDX(pagenum*PGSIZE)]&PTE_P) == 0 || (uvpt[pagenum]&PTE_P) == 0)
			continue;

		if(pagenum == PGNUM(UXSTACKTOP-PGSIZE))
			// Found the exception stack page
			sys_page_alloc(child, (void *)(pagenum*PGSIZE), PTE_U|PTE_W);
		else
			// Duplicate the page
			duppage(child, pagenum);
	}

	// Get the child environment struct and set its pagefault handlers
	//  by copying the ones from the parent.
	if(sys_env_set_pgfault_upcall(child, thisenv->env_pgfault_upcall) != 0)
		panic("unable to set child page fault upcall");
	if(sys_env_set_global_pgfault(child, thisenv->env_pgfault_global) != 0)
		panic("unable to set child page fault handler");
	for(i = 0; i < MAXHANDLERS; i++) {
		// Don't add a handler that doesn't exist
		if(thisenv->env_pgfault_handlers[i].erh_maxaddr == 0) continue;

		// Attempt to set the handler
		if(sys_env_set_region_pgfault(child,
					      thisenv->env_pgfault_handlers[i].erh_handler,
					      (void *)thisenv->env_pgfault_handlers[i].erh_minaddr,
					      (void *)thisenv->env_pgfault_handlers[i].erh_maxaddr) != 0);
			panic("unable to set child page fault handler");
	}

	// Finally, mark the child as runnable.
	if(sys_env_set_status(child, ENV_RUNNABLE) != 0)
		panic("can't set child status to runnable");

	// Return the child id
	return child;
}
示例#4
0
// Choose a user environment to run and run it.
void
sched_yield(void)
{
	// Implement simple round-robin scheduling.
	// Search through 'envs' for a runnable environment,
	// in circular fashion starting after the previously running env,
	// and switch to the first such environment found.
	// It's OK to choose the previously running env if no other env
	// is runnable.
	// But never choose envs[0], the idle environment,
	// unless NOTHING else is runnable.

	// LAB 4: Your code here.
#if LAB4A_SCHED_PRI
	int cur_index=0, next_index=0, priority_index=0,selected_index=0;
	int  priority_selected = 0 ;

	if(NULL != curenv){
		cur_index = ENVX(curenv->env_id);
	}

	next_index = (cur_index + 1)%NENV;

	for(;next_index != cur_index; next_index=(next_index+1)%NENV){
		if((envs[next_index].env_status == ENV_RUNNABLE) && (next_index != 0)){

			if(next_index & 0x01){
				priority_index = next_index;
				priority_selected = 1;
			}else{
				if(selected_index == 0)
				{
					selected_index=next_index;

				}
			}
			//          env_run(&envs[next_index]);
		}
	}
	if(priority_selected){
		env_run(&envs[priority_index]);
	}else{
		env_run(&envs[selected_index]);
	}
#else
	struct Env *penv, *pstart;
	int i = 0;

	if ((curenv == NULL) || (curenv == &envs[NENV - 1])) {
		// Skip envs[0]
		pstart = &envs[1];
	}
	else {
		pstart = curenv + 1;
	}
	penv = pstart;
	while (1) {
		++i;
		if ((penv == pstart) && (i > 1)) {
			// We've come back to start full-circle, time to break out
			break;
		}

		if (penv->env_status == ENV_RUNNABLE) {
			env_run(penv);
			break;
		}

		if (penv == &envs[NENV - 1]) {
			// Skip envs[0]
			penv = &envs[1];
		}
		else {
			++penv;
		}
	}
#endif

	// Run the special idle environment when nothing else is runnable.
	if (envs[0].env_status == ENV_RUNNABLE)
		env_run(&envs[0]);
	else {
		cprintf("Destroyed all environments - nothing more to do!\n");
		while (1)
			monitor(NULL);
	}
}
示例#5
0
文件: spawn.c 项目: jguo2013/smallOS
// Spawn a child process from a program image loaded from the file system.
// prog: the pathname of the program to run.
// argv: pointer to null-terminated array of pointers to strings,
// 	 which will be passed to the child as its command-line arguments.
// Returns child envid on success, < 0 on failure.
int
spawn(const char *prog, const char **argv)
{
	unsigned char elf_buf[512];
	struct Trapframe child_tf;
	envid_t child;
	struct Env * child_env;

	int fd, i, r;
	struct Elf *elf;
	struct Proghdr *ph;
	int perm;

	// This code follows this procedure:
	//
	//   - Open the program file.
	//
	//   - Read the ELF header, as you have before, and sanity check its
	//     magic number.  (Check out your load_icode!)
	//
	//   - Use sys_exofork() to create a new environment.
	//
	//   - Set child_tf to an initial struct Trapframe for the child.
	//
	//   - Call the init_stack() function above to set up
	//     the initial stack page for the child environment.
	//
	//   - Map all of the program's segments that are of p_type
	//     ELF_PROG_LOAD into the new environment's address space.
	//     Use the p_flags field in the Proghdr for each segment
	//     to determine how to map the segment:
	//
	//	* If the ELF flags do not include ELF_PROG_FLAG_WRITE,
	//	  then the segment contains text and read-only data.
	//	  Use read_map() to read the contents of this segment,
	//	  and map the pages it returns directly into the child
	//        so that multiple instances of the same program
	//	  will share the same copy of the program text.
	//        Be sure to map the program text read-only in the child.
	//        Read_map is like read but returns a pointer to the data in
	//        *blk rather than copying the data into another buffer.
	//
	//	* If the ELF segment flags DO include ELF_PROG_FLAG_WRITE,
	//	  then the segment contains read/write data and bss.
	//	  As with load_icode() in Lab 3, such an ELF segment
	//	  occupies p_memsz bytes in memory, but only the FIRST
	//	  p_filesz bytes of the segment are actually loaded
	//	  from the executable file - you must clear the rest to zero.
	//        For each page to be mapped for a read/write segment,
	//        allocate a page in the parent temporarily at UTEMP,
	//        read() the appropriate portion of the file into that page
	//	  and/or use memset() to zero non-loaded portions.
	//	  (You can avoid calling memset(), if you like, if
	//	  page_alloc() returns zeroed pages already.)
	//        Then insert the page mapping into the child.
	//        Look at init_stack() for inspiration.
	//        Be sure you understand why you can't use read_map() here.
	//
	//     Note: None of the segment addresses or lengths above
	//     are guaranteed to be page-aligned, so you must deal with
	//     these non-page-aligned values appropriately.
	//     The ELF linker does, however, guarantee that no two segments
	//     will overlap on the same page; and it guarantees that
	//     PGOFF(ph->p_offset) == PGOFF(ph->p_va).
	//
	//   - Call sys_env_set_trapframe(child, &child_tf) to set up the
	//     correct initial eip and esp values in the child.
	//
	//   - Start the child process running with sys_env_set_status().

	if ((r = open(prog, O_RDONLY)) < 0)
		return r;
	fd = r;

	// Read elf header
	elf = (struct Elf*) elf_buf;
	if (readn(fd, elf_buf, sizeof(elf_buf)) != sizeof(elf_buf)
	    || elf->e_magic != ELF_MAGIC) {
		close(fd);
		cprintf("elf magic %08x want %08x\n", elf->e_magic, ELF_MAGIC);
		return -E_NOT_EXEC;
	}

	// Create new child environment
	if ((r = sys_exofork()) < 0)
		return r;
	child = r;

	// Set up trap frame, including initial stack.
	child_tf = envs[ENVX(child)].env_tf;
	child_tf.tf_eip = elf->e_entry;

	if ((r = init_stack(child, argv, &(child_tf.tf_esp))) < 0)
		return r;

	// Set up program segments as defined in ELF header.
	ph = (struct Proghdr*) (elf_buf + elf->e_phoff);
	for (i = 0; i < elf->e_phnum; i++, ph++) {
		if (ph->p_type != ELF_PROG_LOAD)
			continue;
		perm = PTE_P | PTE_U;
		if (ph->p_flags & ELF_PROG_FLAG_WRITE)
			perm |= PTE_W;
		if ((r = map_segment(child, ph->p_va, ph->p_memsz,
				     fd, ph->p_filesz, ph->p_offset, perm)) < 0)
			goto error;
	}
	close(fd);
	fd = -1;

	cprintf("copy sharing pages\n");
	// Copy shared library state.
	if ((r = copy_shared_pages(child)) < 0)
		panic("copy_shared_pages: %e", r);
	cprintf("complete copy sharing pages\n");	

	if ((r = sys_env_set_trapframe(child, &child_tf)) < 0)
		panic("sys_env_set_trapframe: %e", r);
	
	//thisenv = &envs[ENVX(child)];
	//cprintf("%s %x\n",__func__,thisenv->env_id);
	
	if ((r = sys_env_set_status(child, ENV_RUNNABLE)) < 0)
		panic("sys_env_set_status: %e", r);
	
	return child;

error:
	sys_env_destroy(child);
	close(fd);
	return r;
}