/** * 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; }
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 = ¤t->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; }
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)); }
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)); }
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); }
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 = ¤t->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; }
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); }
/** * 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; }