Beispiel #1
0
struct execution_result executor_instruction_execute(uint8_t *instruction, size_t instruction_length,
		struct tracking_trace *trace, struct context *context, void *code, struct tbgen_result tbgen_result) {

	result.type = EXECUTION_RTYPE_SUCCESS;

	struct stack *mappings = stack_init();

	char retval = map_and_copy(mappings, trace, context, tbgen_result);
	if(retval) {
		result.type = EXECUTION_RTYPE_MAPPING_ERROR;
		goto unmap_all;
	}

	struct sigaction act;
	memset(&act, 0, sizeof(act));
	act.sa_sigaction = sighandler;
	act.sa_flags = SA_SIGINFO;

	sigaction(SIGSEGV, &act, NULL);
	sigaction(SIGILL, &act, NULL);
	sigaction(SIGALRM, &act, NULL);
	sigaction(SIGBUS, &act, NULL);
	sigaction(SIGFPE, &act, NULL);
	sigaction(SIGSYS, &act, NULL);
	sigaction(SIGTRAP, &act, NULL);

//	alarm(1);

//	__asm__ ("mov $0x00112244556677, %rsi\nbtc %ax, (%rsi)\n");

#ifndef DRYRUN
	if(!setjmp(jbuf))
		((void (*)(void))code)();
	else
		result.type = EXECUTION_RTYPE_SIGNAL;
#endif

	alarm(0);

	act.sa_sigaction = NULL;
	sigaction(SIGSEGV, &act, NULL);
	sigaction(SIGILL, &act, NULL);
	sigaction(SIGALRM, &act, NULL);
	sigaction(SIGBUS, &act, NULL);
	sigaction(SIGFPE, &act, NULL);
	sigaction(SIGSYS, &act, NULL);
	sigaction(SIGTRAP, &act, NULL);

	write_back(trace, context);

	unmap_all: unmap_all(mappings);
	stack_free(mappings);

	executor_virt_calc(context);

	return result;
}
Beispiel #2
0
/*
 * syscall_fork
 * 
 * Implements the fork system call, which makes a copy of an existing process.
 * After this call has completed, the two processes will have exactly the same
 * state, with the exception of their process ids and the return value from the
 * fork call. The return value that the parent process sees will be the (non-zero)
 * process id of the child. The child will see a return value of 0. Based on this,
 * each of the two processes can go their separate ways, with the child process
 * typically taking completely different code
 * path, such as a call to exec.
 * 
 * This call is an alternative to start_process. fork is the standard way to create
 * processes under UNIX, and in most cases is the *only* way for new processes to
 * be started, at least from user-space.
 * 
 * The *full* state of a process must be copied here, including all fields of the
 * process object, and all of the memory associated with the process in its various
 * segments (text, data, and stack).
 */
pid_t syscall_fork(regs * r)
{
	/*
	 * Find a free process identifier 
	 */
	pid_t child_pid = get_free_pid();
	if (0 > child_pid)
		return -EAGAIN;

	process *parent = current_process;
	process *child = &processes[child_pid];
	memset(child, 0, sizeof(process));
	child->pid = child_pid;
	child->parent_pid = parent->pid;
	child->exists = 1;

	/*
	 * Create a page directory for the new process, and set the segment ranges.
	 * Note that we have to temporarily disable paging here, because we need to
	 * deal with physical memory when allocating a page directory and setting up
	 * the mappings. 
	 */
	disable_paging();
	child->pdir = (page_dir) alloc_page();

	child->text_start = parent->text_start;
	child->text_end = parent->text_end;
	child->data_start = parent->data_start;
	child->data_end = parent->data_end;
	child->stack_start = parent->stack_start;
	child->stack_end = parent->stack_end;

	/*
	 * Identity map memory 0-6Mb 
	 */
	unsigned int addr;
	for (addr = 0 * MB; addr < 6 * MB; addr += PAGE_SIZE)
		map_page(child->pdir, addr, addr, PAGE_USER, PAGE_READ_ONLY);

	/*
	 * Copy parent's text, data, and stack segments to child 
	 */
	map_and_copy(parent->pdir, child->pdir, child->text_start,
		     child->text_end);
	map_and_copy(parent->pdir, child->pdir, child->data_start,
		     child->data_end);
	map_and_copy(parent->pdir, child->pdir, child->stack_start,
		     child->stack_end);

	enable_paging(current_process->pdir);

	/*
	 * Copy file handles. The reference count is increased on each of them, so
	 * that we can keep track of how many file descriptors refere to each file
	 * handle. This information is needed so we know when to destroy a file handle
	 * (i.e. when its reference count reaches 0). 
	 */
	int i;
	for (i = 0; i < MAX_FDS; i++) {
		if (NULL != parent->filedesc[i]) {
			child->filedesc[i] = parent->filedesc[i];
			child->filedesc[i]->refcount++;
		}
	}
	/*
	 * Copy the saved CPU registers of the current process, which determines its
	 * execution state (instruction pointer, stack pointer etc.) 
	 */
	child->saved_regs = *r;
	child->saved_regs.eax = 0;	/* child's return value from fork */

	memmove(child->cwd, parent->cwd, PATH_MAX);

	/*
	 * Place the process on the ready list, so that it can begin execution on a
	 * subsequent context switch 
	 */
	child->ready = 1;
	list_add(&ready, child);

	/*
	 * Return the child's process id... note that this value will only go to the
	 * parent, since we set the child's return value from fork above 
	 */
	return child_pid;
}