diff --git a/include/l4/api/exregs.h b/include/l4/api/exregs.h index c1cf099..f6b50d3 100644 --- a/include/l4/api/exregs.h +++ b/include/l4/api/exregs.h @@ -11,10 +11,16 @@ #include INC_GLUE(context.h) #include +enum exregs_flags { + EXREGS_SET_PAGER = 1, +}; + /* Structure passed by userspace pagers for exchanging registers */ struct exregs_data { exregs_context_t context; u32 valid_vect; + u32 flags; + l4id_t pagerid; }; diff --git a/include/l4/arch/arm/exception.h b/include/l4/arch/arm/exception.h index 2cf880b..55dfed1 100644 --- a/include/l4/arch/arm/exception.h +++ b/include/l4/arch/arm/exception.h @@ -75,16 +75,9 @@ static inline void irq_local_disable() /* This is filled on entry to irq handler, only if a process was interrupted.*/ extern unsigned int preempted_psr; -#include -static inline int task_in_kernel(struct tcb *t) -{ - return ((t->context.spsr & ARM_MODE_MASK) == ARM_MODE_SVC) ? 1 : 0; -} - -static inline int task_in_user(struct tcb *t) -{ - return !task_in_kernel(t); -} +/* Implementing these as functions cause circular include dependency for tcb.h */ +#define TASK_IN_KERNEL(tcb) (((tcb)->context.spsr & ARM_MODE_MASK) == ARM_MODE_SVC) +#define TASK_IN_USER(tcb) (!TASK_IN_KERNEL(tcb)) static inline int in_kernel() { diff --git a/include/l4/generic/scheduler.h b/include/l4/generic/scheduler.h index 932d762..3fc55ba 100644 --- a/include/l4/generic/scheduler.h +++ b/include/l4/generic/scheduler.h @@ -35,6 +35,7 @@ static inline struct ktcb *current_task(void) | SCHED_FL_SUSPEND) void sched_runqueue_init(void); +void sched_init_task(struct ktcb *task); void sched_start_task(struct ktcb *task); void sched_resume_task(struct ktcb *task); void sched_suspend_task(struct ktcb *task); diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 996b96c..abe5627 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -102,12 +102,6 @@ static inline int add_task_global(struct ktcb *new) return 0; } - -static inline void set_task_flags(struct ktcb *task, unsigned int fl) -{ - task->flags |= fl; -} - /* * Each task is allocated a unique global id. A thread group can only belong to * a single leader, and every thread can only belong to a single thread group. diff --git a/include/l4/glue/arm/context.h b/include/l4/glue/arm/context.h index 9ecd428..f75dfd3 100644 --- a/include/l4/glue/arm/context.h +++ b/include/l4/glue/arm/context.h @@ -5,10 +5,10 @@ /* * This describes the register context of each task. Simply set - * them as regular structure fields, and they'll be copied onto - * real registers upon a context switch to that task. Normally - * exchange_registers() system call is designed for this, whose - * input structure is defined further below. + * them and they'll be copied onto real registers upon a context + * switch to that task. exchange_registers() system call is + * designed for this, whose input structure is defined further + * below. */ typedef struct arm_context { u32 spsr; /* 0x0 */ diff --git a/src/api/syscall.c b/src/api/syscall.c index 4c43d18..04f6174 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -28,148 +28,55 @@ void print_syscall_context(struct ktcb *t) r->r5, r->r6, r->r7, r->r8, r->sp_usr, r->lr_usr); } -/* - * Bigger, slower but typed, i.e. if task_context_t or syscall_context_t - * fields are reordered in the future, this would not break. - */ -void do_exchange_registers_bigslow(struct tcb *task, struct exregs_data *exregs) +/* Copy each register to task's context if its valid bit is set */ +void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs) { - unsigned int create_flags = task->flags; task_context_t *context = &task->context; - syscall_context_t *sysregs = task->syscall_regs; /* * NOTE: * We don't care if register values point at invalid addresses * since memory protection would prevent any kernel corruption. - * We do however, make sure spsr is not modified, and pc is - * modified only for the userspace. + * We do however, make sure spsr is not modified */ - /* - * If the thread is returning from a syscall, - * we modify the register state pushed to syscall stack. - */ - if ((create_flags == THREAD_COPY_SPACE) || - (create_flags == THREAD_SAME_SPACE)) { - /* Check register valid bit and copy registers */ - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r0)) - syscall_regs->r0 = exregs->context.r0; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r1)) - syscall_regs->r1 = exregs->context.r1; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r2)) - syscall_regs->r2 = exregs->context.r2; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r3)) - syscall_regs->r3 = exregs->context.r3; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r4)) - syscall_regs->r4 = exregs->context.r4; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r5)) - syscall_regs->r5 = exregs->context.r5; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r6)) - syscall_regs->r6 = exregs->context.r6; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r7)) - syscall_regs->r7 = exregs->context.r7; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r8)) - syscall_regs->r8 = exregs->context.r8; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r9)) - syscall_regs->r9 = exregs->context.r9; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r10)) - syscall_regs->r10 = exregs->context.r10; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r11)) - syscall_regs->r11 = exregs->context.r11; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, r12)) - syscall_regs->r12 = exregs->context.r12; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, sp_usr)) - syscall_regs->sp_usr = exregs->context.sp; - if (exregs.valid_vect & FIELD_TO_BIT(syscall_regs_t, sp_lr)) - syscall_regs->sp_lr = exregs->context.lr; - /* Cannot modify program counter of a thread in kernel */ + /* Check register valid bit and copy registers */ + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r0)) + context->r0 = exregs->context.r0; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r1)) + context->r1 = exregs->context.r1; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r2)) + context->r2 = exregs->context.r2; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r3)) + context->r3 = exregs->context.r3; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r4)) + context->r4 = exregs->context.r4; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r5)) + context->r5 = exregs->context.r5; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r6)) + context->r6 = exregs->context.r6; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r7)) + context->r7 = exregs->context.r7; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r8)) + context->r8 = exregs->context.r8; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r9)) + context->r9 = exregs->context.r9; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r10)) + context->r10 = exregs->context.r10; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r11)) + context->r11 = exregs->context.r11; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, r12)) + context->r12 = exregs->context.r12; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, sp)) + context->sp = exregs->context.sp; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, lr)) + context->lr = exregs->context.lr; + if (exregs->valid_vect & FIELD_TO_BIT(task_context_t, pc)) + context->pc = exregs->context.pc; - /* If it's a new thread or it's in userspace, modify actual context */ - } else if ((create_flags == THREAD_NEW_SPACE) || - (!create_flags && task_in_user(task))) { - /* Copy registers */ - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r0)) - context->r0 = exregs->context.r0; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r1)) - context->r1 = exregs->context.r1; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r2)) - context->r2 = exregs->context.r2; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r3)) - context->r3 = exregs->context.r3; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r4)) - context->r4 = exregs->context.r4; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r5)) - context->r5 = exregs->context.r5; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r6)) - context->r6 = exregs->context.r6; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r7)) - context->r7 = exregs->context.r7; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r8)) - context->r8 = exregs->context.r8; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r9)) - context->r9 = exregs->context.r9; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r10)) - context->r10 = exregs->context.r10; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r11)) - context->r11 = exregs->context.r11; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, r12)) - context->r12 = exregs->context.r12; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, sp)) - context->sp = exregs->context.sp; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, lr)) - context->lr = exregs->context.lr; - if (exregs.valid_vect & FIELD_TO_BIT(task_context_t, pc)) - context->pc = exregs->context.pc; - - /* Set spsr as user mode if thread is new */ - if (create_flags == THREAD_NEW_SPACE) - task->context.spsr = ARM_MODE_USR; - } else - BUG(); -} - -/* - * This is smaller and faster but would break if task_context_t or - * syscall_regs_t types change, i.e. if their fields are reordered. - */ -void do_exchange_registers(struct tcb *task, struct exregs_data *exregs) -{ - unsigned int create_flags = task->flags; - u32 *context_ptr, *exregs_ptr = (u32 *)&exregs.context; - - /* - * NOTE: - * We don't care if register values point at invalid addresses - * since memory protection would prevent any kernel corruption. - */ - - /* - * If the thread is returning from a syscall, - * we modify the register state pushed to syscall stack. - */ - if ((create_flags == THREAD_COPY_SPACE) || - (create_flags == THREAD_SAME_SPACE)) { - context_ptr = (u32 *)&task->syscall_regs->r0; - } else if (create_flags == THREAD_NEW_SPACE) { - context_ptr = (u32 *)&task->context.r0; - task->context.spsr = ARM_MODE_USR; - } else - BUG(); - - /* Traverse the validity bit vector and copy exregs to task context */ - for (int i = 0; i < (sizeof(exregs->context) / sizeof(u32)); i++) { - if (exregs.valid_vect & (1 << i)) { - /* NOTE: If structures change, this may break. */ - context_ptr[i] = exregs_ptr[i]; - } - } - if (create_flags == THREAD_NEW_SPACE) - - /* Set its registers */ - task->context.pc = pc; - task->context.sp = sp; - task->context.spsr = ARM_MODE_USR; + /* Set thread's pager if one is supplied */ + if (exregs->flags & EXREGS_SET_PAGER) + task->pagerid = exregs->pagerid; } @@ -178,34 +85,22 @@ void do_exchange_registers(struct tcb *task, struct exregs_data *exregs) * * This call is used by the pagers to set (and in the future read) * the register context of a thread. The thread's registers can be - * set in 2 thread states: - * - * 1) The thread is executing in userspace: - * i. A newly created thread with a new address space. - * ii. An existing thread that is in userspace. - * - * 2) The thread is executing in the kernel, but suspended when it - * is about to execute "return_from_syscall": - * i. A thread that is just created in an existing address space. - * ii. A thread that is just created copying an existing address space. - * - * These conditions are detected and accordingly the task context is - * modified. A thread executing in the kernel cannot be modified - * since this would compromise the kernel. Also the thread must be - * in suspended condition so that it does not start to execute as we - * modify its context. - * - * TODO: This is an arch-specific call, can move it to ARM + * set only when the thread is in user mode. A newly created thread + * that is the copy of another thread (forked or cloned) will also + * be given its user mode context so such threads can also be + * modified by this call before execution. * + * A thread executing in the kernel cannot be modified since this + * would compromise the kernel. Also the thread must be in suspended + * condition so that the scheduler does not execute it as we modify + * its context. */ int sys_exchange_registers(syscall_context_t *regs) { + int err = 0; struct ktcb *task; - struct exregs_data *exregs = regs->r0; - unsigned int pagerid = regs->r1; - l4id_t tid = regs->r2; - unsigned int create_flags = task->flags & TASK_CREATE_FLAGS; - int err; + struct exregs_data *exregs = (struct exregs_data *)regs->r0; + l4id_t tid = regs->r1; /* Find tcb from its list */ if (!(task = find_task(tid))) @@ -220,46 +115,26 @@ int sys_exchange_registers(syscall_context_t *regs) /* Now check that the task is suspended */ if (task->state != TASK_INACTIVE) { - mutex_unlock(&task->thread_control_lock); - return -EACTIVE; + err = -EACTIVE; + goto out; } /* - * Check that it is legitimate to modify - * the task registers state + * The thread must be in user mode for its context + * to be modified. */ - if (!create_flags) { - /* - * Task is not new. We only allow such tasks - * to be modified in userspace. - */ - if (!task_in_user(task)) - return -EPERM; - } else { /* TODO: Simplify it here. */ - /* New threads with new address space */ - if (create_flags == THREAD_NEW_SPACE) - do_exchange_registers_bigslow(task, exregs); - else if ((create_flags == THREAD_COPY_SPACE) || - (create_flags == THREAD_SAME_SPACE)) { - /* - * Further check that the task is in - * the kernel but about to exit. - */ - if (task->context.pc != &return_from_syscall || - !task_in_kernel(task)) { - /* Actually its a bug if not true */ - BUG(); - return -EPERM; - } - do_exchange_registers_bigslow(task, exregs); - } + if (!TASK_IN_USER(task)) { + err = -EPERM; + goto out; } - /* Set its pager if one is supplied */ - if (pagerid != THREAD_ID_INVALID) - task->pagerid = pagerid; + /* Copy registers */ + do_exchange_registers(task, exregs); - return 0; +out: + /* Unlock and return */ + mutex_unlock(&task->thread_control_lock); + return err; } int sys_schedule(syscall_context_t *regs) diff --git a/src/api/thread.c b/src/api/thread.c index 5ae69d4..3ac37ba 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -66,10 +66,6 @@ int thread_start(struct task_ids *ids) if (!mutex_trylock(&task->thread_control_lock)) return -EAGAIN; - /* Clear creation flags if thread is new */ - if (task->flags & THREAD_CREATE_FLAGS) - task->flags &= ~THREAD_CREATE_FLAGS; - /* Notify scheduler of task resume */ sched_notify_resume(task); @@ -78,6 +74,50 @@ int thread_start(struct task_ids *ids) return 0; } +int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig, unsigned int flags) +{ + /* New threads just need their mode set up */ + if (flags == THREAD_NEW_SPACE) { + BUG_ON(orig); + new->context.spsr = ARM_MODE_USR; + return 0; + } + + /* + * For duplicated threads pre-syscall context is saved on + * the kernel stack. We copy this context of original + * into the duplicate thread's current context structure + * + * We don't lock for context modification because the + * thread is not known to the system yet. + */ + new->context.spsr = orig->syscall_regs->spsr; /* User mode */ + new->context.r0 = orig->syscall_regs->r0; + new->context.r1 = orig->syscall_regs->r1; + new->context.r2 = orig->syscall_regs->r2; + new->context.r3 = orig->syscall_regs->r3; + new->context.r4 = orig->syscall_regs->r4; + new->context.r5 = orig->syscall_regs->r5; + new->context.r6 = orig->syscall_regs->r6; + new->context.r7 = orig->syscall_regs->r7; + new->context.r8 = orig->syscall_regs->r8; + new->context.r9 = orig->syscall_regs->r9; + new->context.r10 = orig->syscall_regs->r10; + new->context.r11 = orig->syscall_regs->r11; + new->context.r12 = orig->syscall_regs->r12; + new->context.sp = orig->syscall_regs->sp_usr; + /* Skip lr_svc since it's not going to be used */ + new->context.pc = orig->syscall_regs->lr_usr; + + /* Copy other relevant fields from original ktcb */ + new->pagerid = orig->pagerid; + + /* Distribute original thread's ticks into two threads */ + new->ticks_left = orig->ticks_left / 2; + orig->ticks_left /= 2; + + return 0; +} extern unsigned int return_from_syscall; @@ -89,7 +129,7 @@ extern unsigned int return_from_syscall; * stack is restored. It also modifies r0 to ensure POSIX child return * semantics. */ -int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig) +int arch_setup_new_thread_orig(struct ktcb *new, struct ktcb *orig) { /* * Pre-syscall context is saved on the kernel stack upon @@ -230,20 +270,7 @@ out: waitqueue_head_init(&new->wqh_send); waitqueue_head_init(&new->wqh_recv); - /* - * When space is copied this restores the new thread's - * system call return environment so that it can safely - * return as a copy of its original thread. - */ - if (flags == THREAD_COPY_SPACE || - flags == THREAD_SAME_SPACE) - arch_setup_new_thread(new, task); - - /* - * Set thread's creation flags. They will clear - * when the thread is run for the first time - */ - new->flags = THREAD_CREATE_MASK & flags; + arch_setup_new_thread(new, task, flags); /* Add task to global hlist of tasks */ add_task_global(new); diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index 0189cd3..d37a58c 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -155,7 +155,7 @@ static inline void sched_rq_remove_task(struct ktcb *task) task->rq = 0; } -static inline void sched_init_task(struct ktcb *task) +void sched_init_task(struct ktcb *task) { INIT_LIST_HEAD(&task->rq_list); task->ticks_left = TASK_TIMESLICE_DEFAULT; @@ -226,7 +226,7 @@ void sched_notify_resume(struct ktcb *task) /* NOTE: Might as well just set need_resched instead of full yield. * This would work on irq context as well. */ /* Same as resume, but also yields. */ -int sched_resume_task(struct ktcb *task) +void sched_resume_task(struct ktcb *task) { sched_notify_resume(task); sched_yield(); diff --git a/tasks/libl4/include/l4lib/arch-arm/syscalls.h b/tasks/libl4/include/l4lib/arch-arm/syscalls.h index ae6d0f8..035d6dc 100644 --- a/tasks/libl4/include/l4lib/arch-arm/syscalls.h +++ b/tasks/libl4/include/l4lib/arch-arm/syscalls.h @@ -59,10 +59,9 @@ typedef int (*__l4_ipc_control_t)(unsigned int action, l4id_t blocked_sender, extern __l4_ipc_control_t __l4_ipc_control; int l4_ipc_control(unsigned int, l4id_t blocked_sender, u32 blocked_tag); -typedef int (*__l4_exchange_registers_t)(void *exregs_struct, - l4id_t pager, l4id_t tid); +typedef int (*__l4_exchange_registers_t)(void *exregs_struct, l4id_t tid); extern __l4_exchange_registers_t __l4_exchange_registers; -int l4_exchange_registers(void *exregs_struct, l4id_t pager, l4id_t tid); +int l4_exchange_registers(void *exregs_struct, l4id_t tid); typedef int (*__l4_kmem_control_t)(unsigned long pfn, int npages, int grant); extern __l4_kmem_control_t __l4_kmem_control; diff --git a/tasks/libl4/src/arm/syscalls.S b/tasks/libl4/src/arm/syscalls.S index a2c520b..f65b4f5 100644 --- a/tasks/libl4/src/arm/syscalls.S +++ b/tasks/libl4/src/arm/syscalls.S @@ -45,8 +45,11 @@ END_PROC(l4_kread) * * NOTE: MR_RETURN register is hardcoded here. * It must be updated if MR_RETURN offset is changed! + * + * NOTE: Note that this also breaks l4 system call interface, + * this should be moved elsewhere and modified using existing l4 mechanisms. */ -BEGIN_PROC(clone_asm) +BEGIN_PROC(arch_clone) stmfd sp!, {r4-r8,lr} @ Save context. utcb_address r12 @ Get utcb address. ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5 @@ -79,7 +82,7 @@ ipc_failed: utcb_address r12 @ Get utcb stmia r12, {r3-r8} @ Store mrs. ldmfd sp!, {r4-r8,pc} @ Return restoring pc and context. -END_PROC(clone_asm) +END_PROC(arch_clone) /* * Inter-process communication. Loads message registers as arguments before the call, @@ -186,7 +189,7 @@ END_PROC(l4_space_control) /* * Sets registers of a thread and its pager. - * @r0 = ptr to exchange_registers structure, @r1 = pager id, @r2 = tid of thread. + * @r0 = ptr to exregs_data structure, @r1 = tid of thread. */ BEGIN_PROC(l4_exchange_registers) stmfd sp!, {lr} diff --git a/tasks/mm0/include/exregs.h b/tasks/mm0/include/exregs.h index a17629a..5d5b17a 100644 --- a/tasks/mm0/include/exregs.h +++ b/tasks/mm0/include/exregs.h @@ -6,6 +6,7 @@ void exregs_set_stack(struct exregs_data *s, unsigned long sp); void exregs_set_mr_return(struct exregs_data *s, unsigned long retreg); void exregs_set_pc(struct exregs_data *s, unsigned long pc); +void exregs_set_pager(struct exregs_data *s, l4id_t pagerid); /* exregs_set_stack(unsigned long sp) diff --git a/tasks/mm0/include/memory.h b/tasks/mm0/include/memory.h index 3a2fc36..d10e8f8 100644 --- a/tasks/mm0/include/memory.h +++ b/tasks/mm0/include/memory.h @@ -21,7 +21,4 @@ void init_mm_descriptors(struct page_bitmap *page_map, struct bootdesc *bootdesc, struct membank *membank); void init_physmem(struct initdata *initdata, struct membank *membank); -int do_mmap(struct vm_file *mapfile, unsigned long f_offset, struct tcb *t, - unsigned long map_address, unsigned int flags, unsigned int pages); - #endif /* __MEMORY_H__ */ diff --git a/tasks/mm0/include/mmap.h b/tasks/mm0/include/mmap.h index 5b5baab..c56840e 100644 --- a/tasks/mm0/include/mmap.h +++ b/tasks/mm0/include/mmap.h @@ -26,8 +26,8 @@ struct vm_area *vma_new(unsigned long pfn_start, unsigned long npages, int do_munmap(void *vaddr, unsigned long size, struct tcb *task); -int do_mmap(struct vm_file *mapfile, unsigned long f_offset, struct tcb *t, - unsigned long map_address, unsigned int flags, unsigned int pages); +void *do_mmap(struct vm_file *mapfile, unsigned long f_offset, struct tcb *t, + unsigned long map_address, unsigned int flags, unsigned int pages); int mmap_address_validate(struct tcb *t, unsigned long map_address, unsigned int vm_flags); diff --git a/tasks/mm0/src/arch-arm/exregs.c b/tasks/mm0/src/arch-arm/exregs.c index bed1a91..a5bdb50 100644 --- a/tasks/mm0/src/arch-arm/exregs.c +++ b/tasks/mm0/src/arch-arm/exregs.c @@ -7,6 +7,12 @@ #include +void exregs_set_pager(struct exregs_data *s, l4id_t pagerid) +{ + s->pagerid = pagerid; + s->flags |= EXREGS_SET_PAGER; +} + void exregs_set_stack(struct exregs_data *s, unsigned long sp) { s->context.sp = sp; diff --git a/tasks/mm0/src/mmap.c b/tasks/mm0/src/mmap.c index b335d63..a079caa 100644 --- a/tasks/mm0/src/mmap.c +++ b/tasks/mm0/src/mmap.c @@ -380,6 +380,9 @@ int vma_intersect(unsigned long pfn_start, unsigned long pfn_end, } /* + * FIXME: PASS THIS A VM_SHARED FLAG SO THAT IT CAN SEARCH FOR AN EMPTY + * SEGMENT FOR SHM, instead of shmat() searching for one. + * * Search an empty space in the task's mmapable address region. */ unsigned long find_unmapped_area(unsigned long npages, struct tcb *task) @@ -470,9 +473,9 @@ int mmap_address_validate(struct tcb *task, unsigned long map_address, * The actual paging in/out of the file from/into memory pages is handled by * the file's pager upon page faults. */ -int do_mmap(struct vm_file *mapfile, unsigned long file_offset, - struct tcb *task, unsigned long map_address, unsigned int flags, - unsigned int npages) +void *do_mmap(struct vm_file *mapfile, unsigned long file_offset, + struct tcb *task, unsigned long map_address, unsigned int flags, + unsigned int npages) { unsigned long map_pfn = __pfn(map_address); struct vm_area *new, *mapped; @@ -485,7 +488,7 @@ int do_mmap(struct vm_file *mapfile, unsigned long file_offset, BUG_ON(!(mapfile = get_devzero())); file_offset = 0; } else - BUG(); + return PTR_ERR(-EINVAL); } /* Get total file pages, check if mapping is within file size */ @@ -494,25 +497,24 @@ int do_mmap(struct vm_file *mapfile, unsigned long file_offset, printf("%s: Trying to map %d pages from page %d, " "but file length is %d\n", __FUNCTION__, npages, file_offset, file_npages); - return -EINVAL; + return PTR_ERR(-EINVAL); } /* Check invalid page size */ if (npages == 0) { printf("Trying to map %d pages.\n", npages); - return -EINVAL; + return PTR_ERR(-EINVAL); } if (npages > __pfn(task->stack_start - task->data_end)) { printf("Trying to map too many pages: %d\n", npages); - return -ENOMEM; + return PTR_ERR(-ENOMEM); } /* Check invalid map address */ if (!mmap_address_validate(task, map_address, flags)) { /* Get new map address for region of this size */ - map_address = find_unmapped_area(npages, task); - if ((int)map_address < 0) - return (int)map_address; + if(!(map_address = find_unmapped_area(npages, task))) + return PTR_ERR(-ENOMEM); } else { /* * FIXME: Currently we don't allow overlapping vmas. @@ -526,12 +528,12 @@ int do_mmap(struct vm_file *mapfile, unsigned long file_offset, /* For valid regions that aren't allocated by us, create the vma. */ if (!(new = vma_new(__pfn(map_address), npages, flags, file_offset))) - return -ENOMEM; + return PTR_ERR(-ENOMEM); /* Attach the file as the first vm object of this vma */ if (!(vmo_link = vm_objlink_create())) { kfree(new); - return -ENOMEM; + return PTR_ERR(-ENOMEM); } /* Attach link to object */ @@ -557,7 +559,7 @@ int do_mmap(struct vm_file *mapfile, unsigned long file_offset, if (!(vmo_link2 = vm_objlink_create())) { kfree(new); kfree(vmo_link); - return -ENOMEM; + return PTR_ERR(-ENOMEM); } vm_link_object(vmo_link2, &dzero->vm_obj); list_add_tail(&vmo_link2->list, &new->vm_obj_list); @@ -565,7 +567,7 @@ int do_mmap(struct vm_file *mapfile, unsigned long file_offset, /* Finished initialising the vma, add it to task */ dprintf("%s: Mapping 0x%x - 0x%x\n", __FUNCTION__, - map_address, map_address + npages * PAGE_SIZE); + map_address, map_address + __pfn_to_addr(npages)); task_add_vma(task, new); /* @@ -573,9 +575,9 @@ int do_mmap(struct vm_file *mapfile, unsigned long file_offset, * we return the *end* of the area as the start address. */ if (flags & VMA_GROWSDOWN) - map_address += npages; + map_address += __pfn_to_addr(npages); - return map_address; + return (void *)map_address; } /* mmap system call implementation */ @@ -635,9 +637,9 @@ int sys_mmap(l4id_t sender, void *start, size_t length, int prot, if (prot & PROT_EXEC) vmflags |= VM_EXEC; - base = do_mmap(file, __pfn_to_addr(pfn), task, base, vmflags, npages); + start = do_mmap(file, __pfn_to_addr(pfn), task, base, vmflags, npages); - l4_ipc_return(base); + l4_ipc_return((int)start); return 0; } diff --git a/tasks/mm0/src/shm.c b/tasks/mm0/src/shm.c index 0eb9188..5af4226 100644 --- a/tasks/mm0/src/shm.c +++ b/tasks/mm0/src/shm.c @@ -56,7 +56,7 @@ static void *do_shmat(struct vm_file *shm_file, void *shm_addr, int shmflg, { struct shm_descriptor *shm = shm_file_to_desc(shm_file); unsigned int vmflags; - int err; + void *mapped; if (!task) { printf("%s:%s: Cannot find caller task with tid %d\n", @@ -85,7 +85,7 @@ static void *do_shmat(struct vm_file *shm_file, void *shm_addr, int shmflg, if (mmap_address_validate(task, (unsigned long)shm_addr, vmflags)) shm->shm_addr = shm_addr; - else + else /* FIXME: Do this in do_mmap/find_unmapped_area !!! */ shm->shm_addr = address_new(&shm_vaddr_pool, shm->npages); else /* Address must be already assigned */ @@ -95,9 +95,11 @@ static void *do_shmat(struct vm_file *shm_file, void *shm_addr, int shmflg, * mmap the area to the process as shared. Page fault handler would * handle allocating and paging-in the shared pages. */ - if ((err = do_mmap(shm_file, 0, task, (unsigned long)shm->shm_addr, - vmflags, shm->npages)) < 0) { - printf("do_mmap: Mapping shm area failed with %d.\n", err); + if (IS_ERR(mapped = do_mmap(shm_file, 0, task, + (unsigned long)shm->shm_addr, + vmflags, shm->npages))) { + printf("do_mmap: Mapping shm area failed with %d.\n", + (int)mapped); BUG(); } diff --git a/tasks/mm0/src/task.c b/tasks/mm0/src/task.c index 86b74fe..3b38bd8 100644 --- a/tasks/mm0/src/task.c +++ b/tasks/mm0/src/task.c @@ -225,36 +225,40 @@ struct tcb *task_create(struct tcb *orig, struct task_ids *ids, int task_mmap_regions(struct tcb *task, struct vm_file *file) { - int err; + void *mapped; struct vm_file *shm; /* * mmap each task's physical image to task's address space. * TODO: Map data and text separately when available from bootdesc. */ - if ((err = do_mmap(file, 0, task, task->text_start, - VM_READ | VM_WRITE | VM_EXEC | VMA_PRIVATE, - __pfn(page_align_up(task->text_end) - - task->text_start))) < 0) { - printf("do_mmap: failed with %d.\n", err); - return err; + if (IS_ERR(mapped = do_mmap(file, 0, task, task->text_start, + VM_READ | VM_WRITE | VM_EXEC | VMA_PRIVATE, + __pfn(page_align_up(task->text_end) - + task->text_start)))) { + printf("do_mmap: failed with %d.\n", (int)mapped); + return (int)mapped; } /* mmap each task's environment as anonymous memory. */ - if ((err = do_mmap(0, 0, task, task->env_start, - VM_READ | VM_WRITE | VMA_PRIVATE | VMA_ANONYMOUS, - __pfn(task->env_end - task->env_start))) < 0) { + if (IS_ERR(mapped = do_mmap(0, 0, task, task->env_start, + VM_READ | VM_WRITE | + VMA_PRIVATE | VMA_ANONYMOUS, + __pfn(task->env_end - task->env_start)))) { printf("do_mmap: Mapping environment failed with %d.\n", - err); - return err; + (int)mapped); + return (int)mapped; } /* mmap each task's stack as anonymous memory. */ - if ((err = do_mmap(0, 0, task, task->stack_start, - VM_READ | VM_WRITE | VMA_PRIVATE | VMA_ANONYMOUS, - __pfn(task->stack_end - task->stack_start))) < 0) { - printf("do_mmap: Mapping stack failed with %d.\n", err); - return err; + if (IS_ERR(mapped = do_mmap(0, 0, task, task->stack_start, + VM_READ | VM_WRITE | + VMA_PRIVATE | VMA_ANONYMOUS, + __pfn(task->stack_end - + task->stack_start)))) { + printf("do_mmap: Mapping stack failed with %d.\n", + (int)mapped); + return (int)mapped; } /* Task's utcb */ @@ -304,7 +308,7 @@ int task_setup_registers(struct tcb *task, unsigned int pc, unsigned int sp, l4id_t pager) { int err; - struct exregs_data regs; + struct exregs_data exregs; /* Set up task's registers to default. */ if (!sp) @@ -315,9 +319,11 @@ int task_setup_registers(struct tcb *task, unsigned int pc, pager = self_tid(); /* Set up the task's thread details, (pc, sp, pager etc.) */ - exregs_set_stack(®s, sp); - exregs_set_pc(®s, pc); - if ((err = l4_exchange_registers(®s, pager, task->tid) < 0)) { + exregs_set_stack(&exregs, sp); + exregs_set_pc(&exregs, pc); + exregs_set_pager(&exregs, pager); + + if ((err = l4_exchange_registers(&exregs, task->tid) < 0)) { printf("l4_exchange_registers failed with %d.\n", err); return err; }