mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
Managed to self-destruct pager.
Issues: - A page-faulting thread suspends if receives -1 from pager page fault ipc. This is fine if pager is about to delete the thread, but it is not if it is a buggy pager. - Need to find a way to completely get rid of suspended pager. - A method of deleting suspended tasks could remedy both cases above.
This commit is contained in:
@@ -187,10 +187,17 @@ void handle_requests(void)
|
||||
|
||||
void main(void)
|
||||
{
|
||||
struct task_ids ids;
|
||||
|
||||
l4_getid(&ids);
|
||||
|
||||
printf("\n%s: Started with thread id %d\n", __TASKNAME__, self_tid());
|
||||
|
||||
init();
|
||||
|
||||
printf("\n%s: Destroying self (%d), along with any tasks.\n", __TASKNAME__, self_tid());
|
||||
l4_thread_control(THREAD_DESTROY, &ids);
|
||||
|
||||
printf("%s: Memory/Process manager initialized. Listening requests.\n", __TASKNAME__);
|
||||
while (1) {
|
||||
handle_requests();
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define TASK_INTERRUPTED (1 << 0)
|
||||
#define TASK_SUSPENDING (1 << 1)
|
||||
#define TASK_RESUMING (1 << 2)
|
||||
#define TASK_EXITING (1 << 3)
|
||||
|
||||
/* Task states */
|
||||
enum task_state {
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
#ifndef __THREAD_H__
|
||||
#define __THREAD_H__
|
||||
|
||||
#include <l4/generic/tcb.h>
|
||||
|
||||
/* Thread id creation and deleting */
|
||||
void thread_id_pool_init(void);
|
||||
int thread_id_new(void);
|
||||
int thread_id_del(int tid);
|
||||
|
||||
void thread_destroy_self(void);
|
||||
int thread_destroy(struct task_ids *ids);
|
||||
|
||||
#endif /* __THREAD_H__ */
|
||||
|
||||
@@ -91,6 +91,8 @@ static inline int is_err(int x)
|
||||
|
||||
#define BUG_ON(x) {if (x) BUG();}
|
||||
|
||||
#define WARN_ON(x) {if (x) printk("%s, %s, %s: Warning something is off here.\n", __FILE__, __FUNCTION__, __LINE__); }
|
||||
|
||||
#define BUG_ON_MSG(msg, x) do { \
|
||||
printk(msg); \
|
||||
BUG_ON(x) \
|
||||
|
||||
@@ -215,10 +215,13 @@ int ipc_handle_errors(void)
|
||||
/* Interruptible ipc */
|
||||
int ipc_send(l4id_t recv_tid, unsigned int flags)
|
||||
{
|
||||
struct ktcb *receiver = tcb_find(recv_tid);
|
||||
struct ktcb *receiver;
|
||||
struct waitqueue_head *wqhs, *wqhr;
|
||||
int ret = 0;
|
||||
|
||||
if (!(receiver = tcb_find(recv_tid)))
|
||||
return -ESRCH;
|
||||
|
||||
wqhs = &receiver->wqh_send;
|
||||
wqhr = &receiver->wqh_recv;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ int sys_map(unsigned long phys, unsigned long virt, unsigned long npages,
|
||||
return -EINVAL;
|
||||
|
||||
found:
|
||||
printk("%s (%d) Mapping from 0x%lx to 0x%lxp, %lu pages\n", __FUNCTION__, tid, phys, virt, npages);
|
||||
// printk("%s (%d) Mapping from 0x%lx to 0x%lxp, %lu pages\n", __FUNCTION__, tid, phys, virt, npages);
|
||||
add_mapping_pgd(phys, virt, npages << PAGE_BITS, flags, TASK_PGD(target));
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Copyright (C) 2007 Bahadir Balban
|
||||
*/
|
||||
#include <l4/generic/scheduler.h>
|
||||
#include <l4/generic/container.h>
|
||||
#include <l4/api/thread.h>
|
||||
#include <l4/api/syscall.h>
|
||||
#include <l4/api/errno.h>
|
||||
@@ -25,12 +26,12 @@ int sys_thread_switch(void)
|
||||
* This suspends a thread which is in either suspended,
|
||||
* sleeping or runnable state.
|
||||
*/
|
||||
int thread_suspend(struct task_ids *ids)
|
||||
int thread_suspend(l4id_t tid)
|
||||
{
|
||||
struct ktcb *task;
|
||||
int ret = 0;
|
||||
|
||||
if (!(task = tcb_find(ids->tid)))
|
||||
if (!(task = tcb_find(tid)))
|
||||
return -ESRCH;
|
||||
|
||||
if (task->state == TASK_INACTIVE)
|
||||
@@ -90,7 +91,7 @@ int thread_recycle(struct task_ids *ids)
|
||||
if (!(task = tcb_find(ids->tid)))
|
||||
return -ESRCH;
|
||||
|
||||
if ((ret = thread_suspend(ids)) < 0)
|
||||
if ((ret = thread_suspend(ids->tid)) < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
@@ -112,15 +113,27 @@ int thread_recycle(struct task_ids *ids)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread_destroy(struct task_ids *ids)
|
||||
void thread_destroy_self();
|
||||
|
||||
int thread_destroy(l4id_t tid)
|
||||
{
|
||||
struct ktcb *task;
|
||||
int ret;
|
||||
|
||||
if (!(task = tcb_find(ids->tid)))
|
||||
printk("%s: Destroying (%d)\n", __FUNCTION__, tid);
|
||||
|
||||
/*
|
||||
* Pager destroying itself
|
||||
*/
|
||||
if (tid == current->tid) {
|
||||
thread_destroy_self();
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (!(task = tcb_find(tid)))
|
||||
return -ESRCH;
|
||||
|
||||
if ((ret = thread_suspend(ids)) < 0)
|
||||
if ((ret = thread_suspend(tid)) < 0)
|
||||
return ret;
|
||||
|
||||
/* Remove tcb from global list so any callers will get -ESRCH */
|
||||
@@ -139,6 +152,60 @@ int thread_destroy(struct task_ids *ids)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pagers destroy themselves either by accessing an illegal
|
||||
* address or voluntarily. All threads managed also get
|
||||
* destroyed.
|
||||
*/
|
||||
void thread_destroy_self(void)
|
||||
{
|
||||
struct ktcb *task, *n;
|
||||
|
||||
/* Destroy all threads under control of this pager */
|
||||
spin_lock(&curcont->ktcb_list.list_lock);
|
||||
list_foreach_removable_struct(task, n,
|
||||
&curcont->ktcb_list.list,
|
||||
task_list) {
|
||||
if (task->tid == current->tid)
|
||||
continue;
|
||||
spin_unlock(&curcont->ktcb_list.list_lock);
|
||||
thread_destroy(task->tid);
|
||||
spin_lock(&curcont->ktcb_list.list_lock);
|
||||
}
|
||||
spin_unlock(&curcont->ktcb_list.list_lock);
|
||||
|
||||
/*
|
||||
* Indicate intention to destroy to any
|
||||
* destroyer code we will add later on
|
||||
*/
|
||||
current->flags |= TASK_EXITING;
|
||||
|
||||
tcb_remove(current);
|
||||
|
||||
/*
|
||||
* If there are any sleepers on any of the task's
|
||||
* waitqueues, we need to wake those tasks up.
|
||||
*
|
||||
* These could be tasks that have called us from
|
||||
* other containers.
|
||||
*/
|
||||
wake_up_all(¤t->wqh_send, 0);
|
||||
wake_up_all(¤t->wqh_recv, 0);
|
||||
|
||||
printk("%s: Suspending self (%d)\n", __FUNCTION__, current->tid);
|
||||
|
||||
/* Remain as a zombie for now */
|
||||
sched_suspend_sync();
|
||||
|
||||
/* NOTE:
|
||||
* If we deleted ourself here, probably that would be
|
||||
* the end of what we need to do and could get away
|
||||
* with that because ktcb's are cached and always mapped.
|
||||
* It wouldn't hurt to delete ourself inside a
|
||||
* non-preemptable point and schedule never to return.
|
||||
*/
|
||||
}
|
||||
|
||||
int thread_resume(struct task_ids *ids)
|
||||
{
|
||||
struct ktcb *task;
|
||||
@@ -365,13 +432,13 @@ int sys_thread_control(unsigned int flags, struct task_ids *ids)
|
||||
ret = thread_start(ids);
|
||||
break;
|
||||
case THREAD_SUSPEND:
|
||||
ret = thread_suspend(ids);
|
||||
ret = thread_suspend(ids->tid);
|
||||
break;
|
||||
case THREAD_RESUME:
|
||||
ret = thread_resume(ids);
|
||||
break;
|
||||
case THREAD_DESTROY:
|
||||
ret = thread_destroy(ids);
|
||||
ret = thread_destroy(ids->tid);
|
||||
break;
|
||||
case THREAD_RECYCLE:
|
||||
ret = thread_recycle(ids);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Copyright (C) 2007, 2008 Bahadir Balban
|
||||
*/
|
||||
#include <l4/generic/scheduler.h>
|
||||
#include <l4/generic/thread.h>
|
||||
#include <l4/api/thread.h>
|
||||
#include <l4/generic/space.h>
|
||||
#include <l4/generic/tcb.h>
|
||||
#include <l4/lib/printk.h>
|
||||
@@ -62,9 +64,14 @@ void ipc_restore_state(struct ipc_state *state)
|
||||
/* Send data fault ipc to the faulty task's pager */
|
||||
void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* mr[0] has the fault tag. The rest is the fault structure */
|
||||
u32 mr[MR_TOTAL] = { [MR_TAG] = L4_IPC_TAG_PFAULT,
|
||||
[MR_SENDER] = current->tid };
|
||||
u32 mr[MR_TOTAL] = {
|
||||
[MR_TAG] = L4_IPC_TAG_PFAULT,
|
||||
[MR_SENDER] = current->tid
|
||||
};
|
||||
|
||||
fault_kdata_t *fault = (fault_kdata_t *)&mr[MR_UNUSED_START];
|
||||
|
||||
/* Fill in fault information to pass over during ipc */
|
||||
@@ -94,16 +101,22 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far)
|
||||
/* Set current flags to short ipc */
|
||||
tcb_set_ipc_flags(current, IPC_FLAGS_SHORT);
|
||||
|
||||
/* Send ipc to the task's pager */
|
||||
ipc_sendrecv(current->pagerid, current->pagerid, 0);
|
||||
/* Detect if a pager is self-faulting */
|
||||
if (current->tid == current->pagerid) {
|
||||
printk("Pager (%d) self-faulting. Exiting.\n",
|
||||
current->tid);
|
||||
thread_destroy_self();
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: CHECK TASK KILL REPLY !!!
|
||||
* Here, pager has handled the request and sent us back a message.
|
||||
* It is natural that a pager might want to kill the task due to
|
||||
* illegal access. Here we ought to check this and kill it rather
|
||||
* than return back to it.
|
||||
*/
|
||||
/* Send ipc to the task's pager */
|
||||
if ((err = ipc_sendrecv(current->pagerid,
|
||||
current->pagerid, 0)) < 0) {
|
||||
//printk("Thread (%d) faulted in kernel and its pager "
|
||||
// "returned error (%d). Suspending.\n",
|
||||
// current->tid, err);
|
||||
BUG_ON(current->nlocks);
|
||||
sched_suspend_sync();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -226,11 +239,6 @@ void data_abort_handler(u32 faulted_pc, u32 fsr, u32 far)
|
||||
{
|
||||
set_abort_type(fsr, ARM_DABT);
|
||||
|
||||
/*
|
||||
* FIXME: Find why if we use a clause like if tid == PAGER_TID
|
||||
* this prints just the faulted_pc but not the text "Data abort @ PC:"
|
||||
* Strange.
|
||||
*/
|
||||
dbg_abort("Data abort @ PC: ", faulted_pc);
|
||||
|
||||
/* Check for more details */
|
||||
@@ -244,6 +252,11 @@ void data_abort_handler(u32 faulted_pc, u32 fsr, u32 far)
|
||||
/* This notifies the pager */
|
||||
fault_ipc_to_pager(faulted_pc, fsr, far);
|
||||
|
||||
if (current->flags & TASK_SUSPENDING) {
|
||||
BUG_ON(current->nlocks);
|
||||
sched_suspend_sync();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -256,7 +269,6 @@ error:
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void prefetch_abort_handler(u32 faulted_pc, u32 fsr, u32 far, u32 lr)
|
||||
{
|
||||
set_abort_type(fsr, ARM_PABT);
|
||||
@@ -268,6 +280,11 @@ void prefetch_abort_handler(u32 faulted_pc, u32 fsr, u32 far, u32 lr)
|
||||
if (KERN_ADDR(lr))
|
||||
goto error;
|
||||
fault_ipc_to_pager(faulted_pc, fsr, far);
|
||||
|
||||
if (current->flags & TASK_SUSPENDING) {
|
||||
BUG_ON(current->nlocks);
|
||||
sched_suspend_sync();
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
|
||||
@@ -162,9 +162,10 @@ int init_first_pager(struct pager *pager,
|
||||
space->pgd = current_pgd;
|
||||
address_space_attach(task, space);
|
||||
|
||||
/* Initialize container relationships */
|
||||
/* Initialize container/pager relationships */
|
||||
pager->tcb = task;
|
||||
task->pager = pager;
|
||||
task->pagerid = task->tid;
|
||||
task->container = cont;
|
||||
task->cap_list_ptr = &pager->cap_list;
|
||||
|
||||
@@ -220,12 +221,13 @@ int init_pager(struct pager *pager, struct container *cont)
|
||||
|
||||
task->space = address_space_create(0);
|
||||
|
||||
/* Initialize container relationships */
|
||||
/* Initialize container/pager relationships */
|
||||
pager->tcb = task;
|
||||
task->pager = pager;
|
||||
task->container = cont;
|
||||
task->cap_list_ptr = &pager->cap_list;
|
||||
task->pagerid = task->tid;
|
||||
|
||||
task->cap_list_ptr = &pager->cap_list;
|
||||
add_mapping_pgd(pager->start_lma, pager->start_vma,
|
||||
page_align_up(pager->memsize),
|
||||
MAP_USR_DEFAULT_FLAGS, TASK_PGD(task));
|
||||
|
||||
@@ -236,11 +236,23 @@ void sched_suspend_sync(void)
|
||||
current->state = TASK_INACTIVE;
|
||||
current->flags &= ~TASK_SUSPENDING;
|
||||
scheduler.prio_total -= current->priority;
|
||||
BUG_ON(scheduler.prio_total <= 0);
|
||||
BUG_ON(scheduler.prio_total < 0);
|
||||
preempt_enable();
|
||||
|
||||
/* Async wake up any waiters */
|
||||
wake_up_task(tcb_find(current->pagerid), 0);
|
||||
/*
|
||||
* Async wake up any waiting pagers
|
||||
*
|
||||
* If we're not a pager, then a pager must have
|
||||
* signalled us to suspend, and it must have been
|
||||
* waiting for us to wake it up when we suspend.
|
||||
* We do it here.
|
||||
*
|
||||
* If though, we _are_ a pager that is suspending,
|
||||
* we silently do so. Noone is waiting us.
|
||||
*/
|
||||
if (current->pagerid != current->tid)
|
||||
wake_up_task(tcb_find(current->pagerid), 0);
|
||||
|
||||
schedule();
|
||||
}
|
||||
|
||||
@@ -251,13 +263,25 @@ void sched_suspend_async(void)
|
||||
current->state = TASK_INACTIVE;
|
||||
current->flags &= ~TASK_SUSPENDING;
|
||||
scheduler.prio_total -= current->priority;
|
||||
BUG_ON(scheduler.prio_total <= 0);
|
||||
BUG_ON(scheduler.prio_total < 0);
|
||||
|
||||
/* This will make sure we yield soon */
|
||||
preempt_enable();
|
||||
|
||||
/* Async wake up any waiters */
|
||||
wake_up_task(tcb_find(current->pagerid), 0);
|
||||
/*
|
||||
* Async wake up any waiting pagers
|
||||
*
|
||||
* If we're not a pager, then a pager must have
|
||||
* signalled us to suspend, and it must have been
|
||||
* waiting for us to wake it up when we suspend.
|
||||
* We do it here.
|
||||
*
|
||||
* If though, we _are_ a pager that is suspending,
|
||||
* we silently do so. Noone is waiting us.
|
||||
*/
|
||||
if (current->pagerid != current->tid)
|
||||
wake_up_task(tcb_find(current->pagerid), 0);
|
||||
|
||||
need_resched = 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user