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.
This commit is contained in:
Bahadir Balban
2009-10-18 15:01:38 +03:00
parent 7ba7a2e796
commit 2bd3266498
11 changed files with 79 additions and 58 deletions

View File

@@ -6,7 +6,7 @@
#include <l4lib/arch/syscalls.h> #include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h> #include <l4lib/arch/syslib.h>
#include <l4lib/utcb.h> #include <l4lib/utcb.h>
#include <l4lib/exregs.h>
#include <l4/lib/list.h> #include <l4/lib/list.h>
#include <l4/generic/cap-types.h> /* TODO: Move this to API */ #include <l4/generic/cap-types.h> /* TODO: Move this to API */
#include <l4/api/capability.h> #include <l4/api/capability.h>
@@ -70,7 +70,9 @@ int pager_setup_task(void)
{ {
struct tcb *task; struct tcb *task;
struct task_ids ids; struct task_ids ids;
struct exregs_data exregs;
void *mapped; void *mapped;
int err;
/* /*
* The thread itself is already known by the kernel, * The thread itself is already known by the kernel,
@@ -131,19 +133,21 @@ int pager_setup_task(void)
BUG(); BUG();
} }
task_setup_utcb(task);
/* Set pager as child and parent of itself */ /* Set pager as child and parent of itself */
list_insert(&task->child_ref, &task->children); list_insert(&task->child_ref, &task->children);
task->parent = task; task->parent = task;
/* /* Allocate and set own utcb */
* The first UTCB address is already assigned by the task_setup_utcb(task);
* microkernel for this pager. Ensure that we also get memset(&exregs, 0, sizeof(exregs));
* the same from our internal utcb bookkeeping. exregs_set_utcb(&exregs, task->utcb_address);
*/ if ((err = l4_exchange_registers(&exregs, task->tid)) < 0) {
BUG_ON(task->utcb_address != printf("FATAL: Pager could not set own utcb. "
__pfn_to_addr(cont_mem_regions.utcb->start)); "UTCB address: 0x%lx, error: %d\n",
task->utcb_address, err);
BUG();
}
/* Pager must prefault its utcb */ /* Pager must prefault its utcb */
prefault_page(task, task->utcb_address, prefault_page(task, task->utcb_address,

View File

@@ -18,6 +18,8 @@
#define CAP_TYPE_UMUTEX (1 << 5) #define CAP_TYPE_UMUTEX (1 << 5)
#define CAP_TYPE_QUANTITY (1 << 6) #define CAP_TYPE_QUANTITY (1 << 6)
#define cap_type(c) ((c)->type & CAP_TYPE_MASK)
/* /*
* Resource types * Resource types
*/ */
@@ -36,6 +38,8 @@
#define CAP_RTYPE_MAPPOOL (1 << 27) /* For pmd spending */ #define CAP_RTYPE_MAPPOOL (1 << 27) /* For pmd spending */
#define CAP_RTYPE_CAPPOOL (1 << 28) /* For new cap generation */ #define CAP_RTYPE_CAPPOOL (1 << 28) /* For new cap generation */
#define cap_rtype(c) ((c)->type & CAP_RTYPE_MASK)
/* /*
* Access permissions * Access permissions
*/ */

View File

@@ -161,7 +161,7 @@ struct ktcb *tcb_alloc_init(void);
void tcb_delete(struct ktcb *tcb); void tcb_delete(struct ktcb *tcb);
void init_ktcb_list(struct ktcb_list *ktcb_list); 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); int tcb_check_and_lazy_map_utcb(struct ktcb *task);
#endif /* __TCB_H__ */ #endif /* __TCB_H__ */

View File

@@ -15,9 +15,6 @@
#define KERNEL_AREA_SIZE (KERNEL_AREA_END - KERNEL_AREA_START) #define KERNEL_AREA_SIZE (KERNEL_AREA_END - KERNEL_AREA_START)
#define KERNEL_AREA_SECTIONS (KERNEL_AREA_SIZE / ARM_SECTION_SIZE) #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 UTCB_SIZE (sizeof(int) * 64)
#define IO_AREA_START 0xF9000000 #define IO_AREA_START 0xF9000000

View File

@@ -9,7 +9,7 @@ static inline int set_intersection(unsigned long a, unsigned long b,
unsigned long c, unsigned long d) 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 ;-) * of 2 ranges, much simpler ;-)
*/ */
if (b <= c || a >= d) if (b <= c || a >= d)

View File

@@ -10,6 +10,8 @@
#include <l4/generic/resource.h> #include <l4/generic/resource.h>
#include <l4/generic/tcb.h> #include <l4/generic/tcb.h>
#include <l4/generic/space.h> #include <l4/generic/space.h>
#include <l4/generic/capability.h>
#include <l4/generic/container.h>
#include <l4/api/space.h> #include <l4/api/space.h>
#include <l4/api/ipc.h> #include <l4/api/ipc.h>
#include <l4/api/kip.h> #include <l4/api/kip.h>
@@ -33,6 +35,8 @@ void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs)
{ {
task_context_t *context = &task->context; task_context_t *context = &task->context;
if (!exregs->valid_vect)
goto flags;
/* /*
* NOTE: * NOTE:
* We don't care if register values point at invalid addresses * 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)) if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, pc))
context->pc = exregs->context.pc; context->pc = exregs->context.pc;
flags:
/* Set thread's pager if one is supplied */ /* Set thread's pager if one is supplied */
if (exregs->flags & EXREGS_SET_PAGER) if (exregs->flags & EXREGS_SET_PAGER)
task->pagerid = exregs->pagerid; task->pagerid = exregs->pagerid;
/* Set thread's utcb if supplied */ /* Set thread's utcb if supplied */
if (exregs->flags & EXREGS_SET_UTCB) if (exregs->flags & EXREGS_SET_UTCB) {
task->utcb_address = exregs->utcb_address; 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() * exchange_registers()
* *
* This call is used by the pagers to set (and in the future read) * 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 * the register context of a thread. The thread's registers that are
* set only when the thread is in user mode. A newly created thread * set by this call are loaded whenever the thread gets a chance to
* that is the copy of another thread (forked or cloned) will also * run in user mode.
* be given its user mode context on the first chance to execute so *
* such threads can also be modified by this call before execution. * 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 * A thread executing in the kernel cannot be modified since this
* would compromise the kernel. Also the thread must be in suspended * would compromise the kernel. Also the thread must be in suspended
* condition so that the scheduler does not execute it as we modify * condition so that the scheduler does not execute it as we modify
* its context. * 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) 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)) if (!mutex_trylock(&task->thread_control_lock))
return -EAGAIN; 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; err = -EACTIVE;
goto out; 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 * FIXME:
* to be modified. * 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 */ /* Copy registers */
do_exchange_registers(task, exregs); do_exchange_registers(task, exregs);

View File

@@ -61,10 +61,8 @@ struct capability *capability_find_by_rtype(struct cap_list *clist,
{ {
struct capability *cap; struct capability *cap;
list_foreach_struct(cap, &clist->caps, list) { list_foreach_struct(cap, &clist->caps, list)
if ((cap->type & CAP_RTYPE_MASK) == rtype) if ((cap->type & CAP_RTYPE_MASK) == rtype)
return cap; return cap;
}
return 0; return 0;
} }

View File

@@ -23,7 +23,7 @@ int container_init(struct container *c)
init_ktcb_list(&c->ktcb_list); init_ktcb_list(&c->ktcb_list);
init_mutex_queue_head(&c->mutex_queue_head); init_mutex_queue_head(&c->mutex_queue_head);
/* Ini pager structs */ /* Init pager structs */
for (int i = 0; i < CONFIG_MAX_PAGERS_USED; i++) for (int i = 0; i < CONFIG_MAX_PAGERS_USED; i++)
cap_list_init(&c->pager[i].cap_list); 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 * 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 * 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. * 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; struct capability *cap;
/* Find a virtual memory capability with UTCB map permissions */ /* Find a virtual memory capability with UTCB map permissions */
list_foreach_struct(cap, &pager->cap_list.caps, list) { list_foreach_struct(cap, &pager->cap_list.caps, list) {
if (((cap->type & CAP_RTYPE_MASK) == if (cap_rtype(cap) == CAP_RTYPE_VIRTMEM &&
CAP_RTYPE_VIRTMEM) && cap->access & CAP_MAP_UTCB) {
(cap->access & CAP_MAP_UTCB)) { /* Use first address slot as pager's utcb */
/* Use first address slot as pager's utcb */ task->utcb_address = __pfn_to_addr(cap->start);
task->utcb_address = __pfn_to_addr(cap->start); break;
return; }
}
} }
} }
@@ -146,7 +146,8 @@ int init_first_pager(struct pager *pager,
/* Initialize ktcb */ /* Initialize ktcb */
task_init_registers(task, pager->start_vma); task_init_registers(task, pager->start_vma);
task_setup_utcb(task, pager);
pager_init_utcb(task, pager);
/* Allocate space structure */ /* Allocate space structure */
if (!(space = alloc_space())) 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_init_registers(task, pager->start_vma);
task_setup_utcb(task, pager); pager_init_utcb(task, pager);
task->space = address_space_create(0); task->space = address_space_create(0);

View File

@@ -274,7 +274,7 @@ static inline void context_switch(struct ktcb *next)
arch_hardware_flush(TASK_PGD(next)); arch_hardware_flush(TASK_PGD(next));
/* Update utcb region for next task */ /* Update utcb region for next task */
task_update_utcb(cur, next); task_update_utcb(next);
/* Switch context */ /* Switch context */
arch_switch(cur, next); arch_switch(cur, next);

View File

@@ -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 * 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 * 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 */ /* Update the KIP pointer */
kip.utcb = next->utcb_address; kip.utcb = task->utcb_address;
} }
/* /*

View File

@@ -188,9 +188,6 @@ void kip_init()
/* KIP + 0xFF0 is pointer to UTCB segment start address */ /* KIP + 0xFF0 is pointer to UTCB segment start address */
utcb_ref = (struct utcb **)((unsigned long)&kip + UTCB_KIP_OFFSET); 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, add_boot_mapping(virt_to_phys(&kip), USER_KIP_PAGE, PAGE_SIZE,
MAP_USR_RO_FLAGS); MAP_USR_RO_FLAGS);
printk("%s: Kernel built on %s, %s\n", __KERNELNAME__, printk("%s: Kernel built on %s, %s\n", __KERNELNAME__,