diff --git a/arch/sparc/kernel/thread.c b/arch/sparc/kernel/thread.c
index 8b26071e19946ab0af134fecc10ca9158cebd892..28ce210dc37f34c773bdcab59d07396b127fd8e5 100644
--- a/arch/sparc/kernel/thread.c
+++ b/arch/sparc/kernel/thread.c
@@ -37,15 +37,27 @@ extern struct thread_info *current_set[];
 /**
  * @brief this is a wrapper that actually executes the thread function
  */
-
+#include <kernel/time.h>
 static void th_starter(void)
 {
 	struct task_struct *task = current_set[0]->task;
 
+	struct timespec ts;
+	double start;
+	double stop;
+
+	ts = get_uptime();
+
+	start = (double) ts.tv_sec + (double) ts.tv_nsec / 1e9;
+
 	task->thread_fn(task->data);
 
-	printk("thread: %p returned\n", task->thread_fn);
+	arch_local_irq_disable();
+	ts = get_uptime();
+	stop = (double) ts.tv_sec + (double) ts.tv_nsec / 1e9;
+	printk("thread: %p returned after %gs\n", task->stack, stop-start);
 	task->state = TASK_DEAD;
+	arch_local_irq_enable();
 
 	schedule();
 
diff --git a/arch/sparc/kernel/traps/data_access_exception_trap.S b/arch/sparc/kernel/traps/data_access_exception_trap.S
index 65445e42e30b4eb01fe1742943e09682a450cdcb..2c151b823a49a404cbec0b7ad74a23a5dd9764b6 100644
--- a/arch/sparc/kernel/traps/data_access_exception_trap.S
+++ b/arch/sparc/kernel/traps/data_access_exception_trap.S
@@ -2,25 +2,27 @@
  * @file arch/sparc/kernel/traps/data_access_exception_trap.S
  * @brief this is a function that is called by a custom trap handler to handle
  *        an MMU or EDAC trap
- *
- * @todo this is BCC-specific
  */
 
 
-
+#ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE
+#include <asm/ttable.h>
+#else
+/* XXX: BCC */
 #define SAVE_ALL_HEAD \
         sethi   %hi(leonbare_trapsetup), %l4; \
         jmpl    %l4 + %lo(leonbare_trapsetup), %l6;
 #define SAVE_ALL \
         SAVE_ALL_HEAD \
          nop;
+/* All traps low-level code here must end with this macro. */
+#define RESTORE_ALL b leonbare_trapreturn; clr %l6;
+#endif
 
 
 #define FW_REGS_SZ     0x90 /* 36*4 */
 #define SF_REGS_SZ     0x60 /* 24*4 */
 
-/* All traps low-level code here must end with this macro. */
-#define RESTORE_ALL b leonbare_trapreturn; clr %l6;
 
 
 
@@ -40,14 +42,14 @@ data_access_exception_trap:
 	 * hence we have to point %pc to %npc and increment %npc to the
 	 * following instruction
          */
-	
+
 	/* ...but we can for the MMU
 	 mov	%l2, %l1
 	 add	%l2, 4, %l2
 	*/
 
 	rd	%wim, %l3	/* trap setup needs the %wim in %l3 */
-	
+
 	SAVE_ALL	/* create a trap window */
 
 	/* re-enable traps but not interrupts (set level to max) */
diff --git a/include/kernel/kthread.h b/include/kernel/kthread.h
index 81e4cbb2a90f1d8c086142c5caf0c73ae9ac3aa5..74ce47db77a9ee2380733bd6baa14d0955fa74bf 100644
--- a/include/kernel/kthread.h
+++ b/include/kernel/kthread.h
@@ -32,7 +32,7 @@ enum sched_policy {
 	SCHED_OTHER,
 };
 
-
+extern volatile int sched_edf;
 struct task_struct {
 
 	struct thread_info thread_info;
@@ -69,7 +69,11 @@ struct task_struct {
 	ktime				deadline; /* deadline of current period */
 
 	ktime				exec_start;
+	ktime				total;
+	unsigned long			slices;
 
+	ktime			first_wake;
+	ktime			first_dead;
 
 	/* Tasks may have a parent and any number of siblings or children.
 	 * If the parent is killed or terminated, so are all siblings and
@@ -96,6 +100,7 @@ void switch_to(struct task_struct *next);
 void schedule(void);
 void sched_yield(void);
 
+void sched_print_edf_list_internal(ktime now);
 void sched_print_edf_list(void);
 
 void kthread_set_sched_edf(struct task_struct *task, unsigned long period_us,
diff --git a/init/main.c b/init/main.c
index a212233933d4ff8e8e94044991485ffd35073352..61dbe82b43fad66140595aa79a3f95c535f78fe0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -45,160 +45,28 @@
 #endif /* GCC_VERSION */
 
 
-#include <kernel/irq.h>
 
-irqreturn_t dummy(unsigned int irq, void *userdata)
+int task1(void *data)
 {
-	// printk("IRQ!\n");
-	//schedule();
-	return 0;
-}
-
-
-/**
- * @brief do something useless
- */
-__attribute__((unused))
-static void twiddle(void)
-{
-	static int i;
-	const char cursor[] = {'/', '-', '\\', '|'};
-
-	printk("%c\b\b ", cursor[i]);
-
-	i = (i + 1) % ARRAY_SIZE(cursor);
-}
-
-
-
-#define TREADY 4
-
-#if 0
-static volatile int *console = (int *)0x80100100;
-#else
-static volatile int *console = (int *)0x80000100;
-#endif
-
-static int putchar(int c)
-{
-	while (!(console[1] & TREADY));
-
-	console[0] = 0x0ff & c;
-
-	if (c == '\n') {
-		while (!(console[1] & TREADY));
-		console[0] = (int) '\r';
-	}
-
-	return c;
-}
-
-
-
-int edf1(void *data)
-{
-	struct timespec ts;
-	static struct timespec t0;
-	int i;
-
 	while (1) {
-		ts = get_ktime();
-#if 0
-		printk("\tedf1: %g s; delta: %g s (%g Hz)\n",
-		       (double) ts.tv_sec + (double) ts.tv_nsec / 1e9,
-		       difftime(ts, t0), 1.0/difftime(ts, t0));
-#endif
-		for (i = 0; i < 100000; i++)
-			putchar('.');
-
-
-		t0 = ts;
-		sched_yield();
+		printk(".");
+	//	sched_yield();
 	}
 }
 
-int edf2(void *data)
-{
-	while (1)
-		putchar( *((char *) data) );
-}
-
 
-int edf3(void *data)
+int task2(void *data)
 {
 	while (1) {
-		putchar( *((char *) data) );
-		putchar( *((char *) data) );
-		sched_yield();
+		printk("-");
+	//	sched_yield();
 	}
 }
 
-int edf4(void *data)
-{
-	while (1) {
-		//sched_print_edf_list();
-		putchar('-');
-		sched_yield();
-	}
-}
-
-
-int add0r(void *data)
-{
-	volatile int *add = (int *) data;
-
-	while (1) 
-		add[0]++;
-}
-
-int print0r(void *data)
-{
-	int i;
-	int *s = (int *) data;
-	static int addx[30];
-
-	while (1) {
-		for (i = 0; i < 30; i++)
-			addx[i] = s[i];
-
-		printk("delta: ");
-		for (i = 0; i < 30; i++)
-			 printk("%d ", s[i]- addx[i]);
-		printk("\nabs:   ");
-		for (i = 0; i < 30; i++)
-			 printk("%d ", s[i]);
-		printk("\n\n");
-		sched_yield();
-	}
-}
 
 
 extern struct task_struct *kernel;
 
-int threadx(void *data)
-{
-
-	char c = (char) (* (char *)data);
-	int b = 0;
-
-	while(1) {
-		//printk(".");
-		int i;
-		for (i = 0; i < (int) c; i++) {
-			putchar(c);
-			b++;
-		}
-		putchar('\n');
-#if 1
-		if (b > (int) c * (int)c)
-			break;
-#endif
-	//	schedule();putchar( *((char *) data) );
-		//twiddle();
-		//cpu_relax();
-	}
-	return 0;
-}
 
 /**
  * @brief kernel initialisation routines
@@ -224,8 +92,8 @@ arch_initcall(kernel_init);
 #include <kernel/clockevent.h>
 int kernel_main(void)
 {
-	struct task_struct *tasks[MAX_TASKS];
-	int tcnt = 0;
+	struct task_struct *t;
+
 #if 0
 	void *addr;
 	struct elf_module m;
@@ -280,165 +148,26 @@ int kernel_main(void)
 
 
 
+	/* elevate boot thread */
 	kernel = kthread_init_main();
 
 
-#if 0
-	{
-	struct task_struct *t1;
-	t1 = kthread_create(edf1, NULL, KTHREAD_CPU_AFFINITY_NONE, "Thread2");
-	kthread_set_sched_edf(t1, 2e5,  1e5);
-	kthread_wake_up(t1);
-	}
-#endif
-#if 0
-	{
-	struct task_struct *t2;
-	struct task_struct *t3;
-
-	t2 = kthread_create(edf3, "\n", KTHREAD_CPU_AFFINITY_NONE, "EDF%d", 1);
-	kthread_set_sched_edf(t2, 1 * USEC_PER_SEC,  40 * USEC_PER_MSEC, 60 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t2);
-
-
-	t2 = kthread_create(edf3, "?", KTHREAD_CPU_AFFINITY_NONE, "EDF%d", 1);
-	kthread_set_sched_edf(t2, 1 * USEC_PER_SEC,  40 * USEC_PER_MSEC, 60 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t2);
-
-	t3 = kthread_create(edf4, NULL, KTHREAD_CPU_AFFINITY_NONE, "EDF_other");
-	kthread_set_sched_edf(t3, 200 * USEC_PER_MSEC,  10 * USEC_PER_MSEC, 10 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t3);
-
-	t3 = kthread_create(edf2, "x", KTHREAD_CPU_AFFINITY_NONE, "EDF_otherx");
-	kthread_set_sched_edf(t3, 300 * USEC_PER_MSEC,  5 * USEC_PER_MSEC, 5 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t3);
-
-	t3 = kthread_create(edf2, ":", KTHREAD_CPU_AFFINITY_NONE, "EDF_otherx");
-	kthread_set_sched_edf(t3, 50 * USEC_PER_MSEC,  5 * USEC_PER_MSEC, 5 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t3);
-
-	t3 = kthread_create(edf2, "o", KTHREAD_CPU_AFFINITY_NONE, "EDF_otherx");
-	kthread_set_sched_edf(t3, 50 * USEC_PER_MSEC,  5 * USEC_PER_MSEC, 5 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t3);
-
-	t3 = kthread_create(edf2, "/", KTHREAD_CPU_AFFINITY_NONE, "EDF_otherx");
-	kthread_set_sched_edf(t3, 30 * USEC_PER_MSEC,  3 * USEC_PER_MSEC, 3 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t3);
-
-	t3 = kthread_create(edf2, "\\", KTHREAD_CPU_AFFINITY_NONE, "EDF_otherx");
-	kthread_set_sched_edf(t3, 6 * USEC_PER_MSEC,  2 * USEC_PER_MSEC, 2 * USEC_PER_MSEC + 1);
-	kthread_wake_up(t3);
-
-	}
-#endif
-
-
-#if 1
-	{
-		int i;
-		struct task_struct *t;
-		static int add[30];
 
-		t = kthread_create(print0r, add, KTHREAD_CPU_AFFINITY_NONE, "print");
-		kthread_set_sched_edf(t, 1e6,  300 * USEC_PER_MSEC, 300 * USEC_PER_MSEC + 1);
-		kthread_wake_up(t);
-#if 1
-
-		for (i = 0; i < 30; i++) {
-			t = kthread_create(add0r, &add[i], KTHREAD_CPU_AFFINITY_NONE, "EDF%d", i);
-			kthread_set_sched_edf(t, 45 * USEC_PER_MSEC,  1 * USEC_PER_MSEC, 1 * USEC_PER_MSEC + 1);
-			kthread_wake_up(t);
-		}
-#endif
-	}
-#endif
 
+	t = kthread_create(task1, NULL, KTHREAD_CPU_AFFINITY_NONE, "print");
+	//kthread_set_sched_edf(t, 1000000,  50000, 90000);
+	t->priority = 4;
+	kthread_wake_up(t);
 
+	t = kthread_create(task2, NULL, KTHREAD_CPU_AFFINITY_NONE, "print1");
+	//kthread_set_sched_edf(t, 1000000,  50000, 90000);
+	t->priority = 8;
+	kthread_wake_up(t);
 
 
 
-
-
-
-	while(1) {
-	//	putchar('o');
-#if 0
-		static ktime t0;
-		ktime ts;
-
-		ts = ktime_get();
-
-		printk("now: %llu %llu delta %lld\n\n", ts, t0, ts-t0);
-		t0 = ts;
-#endif
-		cpu_relax();
-	}
-
-
-
-	while(1) {
-		struct timespec ts;
-		static struct timespec t0;
-
-		ts = get_ktime();
-		//printk("now: %g s; delta: %g ns (%g Hz)\n", (double) ts.tv_sec + (double) ts.tv_nsec / 1e9, difftime(ts, t0), 1.0/difftime(ts, t0) );
-		t0 = ts;
-		cpu_relax();
-	}
-
-	{
-	static char zzz[] = {':', '/', '\\', '~', '|'};
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(zzz); i++)
-		kthread_create(threadx, &zzz[i], KTHREAD_CPU_AFFINITY_NONE, "Thread2");
-	}
-
-	{
-		static char zzz[] = {':', '/', '\\', '~', '|'};
-		static int z;
-		char *buf = NULL;
-		int i;
-		struct timespec ts;
-		ts = get_uptime();
-		printk("creating tasks at %d s %d ns (%g)\n", ts.tv_sec, ts.tv_nsec, (double) ts.tv_sec + (double) ts.tv_nsec / 1e9);
-
-
-
-		for (i = 0; i < MAX_TASKS; i++) {
-		//	buf = kmalloc(30);
-		//	BUG_ON(!buf);
-
-		//	sprintf(buf, "Thread %d", z);
-			z++;
-
-			tasks[tcnt++] = kthread_create(threadx, &zzz[i], KTHREAD_CPU_AFFINITY_NONE, buf);
-		//	kfree(buf);
-		}
-
-	}
-
-
-	{
-		int i;
-
-		struct timespec ts;
-		ts = get_uptime();
-		printk("total %d after %d s %d ns (%g)\n", tcnt, ts.tv_sec, ts.tv_nsec, (double) ts.tv_sec + (double) ts.tv_nsec / 1e9);
-		BUG_ON(tcnt > MAX_TASKS);
-
-		for (i = 0; i < tcnt; i++)
-			kthread_wake_up(tasks[i]);
-
-		arch_local_irq_disable();
-		ts = get_uptime();
-		printk("all awake after %d s %d ns (%g)\n", ts.tv_sec, ts.tv_nsec, (double) ts.tv_sec + (double) ts.tv_nsec / 1e9);
-		arch_local_irq_enable();
-	}
-
-
 	while(1) {
-		twiddle();
+		printk("|");
 		cpu_relax();
 	}
 
diff --git a/kernel/kthread.c b/kernel/kthread.c
index cf18fe14d0b0635993b8980f2f2a5e5493f15616..c7ff049b644dc3bd7d5faec41b188774fb33a2a9 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -27,12 +27,12 @@
 static struct {
 	struct list_head new;
 	struct list_head run;
-	struct list_head idle;
+	struct list_head wake;
 	struct list_head dead;
 } _kthreads = {
 	.new  = LIST_HEAD_INIT(_kthreads.new),
 	.run  = LIST_HEAD_INIT(_kthreads.run),
-	.idle = LIST_HEAD_INIT(_kthreads.idle),
+	.wake = LIST_HEAD_INIT(_kthreads.wake),
 	.dead = LIST_HEAD_INIT(_kthreads.dead)
 };
 
@@ -86,238 +86,62 @@ void kthread_cleanup_dead(void)
 }
 
 
-void sched_print_edf_list(void)
-{
-	ktime now;
-	char state = 'U';
-	int64_t rel_deadline;
-	int64_t rel_wait;
-
-	struct task_struct *tsk;
-	struct task_struct *tmp;
-
-
-	now = ktime_get();
-
-
-	printk("\nt: %lld\n", ktime_to_us(now));
-	printk("S\tDeadline\tWakeup\tdelta W\tdelta P\tt_rem\tName\n");
-	printk("----------------------------------------------\n");
-
-	list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
-
-		if (tsk->policy != SCHED_EDF)
-			continue;
-
-		rel_deadline = ktime_delta(tsk->deadline, now);
-		rel_wait     = ktime_delta(tsk->wakeup,   now);
-		if (rel_wait < 0)
-			rel_wait = 0; /* running */
-
-		if (tsk->state == TASK_IDLE)
-			state = 'I';
-		if (tsk->state == TASK_RUN)
-			state = 'R';
-
-		printk("%c\t%lld\t%lld\t%lld\t%lld\t%lld\t%s\n",
-		       state, ktime_to_us(tsk->deadline), ktime_to_us(tsk->wakeup),
-		       ktime_to_us(rel_wait), ktime_to_us(rel_deadline), ktime_to_us(tsk->runtime), tsk->name);
-	}
-
-}
-
-/**
- * Our EDF task scheduling timeline:
- *
- *
- *
- *  wakeup/
- *  activation
- *   |                      absolute
- *   |                      deadline
- *   |  start                  |
- *   |  time                   |               next
- *   |   |                     |              wakeup
- *   |   | computation|        |                |
- *   |   |    time    |        |                |
- *   |   |############|        |                |
- *   +-----+-------------------+-----------------
- *         |------ WCET -------|
- *         ^- latest start time
- *   |--- relative deadline ---|
- *   |---------------- period ------------------|
- *
- *
- *
- *
- */
-
-
-/**
- * @brief check if an EDF task can still execute given its deadline
- *
- * @note effectively checks
- *	 wcet         remaining runtime in slot
- *	------   <   --------------------------
- *	period        remaining time to deadline
- *
- * @returns true if can still execute before deadline
- */
-
-static inline bool schedule_edf_can_execute(struct task_struct *tsk, ktime now)
-{
-	int64_t rel_deadline;
-
-
-	if (tsk->runtime <= 0)
-		return false;
-
-	rel_deadline = ktime_delta(tsk->deadline, now);
-	if (rel_deadline <= 0)
-		return false;
 
-	if (tsk->wcet * rel_deadline < tsk->period * tsk->runtime)
-		return true;
-
-	return false;
-}
-
-
-static inline void schedule_edf_reinit_task(struct task_struct *tsk, ktime now)
+void sched_yield(void)
 {
-	tsk->state = TASK_IDLE;
-
-	tsk->wakeup = ktime_add(tsk->wakeup, tsk->period);
-//	BUG_ON(ktime_after(tsk->wakeup, now)); /* deadline missed earlier? */
+	struct task_struct *tsk;
 
-	tsk->deadline = ktime_add(tsk->wakeup, tsk->deadline_rel);
+	tsk = current_set[0]->task;
+	if (tsk->policy == SCHED_EDF)
+		tsk->runtime = 0;
 
-	tsk->runtime = tsk->wcet;
+	schedule();
 }
 
 
-#define SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE 3000000000UL
-/* stupidly sort EDFs */
-static int64_t schedule_edf(ktime now)
+void sched_wake(struct task_struct *next, ktime now, int64_t slot_ns)
 {
-//	ktime now;
-
-	int64_t delta;
-
-	int64_t slot = SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE;
-
-	struct task_struct *tsk;
-	struct task_struct *tmp;
 
-	ktime wake;
-
-//	now = ktime_get();
-
-//	printk("vvvv\n");
-	list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
-
-		if (tsk->policy != SCHED_EDF)
-			continue;
+	struct task_struct *task;
 
-	//	printk("%s: %lld\n", tsk->name, ktime_to_us(tsk->wakeup));
-		/* time to wake up yet? */
-		if (ktime_after(tsk->wakeup, now)) {
-			/* nope, update minimum runtime for this slot */
-			delta = ktime_delta(tsk->wakeup, now);
-			if (delta > 0  && (delta < slot))
-				slot = delta;
-			continue;
-		}
+	if (list_empty(&_kthreads.wake))
+		return;
 
-		/* if it's already running, see if there is time remaining */
-		if (tsk->state == TASK_RUN) {
-			if (ktime_after(tsk->wakeup, now)) {
-				printk("violated %s\n", tsk->name);
-			}
-			if (!schedule_edf_can_execute(tsk, now)) {
-				schedule_edf_reinit_task(tsk, now);
-				/* nope, update minimum runtime for this slot */
-				delta = ktime_delta(tsk->wakeup, now);
-				if (delta > 0  && (delta < slot))
-					slot = delta;
-				continue;
-			}
-
-			/* move to top */
-			list_move(&tsk->node, &_kthreads.run);
-			continue;
-		}
+	task = list_entry(_kthreads.wake.next, struct task_struct, node);
 
-		/* time to wake up */
-		if (tsk->state == TASK_IDLE) {
-			tsk->state = TASK_RUN;
-			/* move to top */
-			list_move(&tsk->node, &_kthreads.run);
-		}
+	if (task->policy == SCHED_EDF) {
+		if (next->policy == SCHED_EDF)
+			return;
+		/* initially set current time as wakeup */
+		task->wakeup = ktime_add(now, slot_ns);
+		task->deadline = ktime_add(task->wakeup, task->deadline_rel);
+		task->first_wake = task->wakeup;
+		task->first_dead = task->deadline;
 
+		list_move(&task->node, &_kthreads.run);
 	}
-//	printk("---\n");
-	/* now find the closest relative deadline */
-
-	wake = ktime_add(now, slot);
-	list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
-
-		if (tsk->policy != SCHED_EDF)
-			break;
-
-		/* all currently runnable task are at the top of the list */
-		if (tsk->state != TASK_RUN)
-			break;
-
-		if (ktime_before(wake, tsk->deadline))
-			continue;
-
-		delta = ktime_delta(wake, tsk->deadline);
 
-		if (delta < 0) {
-			delta = ktime_delta(now, tsk->deadline);
-			printk("\n [%lld] %s deadline violated by %lld us\n", ktime_to_ms(now), tsk->name, ktime_to_us(delta));
-		}
-
-
-		if (delta < slot) {
-			if (delta)
-				slot = delta;
-			else
-				delta = tsk->runtime;
-			wake = ktime_add(now, slot); /* update next wakeup */
-			/* move to top */
-			list_move(&tsk->node, &_kthreads.run);
-			BUG_ON(slot <= 0);
-		}
+	if (task->policy == SCHED_RR) {
+		task->state = TASK_RUN;
+		list_move(&task->node, &_kthreads.run);
 	}
 
-//	printk("in: %lld\n", ktime_to_us(ktime_delta(ktime_get(), now)));
-	BUG_ON(slot < 0);
-
-	return slot;
 }
 
 
-void sched_yield(void)
-{
-	struct task_struct *tsk;
-
-	tsk = current_set[0]->task;
-	if (tsk->policy == SCHED_EDF)
-		tsk->runtime = 0;
-
-	schedule();
-}
-
+#define MIN_SLICE	1000000LL	/* 1 ms */
 
+#define OVERHEAD	0LL
 
 void schedule(void)
 {
 	struct task_struct *next;
 	struct task_struct *current;
-	int64_t slot_ns;
-	ktime now = ktime_get();
+	int64_t slot_ns = MIN_SLICE;
+
+
+
+	ktime now;
 
 
 	if (list_empty(&_kthreads.run))
@@ -336,24 +160,32 @@ void schedule(void)
 	arch_local_irq_disable();
 
 	kthread_lock();
+
+	now = ktime_add(ktime_get(), OVERHEAD);
+
 	tick_set_next_ns(1e9);
 
 
 
 	current = current_set[0]->task;
+
+
+
 	if (current->policy == SCHED_EDF) {
 		ktime d;
 		d = ktime_delta(now, current->exec_start);
-//		if (d > current->runtime);
-//			printk("\ntrem: %lld, %lld\n", ktime_to_us(current->runtime), ktime_to_us(d));
-		if (current->runtime)
-			current->runtime -= d;
+		BUG_ON(d < 0);
+		current->total = ktime_add(current->total, d);
+		current->slices++;
+		current->runtime = ktime_sub(current->runtime, d);
+		//printk("%lld %lld\n", d, current->runtime);
 	}
 
 
 	/** XXX not here, add cleanup thread */
 	kthread_cleanup_dead();
 
+
 #if 1
 	{
 		static int init;
@@ -363,16 +195,25 @@ void schedule(void)
 		}
 	}
 #endif
+
+
+
+
+
+
+
+
+#if 0
 	slot_ns = schedule_edf(now);
+#endif
+
 
 	/* round robin as before */
 	do {
 
 		next = list_entry(_kthreads.run.next, struct task_struct, node);
 
-		//printk("[%lld] %s\n", ktime_to_ms(ktime_get()), next->name);
-		if (!next)
-			BUG();
+		BUG_ON(!next);
 
 		if (next->state == TASK_RUN) {
 			list_move_tail(&next->node, &_kthreads.run);
@@ -390,45 +231,28 @@ void schedule(void)
 
 
 	if (next->policy == SCHED_EDF) {
-		if (next->runtime <= slot_ns) {
+		if (next->runtime <= slot_ns)
 			slot_ns = next->runtime; /* XXX must track actual time because of IRQs */
-			next->runtime = 0;
-		}
 	}
 
-	next->exec_start = now;
+	if (next->policy == SCHED_RR)
+		slot_ns = (ktime) next->priority * MIN_SLICE;
+
 
-	kthread_unlock();
 
 	if (slot_ns > 0xffffffff)
 		slot_ns = 0xffffffff;
 
-	if (slot_ns < 18000) {
-		printk("%u\n",slot_ns);
-		slot_ns = 18000;
-	}
-//	printk("\n%lld ms\n", ktime_to_ms(slot_ns));
+	BUG_ON (slot_ns < 18000);
+
+
+	sched_wake(next, now, slot_ns);
+
+	next->exec_start = ktime_get();
+
+	kthread_unlock();
+
 	tick_set_next_ns(slot_ns);
-#if 0
-#if 0
-	tick_set_next_ns(30000);
-#else
-	{
-		static int cnt = 2;
-		static int sig = 1;
-		struct timespec now;
-		now = get_ktime();
-		now.tv_nsec += 1000000000 / cnt; // 10k Hz
-
-		if (cnt > 100)
-			sig = -1;
-		if (cnt < 2)
-			sig = 1;
-		cnt = cnt + sig;
-		BUG_ON(tick_set_next_ktime(now) < 0);
-	}
-#endif
-#endif
 
 	prepare_arch_switch(1);
 	switch_to(next);
@@ -436,7 +260,7 @@ void schedule(void)
 	arch_local_irq_enable();
 }
 
-
+__attribute__((unused))
 static void kthread_set_sched_policy(struct task_struct *task,
 				     enum sched_policy policy)
 {
@@ -448,139 +272,20 @@ static void kthread_set_sched_policy(struct task_struct *task,
 }
 
 
-void kthread_set_sched_edf(struct task_struct *task, unsigned long period_us,
-			  unsigned long wcet_us, unsigned long deadline_rel_us)
-{
-	/* XXX schedulability tests */
-
-	if (wcet_us >= period_us) {
-		printk("Cannot schedule EDF task with WCET %u >= PERIOD %u !\n", wcet_us, period_us);
-		return;
-	}
-
-	if (wcet_us >= deadline_rel_us) {
-		printk("Cannot schedule EDF task with WCET %u >= DEADLINE %u !\n", wcet_us, deadline_rel_us);
-		return;
-	}
-
-	if (deadline_rel_us >= period_us) {
-		printk("Cannot schedule EDF task with DEADLINE %u >= PERIOD %u !\n", deadline_rel_us, period_us);
-		return;
-	}
-
-
-	arch_local_irq_disable();
-	task->period   = us_to_ktime(period_us);
-	task->wcet     = us_to_ktime(wcet_us);
-	task->runtime  = task->wcet;
-	task->deadline_rel = us_to_ktime(deadline_rel_us);
-
-
-
-
-	{
-		double u = 0.0;	/* utilisation */
-
-		struct task_struct *tsk;
-		struct task_struct *tmp;
-
-
-		u += (double) (int32_t) task->wcet / (double) (int32_t) task->period;
-
-
-		list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
-
-			if (tsk->policy != SCHED_EDF)
-				continue;
-
-			u += (double) (int32_t) tsk->wcet / (double) (int32_t) tsk->period;
-		}
-		if (u > 1.0)
-			printk("I am not schedule-able: %g\n", u);
-	}
-
-
-
-	kthread_set_sched_policy(task, SCHED_EDF);
-
-	arch_local_irq_enable();
-
-
-
-
-
-}
-
-
-
-/**
- * t1:        | ##d
- *
- * t2:   |    #####d
- *
- * t3:      |       ############d
- *  --------------------------------------------------
- *
- * |...wakeup
- * #...wcet
- * d...deadline
- */
 
 void kthread_wake_up(struct task_struct *task)
 {
-//	printk("wake thread %p\n", task->stack_top);
 	arch_local_irq_disable();
 	kthread_lock();
 
-	/* for now, simply take the current time and add the task wakeup
-	 * period to configure the first wakeup, then set the deadline
-	 * accordingly.
-	 * note: once we have more proper scheduling, we will want to
-	 * consider the following: if a EDF task is in paused state (e.g.
-	 * with a semaphore locked, do the same when the semaphore is unlocked,
-	 * but set the deadline to now + wcet
-	 */
-
 	BUG_ON(task->state != TASK_NEW);
 
 	task->state = TASK_IDLE;
 
-	if (task->policy == SCHED_EDF) {
-
-		struct task_struct *tsk;
-		struct task_struct *tmp;
-
-		/* initially set current time as wakeup */
-		task->wakeup = ktime_add(ktime_get(), task->period);
-		task->deadline = ktime_add(task->wakeup, task->deadline_rel);
-
-	//	printk("%s initial wake: %llu, deadline: %llu\n", task->name, ktime_to_us(task->wakeup), ktime_to_us(task->deadline));
-
-		list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
-
-			if (tsk->policy != SCHED_EDF)
-				continue;
-
-			if (ktime_before(tsk->deadline, task->deadline))
-				continue;
-
-			/* move the deadline forward */
-			task->deadline = ktime_add(tsk->deadline, task->deadline_rel);
-		//	printk("%s deadline now: %llu\n", task->name, ktime_to_us(task->deadline));
-		}
-
-		/* update first wakeup time */
-//		printk("%s deadline fin: %llu\n", task->name, ktime_to_us(task->deadline));
-		task->wakeup = ktime_sub(task->deadline, task->deadline_rel);
-//		printk("%s wakeup now: %llu\n", task->name, ktime_to_us(task->wakeup));
-	}
-
-	list_move_tail(&task->node, &_kthreads.run);
+	list_move_tail(&task->node, &_kthreads.wake);
 
 	kthread_unlock();
 	arch_local_irq_enable();
-
-	schedule();
 }
 
 
@@ -596,6 +301,7 @@ struct task_struct *kthread_init_main(void)
 
 	/* XXX accessors */
 	task->policy = SCHED_RR; /* default */
+	task->priority = 1;
 
 	arch_promote_to_task(task);
 
@@ -673,7 +379,10 @@ static struct task_struct *kthread_create_internal(int (*thread_fn)(void *data),
 
 	/* XXX accessors */
 	task->policy = SCHED_RR; /* default */
+	task->priority = 1;
 
+	task->total = 0;
+	task->slices = 0;
 	arch_init_task(task, thread_fn, data);
 
 	task->state = TASK_NEW;
@@ -686,169 +395,13 @@ static struct task_struct *kthread_create_internal(int (*thread_fn)(void *data),
 	kthread_unlock();
 	arch_local_irq_enable();
 
-
-	//printk("%s is next at %p stack %p\n", namefmt, &task->thread_info, task->stack);
-	//printk("%s\n", namefmt);
-
-
 	return task;
 }
 
 
 
 
-
 /**
- * try_to_wake_up - wake up a thread
- * @p: the thread to be awakened
- * @state: the mask of task states that can be woken
- * @wake_flags: wake modifier flags (WF_*)
- *
- * If (@state & @p->state) @p->state = TASK_RUN.
- *
- * If the task was not queued/runnable, also place it back on a runqueue.
- *
- * Atomic against schedule() which would dequeue a task, also see
- * set_current_state().
- *
- * Return: %true if @p->state changes (an actual wakeup was done),
- *	   %false otherwise.
- */
-static int
-wake_up_thread_internal(struct task_struct *p, unsigned int state, int wake_flags)
-{
-	//unsigned long flags;
-	//int cpu = 0;
-	int success = 0;
-#if 0
-	/*
-	 * If we are going to wake up a thread waiting for CONDITION we
-	 * need to ensure that CONDITION=1 done by the caller can not be
-	 * reordered with p->state check below. This pairs with mb() in
-	 * set_current_state() the waiting thread does.
-	 */
-	raw_spin_lock_irqsave(&p->pi_lock, flags);
-	smp_mb__after_spinlock();
-	if (!(p->state & state))
-		goto out;
-
-	trace_sched_waking(p);
-
-	/* We're going to change ->state: */
-	success = 1;
-	cpu = task_cpu(p);
-
-	/*
-	 * Ensure we load p->on_rq _after_ p->state, otherwise it would
-	 * be possible to, falsely, observe p->on_rq == 0 and get stuck
-	 * in smp_cond_load_acquire() below.
-	 *
-	 * sched_ttwu_pending()                 try_to_wake_up()
-	 *   [S] p->on_rq = 1;                  [L] P->state
-	 *       UNLOCK rq->lock  -----.
-	 *                              \
-	 *				 +---   RMB
-	 * schedule()                   /
-	 *       LOCK rq->lock    -----'
-	 *       UNLOCK rq->lock
-	 *
-	 * [task p]
-	 *   [S] p->state = UNINTERRUPTIBLE     [L] p->on_rq
-	 *
-	 * Pairs with the UNLOCK+LOCK on rq->lock from the
-	 * last wakeup of our task and the schedule that got our task
-	 * current.
-	 */
-	smp_rmb();
-	if (p->on_rq && ttwu_remote(p, wake_flags))
-		goto stat;
-
-#ifdef CONFIG_SMP
-	/*
-	 * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be
-	 * possible to, falsely, observe p->on_cpu == 0.
-	 *
-	 * One must be running (->on_cpu == 1) in order to remove oneself
-	 * from the runqueue.
-	 *
-	 *  [S] ->on_cpu = 1;	[L] ->on_rq
-	 *      UNLOCK rq->lock
-	 *			RMB
-	 *      LOCK   rq->lock
-	 *  [S] ->on_rq = 0;    [L] ->on_cpu
-	 *
-	 * Pairs with the full barrier implied in the UNLOCK+LOCK on rq->lock
-	 * from the consecutive calls to schedule(); the first switching to our
-	 * task, the second putting it to sleep.
-	 */
-	smp_rmb();
-
-	/*
-	 * If the owning (remote) CPU is still in the middle of schedule() with
-	 * this task as prev, wait until its done referencing the task.
-	 *
-	 * Pairs with the smp_store_release() in finish_task().
-	 *
-	 * This ensures that tasks getting woken will be fully ordered against
-	 * their previous state and preserve Program Order.
-	 */
-	smp_cond_load_acquire(&p->on_cpu, !VAL);
-
-	p->sched_contributes_to_load = !!task_contributes_to_load(p);
-	p->state = TASK_WAKING;
-
-	if (p->in_iowait) {
-		delayacct_blkio_end(p);
-		atomic_dec(&task_rq(p)->nr_iowait);
-	}
-
-	cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags);
-	if (task_cpu(p) != cpu) {
-		wake_flags |= WF_MIGRATED;
-		set_task_cpu(p, cpu);
-	}
-
-#else /* CONFIG_SMP */
-
-	if (p->in_iowait) {
-		delayacct_blkio_end(p);
-		atomic_dec(&task_rq(p)->nr_iowait);
-	}
-
-#endif /* CONFIG_SMP */
-
-	ttwu_queue(p, cpu, wake_flags);
-stat:
-	ttwu_stat(p, cpu, wake_flags);
-out:
-	raw_spin_unlock_irqrestore(&p->pi_lock, flags);
-#endif
-	return success;
-}
-
-/**
- * wake_up_process - Wake up a specific process
- * @p: The process to be woken up.
- *
- * Attempt to wake up the nominated process and move it to the set of runnable
- * processes.
- *
- * Return: 1 if the process was woken up, 0 if it was already running.
- *
- * It may be assumed that this function implies a write memory barrier before
- * changing the task state if and only if any tasks are woken up.
- */
-/* Used in tsk->state: */
-
-int wake_up_thread(struct task_struct *p)
-{
-	return wake_up_thread_internal(p, 0xdead, 0);
-}
-EXPORT_SYMBOL(wake_up_thread);
-
-
-/**
- *
  * @brief create a new kernel thread
  *
  * @param thread_fn the function to run in the thread
@@ -859,27 +412,6 @@ EXPORT_SYMBOL(wake_up_thread);
  * @param name_fmt a printf format string name for the thread
  *
  * @param ... parameters to the format string
- *
- * Create a named kernel thread. The thread will be initially stopped.
- * Use wake_up_thread to activate it.
- *
- * If cpu is set to KTHREAD_CPU_AFFINITY_NONE, the thread will be affine to all
- * CPUs. IF the selected CPU index excceds the number of available CPUS, it
- * will default to KTHREAD_CPU_AFFINITY_NONE, otherwise the thread will be
- * bound to that CPU
- *
- * The new thread has SCHED_NORMAL policy.
- *
- * If thread is going to be bound on a particular cpu, give its node
- * in @node, to get NUMA affinity for kthread stack, or else give NUMA_NO_NODE.
- * When woken, the thread will run @threadfn() with @data as its
- * argument. @threadfn() can either call do_exit() directly if it is a
- * standalone thread for which no one will call kthread_stop(), or
- * return when 'kthread_should_stop()' is true (which means
- * kthread_stop() has been called).  The return value should be zero
- * or a negative error number; it will be passed to kthread_stop().
- *
- * Returns a task_struct or ERR_PTR(-ENOMEM) or ERR_PTR(-EINTR).
  */
 
 struct task_struct *kthread_create(int (*thread_fn)(void *data),
diff --git a/kernel/sched/edf.c b/kernel/sched/edf.c
new file mode 100644
index 0000000000000000000000000000000000000000..e19040f84fd9b5d8fd19d8baa3fc667b0fda1157
--- /dev/null
+++ b/kernel/sched/edf.c
@@ -0,0 +1,703 @@
+/**
+ * @file kernel/sched/edf.c
+ */
+
+
+#include <kernel/kthread.h>
+#include <kernel/export.h>
+#include <kernel/kmem.h>
+#include <kernel/err.h>
+#include <kernel/printk.h>
+
+#include <asm-generic/irqflags.h>
+#include <asm-generic/spinlock.h>
+
+
+#include <asm/switch_to.h>
+
+#include <kernel/string.h>
+
+#include <kernel/tick.h>
+
+
+
+void sched_print_edf_list_internal(ktime now)
+{
+//	ktime now;
+	char state = 'U';
+	int64_t rel_deadline;
+	int64_t rel_wait;
+
+	struct task_struct *tsk;
+	struct task_struct *tmp;
+
+
+//	now = ktime_get();
+	ktime prev = 0;
+	ktime prevd = 0;
+
+	printk("\nt: %lld\n", ktime_to_us(now));
+	printk("S\tDeadline\tWakeup\tdelta W\tdelta P\tt_rem\ttotal\tslices\tName\t\tfirstwake, firstdead, execstart\n");
+	printk("----------------------------------------------\n");
+	list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
+
+		if (tsk->policy == SCHED_RR)
+			continue;
+
+		rel_deadline = ktime_delta(tsk->deadline, now);
+		rel_wait     = ktime_delta(tsk->wakeup,   now);
+		if (rel_wait < 0)
+			rel_wait = 0; /* running */
+
+		if (tsk->state == TASK_IDLE)
+			state = 'I';
+		if (tsk->state == TASK_RUN)
+			state = 'R';
+
+		printk("%c\t%lld\t\t%lld\t%lld\t%lld\t%lld\t%lld\t%d\t%s %lld | %lld %lld %lld %lld\n",
+		       state, ktime_to_us(tsk->deadline), ktime_to_us(tsk->wakeup),
+		       ktime_to_us(rel_wait), ktime_to_us(rel_deadline), ktime_to_us(tsk->runtime), ktime_to_us(tsk->total),
+		       tsk->slices, tsk->name, ktime_us_delta(prev, tsk->wakeup), ktime_us_delta(prevd, tsk->deadline),
+		       ktime_to_us(tsk->first_wake),
+		       ktime_to_us(tsk->first_dead),
+		       ktime_to_us(tsk->exec_start));
+		prev = tsk->wakeup;
+		prevd = tsk->deadline;
+	}
+}
+
+void sched_print_edf_list(void)
+{
+	printk("avg: %lld\n", ktime_to_us(total/times));
+}
+
+/**
+ * Our EDF task scheduling timeline:
+ *
+ *
+ *
+ *  wakeup/
+ *  activation
+ *   |                      absolute
+ *   |                      deadline
+ *   |  start                  |
+ *   |  time                   |               next
+ *   |   |                     |              wakeup
+ *   |   | computation|        |                |
+ *   |   |    time    |        |                |
+ *   |   |############|        |                |
+ *   +-----+-------------------+-----------------
+ *         |------ WCET -------|
+ *         ^- latest start time
+ *   |--- relative deadline ---|
+ *   |---------------- period ------------------|
+ */
+
+
+/**
+ * @brief check if an EDF task can still execute given its deadline
+ *
+ * @note effectively checks
+ *	 wcet         remaining runtime in slot
+ *	------   <   --------------------------
+ *	period        remaining time to deadline
+ *
+ * @returns true if can still execute before deadline
+ */
+
+static inline bool schedule_edf_can_execute(struct task_struct *tsk, ktime now)
+{
+	int64_t to_deadline;
+
+
+
+
+	if (tsk->runtime <= 0)
+		return false;
+
+	if (ktime_before(tsk->deadline, now))  {
+		printk("%s violated, %lld %lld, %lld %lld\n", tsk->name,
+		       tsk->runtime, ktime_us_delta(tsk->deadline, now),
+		       tsk->deadline, now);
+		sched_print_edf_list_internal(now);
+		BUG();
+		return false;
+	}
+
+	to_deadline = ktime_delta(tsk->deadline, now);
+
+	if (to_deadline <= 0)
+		return false;
+
+
+
+	if (tsk->wcet * to_deadline < tsk->period * tsk->runtime)
+		return true;
+
+
+
+
+
+	return false;
+}
+
+
+static inline void schedule_edf_reinit_task(struct task_struct *tsk, ktime now)
+{
+	tsk->state = TASK_IDLE;
+
+	tsk->wakeup = ktime_add(tsk->wakeup, tsk->period);
+#if 0
+	if (ktime_after(now, tsk->wakeup))
+		printk("%s delta %lld\n",tsk->name, ktime_us_delta(tsk->wakeup, now));
+
+	BUG_ON(ktime_after(now, tsk->wakeup)); /* deadline missed earlier? */
+#endif
+	tsk->deadline = ktime_add(tsk->wakeup, tsk->deadline_rel);
+
+	tsk->runtime = tsk->wcet;
+}
+
+
+#define SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE 10000000LL
+/* stupidly sort EDFs */
+static int64_t schedule_edf(ktime now)
+{
+//	ktime now;
+
+	int64_t delta;
+
+	int64_t slot = SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE;
+
+	struct task_struct *tsk;
+	struct task_struct *tmp;
+	ktime wake;
+
+
+
+	list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
+
+		if (tsk->policy != SCHED_EDF)
+			continue;
+
+		/* time to wake up yet? */
+		delta = ktime_delta(tsk->wakeup, now);
+		if (delta >= 0) {
+			/* nope, just update minimum runtime for this slot */
+			if (delta < slot)
+				slot = delta;
+
+			continue;
+		}
+
+		/* if it's already running, see if there is time remaining */
+		if (tsk->state == TASK_RUN) {
+			if (!schedule_edf_can_execute(tsk, now)) {
+				schedule_edf_reinit_task(tsk, now);
+				/* nope, update minimum runtime for this slot */
+				delta = ktime_delta(tsk->wakeup, now);
+				if (delta < slot)
+					slot = delta;
+				continue;
+			}
+
+			/* move to top */
+			list_move(&tsk->node, &_kthreads.run);
+			continue;
+		}
+
+		/* time to wake up */
+		if (tsk->state == TASK_IDLE) {
+			tsk->state = TASK_RUN;
+			/* move to top */
+			list_move(&tsk->node, &_kthreads.run);
+		}
+
+	}
+
+	/* now find the closest relative deadline */
+
+	wake = ktime_add(now, slot);
+	list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
+
+		if (tsk->policy != SCHED_EDF)
+			break;
+
+		/* all currently runnable task are at the top of the list */
+		if (tsk->state != TASK_RUN)
+			break;
+
+		if (ktime_before(wake, tsk->deadline))
+			continue;
+
+		delta = ktime_delta(wake, tsk->deadline);
+
+		if (delta < 0) {
+			delta = ktime_delta(now, tsk->deadline);
+			printk("\n [%lld] %s deadline violated by %lld us\n", ktime_to_ms(now), tsk->name, ktime_to_us(delta));
+		}
+
+
+		if (delta < slot) {
+			if (delta)
+				slot = delta;
+			else
+				delta = tsk->runtime;
+			wake = ktime_add(now, slot); /* update next wakeup */
+			/* move to top */
+			list_move(&tsk->node, &_kthreads.run);
+			BUG_ON(slot <= 0);
+		}
+	}
+
+	total = ktime_add(total, ktime_delta(ktime_get(), now));
+	times++;
+
+	//printk("%3.d %3.lld\n", cnt, ktime_to_us(total / times) );
+	BUG_ON(slot < 0);
+
+	return slot;
+}
+
+
+/**
+ *
+ * we allow online task admission, so we need to be able to determine
+ * schedulability on the fly:
+ *
+ * EDF schedulability
+ *
+ *
+ * # comp time
+ * | deadline (== unused slot)
+ * _ unused slot
+ * > wakeup (== deadline if D == P)
+ * o free slots (deadline - wcet)
+ *
+ * simplest case: one long period task, one or more short period tasks
+ *
+ *  W                    D                             W
+ *  >oooooooooo##########|_____________________________> (P=50, D=20, R=10) (T1)
+ *  >o#|_>                                               (P= 4, D= 2, R= 1) (T2)
+ *  >o#>                                                 (P= 2, D= 2, R= 1) (T3)
+ *  >#>                                                  (P= 1, D= 1, R= 1) (T4)
+ *  >ooooooo#####|_______>                               (P=20, D=12, R= 5) (T5)
+ *  >oooooooooooooooooooooooooo####|__>			 (P=33, D=30, R= 4) (T6)
+ *  >oooooooooooooooooooooooooooooooooooooooo######|___> (P=50, D=46, R= 6) (T7)
+ *
+ * If we map the short period task into the long period tasks "free" slots,
+ * we see that tasks with periods shorter than the deadline of the task
+ * of the longest period can only be scheduled, if their utilisation
+ * or "time density" R / D is smaller that the utilisation of the longest
+ * period task
+ *
+ *
+ *  easily schedulable:
+ *   ____________________________________________________________________________________________________
+ *   .... .   .. .........    .   .  .    .   .   .   .....   . ... .......   .   .   .   .   .   .   .
+ *  >o###oooooo#oo####o##|_____________________________###oooooo##oo##o###o|_____________________________
+ *  >#o|_o#|_o#|_#o|_o#|_#o|_o#|_o#|_#o|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_
+ *
+ *
+ *                            R/D                     R/P
+ *  T1: (P=50, D=20, R=10)   10/20 = 1/2        10/50 = 20/100
+ *  T2: (P= 4, D= 2, R= 1)    1/2  = 1/2 100%    1/4  = 25/100 45% (== number of used slots)
+ *
+ *
+ *  correct analysis sum(R_i/P_i)
+ *
+ *  T1 (D-R) / D = 1/2
+ *  T1 (D-R) / P = 1/5
+ *
+ *  T2 (D-R) / P = 1/4	 T1DRD > T2DRP	-> R/P (correct)
+ *
+ *
+ *
+ *  just schedulable:
+ *   ____________________________________________________________________________________________________
+ *   .................... . . . . . . . . . . . . . . ..................... . . . . . . . . . . . . . . .
+ *  >#o#o#o#o#o#o#o#o#o#o|_____________________________#o#o#o#o#o#o#o#o#o#o|_____________________________
+ *  >o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#
+ *
+ *                            R/D                     R/P
+ *  T1: (P=50, D=20, R=10)   10/20 = 1/2        10/50 = 2/10
+ *  T3: (P= 2, D= 2, R= 1)    1/2  = 1/2 100%    1/2  = 5/10  70% (== number of used slots)
+ *
+ *  -> this must be 100%, impossible to fit more slots into relative deadline of
+ *     long task
+ *
+ *  correct analysis sum(R_i/D_i)
+ *
+ *  T1 (D-R) / D = 1/2
+ *  T1 (D-R) / P = 1/5
+ *
+ *  T3 (D-R) / P = 1/2		T1DRD <= T3DRP	-> R/D (correct)
+ *
+ *  not schedulable:
+ *   ____________________________________________________________________________________________________
+ *   ..........::::::::::........................................::::::::::..............................
+ *  >oooooooooo##########|_____________________________oooooooooo##########|_____________________________
+ *  >####################################################################################################
+ *
+ *                            R/D                     R/P
+ *  T1: (P=50, D=20, R=10)   10/20 = 1/2        10/50 = 1/5
+ *  T4: (P= 1, D= 1, R= 1)    1/1  = 1/1 150%    1/1  = 1/1 120%
+ *
+ *  both correct, but R/P "more correct" -> actual slot usage
+ *
+ *  T1 (D-R) / D = 1/2
+ *  T1 (D-R) / P = 1/5
+ *
+ *  T4 (D-R) / P = 0		T1DRD > T4DRD	-> R/P	(correct)
+ *
+ *
+ *  schedulable:
+ *
+ *   ____________________________________________________________________________________________________
+ *   .................................................................................................xxx
+ *  >o###oooooo#oo###o###|_____________________________##o###o#ooooooo###o#|_____________________________
+ *  >#o|_#o|_o#|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_
+ *  >ooooo####oo#|_______o###oooooo##|_______o#ooo###o#oo|_______o###oooooo##|_______o###oooooo##|_______
+ *  >ooooooooooooooooooooooooo###o#|__ooooooooo##ooppoooooooooo##ooo|__ooooooooooooooooooo###o#oooooo|__x
+ *  >ooooooooooooooooooooooooooooooooo###o###oooooo|___ooooooooooooooooooooooo###o###ooooooooooooo###|___
+ *
+ *                            R/D            R/P
+ *  T1: (P=50, D=20, R=10)   10/20   50%    10/50  20%
+ *  T2: (P= 4, D= 2, R= 1)    1/2   100%     1/4   45%
+ *  T5: (P=20, D=12, R= 5)    5/12  142%     5/20  70%
+ *  T6: (P=33, D=30, R= 4)    4/30  155%     4/33  82%
+ *  T7: (P=50, D=46, R= 6)    6/46  168%     6/50  94%
+ *
+ *
+ *
+ *  sum(R_i/P_i) correct, sum(R_i/D_i) absolutely incorrect!
+ *
+ *  thread(p_max):
+ *  T1 (D-R) / D = 1/2
+ *  T1 (D-R) / P = 1/5
+ *  ------------------
+ *  T2 (D-R) / P = 1/4			T1DRD > T2DRP -> R/P (correct)
+ *  T5 (D-R) / P = 7/20			T1DRD > T5DRP -> R/P (correct)
+ *  T6 (D-R) / P = 26/33		T1RD <= T6DRP -> R/D (correct? looks ok)
+ *  T7 (D-R) / P = 40/50		T1RD <= T6DRP -> R/D (correct? looks ok)
+ *
+ *  usage: 96.4%
+ *
+ *
+ *
+ *
+ *
+ * try 1:
+ *
+ *  T1: (P=50, D=20, R=10) (20%) T1DRP = 0.2 (0.95)
+ *  TX: (P=10, D= 8, R=6) -> (D-R)/P = 0.2  T1DRD > T2DRP -> R/P (incorrect, should be R/D at least) (0.75)
+ *  ................::..
+ * >##oooooo####oooo####|_____________________________
+ * >oo######|_oo######|_
+ *
+ * 22/20 slots used = 110%
+ *
+ * free T1 slots before deadline:	D-R = 10
+ *
+ * TX runtime slots cannot be larger than that!
+ *
+ * TX runtime slots for T1 deadline periods:
+ *
+ *
+ *	(D_x - R_x) / D_x * D_1 = 12.5  < 10 -> not schedulable
+ *
+ *	sum((D_i - R_i) / D_i) * D_1 < 10 -> schedulable?
+ *
+ *
+ *
+ *	i != D_1 && P_i < D_1
+ *		sum((D_1 / P_i) * R_i) < (D_1 - R_1) ?
+ *
+ *	i != D1 && P_i >
+ *
+ *	(T1: 4 < 10 ok)
+ *
+ *	T2: 5
+ *	T5: 5
+ *	T6  2.42
+ *
+ *
+ *
+ *
+ * new test:
+ *
+ * if (P_x < D_1) :
+ *	 if ((R_x - D_x) > 0) // otherwise we are at 100% slot usage within deadline
+ *		(D_x - R_x) / D_x * (D_1 - R_1) = 12.5 > (D_1 - R_1) -> not schedulable
+ *	 else ?
+ *		R_x / P_x * D_1 < (D_1 - R_1)
+ *
+ * (schedulable):
+ *   ____________________________________________________________________________________________________
+ *   .................................................................................................xxx
+ *  >o###oooooo#oo###o###|_____________________________##o###o#ooooooo###o#|_____________________________
+ *  >#o|_#o|_o#|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_
+ *  >ooooo####oo#|_______o###oooooo##|_______o#ooo###o#oo|_______o###oooooo##|_______o###oooooo##|_______
+ *  >ooooooooooooooooooooooooo###o#|__ooooooooo##ooppoooooooooo##ooo|__ooooooooooooooooooo###o#oooooo|__x
+ *  >ooooooooooooooooooooooooooooooooo###o###oooooo|___ooooooooooooooooooooooo###o###oooooooooooooooo|___
+ *
+ *
+ *  T1: (P=50, D=20, R=10) -> max P -> D_1 = 20, D_1 - R_1 = 10 = F_1
+ *
+ *  T2: (P= 4, D= 2, R= 1)  F2 = 1   F2D = 1/2
+ *  T5: (P=20, D=12, R= 5)  F5 = 7   F5D = 7/12
+ *  T6: (P=33, D=30, R= 4)  F6 = 26  F6D = 26/30
+ *  T7: (P=50, D=46, R= 6)  F7 = 40  F7D = 40/46
+ *
+ *
+ * Utilisation:	U1 = D_1 - R_1 = 10;	U2 = P_1 - D_1 = 30
+ *
+ * check T2:
+ *	f2 > 0 ->  f2d * F1 = 5 <= U1 -> schedulable
+ *		   f2d * U2 = 10
+ *		-> U1 = 5, U2 = 20
+ *
+ * check t5:
+ *	f5 > 0 -> int(f5d * F1) = 5;	5 <= U1 -> schedulable
+ *		   f5d * U2 = int(11) ->
+ *		   U1 = 0, U2 = 9
+ *
+ *
+ * 1) determine task with longest period
+ *
+ *	T1: (P=50, D=20, R=10)
+ *
+ * 2) calculate unused head and tail (before and after deadline)
+ *
+ *	UH = D1 - R1				(= 20) (Hyperperiod)
+ *	UT = P1 - D1				(= 60) 
+ *
+ * 3) loop over other tasks (Period < Deadline of Task 1)
+ *
+ *	calculate slots usage before deadline of Task 1:
+ *
+ *	H * Ri * D1 / Pi		(T2: 10, T5: 10)
+ *
+ *	update head slots UH = UH - 20 = 0 -> all used
+ *
+ *
+ *	calculate slot usage after deadline of Task2:
+ *
+ *	H * Ri * F1 / Pi		(T2: 15, T5: 15)
+ *
+ *	update tail slots: UT = UT - 30 = 30
+ *
+ *	-> need hyperperiod factor H = 2
+ *
+ *
+ *
+ *	if (DEADLINE >
+ *   ____________________________________________________________________________________________________
+ *   .........................   . ............  ..............  .........................   . ...   .
+ *  >o###oooooo#oo###o###|_____________________________##o###o#ooooooo###o#|_____________________________
+ *  >#o|_#o|_o#|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_
+ *  >ooooo####oo#|_______o###oooooo##|_______o#ooo###o#oo|_______o###oooooo##|_______o###oooooo##|_______
+ *  >ooooooooooooooooooooooooooooooooo###o###oooooo|___ooooooooooooooooooooooo###o###oooooooooooooooo|___
+ *
+ *
+ *
+ */
+
+static ktime hyperperiod(void)
+{
+	ktime lcm = 0;
+
+	ktime a,b;
+
+	struct task_struct *t0;
+	struct task_struct *tsk;
+	struct task_struct *tmp;
+
+
+	if (list_empty(&_kthreads.new))
+	    return 0;
+
+	t0 = list_entry(_kthreads.new.next, struct task_struct, node);
+
+	lcm = t0->period;
+
+	list_for_each_entry_safe(tsk, tmp, &_kthreads.new, node) {
+
+		if (tsk == t0)
+			continue;
+
+		a = lcm;
+		b = tsk->period;
+
+		/* already a multiple? */
+		if (a % b == 0)
+			continue;
+
+		while (a != b) {
+			if (a > b)
+				a -= b;
+			else
+				b -= a;
+		}
+
+		lcm = lcm * (tsk->period / a);
+	}
+
+	return lcm;
+}
+
+#define MIN(A,B)	((A) < (B) ? (A) : (B))
+
+void kthread_set_sched_edf(struct task_struct *task, unsigned long period_us,
+			  unsigned long wcet_us, unsigned long deadline_rel_us)
+{
+	/* XXX schedulability tests */
+
+	if (wcet_us >= period_us) {
+		printk("Cannot schedule EDF task with WCET %u >= PERIOD %u !\n", wcet_us, period_us);
+		return;
+	}
+
+	if (wcet_us >= deadline_rel_us) {
+		printk("Cannot schedule EDF task with WCET %u >= DEADLINE %u !\n", wcet_us, deadline_rel_us);
+		return;
+	}
+
+	if (deadline_rel_us >= period_us) {
+		printk("Cannot schedule EDF task with DEADLINE %u >= PERIOD %u !\n", deadline_rel_us, period_us);
+		return;
+	}
+
+
+	arch_local_irq_disable();
+	task->period   = us_to_ktime(period_us);
+	task->wcet     = us_to_ktime(wcet_us);
+	//task->runtime  = ktime_sub(task->wcet, 7000LL);
+	task->runtime  = task->wcet;
+	task->deadline_rel = us_to_ktime(deadline_rel_us);
+	arch_local_irq_enable();
+
+
+	{
+		ktime p = hyperperiod();
+		ktime h ;
+		ktime max = 0;
+
+		ktime uh, ut, f1;
+
+		struct task_struct *t0 = NULL;
+		struct task_struct *tsk = NULL;
+		struct task_struct *tmp;
+
+		if (p < 0)
+			printk("appears to be empty\n");
+
+		list_for_each_entry_safe(tsk, tmp, &_kthreads.new, node) {
+
+			if (tsk->period > max) {
+				t0 = tsk;
+				max = tsk->period;
+			}
+		}
+
+		BUG_ON(!t0);
+
+		BUG_ON(p < t0->period);
+		h = p / t0->period;
+
+//		printk("Period factor %lld %lld %lld\n", h, p, t0->period);
+
+
+
+		uh = h * (t0->deadline_rel - t0->wcet);
+		ut = h * (t0->period - t0->deadline_rel);
+		f1 = ut/h;
+
+
+		printk("max UH: %lld, UT: %lld\n", (uh), (ut));
+
+
+		list_for_each_entry_safe(tsk, tmp, &_kthreads.new, node) {
+			ktime sh, st;
+
+			if (tsk == t0)
+				continue;
+
+
+			if (tsk->deadline_rel < t0->deadline_rel) {
+
+				/* slots before deadline of  T0 */
+				sh = h * tsk->wcet * t0->deadline_rel / tsk->period;
+
+				if (sh > uh) {
+					printk("NOT SCHEDULABLE in head: %s\n", tsk->name);
+					BUG();
+				}
+				uh = uh - sh;
+
+			}
+
+			/* slots after deadline of T0 */
+			st = h * tsk->wcet * f1 / tsk->period;
+			printk("%s tail usage: %lld\n", tsk->name, ktime_to_ms(st));
+			if (st > ut) {
+				printk("NOT SCHEDULABLE in tail: %s\n", tsk->name);
+				BUG();
+			}
+			ut = ut - st;
+
+
+			printk("UH: %lld, UT: %lld\n", (uh),(ut));
+
+
+		}
+
+
+	}
+
+
+
+
+	{
+		double u = 0.0;	/* utilisation */
+
+		struct task_struct *tsk;
+		struct task_struct *tmp;
+
+		static int64_t dmin = 0x7fffffffffffffLL;
+
+
+		if (dmin > task->deadline_rel)
+			dmin = task->deadline_rel;
+
+
+		u += (double) (int32_t) task->wcet / (double) (int32_t) task->period;
+
+
+		list_for_each_entry_safe(tsk, tmp, &_kthreads.new, node) {
+
+			if (tsk->policy != SCHED_EDF)
+				continue;
+
+			u += (double) (int32_t) tsk->wcet / (double) (int32_t) tsk->period;
+		}
+
+		if (u > 1.0) {
+			printk("I am NOT schedul-ableh: %g ", u);
+			kthread_set_sched_policy(task, SCHED_RR);
+			printk("changed task mode to RR\n", u);
+		} else {
+			printk("Utilisation %g\n", u);
+			kthread_set_sched_policy(task, SCHED_EDF);
+		}
+	}
+
+
+
+//	arch_local_irq_enable();
+
+
+	printk("\n");
+
+}
+