Ongoing work for adding per-thread UTCB structures.

Added setting of utcb address to l4_thread_control.
This is going to be moved to exchange_registers() since we need to pass
both the utcb physical and virtual address and exregs fits such context
modification better than thread_control.
This commit is contained in:
Bahadir Balban
2009-04-29 16:53:04 +03:00
parent 54a9b2901d
commit 7a81db8782
35 changed files with 424 additions and 72 deletions

View File

@@ -78,6 +78,13 @@ void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs)
if (exregs->flags & EXREGS_SET_PAGER)
task->pagerid = exregs->pagerid;
/* Set thread's utcb if supplied */
if (exregs->flags & EXREGS_SET_UTCB) {
BUG(); /* Check that physical and virtual addresses are in range */
task->utcb_phys = exregs->utcb_phys;
task->utcb_virt = exregs->utcb_virt;
}
}
/*

View File

@@ -164,10 +164,92 @@ int thread_start(struct task_ids *ids)
return 0;
}
int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig, unsigned int flags)
/*
* Given thread creation flags, determines whether to use a new user
* (pager)-supplied utcb address, the utcb address of the original thread,
* or no utcb at all. Validation of flags done at beginning of thread_create().
*/
int arch_new_thread_setup_utcb(struct ktcb *new, struct ktcb *orig, unsigned int flags,
unsigned long utcb_address)
{
unsigned int create_flags = flags & THREAD_CREATE_MASK;
unsigned int utcb_flags = flags & THREAD_UTCB_MASK;
/* In case of multiple threads in same address space */
if (create_flags == THREAD_SAME_SPACE) {
switch (utcb_flags) {
case THREAD_UTCB_SAME:
new->utcb_address = orig->utcb_address;
break;
case THREAD_UTCB_NEW:
new->utcb_address = utcb_address;
break;
case THREAD_UTCB_NONE:
new->utcb_address = 0;
break;
default:
printk("%s: Bad thread creation flags. "
"Incorrect flag validation?\n",__FUNCTION__);
BUG();
}
}
/* In case of brand new address space and thread */
if (create_flags == THREAD_NEW_SPACE) {
switch (utcb_flags) {
case THREAD_UTCB_NEW:
new->utcb_address = utcb_address;
break;
/*
* No UTCB for brand new space means the thread cannot do
* an ipc other than exceptions. This is allowed for now.
*/
case THREAD_UTCB_NONE:
new->utcb_address = 0;
break;
default:
printk("%s: Bad thread creation flags. "
"Incorrect flag validation?\n",__FUNCTION__);
BUG();
}
}
/*
* This essentially corresponds to fork() and normally we would expect
* the UTCB to be the same as original thread, since the whole address
* space is an identical image of the original. Nevertheless it doesn't
* do harm to have none or different utcb address and this is left to
* the implementor to decide.
*/
if (create_flags == THREAD_COPY_SPACE) {
switch (utcb_flags) {
case THREAD_UTCB_SAME:
new->utcb_address = orig->utcb_address;
break;
case THREAD_UTCB_NEW:
new->utcb_address = utcb_address;
break;
case THREAD_UTCB_NONE:
new->utcb_address = 0;
break;
default:
printk("%s: Bad thread creation flags. "
"Incorrect flag validation?\n",__FUNCTION__);
BUG();
}
}
return 0;
}
int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig,
unsigned int flags, unsigned long utcb_address)
{
/* Set up the utcb address */
arch_new_thread_setup_utcb(new, orig, flags, utcb_address);
/* New threads just need their mode set up */
if (flags == THREAD_NEW_SPACE) {
if ((flags & THREAD_CREATE_MASK) == THREAD_NEW_SPACE) {
BUG_ON(orig);
new->context.spsr = ARM_MODE_USR;
return 0;
@@ -262,12 +344,28 @@ int thread_setup_new_ids(struct task_ids *ids, unsigned int flags,
* are respectively used when creating a brand new task, creating a
* new thread in an existing address space, or forking a task.
*/
int thread_create(struct task_ids *ids, unsigned int flags)
int thread_create(struct task_ids *ids, unsigned int flags,
unsigned long utcb_address)
{
struct ktcb *task = 0, *new = (struct ktcb *)zalloc_page();
flags &= THREAD_CREATE_MASK;
unsigned int create_flags = flags & THREAD_CREATE_MASK;
unsigned int utcb_flags = flags & THREAD_UTCB_MASK;
if (flags == THREAD_NEW_SPACE) {
/* Handle error cases. Should have valid flags for each */
if (!utcb_flags || !create_flags)
return -EINVAL;
/* Cannot have new space with same utcb */
else if (create_flags == THREAD_NEW_SPACE &&
utcb_flags == THREAD_UTCB_SAME)
return -EINVAL;
/* Cannot have new utcb with invalid address */
else if (utcb_flags == THREAD_UTCB_NEW && !utcb_address)
return -EINVAL;
/* Determine space allocation */
if (create_flags == THREAD_NEW_SPACE) {
/* Allocate new pgd and copy all kernel areas */
new->pgd = alloc_pgd();
copy_pgd_kern_all(new->pgd);
@@ -289,7 +387,7 @@ int thread_create(struct task_ids *ids, unsigned int flags)
}
out:
/* Set up new thread's tid, spid, tgid according to flags */
thread_setup_new_ids(ids, flags, new, task);
thread_setup_new_ids(ids, create_flags, new, task);
/* Initialise task's scheduling state and parameters. */
sched_init_task(new, TASK_PRIO_NORMAL);
@@ -299,7 +397,7 @@ out:
waitqueue_head_init(&new->wqh_recv);
waitqueue_head_init(&new->wqh_pager);
arch_setup_new_thread(new, task, flags);
arch_setup_new_thread(new, task, flags, utcb_address);
/* Add task to global hlist of tasks */
add_task_global(new);
@@ -317,10 +415,11 @@ int sys_thread_control(syscall_context_t *regs)
int ret = 0;
unsigned int flags = regs->r0;
struct task_ids *ids = (struct task_ids *)regs->r1;
unsigned long utcb_address = regs->r2;
switch (flags & THREAD_ACTION_MASK) {
case THREAD_CREATE:
ret = thread_create(ids, flags);
ret = thread_create(ids, flags, utcb_address);
break;
case THREAD_RUN:
ret = thread_start(ids);

View File

@@ -255,6 +255,9 @@ static inline void context_switch(struct ktcb *next)
// printk("(%d) to (%d)\n", cur->tid, next->tid);
/* Update KIP UTCB pointer for new thread to run */
kip.utcb = next->utcb_address;
/* Flush caches and everything */
arch_hardware_flush(next->pgd);