/* Responible for creating the uthread and initializing its user trap frame */ struct uthread *pth_thread_create(void (*func)(void), void *udata) { struct pthread_tcb *pthread; pthread_attr_t *attr = (pthread_attr_t*)udata; pthread = (pthread_t)calloc(1, sizeof(struct pthread_tcb)); assert(pthread); pthread->stacksize = PTHREAD_STACK_SIZE; /* default */ pthread->id = get_next_pid(); pthread->detached = FALSE; /* default */ /* Respect the attributes */ if (attr) { if (attr->stacksize) /* don't set a 0 stacksize */ pthread->stacksize = attr->stacksize; if (attr->detachstate == PTHREAD_CREATE_DETACHED) pthread->detached = TRUE; } /* allocate a stack */ if (__pthread_allocate_stack(pthread)) printf("We're f****d\n"); /* Set the u_tf to start up in __pthread_run, which will call the real * start_routine and pass it the arg. Note those aren't set until later in * pthread_create(). */ init_user_tf(&pthread->uthread.utf, (uint32_t)__pthread_run, (uint32_t)(pthread->stacktop)); return (struct uthread*)pthread; }
/** * Create a kernel task. It's state will be TASK_RUNNABLE and * the type will be TASK_KERN. * @start: function the task will start at, no arguments and returns void */ struct task_struct *ktask_create(void (*start)(void), const char *name) { struct task_struct *task; uint64_t *stack; stack = (uint64_t *)get_free_page(0); if(!stack) return NULL; task = kmalloc(sizeof(*task)); if(!task) goto out_stack; memset(task, 0, sizeof(*task)); task->type = TASK_KERN; task->state = TASK_RUNNABLE; /* Put the start function on the stack for switch_to */ task->first_switch = 1; task->foreground = 1; /* all kernel threads can read input */ stack[510] = (uint64_t)start; task->kernel_rsp = (uint64_t)&stack[510]; task->mm = &kernel_mm; kernel_mm.mm_count++; task->pid = get_next_pid(); task_set_cmdline(task, name); strcpy(task->cwd, "/"); /* set cwd to root for ktasks */ task->timeslice = TIMESLICE_BASE; task_add_new(task); /* add to run queue and task list */ return task; out_stack: free_page((uint64_t)stack); return NULL; }
void sched_init() { // Creamos la tarea ``init`` task_t *init = kmalloc(sizeof(task_t)); init->prog = kmalloc(sizeof(program_t)); init->prog->name = "init"; init->pd = kernel_pd; init->kernel_stack = KERNEL_STACK_TOP; init->kernel_stack_limit = KERNEL_STACK_BOTTOM; init->waiting = FALSE; init->waited = FALSE; init->parent = NULL; init->ticks = 0; init->quantum = SCHED_QUANTUM; restart_quantum(init); init->pid = get_next_pid(); // El stack de nivel 0 no interesa. Deberia sobreescribirse al cambiar de // tarea. Ademas, como estamos en espacio de kernel, no se deberia utilizar // el valor del stack de nivel 0 que esta en la TSS. init->kernel_stack_pointer = NULL; setup_tss(NULL); add_task(init); sti(); init_task(); }
/** * Return a copy of the current task. */ struct task_struct *fork_curr_task(void) { struct task_struct *task; uint64_t *kstack, *curr_kstack; int i; kstack = (uint64_t *)get_free_page(0); if(!kstack) return NULL; task = kmalloc(sizeof(*task)); if(!task) goto out_stack; /* Half the remaining timeslice (split between parent and child) */ curr_task->timeslice >>= 1; memcpy(task, curr_task, sizeof(*task)); /* Exact copy of parent */ /* deep copy the current mm */ task->mm = mm_deep_copy(); if(task->mm == NULL) goto out_task; /* Copy the curr_task's kstack */ curr_kstack = (uint64_t *)ALIGN_DOWN(read_rsp(), PAGE_SIZE); memcpy(kstack, curr_kstack, PAGE_SIZE); task->kernel_rsp = (uint64_t)&kstack[510]; /* new kernel stack */ task->pid = get_next_pid(); /* new pid */ task->parent = curr_task; /* new parent */ task->chld = task->sib = NULL; /* no children/siblings yet */ task->next_task = task->prev_task = task->next_rq = NULL; /* Increment reference counts on any open files */ for(i = 0; i < TASK_FILES_MAX; i++) { struct file *fp = task->files[i]; if(fp) { fp->f_count++; } } /* Add this new child to the parent */ add_child(curr_task, task); /* TODO: Here we steal our parent's foreground status */ if(curr_task->pid > 2) curr_task->foreground = 0;/* change to 1; to let all tasks read */ task_add_new(task); /* add to run queue and task list */ return task; out_task: kfree(task); out_stack: free_page((uint64_t)kstack); return NULL; }
/* Crea una nueva tarea lista para ser ejecutada. * - ``pd`` es la direccion virtual del directorio de paginas de la tarea;; */ task_t *create_task(uint32_t pd[], struct program_t *prog) { task_t *task = kmalloc(sizeof(task_t)); task->prog = prog; task->pd = pd; task->waiting = FALSE; task->waited = FALSE; task->parent = NULL; task->ticks = 0; task->quantum = SCHED_QUANTUM; restart_quantum(task); task->pid = get_next_pid(); // Alojamos memoria para el stack del kernel de la tarea task->kernel_stack = new_kernel_page(); task->kernel_stack_limit = task->kernel_stack + PAGE_SIZE; task->kernel_stack_pointer = task->kernel_stack_limit; // Escribimos el task_state_t en la pila del kernel void *stack_pointer = elf_stack_bottom(prog->file); void *start_task_routine = START_TASK_VIRT_ADDR; task->kernel_stack_pointer -= sizeof(task_state_t); task_state_t *st = (task_state_t *)task->kernel_stack_pointer; // El stack pointer arranca en 2 posiciones abajo del tope. Una es para // la direccion de retorno a la que start_task deberia volver. La otra es // para el parametro de start_task, que sera justamente el punto de // entrada de la tarea. initialize_task_state(st, start_task_routine, stack_pointer - 8); // Direccion del task_t correspondiente a la tarea task->kernel_stack_pointer -= 4; *((void **)task->kernel_stack_pointer) = task; // Direccion de la rutina que inicializa la tarea task->kernel_stack_pointer -= 4; *((void **)task->kernel_stack_pointer) = initialize_task; // El valor de esta entrada en el stack no deberia tener ninguna // importancia. Es el valor que adquiere ebp al cambiar el contexto al // de la tarea nueva. Este registro no es usado hasta que adquiere el valor // que indica el task_state_t inicial de la tarea. task->kernel_stack_pointer -= 4; *((void **)task->kernel_stack_pointer) = NULL; return task; }
process_t* new_process(process_entry_point_t func) { uint32_t user_stack_size = 0x100000; // XXX: this constant is already defined in boot.S, reuse process_t *p = kmalloc(sizeof(process_t)); void *stack = kmalloc(user_stack_size); uint32_t *sp = (uint32_t*)(stack) + user_stack_size/4; p->stack_bottom = sp; p->pid = get_next_pid(); void *env = NULL; //void *exit_fn = NULL; //*(--sp) = 0x00000010; // CPSR (user mode with interrupts enabled) *(--sp) = (uint32_t)func; // 'return' address (i.e. where we come in) *(--sp) = 0x0c0c0c0c; // r12 *(--sp) = 0x0b0b0b0b; // r11 *(--sp) = 0x0a0a0a0a; // r10 *(--sp) = 0x09090909; // r9 *(--sp) = 0x08080808; // r8 *(--sp) = 0x07070707; // r7 *(--sp) = 0x06060606; // r6 *(--sp) = 0x05050505; // r5 *(--sp) = 0x04040404; // r4 *(--sp) = 0x03030303; // r3 *(--sp) = 0x02020202; // r2 *(--sp) = 0x01010101; // r1 *(--sp) = (uint32_t)env; // r0, i.e. arg to entry function /* if ((uint32_t)sp & 0x07) { *(--sp) = 0xdeadc0de; // Stack filler *(--sp) = (uint32_t)exit_fn; // lr, where we go on exit *(--sp) = 0x00000004; // Stack Adjust } else { *(--sp) = (uint32_t)exit_fn; // lr, where we go on exit *(--sp) = 0x00000000; // Stack Adjust } */ p->stack_ptr = sp; return p; }
/* Do whatever init you want. Return a uthread representing thread0 (int * main()) */ struct uthread *pth_init(void) { struct mcs_lock_qnode local_qn = {0}; /* Tell the kernel where and how we want to receive events. This is just an * example of what to do to have a notification turned on. We're turning on * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to * send to vcore 0. Note sys_self_notify will ignore the vcoreid pref. * Also note that enable_kevent() is just an example, and you probably want * to use parts of event.c to do what you want. */ enable_kevent(EV_USER_IPI, 0, EVENT_IPI); /* Handle syscall events. Using small ev_qs, with no internal ev_mbox. */ ev_handlers[EV_SYSCALL] = pth_handle_syscall; /* Set up the per-vcore structs to track outstanding syscalls */ sysc_mgmt = malloc(sizeof(struct sysc_mgmt) * max_vcores()); assert(sysc_mgmt); for (int i = 0; i < max_vcores(); i++) { /* Set up each of the per-vcore syscall event queues so that they point * to the VCPD/default vcore mailbox (for now) Note you'll need the * vcore to be online to get the events (for now). */ sysc_mgmt[i].ev_q.ev_mbox = &__procdata.vcore_preempt_data[i].ev_mbox; sysc_mgmt[i].ev_q.ev_flags = EVENT_IPI; /* totally up to you */ sysc_mgmt[i].ev_q.ev_vcore = i; /* Init the list and other data */ TAILQ_INIT(&sysc_mgmt[i].pending_syscs); sysc_mgmt[i].handling_overflow = FALSE; } /* Create a pthread_tcb for the main thread */ pthread_t t = (pthread_t)calloc(1, sizeof(struct pthread_tcb)); assert(t); t->id = get_next_pid(); assert(t->id == 0); /* Put the new pthread on the active queue */ mcs_lock_notifsafe(&queue_lock, &local_qn); threads_active++; TAILQ_INSERT_TAIL(&active_queue, t, next); mcs_unlock_notifsafe(&queue_lock, &local_qn); return (struct uthread*)t; }
/* Init a dummy idle proc */ void init_idle_proc() { idle_proc = (pcb_t*) malloc(sizeof(pcb_t)); if(!idle_proc) { log_err("Cannot malloc idle proc!"); return; } bzero(idle_proc, sizeof(pcb_t)); idle_proc->user_context.pc = DoDoIdle; idle_proc->user_context.sp = (void *)kernel_memory.stack_low; //idle_proc->user_context.ebp = (void *)kernel_memory.stack_low; //idle_proc->user_context.code = YALNIX_NOP; //idle_proc->user_context.vector = TRAP_KERNEL; idle_proc->page_table = (pte_t*) malloc(sizeof(pte_t) * GET_PAGE_NUMBER(VMEM_1_SIZE)); idle_proc->kernel_stack_pages = (pte_t*) malloc(sizeof(pte_t) * KERNEL_STACK_MAXSIZE / PAGESIZE); map_page_to_frame(idle_proc->page_table, 0, GET_PAGE_NUMBER(VMEM_1_SIZE), PROT_READ); idle_proc->pid = get_next_pid(); idle_proc->state = READY; idle_proc->init_done = 0; //init_process_kernel(idle_proc); return; }
/* A general function to initialize user proc * * @return: A pointer to the newly created pcb; * NULL if creation fails */ pcb_t *init_user_proc(pcb_t* parent) { // Create pcb pcb_t *proc = (pcb_t*) malloc(sizeof(pcb_t)); if(!proc) { log_err("Cannot malloc user proc!"); return NULL; } bzero(proc, sizeof(pcb_t)); // Create page table proc->page_table = (pte_t*) malloc(sizeof(pte_t) * GET_PAGE_NUMBER(VMEM_1_SIZE)); if(!proc->page_table) { log_err("proc->page_table cannot be malloc!"); return NULL; } bzero(proc->page_table, sizeof(pte_t) * GET_PAGE_NUMBER(VMEM_1_SIZE)); // Create kernel stack page table proc->kernel_stack_pages = (pte_t*) malloc(sizeof(pte_t) * KERNEL_STACK_MAXSIZE / PAGESIZE); if(!proc->kernel_stack_pages) { log_err("proc->kernel_stack_pages cannot be malloc!"); return NULL; } bzero(proc->kernel_stack_pages, sizeof(pte_t) * KERNEL_STACK_MAXSIZE / PAGESIZE); // Init vitals proc->init_done = 0; proc->parent = (struct y_PBC*)parent; proc->children = dlist_init(); proc->zombie = dlist_init(); proc->pid = get_next_pid(); if(parent) { dlist_add_tail(parent->children, proc); } proc->state = READY; proc->wait_zombie = 0; return proc; }
static gboolean show_task(TraceViewStore *store, struct pevent *pevent, struct record *record, gint pid) { gint event_id; if (view_task(store, pid)) return TRUE; event_id = pevent_data_type(pevent, record); if (store->sched_switch_next_field && event_id == store->sched_switch_event->id) { /* show sched switch to task */ pid = get_next_pid(store, pevent, record); if (view_task(store, pid)) return TRUE; } if (store->sched_wakeup_pid_field && event_id == store->sched_wakeup_event->id) { /* show sched switch to task */ pid = get_wakeup_pid(store, pevent, record); if (view_task(store, pid)) return TRUE; } if (store->sched_wakeup_new_pid_field && event_id == store->sched_wakeup_new_event->id) { /* show sched switch to task */ pid = get_wakeup_new_pid(store, pevent, record); if (view_task(store, pid)) return TRUE; } return FALSE; }
/** * \private * create a pcb with all the needed value at the specified location */ uint32_t create_proc(char *name, uint32_t prio, uint32_t argc, char **params) { uint32_t *i, j; int32_t pid; pcb *p; prgm *prg; //kdebug_println("Create process in"); if (name == NULL) return NULLPTR; if (prio > MAX_PRI || prio < MIN_PRI) return INVARG; if (pcb_counter <= MAXPCB) { /* * Allocate a pcb */ p = alloc_pcb(); if (p == NULL) return OUTOMEM; /* * Reset the pcb */ pcb_reset(p); /* * Check that the program exist */ prg = search_prgm(name); if (prg == NULL) return INVARG; /* * Set the name */ pcb_set_name(p, name); /* * init the program counter */ pcb_set_epc(p, (uint32_t) prg->address); /* * get a pid */ pid = get_next_pid(); if (pid < 0) return pid; /* contain an error code */ pcb_set_pid(p, pid); /* set the pid */ pcb_set_pri(p, prio); /* set the priority */ /* * Set the supervisor of the process, which is the one we ask for the creation * or -1 if the system ask. * This value is in the global variable current_pcb */ if (current_pcb != NULL) { pcb_set_supervisor(p, pcb_get_pid(current_pcb)); pcb_set_supervised(current_pcb, pid); } else pcb_set_supervisor(p, -1); /* <<<<<<< HEAD:src/kernel/kprocess.c <<<<<<< HEAD:src/kernel/kprocess.c * Set the parameters of the function */ //p->registers.a_reg[0] = (params == NULL) ? 0 : stoi(get_arg(params, 0)) + 1; //p->registers.a_reg[1] = (uint32_t) params; /* the adresse of the first arg */ if (params != NULL) { p->registers.a_reg[0] = argc + 1; p->registers.a_reg[1] = (uint32_t) params; } else { p->registers.a_reg[0] = 0; p->registers.a_reg[1] = 0; } /* ======= >>>>>>> 3e4887fd7d8130975ae6c220ed2077f5f2538be9:src/kernel/kprocess.c * Set the stack pointer ======= * Set the stack pointer >>>>>>> ef0b08729fd10e82db039bea92d2ce232b3a027b:src/kernel/kprocess.c */ i = allocate_stack(pcb_get_pid(p)); if (i == NULL) return OUTOMEM; /* * We add the arg on the stack */ //kprint("sp set\n"); if (params != NULL) { //kprint((char *) params); //kprint("params not null\n"); //kprint(itos((uint32_t) i, c)); //kprint("\n"); i = (uint32_t *) ((uint32_t) i - (ARG_SIZE * (argc + 1) * sizeof(char))); /* set the sp after the arg */ //kprint(itos((uint32_t) i, c)); //kprint("\n"); pcb_set_sp(p, (uint32_t) i); /* set the stack pointer */ for (j = 0; j < (argc + 1) * (ARG_SIZE * sizeof(char) / sizeof(uint32_t)); j++) { //kprint("Copy params\n"); *i = (uint32_t) * params; //kprint("Param copied\n"); //i += ARG_SIZE * sizeof(char); i++; (uint32_t *) params++; } //kprint((char *) pcb_get_sp(p)); } else pcb_set_sp(p, (uint32_t) i); //kprint("copy arg done\n"); /* * Set the parameters of the function * The begin of the parameters are pointed by the stack pointer */ if (params != NULL) { p->registers.a_reg[0] = argc + 1; p->registers.a_reg[1] = (uint32_t) pcb_get_sp(p); } else { p->registers.a_reg[0] = 0; p->registers.a_reg[1] = 0; } /* * Set the state */ pcb_set_state(p, READY); /* * Set the last error */ pcb_set_error(p, OMGROXX); /* * The pcb is no more empty */ pcb_set_empty(p, FALSE); /* * Now we can add the pcb to the ready list */ if (pls_add(&plsready, p) == OUTOMEM) { /* * Adding fail, don't forget to dealloc every allocated stuff */ deallocate_stack(pcb_get_pid(p)); pcb_reset(p); return OUTOMEM; } /* * Everything goes well, we add one to the pcb_counter */ pcb_counter++; } else return OUTOMEM; //kdebug_println("Create process out"); return pid; }