diff --git a/include/kernel/kthread.h b/include/kernel/kthread.h
index 77e36bf01eeec16874e3bf4c8df92fd985369138..81e4cbb2a90f1d8c086142c5caf0c73ae9ac3aa5 100644
--- a/include/kernel/kthread.h
+++ b/include/kernel/kthread.h
@@ -10,6 +10,7 @@
 #include <stdarg.h>
 #include <list.h>
 #include <asm-generic/thread.h>
+#include <kernel/time.h>
 
 
 #define KTHREAD_CPU_AFFINITY_NONE	(-1)
@@ -18,12 +19,20 @@
 
 /* task states */
 
-#define TASK_RUNNING	0xcafe
-#define TASK_PARKED	0x0001
+#define TASK_RUN	0x0000
+#define TASK_IDLE	0x0001
 #define TASK_NEW	0x0002
 #define TASK_DEAD	0x0004
 
 
+enum sched_policy {
+	SCHED_RR,
+	SCHED_EDF,
+	SCHED_FIFO,
+	SCHED_OTHER,
+};
+
+
 struct task_struct {
 
 	struct thread_info thread_info;
@@ -37,8 +46,9 @@ struct task_struct {
 	void				*stack_bottom;
 
 	int				on_cpu;
-	int (*thread_fn)(void *data);
-	void *data;
+	int				(*thread_fn)(void *data);
+	void				*data;
+	char				*name;
 
 
 	/* XXX
@@ -48,6 +58,18 @@ struct task_struct {
 	 */
 	unsigned long stack_canary;
 
+	enum sched_policy		policy;
+	unsigned long			priority;
+	ktime				period; /* wakeup period */
+	ktime				wcet; /* max runtime per period*/
+	ktime				deadline_rel; /* time to deadline from begin of wakeup*/
+
+	ktime				runtime; /* remaining runtime in this period  */
+	ktime				wakeup; /* start of next period */
+	ktime				deadline; /* deadline of current period */
+
+	ktime				exec_start;
+
 
 	/* Tasks may have a parent and any number of siblings or children.
 	 * If the parent is killed or terminated, so are all siblings and
@@ -72,7 +94,11 @@ void kthread_wake_up(struct task_struct *task);
 /* XXX dummy */
 void switch_to(struct task_struct *next);
 void schedule(void);
+void sched_yield(void);
 
+void sched_print_edf_list(void);
 
+void kthread_set_sched_edf(struct task_struct *task, unsigned long period_us,
+			  unsigned long wcet_us, unsigned long deadline_rel_us);
 
 #endif /* _KERNEL_KTHREAD_H_ */
diff --git a/init/main.c b/init/main.c
index a3985180bbff8e9c31d1ee535f0c64049cfefaa8..a212233933d4ff8e8e94044991485ffd35073352 100644
--- a/init/main.c
+++ b/init/main.c
@@ -73,7 +73,7 @@ static void twiddle(void)
 
 #define TREADY 4
 
-#if 1
+#if 0
 static volatile int *console = (int *)0x80100100;
 #else
 static volatile int *console = (int *)0x80000100;
@@ -94,6 +94,85 @@ static int putchar(int 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();
+	}
+}
+
+int edf2(void *data)
+{
+	while (1)
+		putchar( *((char *) data) );
+}
+
+
+int edf3(void *data)
+{
+	while (1) {
+		putchar( *((char *) data) );
+		putchar( *((char *) data) );
+		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)
@@ -114,7 +193,7 @@ int threadx(void *data)
 		if (b > (int) c * (int)c)
 			break;
 #endif
-	//	schedule();
+	//	schedule();putchar( *((char *) data) );
 		//twiddle();
 		//cpu_relax();
 	}
@@ -127,10 +206,6 @@ int threadx(void *data)
 
 static int kernel_init(void)
 {
-	/* registered initcalls are executed by the libgloss boot code at this
-	 * time no need to do anything here at the moment.
-	 */
-
 	setup_arch();
 
 	/* free_bootmem() */
@@ -141,28 +216,12 @@ static int kernel_init(void)
 arch_initcall(kernel_init);
 
 
-#include <kernel/clockevent.h>
-void clk_event_handler(struct clock_event_device *ce)
-{
-
-	struct timespec expires;
-	struct timespec now;
-
-//	printk("DIIIING-DOOONG\n");
-	get_ktime(&now);
-
-	expires = now;
-
-	expires.tv_sec += 1;
-
-	clockevents_program_event(&clk_event_handler, expires, now, CLOCK_EVT_MODE_ONESHOT);
-}
-
 
 /**
- * @brief kernel main function
+ * @brief kernel main functionputchar( *((char *) data) );
  */
-#define MAX_TASKS 800
+#define MAX_TASKS 0
+#include <kernel/clockevent.h>
 int kernel_main(void)
 {
 	struct task_struct *tasks[MAX_TASKS];
@@ -221,23 +280,111 @@ int kernel_main(void)
 
 
 
+	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 timespec expires;
-	struct timespec now;
-	get_ktime(&now);
+	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);
 
-	expires = now;
-	expires.tv_nsec += 18000;
+	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);
 
-	BUG_ON(clockevents_program_event(NULL, expires, now, CLOCK_EVT_MODE_PERIODIC));
+	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
 
 
-	kernel = kthread_init_main();
+#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
+
+
+
+
+
+
+
+
+	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[] = {':', '/', '\\', '~', '|'};
@@ -253,7 +400,7 @@ int kernel_main(void)
 		char *buf = NULL;
 		int i;
 		struct timespec ts;
-		get_uptime(&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);
 
 
@@ -276,7 +423,7 @@ int kernel_main(void)
 		int i;
 
 		struct timespec ts;
-		get_uptime(&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);
 
@@ -284,7 +431,7 @@ int kernel_main(void)
 			kthread_wake_up(tasks[i]);
 
 		arch_local_irq_disable();
-		get_uptime(&ts);
+		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();
 	}
diff --git a/kernel/kthread.c b/kernel/kthread.c
index e4d39d2b44fd6c38b5f392f6d2e554c82d4c2df4..cf18fe14d0b0635993b8980f2f2a5e5493f15616 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -9,11 +9,16 @@
 #include <kernel/err.h>
 #include <kernel/printk.h>
 
-#include <asm/spinlock.h>
+#include <asm-generic/irqflags.h>
+#include <asm-generic/spinlock.h>
+
+
 #include <asm/switch_to.h>
-#include <asm/irqflags.h>
 
-#include <string.h>
+#include <kernel/string.h>
+
+#include <kernel/tick.h>
+
 
 
 #define MSG "KTHREAD: "
@@ -22,10 +27,12 @@
 static struct {
 	struct list_head new;
 	struct list_head run;
+	struct list_head idle;
 	struct list_head dead;
 } _kthreads = {
 	.new  = LIST_HEAD_INIT(_kthreads.new),
 	.run  = LIST_HEAD_INIT(_kthreads.run),
+	.idle = LIST_HEAD_INIT(_kthreads.idle),
 	.dead = LIST_HEAD_INIT(_kthreads.dead)
 };
 
@@ -73,50 +80,355 @@ void kthread_cleanup_dead(void)
 	list_for_each_entry_safe(p_elem, p_tmp, &_kthreads.dead, node) {
 		list_del(&p_elem->node);
 		kfree(p_elem->stack);
+		kfree(p_elem->name);
 		kfree(p_elem);
 	}
 }
 
 
+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)
+{
+	tsk->state = TASK_IDLE;
+
+	tsk->wakeup = ktime_add(tsk->wakeup, tsk->period);
+//	BUG_ON(ktime_after(tsk->wakeup, now)); /* deadline missed earlier? */
+
+	tsk->deadline = ktime_add(tsk->wakeup, tsk->deadline_rel);
+
+	tsk->runtime = tsk->wcet;
+}
+
+
+#define SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE 3000000000UL
+/* 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;
+
+//	now = ktime_get();
+
+//	printk("vvvv\n");
+	list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
+
+		if (tsk->policy != SCHED_EDF)
+			continue;
+
+	//	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 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;
+		}
+
+		/* time to wake up */
+		if (tsk->state == TASK_IDLE) {
+			tsk->state = TASK_RUN;
+			/* move to top */
+			list_move(&tsk->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);
+		}
+	}
+
+//	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();
+}
+
 
 
 void schedule(void)
 {
 	struct task_struct *next;
+	struct task_struct *current;
+	int64_t slot_ns;
+	ktime now = ktime_get();
 
 
 	if (list_empty(&_kthreads.run))
-	    return;
+		return;
 
 
 
+	/* XXX: dummy; need solution for sched_yield() so timer is
+	 * disabled either via disable_tick or need_resched variable
+	 * (in thread structure maybe?)
+	 * If we don't do this here, the timer may fire while interrupts
+	 * are disabled, which may land us here yet again
+	 */
+
 
 	arch_local_irq_disable();
 
 	kthread_lock();
-	kthread_cleanup_dead();
+	tick_set_next_ns(1e9);
 
 
 
-	/* round robin */
+	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;
+	}
+
+
+	/** XXX not here, add cleanup thread */
+	kthread_cleanup_dead();
+
+#if 1
+	{
+		static int init;
+		if (!init) { /* dummy switch */
+			tick_set_mode(TICK_MODE_ONESHOT);
+			init = 1;
+		}
+	}
+#endif
+	slot_ns = schedule_edf(now);
+
+	/* 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();
 
-		if (next->state == TASK_RUNNING) {
+		if (next->state == TASK_RUN) {
 			list_move_tail(&next->node, &_kthreads.run);
 			break;
 		}
+		if (next->state == TASK_IDLE) {
+			list_move_tail(&next->node, &_kthreads.run);
+			continue;
+		}
 
-		list_move_tail(&next->node, &_kthreads.dead);
+		if (next->state == TASK_DEAD)
+			list_move_tail(&next->node, &_kthreads.dead);
 
 	} while (!list_empty(&_kthreads.run));
 
-	kthread_unlock();
 
+	if (next->policy == SCHED_EDF) {
+		if (next->runtime <= slot_ns) {
+			slot_ns = next->runtime; /* XXX must track actual time because of IRQs */
+			next->runtime = 0;
+		}
+	}
+
+	next->exec_start = now;
 
+	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));
+	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);
@@ -125,16 +437,150 @@ void schedule(void)
 }
 
 
+static void kthread_set_sched_policy(struct task_struct *task,
+				     enum sched_policy policy)
+{
+	arch_local_irq_disable();
+	kthread_lock();
+	task->policy = policy;
+	kthread_unlock();
+	arch_local_irq_enable();
+}
+
+
+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);
+//	printk("wake thread %p\n", task->stack_top);
 	arch_local_irq_disable();
 	kthread_lock();
-	task->state = TASK_RUNNING;
+
+	/* 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);
+
 	kthread_unlock();
 	arch_local_irq_enable();
+
+	schedule();
 }
 
 
@@ -148,9 +594,14 @@ struct task_struct *kthread_init_main(void)
 	if (!task)
 		return ERR_PTR(-ENOMEM);
 
+	/* XXX accessors */
+	task->policy = SCHED_RR; /* default */
 
 	arch_promote_to_task(task);
 
+	task->name = "KERNEL";
+	task->policy = SCHED_RR;
+
 	arch_local_irq_disable();
 	kthread_lock();
 
@@ -158,7 +609,8 @@ struct task_struct *kthread_init_main(void)
 	/*** XXX dummy **/
 	current_set[0] = &kernel->thread_info;
 
-	task->state = TASK_RUNNING;
+
+	task->state = TASK_RUN;
 	list_add_tail(&task->node, &_kthreads.run);
 
 
@@ -188,7 +640,9 @@ static struct task_struct *kthread_create_internal(int (*thread_fn)(void *data),
 
 	/* XXX: need stack size detection and realloc/migration code */
 
-	task->stack = kmalloc(8192); /* XXX */
+	task->stack = kmalloc(8192 + STACK_ALIGN); /* XXX */
+
+	BUG_ON((int) task->stack > (0x40800000 - 4096 + 1));
 
 	if (!task->stack) {
 		kfree(task);
@@ -197,9 +651,28 @@ static struct task_struct *kthread_create_internal(int (*thread_fn)(void *data),
 
 
 	task->stack_bottom = task->stack; /* XXX */
-	task->stack_top = task->stack + 8192/4; /* XXX need align */
+	task->stack_top = ALIGN_PTR(task->stack, STACK_ALIGN) +8192/4; /* XXX */
+	BUG_ON(task->stack_top > (task->stack + (8192/4 + STACK_ALIGN/4)));
+
+#if 0
+	/* XXX: need wmemset() */
+	memset(task->stack, 0xab, 8192 + STACK_ALIGN);
+#else
+	{
+		int i;
+		for (i = 0; i < (8192 + STACK_ALIGN) / 4; i++)
+			((int *) task->stack)[i] = 0xdeadbeef;
+
+	}
+#endif
+
+	/* dummy */
+	task->name = kmalloc(32);
+	BUG_ON(!task->name);
+	vsnprintf(task->name, 32, namefmt, args);
 
-	memset(task->stack, 0xdeadbeef, 8192);
+	/* XXX accessors */
+	task->policy = SCHED_RR; /* default */
 
 	arch_init_task(task, thread_fn, data);
 
@@ -215,7 +688,7 @@ static struct task_struct *kthread_create_internal(int (*thread_fn)(void *data),
 
 
 	//printk("%s is next at %p stack %p\n", namefmt, &task->thread_info, task->stack);
-	printk("%s\n", namefmt);
+	//printk("%s\n", namefmt);
 
 
 	return task;
@@ -231,7 +704,7 @@ static struct task_struct *kthread_create_internal(int (*thread_fn)(void *data),
  * @state: the mask of task states that can be woken
  * @wake_flags: wake modifier flags (WF_*)
  *
- * If (@state & @p->state) @p->state = TASK_RUNNING.
+ * If (@state & @p->state) @p->state = TASK_RUN.
  *
  * If the task was not queued/runnable, also place it back on a runqueue.
  *
@@ -424,3 +897,6 @@ struct task_struct *kthread_create(int (*thread_fn)(void *data),
 	return task;
 }
 EXPORT_SYMBOL(kthread_create);
+
+
+