예제 #1
0
파일: proc.c 프로젝트: Aresthu/ucore_plus
/**
 * The hook called before 'do_execve' successfully return.
 *     What we need to do here are:
 *       1. create a new host container if the process doesn't have one yet;
 *       2. create the stack for syscall stub;
 *       3. unmap umUcore kernel area in the child and erasing the info in the page table;
 *       4. copy arguments to the user stack of the child, and free the kernel's copy;
 *       5. call 'userspace'.
 *     If everything is done, the current thread becomes a monitor thread forever.
 * @param argc the number of arguments
 * @param kargv the copy of the arguments in the kernel
 */
int do_execve_arch_hook(int argc, char **kargv)
{
	if (current->arch.host == NULL) {
		current->arch.host = kmalloc(sizeof(struct host_container));
		if (current->arch.host == NULL)
			return -1;
	}

	void *stub_stack = boot_alloc_page();
	if (stub_stack == NULL)
		goto free_host;
	int ret = start_userspace(stub_stack);
	if (ret <= 0)
		goto free_stub_stack;

	current->arch.host->stub_stack = stub_stack;
	current->arch.host->host_pid = ret;
	current->arch.host->nr_threads = 1;

	/* unmap kernel area */
	if (host_munmap(current, (void *)KERNBASE, KERNTOP - KERNBASE) < 0)
		panic("unmap kernel area failed\n");

	/* erase kernel maps in the page table */
	int valid_size = KERNBASE / PTSIZE * sizeof(pte_t);
	memset((void *)((int)(current->mm->pgdir) + valid_size),
	       0, PGSIZE - valid_size);

	/* Copy arguments */
	current->arch.regs.is_user = 1;
	uintptr_t stacktop = USTACKTOP - argc * PGSIZE;
	char **uargv = (char **)(stacktop - argc * sizeof(char *));
	int i, addr;
	for (i = 0; i < argc; i++) {
		addr = stacktop + i * PGSIZE;
		assert(copy_to_user
		       (current->mm, uargv + i, &addr, sizeof(int)));
		assert(copy_to_user
		       (current->mm, (void *)addr, kargv[i],
			strlen(kargv[i]) + 1));
	}
	stacktop = (uintptr_t) uargv - sizeof(int);
	copy_to_user(current->mm, (void *)stacktop, &argc, sizeof(int));

	/* The copy of the args in the kernel will never be used again and we will not return,
	 *     so free them here.
	 */
	while (argc > 0) {
		kfree(kargv[--argc]);
	}
	userspace(&(current->arch.regs));
	/* should never comes here */

free_stub_stack:
	free_page(kva2page(stub_stack));
free_host:
	kfree(current->arch.host);
	current->arch.host = NULL;
	return -1;
}
예제 #2
0
int init_new_context(struct task_struct *task, struct mm_struct *mm)
{
 	struct mm_context *from_mm = NULL;
	struct mm_context *to_mm = &mm->context;
	unsigned long stack = 0;
	int ret = -ENOMEM;

	if (skas_needs_stub) {
		stack = get_zeroed_page(GFP_KERNEL);
		if (stack == 0)
			goto out;
	}

	to_mm->id.stack = stack;
	if (current->mm != NULL && current->mm != &init_mm)
		from_mm = &current->mm->context;

	if (proc_mm) {
		ret = new_mm(stack);
		if (ret < 0) {
			printk(KERN_ERR "init_new_context_skas - "
			       "new_mm failed, errno = %d\n", ret);
			goto out_free;
		}
		to_mm->id.u.mm_fd = ret;
	}
	else {
		if (from_mm)
			to_mm->id.u.pid = copy_context_skas0(stack,
							     from_mm->id.u.pid);
		else to_mm->id.u.pid = start_userspace(stack);

		if (to_mm->id.u.pid < 0) {
			ret = to_mm->id.u.pid;
			goto out_free;
		}
	}

	ret = init_new_ldt(to_mm, from_mm);
	if (ret < 0) {
		printk(KERN_ERR "init_new_context_skas - init_ldt"
		       " failed, errno = %d\n", ret);
		goto out_free;
	}

	return 0;

 out_free:
	if (to_mm->id.stack != 0)
		free_page(to_mm->id.stack);
 out:
	return ret;
}
예제 #3
0
int start_uml_skas(void)
{
	if(proc_mm)
		userspace_pid[0] = start_userspace(0);

	init_new_thread_signals();

	init_task.thread.request.u.thread.proc = start_kernel_proc;
	init_task.thread.request.u.thread.arg = NULL;
	return(start_idle_thread(task_stack_page(&init_task),
				 &init_task.thread.mode.skas.switch_buf,
				 &init_task.thread.mode.skas.fork_buf));
}
예제 #4
0
int start_uml_skas(void)
{
	stack_protections((unsigned long) &cpu0_irqstack);
	set_sigstack(cpu0_irqstack, THREAD_SIZE);
	if(proc_mm)
		userspace_pid[0] = start_userspace(0);

	init_new_thread_signals();

	init_task.thread.request.u.thread.proc = start_kernel_proc;
	init_task.thread.request.u.thread.arg = NULL;
	return(start_idle_thread(task_stack_page(&init_task),
				 &init_task.thread.mode.skas.switch_buf));
}
예제 #5
0
파일: process.c 프로젝트: Benz0X/bdroid
int __init start_uml(void)
{
    stack_protections((unsigned long) &cpu0_irqstack);
    set_sigstack(cpu0_irqstack, THREAD_SIZE);
    if (proc_mm) {
        userspace_pid[0] = start_userspace(0);
        if (userspace_pid[0] < 0) {
            printf("start_uml - start_userspace returned %d\n",
                   userspace_pid[0]);
            exit(1);
        }
    }

    init_new_thread_signals();

    init_task.thread.request.u.thread.proc = start_kernel_proc;
    init_task.thread.request.u.thread.arg = NULL;
    return start_idle_thread(task_stack_page(&init_task),
                             &init_task.thread.switch_buf);
}
예제 #6
0
파일: mmu.c 프로젝트: 3sOx/asuswrt-merlin
int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
{
 	struct mmu_context_skas *from_mm = NULL;
	struct mmu_context_skas *to_mm = &mm->context.skas;
	unsigned long stack = 0;
	int ret = -ENOMEM;

	if(skas_needs_stub){
		stack = get_zeroed_page(GFP_KERNEL);
		if(stack == 0)
			goto out;

		/* This zeros the entry that pgd_alloc didn't, needed since
		 * we are about to reinitialize it, and want mm.nr_ptes to
		 * be accurate.
		 */
		mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);

		ret = init_stub_pte(mm, CONFIG_STUB_CODE,
				    (unsigned long) &__syscall_stub_start);
		if(ret)
			goto out_free;

		ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
		if(ret)
			goto out_free;

		mm->nr_ptes--;
	}

	to_mm->id.stack = stack;
	if(current->mm != NULL && current->mm != &init_mm)
		from_mm = &current->mm->context.skas;

	if(proc_mm){
		ret = new_mm(stack);
		if(ret < 0){
			printk("init_new_context_skas - new_mm failed, "
			       "errno = %d\n", ret);
			goto out_free;
		}
		to_mm->id.u.mm_fd = ret;
	}
	else {
		if(from_mm)
			to_mm->id.u.pid = copy_context_skas0(stack,
							     from_mm->id.u.pid);
		else to_mm->id.u.pid = start_userspace(stack);
	}

	ret = init_new_ldt(to_mm, from_mm);
	if(ret < 0){
		printk("init_new_context_skas - init_ldt"
		       " failed, errno = %d\n", ret);
		goto out_free;
	}

	return 0;

 out_free:
	if(to_mm->id.stack != 0)
		free_page(to_mm->id.stack);
 out:
	return ret;
}
예제 #7
0
파일: test.c 프로젝트: imgits/COSEC
void test_tasks(void) {
    def_task = task_current();

#if 0
    task_kthread_init(&task0, (void *)do_task0,
            (void *)((ptr_t)task0_stack + TASK_KERNSTACK_SIZE - 0x20));
    task_kthread_init(&task1, (void *)do_task1,
            (void *)((ptr_t)task1_stack + TASK_KERNSTACK_SIZE - 0x20));
#else
    const segment_selector ucs = { .as.word = SEL_USER_CS };
    const segment_selector uds = { .as.word = SEL_USER_DS };

    uint espU0 = ((uint)task0_usr_stack + R3_STACK_SIZE - 0x18);
    uint espK0 = ((uint)task0_stack + TASK_KERNSTACK_SIZE - CONTEXT_SIZE - 0x14);

    uint espU1 = ((ptr_t)task1_usr_stack + R3_STACK_SIZE);
    uint espK1 = ((ptr_t)task1_stack + TASK_KERNSTACK_SIZE - CONTEXT_SIZE - 0x14);

    task_init((task_struct *)&task0, (void *)do_task0,
            (void *)espK0, (void *)espU0, ucs, uds);
    task_init((task_struct *)&task1, (void *)do_task1,
            (void *)espK1, (void *)espU1, ucs, uds);
#endif

    /* allow tasks to update cursor with `outl` */
    task0.tss.eflags |= eflags_iopl(PL_USER);
    task1.tss.eflags |= eflags_iopl(PL_USER);

    quit = false;
    kbd_set_onpress((kbd_event_f)key_press);
    task_set_scheduler(next_task);

    /* wait for first timer tick, when execution will be transferred to do_task0 */
    cpu_halt();

    task_set_scheduler(null);
    kbd_set_onpress(null);

    k_printf("\nBye.\n");
}

/***********************************************************/
void run_userspace(void) {
    char buf[100];
    snprintf(buf, 100, "Current privilege level = %d\n", i386_current_privlevel());
    size_t nbuf = strlen(buf);

    asm("int $0x80 \n" ::
            "a"(SYS_WRITE),
            "c"(STDOUT_FILENO),
            "d"((uint)buf),
            "b"(nbuf));
    while (1);
}

extern void start_userspace(uint eip3, uint cs3, uint eflags, uint esp3, uint ss3);

task_struct task3;

void test_userspace(void) {
    /* init task */
    task3.tss.eflags = x86_eflags(); // | eflags_iopl(PL_USER);
    task3.tss.cs = SEL_USER_CS;
    task3.tss.ds = task3.tss.es = task3.tss.fs = task3.tss.gs = SEL_USER_DS;
    task3.tss.ss = SEL_USER_DS;
    task3.tss.esp = (uint)task0_usr_stack + R3_STACK_SIZE - CONTEXT_SIZE - 0x20;
    task3.tss.eip = (uint)run_userspace;
    task3.tss.ss0 = SEL_KERN_DS;
    task3.tss.esp0 = (uint)task0_stack + R0_STACK_SIZE - CONTEXT_SIZE - 0x20;

    /* make a GDT task descriptor */
    segment_descriptor taskdescr;
    segdescr_taskstate_init(taskdescr, (uint)&(task3.tss), PL_USER);
    segdescr_taskstate_busy(taskdescr, 0);

    index_t taskdescr_index = gdt_alloc_entry(taskdescr);

    segment_selector tss_sel;
    tss_sel.as.word = make_selector(taskdescr_index, 0, taskdescr.as.strct.dpl);

    kbd_set_onpress((kbd_event_f)key_press);

    uint efl = 0x00203202;
    test_eflags();
    logmsgf("efl = 0x%x\n", efl);
    logmsgf("tss_sel = 0x%x\n", (uint)tss_sel.as.word);
    logmsgf("tssd = %x %x\n", taskdescr.as.ints[0], taskdescr.as.ints[1]);
    logmsgf("tssd.base = %x\n", taskdescr.as.strct.base_l +
            (taskdescr.as.strct.base_m << 16) + (taskdescr.as.strct.base_h << 24));

    /* load TR and LDT */
    i386_load_task_reg(tss_sel);
    //asm ("lldt %%ax     \n\t"::"a"( SEL_DEF_LDT ));

    /* go userspace */
    start_userspace(
        (uint)run_userspace, task3.tss.cs,
        //(uint)run_userspace, (uint)tss_sel.as.word,
        efl,
        task3.tss.esp, task3.tss.ss);
}
예제 #8
0
파일: proc.c 프로젝트: Aresthu/ucore_plus
/**
 * Make a copy of the current thread/process, giving the parent the child's pid and the child 0.
 *     This is called in do_fork after all structures in the child's PCB are ready.
 * @param clone_flags we need this to determine whether we're creating a 'thread' or a 'process'
 * @param proc the PCB of the child
 * @param user_stack the stack used by the child
 * @param tf the struct containing 'fn' and 'arg'
 * @return 0 if succeeds, or -1 otherwise
 */
int
copy_thread(uint32_t clone_flags, struct proc_struct *proc,
	    uintptr_t user_stack, struct trapframe *tf)
{
	int pid;
	void *stub_stack;

	/* If 'do_fork' is called by the kernel, 'current' should be idle,
	 *     and we're actually creating a kernel thread .
	 * If 'do_fork' is called by the user (i.e. syscall), 'current' is a user PCB,
	 *     and we need to create another user process.
	 */
	if (RUN_AS_USER) {
		if (clone_flags & CLONE_VM) {
			/* Use current host process as its container */
			proc->arch.host = current->arch.host;
			proc->arch.host->nr_threads++;
		} else {
			/* Create a new child process */
			proc->arch.host =
			    kmalloc(sizeof(struct host_container));
			if (proc->arch.host == NULL)
				goto exit;

			stub_stack = boot_alloc_page();
			if (stub_stack == NULL)
				goto exit_free_host;
			pid = start_userspace(stub_stack);

			if (pid < 0)
				goto exit_free_stub;

			/* Initialize host process descriptor */
			proc->arch.forking = 0;
			proc->arch.host->host_pid = pid;
			proc->arch.host->nr_threads = 1;
			proc->arch.host->stub_stack =
			    (struct stub_stack *)stub_stack;
			/* unmap kernel area. */
			if (host_munmap
			    (proc, (void *)KERNBASE, KERNTOP - KERNBASE) < 0)
				panic("unmap kernel area failed \n");
		}
		/* The child should have the same regs as the parent's. */
		memcpy(&(proc->arch.regs.regs), &(current->arch.regs.regs),
		       sizeof(struct user_regs_struct));

		/* make the child return 0 for the syscall */
		proc->arch.regs.regs.eax = 0;

		proc->arch.regs.regs.esp = user_stack;

		/* The current thread will run in 'userspace' */
		proc->context.switch_buf->__ebx = (uint32_t) userspace;
		proc->context.switch_buf->__ebp =
		    (uint32_t) & (proc->arch.regs);
	} else {
		/* For kernel thread */
		proc->context.switch_buf->__ebx = (uint32_t) (tf->fn);
		proc->context.switch_buf->__ebp = (uint32_t) (tf->arg);
	}
	/* All new threads/processes start running from 'kernel_thread_entry'
	 *     for the 'processes' actually means 'monitor threads' to the kernel.
	 */
	proc->context.switch_buf->__eip = (uint32_t) kernel_thread_entry;
	proc->context.switch_buf->__esp = proc->kstack + KSTACKSIZE;

	return 0;

exit_free_stub:
	free_page(kva2page(stub_stack));
exit_free_host:
	kfree(proc->arch.host);
exit:
	return -1;
}