#include #include #include #include #include #include #include #include #include #include #include #include "local.h" /***************************************************************************** ** Current() implementation ** *****************************************************************************/ struct thread_info *current_thread_info(void) { dde26_thread_data *cur = (dde26_thread_data *)ddekit_thread_get_my_data(); return &LX_THREAD(cur); } struct task_struct *get_current(void) { return current_thread_info()->task; } /***************************************************************************** ** PID-related stuff ** ** ** ** Linux manages lists of PIDs that are handed out to processes so that at ** ** a later point it is able to determine which task_struct belongs to a ** ** certain PID. We implement this with a single list holding the mappings ** ** for all our threads. ** *****************************************************************************/ LIST_HEAD(_pid_task_list); ddekit_lock_t _pid_task_list_lock; /** PID to task_struct mapping */ struct pid2task { struct list_head list; /**< list data */ struct pid *pid; /**< PID */ struct task_struct *ts; /**< task struct */ }; struct pid init_struct_pid = INIT_STRUCT_PID; void put_pid(struct pid *pid) { if (pid) atomic_dec(&pid->count); // no freeing here, our struct pid's are always allocated as // part of the dde26_thread_data } /** Attach PID to a certain task struct. */ void attach_pid(struct task_struct *task, enum pid_type type __attribute__((unused)), struct pid *pid) { /* Initialize a new pid2task mapping */ struct pid2task *pt = kmalloc(sizeof(struct pid2task), GFP_KERNEL); pt->pid = get_pid(pid); pt->ts = task; /* add to list */ ddekit_lock_lock(&_pid_task_list_lock); list_add(&pt->list, &_pid_task_list); ddekit_lock_unlock(&_pid_task_list_lock); } /** Detach PID from a task struct. */ void detach_pid(struct task_struct *task, enum pid_type type __attribute__((unused))) { struct list_head *p, *n, *h; h = &_pid_task_list; ddekit_lock_lock(&_pid_task_list_lock); /* search for mapping with given task struct and free it if necessary */ list_for_each_safe(p, n, h) { struct pid2task *pt = list_entry(p, struct pid2task, list); if (pt->ts == task) { put_pid(pt->pid); list_del(p); kfree(pt); break; } } ddekit_lock_unlock(&_pid_task_list_lock); } struct task_struct *find_task_by_pid_type(int type, int nr) { struct list_head *h, *p; h = &_pid_task_list; ddekit_lock_lock(&_pid_task_list_lock); list_for_each(p, h) { struct pid2task *pt = list_entry(p, struct pid2task, list); if (pid_nr(pt->pid) == nr) { ddekit_lock_unlock(&_pid_task_list_lock); return pt->ts; } } ddekit_lock_unlock(&_pid_task_list_lock); return NULL; } struct task_struct *find_task_by_pid_ns(int nr, struct pid_namespace *ns) { /* we don't implement PID name spaces */ return find_task_by_pid_type(0, nr); } struct task_struct *find_task_by_pid(int nr) { return find_task_by_pid_type(0, nr); } /***************************************************************************** ** kernel_thread() implementation ** *****************************************************************************/ /* Struct containing thread data for a newly created kthread. */ struct __kthread_data { int (*fn)(void *); void *arg; ddekit_lock_t lock; dde26_thread_data *kthread; }; /** Counter for running kthreads. It is used to create unique names * for kthreads. */ static atomic_t kthread_count = ATOMIC_INIT(0); /** Entry point for new kernel threads. Make this thread a DDE26 * worker and then execute the real thread fn. */ static void __kthread_helper(void *arg) { struct __kthread_data *k = (struct __kthread_data *)arg; /* * Make a copy of the fn and arg pointers, as the kthread struct is * deleted by our parent after notifying it and this may happen before we * get to execute the function. */ int (*_fn)(void*) = k->fn; void *_arg = k->arg; l4dde26_process_add_worker(); /* * Handshake with creator - we store our thread data in the * kthread struct and then unlock the lock to notify our * creator about completing setup */ k->kthread = (dde26_thread_data *)ddekit_thread_get_my_data(); ddekit_lock_unlock(&k->lock); do_exit(_fn(_arg)); } /** Our implementation of Linux' kernel_thread() function. Setup a new * thread running our __kthread_helper() function. */ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { ddekit_thread_t *t; char name[20]; struct __kthread_data *kt = vmalloc(sizeof(struct __kthread_data)); ddekit_lock_t lock; /* Initialize (and grab) handshake lock */ ddekit_lock_init(&lock); ddekit_lock_lock(&lock); int threadnum = atomic_inc_return(&kthread_count); kt->fn = fn; kt->arg = arg; kt->lock = lock; // Copy lock ptr, note that kt is freed by the // new thread, so we MUST NOT use kt->lock after // this point! snprintf(name, 20, ".kthread%x", threadnum); t = ddekit_thread_create(__kthread_helper, (void *)kt, name); Assert(t); ddekit_lock_lock(&lock); ddekit_lock_deinit(&lock); return pid_nr(VPID_P(kt->kthread)); } /** Our implementation of exit(). For DDE purposes this only relates * to kernel threads. */ void do_exit(long code) { ddekit_thread_t *t = DDEKIT_THREAD(lxtask_to_ddethread(current)); // printk("Thread %s exits with code %x\n", ddekit_thread_get_name(t), code); /* do some cleanup */ detach_pid(current, 0); /* goodbye, cruel world... */ ddekit_thread_exit(); } /***************************************************************************** ** Misc functions ** *****************************************************************************/ char *get_task_comm(char *buf, struct task_struct *tsk) { char *ret; /* buf must be at least sizeof(tsk->comm) in size */ task_lock(tsk); ret = strncpy(buf, tsk->comm, sizeof(tsk->comm)); task_unlock(tsk); return ret; } void set_task_comm(struct task_struct *tsk, char *buf) { task_lock(tsk); strlcpy(tsk->comm, buf, sizeof(tsk->comm)); task_unlock(tsk); } /***************************************************************************** ** DDEKit gluecode, init functions ** *****************************************************************************/ /* Initialize a dde26 thread. * * - Allocate thread data, as well as a Linux task struct, * - Fill in default values for thread_info, and task, * - Adapt task struct's thread_info backreference * - Initialize the DDE sleep lock */ static dde26_thread_data *init_dde26_thread(void) { /* * Virtual PID counter */ static atomic_t pid_counter = ATOMIC_INIT(0); dde26_thread_data *t = vmalloc(sizeof(dde26_thread_data)); Assert(t); memcpy(&t->_vpid, &init_struct_pid, sizeof(struct pid)); t->_vpid.numbers[0].nr = atomic_inc_return(&pid_counter); memcpy(&LX_THREAD(t), &init_thread, sizeof(struct thread_info)); LX_TASK(t) = vmalloc(sizeof(struct task_struct)); Assert(LX_TASK(t)); memcpy(LX_TASK(t), &init_task, sizeof(struct task_struct)); /* nice: Linux backreferences a task`s thread_info from the * task struct (which in turn can be found using the * thread_info...) */ LX_TASK(t)->stack = &LX_THREAD(t); /* initialize this thread's sleep lock */ SLEEP_LOCK(t) = ddekit_sem_init(0); return t; } /* Process setup for worker threads */ int l4dde26_process_add_worker(void) { dde26_thread_data *cur = init_dde26_thread(); /* If this function is called for a kernel_thread, the thread already has * been set up and we just need to store a reference to the ddekit struct. * However, this function may also be called directly to turn an L4 thread * into a DDE thread. Then, we need to initialize here. */ cur->_ddekit_thread = ddekit_thread_myself(); if (cur->_ddekit_thread == NULL) cur->_ddekit_thread = ddekit_thread_setup_myself(".dde26_thread"); Assert(cur->_ddekit_thread); ddekit_thread_set_my_data(cur); attach_pid(LX_TASK(cur), 0, &cur->_vpid); /* Linux' default is to have this set to 1 initially and let the * scheduler set this to 0 later on. */ current_thread_info()->preempt_count = 0; return 0; } /** * Add an already existing DDEKit thread to the set of threads known to the * Linux environment. This is used for the timer thread, which is actually a * DDEKit thread, but Linux code shall see it as a Linux thread as well. */ int l4dde26_process_from_ddekit(ddekit_thread_t *t) { Assert(t); dde26_thread_data *cur = init_dde26_thread(); cur->_ddekit_thread = t; ddekit_thread_set_data(t, cur); attach_pid(LX_TASK(cur), 0, &cur->_vpid); return 0; } /** Function to initialize the first DDE process. */ int __init l4dde26_process_init(void) { ddekit_lock_init_unlocked(&_pid_task_list_lock); int kthreadd_pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); kthreadd_task = find_task_by_pid(kthreadd_pid); l4dde26_process_add_worker(); return 0; } DEFINE_PER_CPU(int, cpu_number); //dde_process_initcall(l4dde26_process_init);