From 2bd3266498d0aadd357d76a8cf136d7daf4ea52b Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sun, 18 Oct 2009 15:01:38 +0300 Subject: [PATCH] Removed bits from kernel where pager utcb is set. Pagers now set their own utcb explicitly via exchange_registers. exregs accepts calls from active pagers for this purpose only. --- conts/posix/mm0/mm/init.c | 22 ++++++----- include/l4/generic/cap-types.h | 4 ++ include/l4/generic/tcb.h | 2 +- include/l4/glue/arm/memlayout.h | 3 -- include/l4/lib/math.h | 2 +- src/api/syscall.c | 68 +++++++++++++++++++++------------ src/generic/capability.c | 4 +- src/generic/container.c | 23 +++++------ src/generic/scheduler.c | 2 +- src/generic/tcb.c | 4 +- src/glue/arm/init.c | 3 -- 11 files changed, 79 insertions(+), 58 deletions(-) diff --git a/conts/posix/mm0/mm/init.c b/conts/posix/mm0/mm/init.c index 44e2af2..a644896 100644 --- a/conts/posix/mm0/mm/init.c +++ b/conts/posix/mm0/mm/init.c @@ -6,7 +6,7 @@ #include #include #include - +#include #include #include /* TODO: Move this to API */ #include @@ -70,7 +70,9 @@ int pager_setup_task(void) { struct tcb *task; struct task_ids ids; + struct exregs_data exregs; void *mapped; + int err; /* * The thread itself is already known by the kernel, @@ -131,19 +133,21 @@ int pager_setup_task(void) BUG(); } - task_setup_utcb(task); /* Set pager as child and parent of itself */ list_insert(&task->child_ref, &task->children); task->parent = task; - /* - * The first UTCB address is already assigned by the - * microkernel for this pager. Ensure that we also get - * the same from our internal utcb bookkeeping. - */ - BUG_ON(task->utcb_address != - __pfn_to_addr(cont_mem_regions.utcb->start)); + /* Allocate and set own utcb */ + task_setup_utcb(task); + memset(&exregs, 0, sizeof(exregs)); + exregs_set_utcb(&exregs, task->utcb_address); + if ((err = l4_exchange_registers(&exregs, task->tid)) < 0) { + printf("FATAL: Pager could not set own utcb. " + "UTCB address: 0x%lx, error: %d\n", + task->utcb_address, err); + BUG(); + } /* Pager must prefault its utcb */ prefault_page(task, task->utcb_address, diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index 8673565..c26d9f4 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -18,6 +18,8 @@ #define CAP_TYPE_UMUTEX (1 << 5) #define CAP_TYPE_QUANTITY (1 << 6) +#define cap_type(c) ((c)->type & CAP_TYPE_MASK) + /* * Resource types */ @@ -36,6 +38,8 @@ #define CAP_RTYPE_MAPPOOL (1 << 27) /* For pmd spending */ #define CAP_RTYPE_CAPPOOL (1 << 28) /* For new cap generation */ +#define cap_rtype(c) ((c)->type & CAP_RTYPE_MASK) + /* * Access permissions */ diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 8428dc9..2ef077a 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -161,7 +161,7 @@ struct ktcb *tcb_alloc_init(void); void tcb_delete(struct ktcb *tcb); void init_ktcb_list(struct ktcb_list *ktcb_list); -void task_update_utcb(struct ktcb *cur, struct ktcb *next); +void task_update_utcb(struct ktcb *task); int tcb_check_and_lazy_map_utcb(struct ktcb *task); #endif /* __TCB_H__ */ diff --git a/include/l4/glue/arm/memlayout.h b/include/l4/glue/arm/memlayout.h index 974348f..b272fd2 100644 --- a/include/l4/glue/arm/memlayout.h +++ b/include/l4/glue/arm/memlayout.h @@ -15,9 +15,6 @@ #define KERNEL_AREA_SIZE (KERNEL_AREA_END - KERNEL_AREA_START) #define KERNEL_AREA_SECTIONS (KERNEL_AREA_SIZE / ARM_SECTION_SIZE) -#define UTCB_AREA_START 0xF8000000 -#define UTCB_AREA_END 0xF9000000 -#define UTCB_AREA_SIZE (UTCB_AREA_END - UTCB_AREA_START) #define UTCB_SIZE (sizeof(int) * 64) #define IO_AREA_START 0xF9000000 diff --git a/include/l4/lib/math.h b/include/l4/lib/math.h index 2752f6d..59e0d24 100644 --- a/include/l4/lib/math.h +++ b/include/l4/lib/math.h @@ -9,7 +9,7 @@ static inline int set_intersection(unsigned long a, unsigned long b, unsigned long c, unsigned long d) { /* - * Below is the complement (') of the intersection + * Below is the complement set (') of the intersection * of 2 ranges, much simpler ;-) */ if (b <= c || a >= d) diff --git a/src/api/syscall.c b/src/api/syscall.c index cf7c79f..3f78961 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -33,6 +35,8 @@ void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs) { task_context_t *context = &task->context; + if (!exregs->valid_vect) + goto flags; /* * NOTE: * We don't care if register values point at invalid addresses @@ -74,29 +78,48 @@ void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs) if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, pc)) context->pc = exregs->context.pc; +flags: /* Set thread's pager if one is supplied */ if (exregs->flags & EXREGS_SET_PAGER) task->pagerid = exregs->pagerid; /* Set thread's utcb if supplied */ - if (exregs->flags & EXREGS_SET_UTCB) + if (exregs->flags & EXREGS_SET_UTCB) { task->utcb_address = exregs->utcb_address; + + /* + * If task is the one currently runnable, + * update kip utcb reference + */ + if (task == current) + task_update_utcb(task); + } } /* * exchange_registers() * * 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 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 on the first chance to execute so - * such threads can also be modified by this call before execution. + * the register context of a thread. The thread's registers that are + * set by this call are loaded whenever the thread gets a chance to + * run in user mode. + * + * It is ensured that whenever this call is made, the thread is + * either already running in user mode, or has been suspended in + * kernel mode, just before returning to user mode. + * + * A newly created thread that is the copy of another thread (forked + * or cloned) will also be given its user mode context on the first + * chance to execute 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. + * + * FIXME: Still looks like suspended threads in the kernel + * need to be made immutable. see src/glue/arm/systable.c */ int sys_exchange_registers(struct exregs_data *exregs, l4id_t tid) { @@ -114,30 +137,27 @@ int sys_exchange_registers(struct exregs_data *exregs, l4id_t tid) if (!mutex_trylock(&task->thread_control_lock)) return -EAGAIN; - /* Now check that the task is suspended */ - if (task->state != TASK_INACTIVE) { + /* + * Now check that the task is suspended. + * + * Only modification of non-register fields are + * allowed on active tasks and those tasks must + * be the pagers making the call on themselves. + */ + if (task->state != TASK_INACTIVE && exregs->valid_vect && + current != task && task->pager->tcb != current) { err = -EACTIVE; goto out; } -#if 0 - A suspended thread implies it cannot do any harm - even if it is in kernel mode. /* - * The thread must be in user mode for its context - * to be modified. + * FIXME: + * Capability Check. + * Whose clist are we ought to check? Pager's or threads? + * Need to check exregs capability + * Need to check utcb capability if present. + * if ((exregs->flags & EXREGS_SET_UTCB) && */ - if (!TASK_IN_USER(task)) { - err = -EPERM; - goto out; - } -#endif - - /* Check UTCB is in valid range */ - if (exregs->flags & EXREGS_SET_UTCB && - !(exregs->utcb_address >= UTCB_AREA_START && - exregs->utcb_address < UTCB_AREA_END)) - return -EINVAL; /* Copy registers */ do_exchange_registers(task, exregs); diff --git a/src/generic/capability.c b/src/generic/capability.c index 24e226f..cd033c0 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -61,10 +61,8 @@ struct capability *capability_find_by_rtype(struct cap_list *clist, { struct capability *cap; - list_foreach_struct(cap, &clist->caps, list) { + list_foreach_struct(cap, &clist->caps, list) if ((cap->type & CAP_RTYPE_MASK) == rtype) return cap; - } return 0; } - diff --git a/src/generic/container.c b/src/generic/container.c index fa8047f..25bcf90 100644 --- a/src/generic/container.c +++ b/src/generic/container.c @@ -23,7 +23,7 @@ int container_init(struct container *c) init_ktcb_list(&c->ktcb_list); init_mutex_queue_head(&c->mutex_queue_head); - /* Ini pager structs */ + /* Init pager structs */ for (int i = 0; i < CONFIG_MAX_PAGERS_USED; i++) cap_list_init(&c->pager[i].cap_list); @@ -48,23 +48,23 @@ void kcont_insert_container(struct container *c, } /* + * FIXME: Remove completely. Need to be done in userspace. * This searches pager capabilities and if it has a virtual memory area * defined as a UTCB, uses the first entry as its utcb. If not, it is * not an error, perhaps another pager will map its utcb. */ -void task_setup_utcb(struct ktcb *task, struct pager *pager) +void pager_init_utcb(struct ktcb *task, struct pager *pager) { struct capability *cap; /* Find a virtual memory capability with UTCB map permissions */ list_foreach_struct(cap, &pager->cap_list.caps, list) { - if (((cap->type & CAP_RTYPE_MASK) == - CAP_RTYPE_VIRTMEM) && - (cap->access & CAP_MAP_UTCB)) { - /* Use first address slot as pager's utcb */ - task->utcb_address = __pfn_to_addr(cap->start); - return; - } + if (cap_rtype(cap) == CAP_RTYPE_VIRTMEM && + cap->access & CAP_MAP_UTCB) { + /* Use first address slot as pager's utcb */ + task->utcb_address = __pfn_to_addr(cap->start); + break; + } } } @@ -146,7 +146,8 @@ int init_first_pager(struct pager *pager, /* Initialize ktcb */ task_init_registers(task, pager->start_vma); - task_setup_utcb(task, pager); + + pager_init_utcb(task, pager); /* Allocate space structure */ if (!(space = alloc_space())) @@ -215,7 +216,7 @@ int init_pager(struct pager *pager, struct container *cont) task_init_registers(task, pager->start_vma); - task_setup_utcb(task, pager); + pager_init_utcb(task, pager); task->space = address_space_create(0); diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index 3a17429..6d296f5 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -274,7 +274,7 @@ static inline void context_switch(struct ktcb *next) arch_hardware_flush(TASK_PGD(next)); /* Update utcb region for next task */ - task_update_utcb(cur, next); + task_update_utcb(next); /* Switch context */ arch_switch(cur, next); diff --git a/src/generic/tcb.c b/src/generic/tcb.c index cf7cd87..2364b89 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -156,10 +156,10 @@ unsigned int syscall_regs_offset = offsetof(struct ktcb, syscall_regs); * space as its context is loaded. The utcb region is a function of * this mapping and its offset that is reached via the KIP UTCB pointer */ -void task_update_utcb(struct ktcb *cur, struct ktcb *next) +void task_update_utcb(struct ktcb *task) { /* Update the KIP pointer */ - kip.utcb = next->utcb_address; + kip.utcb = task->utcb_address; } /* diff --git a/src/glue/arm/init.c b/src/glue/arm/init.c index e343acc..526852d 100644 --- a/src/glue/arm/init.c +++ b/src/glue/arm/init.c @@ -188,9 +188,6 @@ void kip_init() /* KIP + 0xFF0 is pointer to UTCB segment start address */ utcb_ref = (struct utcb **)((unsigned long)&kip + UTCB_KIP_OFFSET); - /* All thread utcbs are allocated starting from UTCB_AREA_START */ - *utcb_ref = (struct utcb *)UTCB_AREA_START; - add_boot_mapping(virt_to_phys(&kip), USER_KIP_PAGE, PAGE_SIZE, MAP_USR_RO_FLAGS); printk("%s: Kernel built on %s, %s\n", __KERNELNAME__,