diff --git a/arch/sparc/include/asm/switch_to.h b/arch/sparc/include/asm/switch_to.h
index 8058fac6e4e377d719ef3f716c1ec845e2723fca..cb6185c8f5f94e448a8e1d8fecc9a0423c9426eb 100644
--- a/arch/sparc/include/asm/switch_to.h
+++ b/arch/sparc/include/asm/switch_to.h
@@ -187,7 +187,7 @@ __asm__ __volatile__(							\
 	" nop\n\t"						\
 	"here:\n\t"						\
 	:							\
-	: "r" (&(current_set[0])),				\
+	: "r" (&(current_set[leon3_cpuid()])),			\
 	  "r" (&(next->thread_info)),				\
 	  "i" (TI_KSP),						\
 	  "i" (TI_KPC),						\
diff --git a/arch/sparc/kernel/bootmem.c b/arch/sparc/kernel/bootmem.c
index c5f20aca66cbeaad0769da82d042c93963daf145..867373144b05d18185186e1269fd7ddb4ab6ac88 100644
--- a/arch/sparc/kernel/bootmem.c
+++ b/arch/sparc/kernel/bootmem.c
@@ -237,7 +237,7 @@ void bootmem_init(void)
 	BUG_ON(mem_size  > (1UL << MM_BLOCK_ORDER_MAX));
 	BUG_ON(PAGE_SIZE < (1UL << MM_BLOCK_ORDER_MIN));
 
-	BUG_ON(page_map_init(mm_init_page_map, base_pfn, end_pfn, PAGE_SIZE));
+	BUG_ON(page_map_init(mm_init_page_map, start_pfn, end_pfn, PAGE_SIZE));
 
 
 	/* reserve all space up to the end of the image, so mapping starts
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 768586a28c05e16be8a555d2805727d1fb762533..4033c51f1bd6dcf914d08e30dbef642929110d50 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -40,6 +40,13 @@ kernel_entry:
 	 * inserting (3) nops.
 	 */
 
+	/* get our cpu id */
+        rd     %asr17, %g3
+	srl	%g3, 28, %g3
+
+	cmp %g3, %g0
+	bne setup_wim
+	 nop
 
 	/* Clear the .bss section or we'll be in trouble later. This section
 	 * is supposed to be double-word aligned (see kernel.lds.S), so we
@@ -63,7 +70,7 @@ zero_bss:
 	/* Now we initialise the window invalid mask to detect under/overflows.
 	 * We set the highest-value window to be invalid.
 	 */
-
+setup_wim:
         mov     (1 << (NWINDOWS - 1)), %g1
         mov     %g1, %wim	! delayed-write instruction
 
@@ -102,8 +109,17 @@ zero_bss:
 	nop
 	nop
 
+	cmp %g3, %g0
+	bne slavego
+	 nop
+
+
 	call do_basic_setup
 	 nop
 
 	call kernel_main
 	 nop
+
+slavego:
+	call smp_cpu_entry
+	 nop
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index b5e4ea9a45cea04edc26541af2d2a474459edbe1..8a1173585a5dec524eb67b3bb276a60676be965b 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -12,11 +12,11 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * @todo eventually replace catch_interrupt() libgloss/newlib functionality
- *       with local/custom code and rework the globals
  * @todo irq configuration should only be done through a syscall,
  *       so traps are disabled
  *
+ * @todo this needs locking for all resouces shared between CPUs
+ *
  * @brief an IRQ manager that dispatches interrupts to registered
  *	  handler functions
  *
@@ -74,7 +74,6 @@ struct irl_vector_elem {
 #define IRL_QUEUE_SIZE	64
 
 
-
 #ifdef CONFIG_LEON2
 #define IRL_SIZE	LEON2_IRL_SIZE
 #define EIRL_SIZE	LEON2_EIRL_SIZE
@@ -93,6 +92,9 @@ static struct leon3_irqctrl_registermap *leon_irqctrl_regs;
 
 #endif /* CONFIG_LEON3 */
 
+#define CPU_AFFINITY_NONE (-1)
+
+static int irq_cpu_affinity[IRL_SIZE + EIRL_SIZE];
 
 static struct list_head	irl_pool_head;
 static struct list_head	irl_queue_head;
@@ -394,7 +396,7 @@ static void leon_clear_irq(unsigned int irq)
  * @param cpu the cpu for which the interrupt is to be unmasked
  */
 
-static void leon_unmask_irq(unsigned int irq, unsigned int cpu)
+static void leon_unmask_irq(unsigned int irq, int cpu)
 {
 	uint32_t mask;
 
@@ -426,7 +428,7 @@ static void leon_unmask_irq(unsigned int irq, unsigned int cpu)
  * @param cpu the cpu for which the interrupt is to be masked
  */
 
-static void leon_mask_irq(unsigned int irq, unsigned int cpu)
+static void leon_mask_irq(unsigned int irq, int cpu)
 {
 	uint32_t mask;
 
@@ -459,7 +461,7 @@ static void leon_mask_irq(unsigned int irq, unsigned int cpu)
  * @param cpu the cpu for which the interrupt is to be enabled
  */
 
-static void leon_enable_irq(unsigned int irq, unsigned int cpu)
+static void leon_enable_irq(unsigned int irq, int cpu)
 {
 	leon_clear_irq(irq);
 
@@ -474,7 +476,7 @@ static void leon_enable_irq(unsigned int irq, unsigned int cpu)
  * @param cpu the cpu for which the interrupt is to be disabled
  */
 
-static void leon_disable_irq(unsigned int irq, unsigned int cpu)
+static void leon_disable_irq(unsigned int irq, int cpu)
 {
 	leon_clear_irq(irq);
 
@@ -598,7 +600,7 @@ static int leon_eirq_dispatch(unsigned int irq)
 {
 	unsigned int eirq;
 #ifdef CONFIG_LEON3
-	unsigned int cpu;
+	int cpu;
 #endif /* CONFIG_LEON3 */
 
 	struct irl_vector_elem *p_elem;
@@ -682,6 +684,8 @@ int irl_register_handler(unsigned int irq,
 			  irq_handler_t handler,
 			  void *data)
 {
+	int cpu;
+
 	uint32_t psr_flags;
 
 	struct irl_vector_elem *p_elem;
@@ -711,8 +715,16 @@ int irl_register_handler(unsigned int irq,
 	spin_lock_restore_irq(psr_flags);
 
 #ifdef CONFIG_LEON3
-	/* XXX for now, just register to the current CPU */
-	leon_enable_irq(irq, leon3_cpuid());
+	/* XXX for now, just register to the current CPU if no affinity is set */
+	cpu = irq_cpu_affinity[irq];
+
+	if (cpu == CPU_AFFINITY_NONE) {
+		cpu = leon3_cpuid();
+		irq_cpu_affinity[irq] = cpu;
+	}
+
+	leon_enable_irq(irq, cpu);
+
 #endif /* CONFIG_LEON3 */
 #ifdef CONFIG_LEON2
 	leon_enable_irq(irq, 0);
@@ -749,6 +761,8 @@ static int eirl_register_handler(unsigned int irq,
 				 irq_handler_t handler,
 				 void *data)
 {
+	int cpu;
+
 	uint32_t psr_flags;
 
 	struct irl_vector_elem *p_elem;
@@ -781,8 +795,15 @@ static int eirl_register_handler(unsigned int irq,
 
 	spin_lock_restore_irq(psr_flags);
 #ifdef CONFIG_LEON3
-	/* XXX for now, just register to the current CPU */
-	leon_enable_irq(irq, leon3_cpuid());
+	/* XXX for now, just register to the current CPU if no affinity is set */
+	cpu = irq_cpu_affinity[irq];
+
+	if (cpu == CPU_AFFINITY_NONE) {
+		cpu = leon3_cpuid();
+		irq_cpu_affinity[irq] = cpu;
+	}
+
+	leon_enable_irq(irq, cpu);
 #endif /* CONFIG_LEON3 */
 #ifdef CONFIG_LEON2
 	leon_enable_irq(irq, 0);
@@ -954,7 +975,8 @@ static int irq_dispatch_init(void)
 		list_add_tail(&irl_queue_pool[i].handler_node,
 			      &irq_queue_pool_head);
 
-
+	for (i = 0; i < IRL_SIZE + EIRL_SIZE; i++)
+		irq_cpu_affinity[i] = CPU_AFFINITY_NONE;
 
 	return 0;
 }
@@ -1026,8 +1048,9 @@ static void leon_setup_eirq(void)
 #endif /* CONFIG_ARCH_CUSTOM_BOOT_CODE */
 
 #ifdef CONFIG_LEON3
-	/* XXX for now, just register to the current CPU */
-	leon_enable_irq(leon_eirq, leon3_cpuid());
+	/* XXX enable for all cpus in the system */
+	leon_enable_irq(leon_eirq, 0);
+	leon_enable_irq(leon_eirq, 1);
 #endif /* CONFIG_LEON3 */
 #ifdef CONFIG_LEON2
 	leon_enable_irq(leon_eirq, 0);
@@ -1134,6 +1157,24 @@ static void execute_deferred_irq(void)
 	leon_irq_queue_execute();
 }
 
+/**
+ * @brief set IRQ affinity to a certain CPU
+ */
+
+static void set_affinity(unsigned int irq, int cpu)
+{
+	/* XXX need CPU range check */
+
+	if (irq_cpu_affinity[irq] == cpu)
+		return;
+
+	if (irq_cpu_affinity[irq] != CPU_AFFINITY_NONE)
+		leon_mask_irq(irq, irq_cpu_affinity[irq]);
+
+	leon_enable_irq(irq, cpu);
+
+	irq_cpu_affinity[irq] = cpu;
+}
 
 
 /**
@@ -1141,11 +1182,12 @@ static void execute_deferred_irq(void)
  */
 
 static struct irq_dev leon_irq = {
-	.irq_enable	= enable_irq,
-	.irq_disable	= disable_irq,
-	.irq_mask	= mask_irq,
-	.irq_unmask	= unmask_irq,
-	.irq_deferred	= execute_deferred_irq,
+	.irq_enable		= enable_irq,
+	.irq_disable		= disable_irq,
+	.irq_mask		= mask_irq,
+	.irq_unmask		= unmask_irq,
+	.irq_deferred		= execute_deferred_irq,
+	.irq_set_affinity	= set_affinity,
 };
 
 
@@ -1162,6 +1204,10 @@ void leon_irq_init(void)
 
 	/* mask all interrupts on this (boot) CPU */
 	iowrite32be(0, &leon_irqctrl_regs->irq_mpmask[leon3_cpuid()]);
+
+	/* XXX MASK FOR ALL CPUS CONFIGURED FOR THE SYSTEM (dummy for N==2)*/
+	iowrite32be(0, &leon_irqctrl_regs->irq_mpmask[1]);
+
 #endif /* CONFIG_LEON3 */
 #ifdef CONFIG_LEON2
 	leon_irqctrl_regs  = (struct leon2_irqctrl_registermap *)
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 115a9b595d3a082bef6f0c0ec70d642916744217..dc5096d8b396c789888cdc966bb9627529165192 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -14,6 +14,7 @@
 #include <asm/irq.h>
 #include <asm/time.h>
 #include <asm/clockevent.h>
+#include <kernel/clockevent.h>
 #include <compiler.h>
 
 #include <page.h>
@@ -55,6 +56,8 @@ static void reserve_kernel_stack(void)
 	/* the (aligned) top of the stack */
 	_kernel_stack_top = (void *) (char *) _kernel_stack_bottom + k_stack_sz;
 	_kernel_stack_top = ALIGN_PTR(_kernel_stack_top, STACK_ALIGN);
+
+	printk("xxxxx reserved %p to %p\n", _kernel_stack_top, _kernel_stack_bottom);
 }
 
 
@@ -86,6 +89,59 @@ static void mem_init(void)
 }
 
 
+int cpu1_ready;
+
+
+#include <asm/io.h>
+/* wake a cpu by writing to the multiprocessor status register */
+void cpu_wake(uint32_t cpu_id)
+{
+	iowrite32be(cpu_id, (uint32_t *) 0x80000210);
+}
+
+/** XXX crappy */
+static void boot_cpus(void)
+{
+	printk("booting cpu1\n");
+	cpu_wake(0x2); /*cpu 1 */
+
+        while (!ioread32be(&cpu1_ready));
+	printk("cpu1 booted\n");
+}
+
+
+#include <asm/processor.h>
+#include <kernel/kthread.h>
+extern struct task_struct *kernel[];
+void smp_cpu_entry(void)
+{
+
+     reserve_kernel_stack();
+     BUG_ON(stack_migrate(NULL, _kernel_stack_top));
+
+     printk("hi i'm cpu %d\n", leon3_cpuid());
+
+     BUG_ON(!leon3_cpuid());
+      /* signal ready */
+      iowrite32be(0x1, &cpu1_ready);
+
+	while (ioread32be(&cpu1_ready) != 0x2);
+	BUG_ON(clockevents_offer_device());
+	kthread_init_main();
+
+      iowrite32be(0x3, &cpu1_ready);
+	while (ioread32be(&cpu1_ready) != 0x4);
+      while(1) {
+	  //   printk("x");
+//	      cpu_relax();
+      }
+//	      printk("1\n");
+}
+
+
+
+
+
 /**
  * @brief architecture setup entry point
  */
@@ -107,4 +163,6 @@ void setup_arch(void)
 	sparc_uptime_init();
 
 	sparc_clockevent_init();
+
+	boot_cpus();
 }
diff --git a/arch/sparc/kernel/thread.c b/arch/sparc/kernel/thread.c
index 28ce210dc37f34c773bdcab59d07396b127fd8e5..73cef273e6b082f64d6f883061db092382033e43 100644
--- a/arch/sparc/kernel/thread.c
+++ b/arch/sparc/kernel/thread.c
@@ -40,7 +40,7 @@ extern struct thread_info *current_set[];
 #include <kernel/time.h>
 static void th_starter(void)
 {
-	struct task_struct *task = current_set[0]->task;
+	struct task_struct *task = current_set[leon3_cpuid()]->task;
 
 	struct timespec ts;
 	double start;
@@ -112,7 +112,7 @@ void arch_promote_to_task(struct task_struct *task)
 	task->data      = NULL;
 
 
-	printk(MSG "kernel stack %x\n", leon_get_fp());
+	printk(MSG "kernel stack %x %x\n", leon_get_fp(), leon_get_sp());
 
 	printk(MSG "is next at %p stack %p\n", &task->thread_info, task->stack);
 
diff --git a/include/kernel/bitops.h b/include/kernel/bitops.h
index 404953e52960269a95ece9d71f4f13e4dabc6775..401a06bb2e0016434470df62bf43e0812e47d473 100644
--- a/include/kernel/bitops.h
+++ b/include/kernel/bitops.h
@@ -17,6 +17,11 @@
 #define BITS_PER_LONG __WORDSIZE
 #endif
 
+#ifndef BITS_PER_LONG_LONG
+#define BITS_PER_LONG_LONG (__WORDSIZE * 2)
+#endif
+
+
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 
 
diff --git a/include/kernel/clockevent.h b/include/kernel/clockevent.h
index 1e1599544ec82d18c907f3e3876d0abf03a49a01..0a36a4e84e74381314ccf8cabaa1b9bdb8aed9eb 100644
--- a/include/kernel/clockevent.h
+++ b/include/kernel/clockevent.h
@@ -100,6 +100,8 @@ void clockevents_set_handler(struct clock_event_device *dev,
 
 void clockevents_register_device(struct clock_event_device *dev);
 
+int clockevents_offer_device(void);
+
 void clockevents_exchange_device(struct clock_event_device *old,
 				 struct clock_event_device *new);
 
@@ -110,4 +112,5 @@ int clockevents_program_timeout_ns(struct clock_event_device *dev,
 				   unsigned long nanoseconds);
 
 
+
 #endif /* _KERNEL_CLOCKEVENT_H_ */
diff --git a/include/kernel/irq.h b/include/kernel/irq.h
index b08bd0470c4dc713286f5e71c9c9f5982b6711e3..df691b22b1359b3b8c6ca183c1b81559377e33f8 100644
--- a/include/kernel/irq.h
+++ b/include/kernel/irq.h
@@ -42,11 +42,12 @@ struct irq_data {
 };
 
 struct irq_dev {
-        unsigned int (*irq_enable)   (struct irq_data *data);
-        void         (*irq_disable)  (struct irq_data *data);
-        void         (*irq_mask)     (struct irq_data *data);
-        void         (*irq_unmask)   (struct irq_data *data);
-        void         (*irq_deferred) (void);
+        unsigned int (*irq_enable)        (struct irq_data *data);
+        void         (*irq_disable)       (struct irq_data *data);
+        void         (*irq_mask)          (struct irq_data *data);
+        void         (*irq_unmask)        (struct irq_data *data);
+        void         (*irq_deferred)      (void);
+        void         (*irq_set_affinity)  (unsigned int irq, int cpu);
 };
 
 
@@ -60,4 +61,6 @@ int irq_request(unsigned int irq, enum isr_exec_priority priority,
 
 int irq_exec_deferred(void);
 
+int irq_set_affinity(unsigned int irq, int cpu);
+
 #endif /* _KERNEL_IRQ_H_ */
diff --git a/include/kernel/kthread.h b/include/kernel/kthread.h
index 33d03f00e3bfe73b8d599fe3c55b0864949e1173..a72c686f285f2e17ee18971bbe5c83fed4d47473 100644
--- a/include/kernel/kthread.h
+++ b/include/kernel/kthread.h
@@ -34,6 +34,7 @@ struct remove_this_declaration {
 #define TASK_IDLE	0x0001
 #define TASK_NEW	0x0002
 #define TASK_DEAD	0x0004
+#define TASK_BUSY	0x0005
 
 
 
diff --git a/include/kernel/sched.h b/include/kernel/sched.h
index fbb3ba55289737dd97c62173f6840d4ca373e030..c080b627f141d2cfb99d2b34422f1e35f99a8bc3 100644
--- a/include/kernel/sched.h
+++ b/include/kernel/sched.h
@@ -64,14 +64,14 @@ struct scheduler {
 
 	const enum sched_policy policy;
 
-	struct task_struct *(*pick_next_task)(struct task_queue *tq);
+	struct task_struct *(*pick_next_task)(struct task_queue *tq, ktime now);
 
 	/* XXX: sucks */
-	void (*wake_next_task)(struct task_queue *tq);
+	void (*wake_next_task)(struct task_queue *tq, ktime now);
 	void (*enqueue_task)  (struct task_queue *tq, struct task_struct *task);
 
 	ktime (*timeslice_ns) (struct task_struct *task);
-	ktime (*task_ready_ns) (struct task_queue *tq);
+	ktime (*task_ready_ns) (struct task_queue *tq, ktime now);
 
 	int (*check_sched_attr) (struct sched_attr *attr);
 
diff --git a/include/kernel/string.h b/include/kernel/string.h
index b5a18adfac2e3f9229d98f5338bc3cb79f2068e6..c0bd31db6a4192a3ef23f0fbf1ab05e3730ee260 100644
--- a/include/kernel/string.h
+++ b/include/kernel/string.h
@@ -37,7 +37,7 @@ int islower(int c);
 
 int atoi(const char *nptr);
 long int strtol(const char *nptr, char **endptr, int base);
-
+long long int strtoll(const char *nptr, char **endptr, int base);
 
 int vprintf(const char *format, va_list ap);
 int vsprintf(char *str, const char *format, va_list ap);
diff --git a/init/main.c b/init/main.c
index 27bb193113c0defcca66edcd3ec17e9ccab78b68..05778b6eedfd37b8a573dfd328178c806f4718b1 100644
--- a/init/main.c
+++ b/init/main.c
@@ -52,8 +52,8 @@ int task1(void *data)
 
 		xa++;
 
-		//printk("#");
-//		sched_yield();
+	//	printk("# %d #\n", leon3_cpuid());
+	//	sched_yield();
 	}
 }
 
@@ -65,7 +65,7 @@ int task2(void *data)
 		//printk("_");
 		xb++;
 	//	sched_yield();
-//		printk("-");
+	//	printk("-");
 	//	sched_yield();
 	}
 }
@@ -89,28 +89,52 @@ int task3(void *data)
 
 #endif
 		//printk("y %llu\n", ktime_get());
-		//printk(".");
+	//	printk(".");
 		xc++;
 
 	//	sched_yield();
 	}
 }
-
-
+#include <kernel/sysctl.h>
+extern ktime sched_last_time;
+extern uint32_t sched_ev;
 int task0(void *data)
 {
+	int last = 0;
+	int curr = 0;
+	char buf1[64];
+
+	uint32_t last_call = 0;
+
+	ktime sched_time;
+	struct sysobj *sys_irq = NULL;
+
+
+
+	printk("HELLO! %d\n", leon3_cpuid());
+	bzero(buf1, 64);
+	sys_irq = sysset_find_obj(sys_set, "/sys/irl/primary");
+
+
 	int a, b, c;
 	while (1) {
+
+
+		if (sys_irq)
+			sysobj_show_attr(sys_irq, "irl", buf1);
+
 		a = xa;
 		b = xb;
 		c = xc;
-		printk("%d %d %d %llu\n", a, b, c, ktime_get());
-		sched_yield();
+		sched_time = sched_last_time;
+		curr = atoi(buf1)/2;
+		printk("%d %d %d %llu irq: %s %d per sec; sched %llu us %llu per call, calls %d cpu %d\n", a, b, c, ktime_get(), buf1, (curr -last), ktime_to_us(sched_last_time), sched_last_time /sched_ev, sched_ev - last_call, leon3_cpuid());
+		last = curr;
+		last_call = sched_ev;
+//		sched_yield();
 	}
 }
 
-extern struct task_struct *kernel;
-
 
 /**
  * @brief kernel initialisation routines
@@ -129,6 +153,8 @@ arch_initcall(kernel_init);
 
 
 
+/** XXX dummy **/
+extern int cpu1_ready;
 /**
  * @brief kernel main functionputchar( *((char *) data) );
  */
@@ -193,7 +219,7 @@ int kernel_main(void)
 
 
 	/* elevate boot thread */
-	kernel = kthread_init_main();
+	kthread_init_main();
 #if 0
 	/*
 	 *  T1: (P=50, D=20, R=10)
@@ -225,7 +251,7 @@ int kernel_main(void)
 
 
 
-
+	cpu1_ready = 2;
 #if 1
 {
 	struct sched_attr attr;
@@ -243,21 +269,22 @@ int kernel_main(void)
 	kthread_wake_up(t);
 #endif
 #if 1
+#if 0
 	t = kthread_create(task2, NULL, KTHREAD_CPU_AFFINITY_NONE, "print1");
 	sched_get_attr(t, &attr);
 	attr.policy = SCHED_EDF;
-	attr.period       = us_to_ktime(1000);
-	attr.deadline_rel = us_to_ktime(900);
-	attr.wcet         = us_to_ktime(200);
+	attr.period       = ms_to_ktime(1000);
+	attr.deadline_rel = ms_to_ktime(900);
+	attr.wcet         = ms_to_ktime(200);
 	sched_set_attr(t, &attr);
 	kthread_wake_up(t);
 #if 1
 	t = kthread_create(task3, NULL, KTHREAD_CPU_AFFINITY_NONE, "print2");
 	sched_get_attr(t, &attr);
 	attr.policy = SCHED_EDF;
-	attr.period       = us_to_ktime(800);
-	attr.deadline_rel = us_to_ktime(700);
-	attr.wcet         = us_to_ktime(100);
+	attr.period       = ms_to_ktime(800);
+	attr.deadline_rel = ms_to_ktime(700);
+	attr.wcet         = ms_to_ktime(200);
 	sched_set_attr(t, &attr);
 	kthread_wake_up(t);
 #endif
@@ -265,19 +292,32 @@ int kernel_main(void)
 	t = kthread_create(task1, NULL, KTHREAD_CPU_AFFINITY_NONE, "print3");
 	sched_get_attr(t, &attr);
 	attr.policy = SCHED_EDF;
-	attr.period       = us_to_ktime(400);
-	attr.deadline_rel = us_to_ktime(200);
-	attr.wcet         = us_to_ktime(100);
+	attr.period       = ms_to_ktime(400);
+	attr.deadline_rel = ms_to_ktime(200);
+	attr.wcet         = ms_to_ktime(100);
 	sched_set_attr(t, &attr);
 	kthread_wake_up(t);
 #endif
+
+#endif
 #if 1
-	t = kthread_create(task0, NULL, KTHREAD_CPU_AFFINITY_NONE, "res");
+
+	t = kthread_create(task0, NULL, 0, "res");
 	sched_get_attr(t, &attr);
 	attr.policy = SCHED_EDF;
-	attr.period       = ms_to_ktime(2000);
+	attr.period       = ms_to_ktime(1000);
 	attr.deadline_rel = ms_to_ktime(900);
-	attr.wcet         = ms_to_ktime(100);
+	attr.wcet         = ms_to_ktime(800);
+	sched_set_attr(t, &attr);
+	kthread_wake_up(t);
+#endif
+#if 1
+	t = kthread_create(task1, NULL, 1, "print3");
+	sched_get_attr(t, &attr);
+	attr.policy = SCHED_EDF;
+	attr.period       = ms_to_ktime(500);
+	attr.deadline_rel = ms_to_ktime(300);
+	attr.wcet         = ms_to_ktime(200);
 	sched_set_attr(t, &attr);
 	kthread_wake_up(t);
 #endif
@@ -289,6 +329,9 @@ int kernel_main(void)
 
 }
 #endif
+
+	while (ioread32be(&cpu1_ready) != 0x3);
+      iowrite32be(0x4, &cpu1_ready);
 	while(1) {
 #if 0
 		int val = inc;
@@ -331,7 +374,8 @@ int kernel_main(void)
 	//	printk("\n");
 
 	//	sched_yield();
-	//	cpu_relax();
+//		printk("cpu1\n");
+//		cpu_relax();
 	}
 
 		//printk("%lld\n", buf[i]);
diff --git a/kernel/clockevent.c b/kernel/clockevent.c
index d2f73c970e23cedb9e262fed60b2adc08c13d551..2ba32ee40af1846f5fab172cf3935e350616239d 100644
--- a/kernel/clockevent.c
+++ b/kernel/clockevent.c
@@ -251,6 +251,32 @@ void clockevents_register_device(struct clock_event_device *dev)
 EXPORT_SYMBOL(clockevents_register_device);
 
 
+/**
+ * @brief if an unused clock event device is available, offer it to the ticker
+ *
+ * @returns 0 on success, -ENODEV if no unused device was available
+ */
+
+int clockevents_offer_device(void)
+{
+	struct clock_event_device *dev;
+
+	list_for_each_entry(dev, &clockevent_devices, node) {
+
+		if (dev->state != CLOCK_EVT_STATE_UNUSED)
+			continue;
+
+		arch_local_irq_disable();
+		tick_check_device(dev);
+		arch_local_irq_enable();
+
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+
 /**
  * @brief program a clock event
  *
diff --git a/kernel/irq.c b/kernel/irq.c
index b162072dd72b9ed6c446e052d884e56c145b4925..1d9104a70432a87f9c688fb5b517283dda73084c 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -84,8 +84,26 @@ int irq_exec_deferred(void)
 
 	return 0;
 }
+EXPORT_SYMBOL(irq_exec_deferred);
 
 
+/**
+ * @brief set CPU affinity to a particular CPU (in SMP)
+ */
+
+int irq_set_affinity(unsigned int irq, int cpu)
+{
+	if (!irq_ctrl)
+		return -EINVAL;
+
+	if (irq_ctrl->irq_set_affinity)
+		irq_ctrl->irq_set_affinity(irq, cpu);
+
+	return 0;
+
+}
+EXPORT_SYMBOL(irq_set_affinity);
+
 /**
  * @brief initialise the IRQ system
  */
diff --git a/kernel/kthread.c b/kernel/kthread.c
index ceb31f8267b7a7de8be7e1049edca06fc61d2b00..ae16357677f6ac80e5b836c610edd4d0342359a0 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -39,18 +39,16 @@ struct remove_this_declaration /*{
 static struct spinlock kthread_spinlock;
 
 
-/** XXX dummy **/
-struct task_struct *kernel;
 
-
-struct thread_info *current_set[1];
+#include <asm/processor.h>
+struct thread_info *current_set[2]; /* XXX */
 
 
 /**
  * @brief lock critical kthread section
  */
 
-static inline void kthread_lock(void)
+ void kthread_lock(void)
 {
 	spin_lock(&kthread_spinlock);
 }
@@ -60,7 +58,7 @@ static inline void kthread_lock(void)
  * @brief unlock critical kthread section
  */
 
-static inline void kthread_unlock(void)
+void kthread_unlock(void)
 {
 	spin_unlock(&kthread_spinlock);
 }
@@ -91,9 +89,9 @@ void sched_yield(void)
 {
 	struct task_struct *tsk;
 
-	tsk = current_set[0]->task;
-	if (tsk->attr.policy == SCHED_EDF)
-		tsk->runtime = 0;
+	tsk = current_set[leon3_cpuid()]->task;
+//	if (tsk->attr.policy == SCHED_EDF)
+	tsk->runtime = 0;
 
 	schedule();
 }
@@ -129,19 +127,22 @@ void kthread_wake_up(struct task_struct *task)
 }
 
 
-
+#include <asm/processor.h>
 struct task_struct *kthread_init_main(void)
 {
 	struct task_struct *task;
 
 	task = kmalloc(sizeof(*task));
 
+//	printk("hi there, someone called %d from %lx\n", leon3_cpuid(), __builtin_return_address(0));
+
 	if (!task)
 		return ERR_PTR(-ENOMEM);
 
 	/* XXX accessors */
 	task->attr.policy = SCHED_RR; /* default */
 	task->attr.priority = 1;
+	task->on_cpu = leon3_cpuid();
 
 	arch_promote_to_task(task);
 
@@ -151,9 +152,7 @@ struct task_struct *kthread_init_main(void)
 	arch_local_irq_disable();
 	kthread_lock();
 
-	kernel = task;
-	/*** XXX dummy **/
-	current_set[0] = &kernel->thread_info;
+	current_set[leon3_cpuid()] = &task->thread_info;
 
 
 	task->state = TASK_RUN;
@@ -226,6 +225,7 @@ static struct task_struct *kthread_create_internal(int (*thread_fn)(void *data),
 
 	task->total = 0;
 	task->slices = 0;
+	task->on_cpu = cpu;
 	arch_init_task(task, thread_fn, data);
 
 	task->state = TASK_NEW;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 43a3ab42ae58fd43f13243bfc77bcaa8edd3a71f..093d17fad3a1020b53a7f88f74f2a38b7621d78b 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -16,6 +16,7 @@
 #include <asm/switch_to.h>
 #include <string.h>
 
+#include <asm/leon.h>
 
 
 #define MSG "SCHEDULER: "
@@ -24,41 +25,56 @@ static LIST_HEAD(kernel_schedulers);
 
 
 /* XXX: per-cpu */
-extern struct thread_info *current_set[1];
-
+extern struct thread_info *current_set[];
 
+ktime sched_last_time;
+uint32_t sched_ev;
 
+ void kthread_lock(void);
+ void kthread_unlock(void);
 void schedule(void)
 {
 	struct scheduler *sched;
 
 	struct task_struct *next = NULL;
+	struct task_struct *prev = NULL;
 
 	struct task_struct *current;
-	int64_t slot_ns;
+	int64_t slot_ns = 1000000LL;
 	int64_t wake_ns = 1000000000;
 
 	ktime rt;
+	ktime now;
 
 
-	static int once;
-	if (!once) {
+	static int once[2];
+	if (!once[leon3_cpuid()]) {
 
 //	tick_set_mode(TICK_MODE_PERIODIC);
 	tick_set_next_ns(1e9);	/* XXX default to 1s ticks initially */
-	once = 1;
+	once[leon3_cpuid()] = 1;
 	return;
 	}
 
 
+
 	arch_local_irq_disable();
-	/* kthread_lock(); */
+//	if (leon3_cpuid() != 0)
+//	printk("cpu %d\n", leon3_cpuid());
+kthread_lock();
 
 	/* get the current task for this CPU */
-	current = current_set[0]->task;
+	/* XXX leon3_cpuid() should be smp_cpu_id() arch call*/
+	current = current_set[leon3_cpuid()]->task;
+
 
+//	if (leon3_cpuid() != 0)
+//	if (current)
+//		printk("current %s\n", current->name);
 
-	rt = ktime_sub(ktime_get(), current->exec_start);
+	now = ktime_get();
+
+	rt = ktime_sub(now, current->exec_start);
 
 	/** XXX need timeslice_update callback for schedulers */
 	/* update remaining runtime of current thread */
@@ -66,6 +82,8 @@ void schedule(void)
 	current->runtime = ktime_sub(current->runtime, rt);
 	current->total = ktime_add(current->total, rt);
 
+       current->state = TASK_RUN;
+//	current->runtime = 0;
 
 
 retry:
@@ -74,9 +92,8 @@ retry:
 	/* XXX: for now, try to wake up any threads not running
 	 * this is a waste of cycles and instruction space; should be
 	 * done in the scheduler's code (somewhere) */
-	list_for_each_entry(sched, &kernel_schedulers, node) {
-		sched->wake_next_task(&sched->tq);
-	}
+	list_for_each_entry(sched, &kernel_schedulers, node)
+		sched->wake_next_task(&sched->tq, now);
 
 
 	/* XXX need sorted list: highest->lowest scheduler priority, e.g.:
@@ -91,7 +108,8 @@ retry:
 		/* if one of the schedulers have a task which needs to run now,
 		 * next is non-NULL
 		 */
-		next = sched->pick_next_task(&sched->tq);
+retry2:
+		next = sched->pick_next_task(&sched->tq, now);
 
 #if 0
 		if (next)
@@ -122,7 +140,31 @@ retry:
 		 */
 
 		if (next) {
-			slot_ns = next->sched->timeslice_ns(next);
+#if 0
+			if (next->on_cpu != KTHREAD_CPU_AFFINITY_NONE) {
+				if (next->on_cpu != leon3_cpuid()) {
+				//	printk("%s on_cpu: %d but am %d\n", next->name, next->on_cpu, leon3_cpuid());
+
+					if (prev == next)
+						continue;
+
+					prev = next;
+					next = NULL;
+					goto retry2;
+				}
+			//	else
+			//		printk("yay %s on_cpu: %d and am %d\n", next->name, next->on_cpu, leon3_cpuid());
+			}
+
+			if (next->sched) {
+#endif
+				slot_ns = next->sched->timeslice_ns(next);
+#if 0
+				if (slot_ns < 0)
+					printk("<0 ! %s\n", next->name);
+			}
+			else continue;
+#endif
 			/* we found something to execute, off we go */
 			break;
 		}
@@ -132,39 +174,42 @@ retry:
 	if (!next) {
 		/* there is absolutely nothing nothing to do, check again later */
 		tick_set_next_ns(wake_ns);
+		kthread_unlock();
 		goto exit;
 	}
 
+//	if (leon3_cpuid() != 0)
+//	printk("next %s\n", next->name);
 	/* see if the remaining runtime in a thread is smaller than the wakeup
 	 * timeout. In this case, we will restrict ourselves to the remaining
 	 * runtime. This is particularly needeed for strictly periodic
 	 * schedulers, e.g. EDF
 	 */
 
-	wake_ns = sched->task_ready_ns(&sched->tq);
+	wake_ns = sched->task_ready_ns(&sched->tq, now);
 
-	if (wake_ns < slot_ns)
-		slot_ns  = wake_ns;
+	if (wake_ns > 0)
+		if (wake_ns < slot_ns)
+			slot_ns  = wake_ns;
 
-	/* statistics */
+	/* ALWAYS get current time here */
 	next->exec_start = ktime_get();
-//	printk("at %llu\n", next->exec_start);
-
-//		if (next)
-//			printk("real next %s %llu %llu\n", next->name, next->exec_start, slot_ns);
-	/* kthread_unlock(); */
 
-//	printk("wake %llu\n", ktime_to_us(slot_ns));
 
 	/* subtract readout overhead */
-	tick_set_next_ns(ktime_sub(slot_ns, 2000LL));
+	tick_set_next_ns(ktime_sub(slot_ns, 1000LL));
+
 #if 1
 	if (slot_ns < 19000UL) {
-	//	printk("wake %llu slot %llu %s\n", wake_ns, slot_ns, next->name);
+		printk("wake %lld slot %lld %s\n", wake_ns, slot_ns, next->name);
+		now = ktime_get();
 		goto retry;
 		BUG();
 	}
+	sched_ev++;
+	sched_last_time = ktime_add(sched_last_time, ktime_delta(ktime_get(), now));
 #endif
+	kthread_unlock(); 
 	prepare_arch_switch(1);
 	switch_to(next);
 
diff --git a/kernel/sched/edf.c b/kernel/sched/edf.c
index 8d57bb71b00b10bf812f1d5b3ccd20d7e87d5ed6..89c678816cea57f652e9e6b9b92711f25fb3aba2 100644
--- a/kernel/sched/edf.c
+++ b/kernel/sched/edf.c
@@ -24,12 +24,11 @@ void sched_print_edf_list_internal(struct task_queue *tq, ktime now)
 	struct task_struct *tmp;
 
 
-//	now = ktime_get();
 	ktime prev = 0;
 	ktime prevd = 0;
 
 	printk("\nktime: %lld\n", ktime_to_us(now));
-	printk("S\tDeadline\tWakeup\tdelta W\tdelta P\tt_rem\ttotal\tslices\tName\t|\tdeltaw\tdeltad\twake0\tdead0\texecstart\n");
+	printk("S\tDeadline\tWakeup\t\tdelta W\tdelta P\tt_rem\ttotal\tslices\tName\twcet\tavg\n");
 	printk("---------------------------------------------------------------------------------------------------------------------------------\n");
 	list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
 
@@ -46,15 +45,16 @@ void sched_print_edf_list_internal(struct task_queue *tq, ktime now)
 		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\t|\t%lld\t%lld\t%lld\t%lld\t%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),
+		if (tsk->slices == 0)
+			tsk->slices = 1;
+
+		printk("%c\t%lld\t%lld\t\t%lld\t%lld\t%lld\t%lld\t%d\t%s\t|\t%lld\t%lld\n",
+		       state, ktime_to_ms(tsk->deadline), ktime_to_ms(tsk->wakeup),
+		       ktime_to_ms(rel_wait), ktime_to_ms(rel_deadline), ktime_to_ms(tsk->runtime), ktime_to_ms(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));
+		       ktime_to_ms(tsk->attr.wcet),
+		       ktime_to_ms(tsk->total/tsk->slices));
+
 		prev = tsk->wakeup;
 		prevd = tsk->deadline;
 	}
@@ -106,8 +106,9 @@ static inline bool schedule_edf_can_execute(struct task_struct *tsk, ktime now)
 
 	if (tsk->runtime <= 0)
 		return false;
+
 	if (ktime_before(tsk->deadline, now))  {
-		sched_print_edf_list_internal(&tsk->sched->tq, ktime_get());
+		sched_print_edf_list_internal(&tsk->sched->tq, now);
 		printk("%s violated, %lld %lld, dead %lld wake %lld now %lld start %lld\n", tsk->name,
 		       tsk->runtime, ktime_us_delta(tsk->deadline, now),
 		       tsk->deadline, tsk->wakeup, now, tsk->exec_start);
@@ -127,9 +128,6 @@ static inline bool schedule_edf_can_execute(struct task_struct *tsk, ktime now)
 		return true;
 
 
-
-
-
 	return false;
 }
 
@@ -216,10 +214,8 @@ static int edf_schedulable(struct task_queue *tq, const struct task_struct *task
 
 
 	/* add all in wakeup */
-	struct task_struct *tmp2;
 	if (!list_empty(&tq->wake)) {
 		list_for_each_entry_safe(tsk, tmp, &tq->wake, node)
-
 			u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period;
 
 
@@ -228,14 +224,13 @@ static int edf_schedulable(struct task_queue *tq, const struct task_struct *task
 	/* add all running */
 	if (!list_empty(&tq->run)) {
 		list_for_each_entry_safe(tsk, tmp, &tq->run, node)
-
 			u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period;
 	}
 
 
 
 
-	if (u > 1.0) {
+	if (u > 1.9) {
 		printk("I am NOT schedul-ableh: %f ", u);
 		BUG();
 		return -EINVAL;
@@ -246,61 +241,56 @@ static int edf_schedulable(struct task_queue *tq, const struct task_struct *task
 	}
 
 
+	/* TODO check against projected interrupt rate, we really need a limit
+	 * there */
+
 	return 0;
 }
 
-/** XXX **/
-static int64_t slot;
-
-
-
-
-static struct task_struct *edf_pick_next(struct task_queue *tq)
+#include <asm/processor.h>
+static struct task_struct *edf_pick_next(struct task_queue *tq, ktime now)
 {
-#define SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE 111111LL
 	int64_t delta;
 
 
-	struct task_struct *go = NULL;
 	struct task_struct *tsk;
 	struct task_struct *tmp;
 	struct task_struct *first;
-	ktime now = ktime_get();
-	slot = 1000000000000; //SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE;
 
+	static int cnt;
+
+	if (list_empty(&tq->run))
+		return NULL;
 
 	list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
 
 		/* time to wake up yet? */
 		delta = ktime_delta(tsk->wakeup, now);
 
-		if (delta > 0) {
-
-			/* nope, optionally adjust slice */
-
-			if (delta < slot)
-				slot = delta;
-
+		if (delta > 0)
 			continue;
-		}
+
+		/* XXX ok: what we need here: are multiple queues: one
+		 * where tasks are stored which are currently able to
+		 * run, here we need one per affinity and one generic one
+		 *
+		 * one where tasks are stored which are currently idle.
+		 * tasks move to the idle queue when they cannot execute anymore
+		 * and are moved from idle to run when their wakeup time has
+		 * passed
+		 */
 
 		/* if it's already running, see if there is time remaining */
 		if (tsk->state == TASK_RUN) {
-
+#if 0
+			if (cnt++ > 10) {
+				sched_print_edf_list_internal(&tsk->sched->tq, now);
+				BUG();
+			}
+#endif
 			if (!schedule_edf_can_execute(tsk, now)) {
 				schedule_edf_reinit_task(tsk, now);
 
-				delta = ktime_delta(tsk->wakeup, now);
-
-				/* if wakeup must happen earlier than the next
-				 * scheduling event, adjust the slice
-				 */
-
-				if (delta < slot)
-					slot = delta;
-
-				BUG_ON(delta < 0);
-
 				/* always queue it up at the tail */
 				list_move_tail(&tsk->node, &tq->run);
 			}
@@ -312,12 +302,15 @@ static struct task_struct *edf_pick_next(struct task_queue *tq)
 
 			first = list_first_entry(&tq->run, struct task_struct, node);
 
+			if (tsk->on_cpu == KTHREAD_CPU_AFFINITY_NONE
+			    || tsk->on_cpu == leon3_cpuid()) {
 			if (ktime_before (tsk->wakeup, now)) {
 				if (ktime_before (tsk->deadline - tsk->runtime, first->deadline)) {
 					tsk->state = TASK_RUN;
 					list_move(&tsk->node, &tq->run);
 				}
 			}
+			}
 
 			continue;
 		}
@@ -326,70 +319,122 @@ static struct task_struct *edf_pick_next(struct task_queue *tq)
 		if (tsk->state == TASK_IDLE) {
 			tsk->state = TASK_RUN;
 
+			BUG_ON(ktime_delta(tsk->wakeup, now) > 0);
+
 			/* if our deadline is earlier than the deadline at the
 			 * head of the list, move us to top */
 
+			if (tsk->on_cpu == KTHREAD_CPU_AFFINITY_NONE
+			    || tsk->on_cpu == leon3_cpuid()) {
 			first = list_first_entry(&tq->run, struct task_struct, node);
 
+			if (first->on_cpu != KTHREAD_CPU_AFFINITY_NONE
+			    || tsk->on_cpu != leon3_cpuid()) {
+				list_move(&tsk->node, &tq->run);
+			}
+
 			if (ktime_before (tsk->deadline - tsk->runtime, first->deadline))
 				list_move(&tsk->node, &tq->run);
+			}
 
 			continue;
 		}
 
 	}
 
-	first = list_first_entry(&tq->run, struct task_struct, node);
-	delta = ktime_delta(first->wakeup, now);
+/* XXX argh, need cpu affinity run lists */
+	list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
 
+		if (tsk->state == TASK_RUN) {
 
-       if (first->state == TASK_RUN) {
-		go = first;
-		slot = first->runtime;
-       }
+			if (tsk->on_cpu == KTHREAD_CPU_AFFINITY_NONE
+			    || tsk->on_cpu == leon3_cpuid()) {
+				tsk->state = TASK_BUSY;
+				return tsk;
+			} else {
+				continue;
+			}
+		}
+	}
 
-#if 1 /* XXX should not be needed, but needs verification! */
-       if (!go) {
-	       list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
+#if 0
+	first = list_first_entry(&tq->run, struct task_struct, node);
+	delta = ktime_delta(first->wakeup, now);
 
-		       if (tsk->state != TASK_RUN)
-			       continue;
 
-		       if (ktime_before (tsk->wakeup, now)) {
-			       go = tsk;
-			       slot = tsk->runtime;
-			       break;
 
-		       }
-	       }
+       if (first->state == TASK_RUN) {
+	     //  printk("c %d\n", leon3_cpuid());
+		first->state = TASK_BUSY;
+	       return first;
        }
 #endif
 
-	return go;
+	return NULL;
 }
 
 
-static void edf_wake_next(struct task_queue *tq)
+static void edf_wake_next(struct task_queue *tq, ktime now)
 {
 	ktime last;
 
 	struct task_struct *tmp;
 	struct task_struct *task;
+	struct task_struct *first = NULL;
+	struct task_struct *t;
+	struct task_struct *prev = NULL;
+
+	ktime wake;
 
 
 
 	if (list_empty(&tq->wake))
 		return;
 
-	last = ktime_get();
-
+	last = now;
+#if 0 /* OK */
 	list_for_each_entry_safe(task, tmp, &tq->run, node) {
 		if (last < task->deadline)
 			last = task->deadline;
 	}
+#endif
 
+#if 1 /* better */
 	task = list_entry(tq->wake.next, struct task_struct, node);
 
+
+	list_for_each_entry_safe(t, tmp, &tq->run, node) {
+
+		first = list_first_entry(&tq->run, struct task_struct, node);
+		if (ktime_before (t->wakeup, now)) {
+			if (ktime_before (t->deadline - t->runtime, first->deadline)) {
+				list_move(&t->node, &tq->run);
+			}
+		}
+	}
+
+	list_for_each_entry_safe(t, tmp, &tq->run, node) {
+
+		/* if the relative deadline of task-to-wake can fit in between the unused
+		 * timeslice of this running task, insert after the next wakeup
+		 */
+		if (task->attr.deadline_rel < ktime_sub(t->deadline, t->wakeup)) {
+		    //last = ktime_add(t->deadline, t->attr.period);
+		    last = t->wakeup;
+
+
+		    break;
+		}
+
+		if (task->attr.wcet < ktime_sub(t->deadline, t->wakeup)) {
+		    //last = ktime_add(t->deadline, t->attr.period);
+		    last = t->deadline;
+
+		    break;
+		}
+	}
+#endif
+
 	task->state = TASK_IDLE;
 
 	/* initially furthest deadline as wakeup */
@@ -490,19 +535,31 @@ error:
 /* called after pick_next() */
 
 
-ktime edf_task_ready_ns(struct task_queue *tq)
+ktime edf_task_ready_ns(struct task_queue *tq, ktime now)
 {
 	int64_t delta;
 
+	struct task_struct *first;
 	struct task_struct *tsk;
 	struct task_struct *tmp;
-	ktime wake = 123456789123LL;
-	ktime now = ktime_get();
+	ktime slice = 12345679123ULL;
+	ktime wake = 123456789123ULL;
 
 
 
-	list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
+	list_for_each_entry_safe(first, tmp, &tq->run, node) {
+		if (first->state != TASK_RUN)
+			continue;
+
+		slice = first->runtime;
+		break;
+	}
 
+	list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
+#if 0
+		if (tsk->state == TASK_BUSY)
+			continue; /*meh */
+#endif
 		delta = ktime_delta(tsk->wakeup, now);
 
 		if (delta <= 0)
@@ -512,13 +569,12 @@ ktime edf_task_ready_ns(struct task_queue *tq)
 			wake = delta;
 	}
 
-	if (slot > wake)
-		slot = wake;
-
+	if (slice > wake)
+		slice = wake;
 
-	BUG_ON(slot <= 0);
+	BUG_ON(slice <= 0);
 
-	return slot;
+	return slice;
 }
 
 
diff --git a/kernel/sched/rr.c b/kernel/sched/rr.c
index 2cf78792420c8a88d9580f89bf9dcb7432b35ef2..9cd49deed605b67c32094a08290560494fc1a185 100644
--- a/kernel/sched/rr.c
+++ b/kernel/sched/rr.c
@@ -12,17 +12,21 @@
 
 #define MSG "SCHED_RR: "
 
-
-static struct task_struct *rr_pick_next(struct task_queue *tq)
+#include <asm/processor.h>
+static struct task_struct *rr_pick_next(struct task_queue *tq, ktime now)
 {
 	struct task_struct *next = NULL;
+	struct task_struct *tmp;
+
 
+	if (list_empty(&tq->run))
+		return NULL;
 
-	while (!list_empty(&tq->run)) {
+	list_for_each_entry_safe(next, tmp, &tq->run, node) {
 
-		next = list_entry(tq->run.next, struct task_struct, node);
 
-		BUG_ON(!next);
+		if (next->on_cpu == KTHREAD_CPU_AFFINITY_NONE
+		    || next->on_cpu == leon3_cpuid()) {
 
 		if (next->state == TASK_RUN) {
 			/* XXX: must pick head first, then move tail on put()
@@ -34,7 +38,8 @@ static struct task_struct *rr_pick_next(struct task_queue *tq)
 			/* reset runtime */
 			next->runtime = (next->attr.priority * tick_get_period_min_ns());
 
-			break;
+
+
 		}
 
 		if (next->state == TASK_IDLE)
@@ -43,6 +48,17 @@ static struct task_struct *rr_pick_next(struct task_queue *tq)
 		if (next->state == TASK_DEAD)
 			list_move_tail(&next->node, &tq->dead);
 
+		break;
+
+
+		} else {
+			next = NULL;
+			continue;
+		}
+
+
+
+
 	}
 
 
@@ -51,7 +67,7 @@ static struct task_struct *rr_pick_next(struct task_queue *tq)
 
 
 /* this sucks, wrong place. keep for now */
-static void rr_wake_next(struct task_queue *tq)
+static void rr_wake_next(struct task_queue *tq, ktime now)
 {
 
 	struct task_struct *task;
@@ -94,7 +110,7 @@ static void rr_enqueue(struct task_queue *tq, struct task_struct *task)
 
 static ktime rr_timeslice_ns(struct task_struct *task)
 {
-	return (ktime) (task->attr.priority * tick_get_period_min_ns());
+	return (ktime) (task->attr.priority * tick_get_period_min_ns() * 50);
 }
 
 
@@ -129,7 +145,7 @@ static int rr_check_sched_attr(struct sched_attr *attr)
  *	 so this function always returns 0
  */
 
-ktime rr_task_ready_ns(struct task_queue *tq)
+ktime rr_task_ready_ns(struct task_queue *tq, ktime now)
 {
 	return (ktime) 0ULL;
 }
diff --git a/kernel/tick.c b/kernel/tick.c
index 4a6e97b961c17e9a50ca9d3bd6488515b704db45..582176da1e9ebc2260ae021ace96f5ca69e7b299 100644
--- a/kernel/tick.c
+++ b/kernel/tick.c
@@ -16,16 +16,18 @@
 #include <kernel/export.h>
 #include <kernel/clockevent.h>
 #include <kernel/kthread.h>
+#include <kernel/irq.h>
 
 #define MSG "TICK: "
 
 /* the minimum effective tick period; default to 1 ms */
 static unsigned long tick_period_min_ns = 1000000UL;
 
-static struct clock_event_device *tick_device;
-
+/* XXX */
+static struct clock_event_device *tick_device[2];
 
 
+#include <asm/processor.h>
 
 static void tick_event_handler(struct clock_event_device *dev)
 {
@@ -35,13 +37,13 @@ static void tick_event_handler(struct clock_event_device *dev)
 
 struct clock_event_device *tick_get_device(__attribute__((unused)) int cpu)
 {
-	return tick_device;
+	return tick_device[cpu];
 }
 
 void tick_set_device(struct clock_event_device *dev,
 					   __attribute__((unused)) int cpu)
 {
-	tick_device = dev;
+	tick_device[cpu] = dev;
 }
 
 /**
@@ -134,7 +136,7 @@ static void tick_calibrate_min(struct clock_event_device *dev)
  * @brief configure the tick device
  */
 
-static void tick_setup_device(struct clock_event_device *dev)
+static void tick_setup_device(struct clock_event_device *dev, int cpu)
 {
 	tick_calibrate_min(dev);
 
@@ -160,7 +162,7 @@ void tick_check_device(struct clock_event_device *dev)
 		return;
 
 	/* XXX need per-cpu selection later */
-	cur = tick_get_device(0);
+	cur = tick_get_device(leon3_cpuid());
 
 	if (!tick_check_preferred(cur, dev))
 		return;
@@ -168,9 +170,12 @@ void tick_check_device(struct clock_event_device *dev)
 	clockevents_exchange_device(cur, dev);
 
 	/* XXX as above */
-	tick_set_device(dev, 0);
+	tick_set_device(dev, leon3_cpuid());
+
+	/* XXX as above */
+	tick_setup_device(dev, leon3_cpuid());
 
-	tick_setup_device(dev);
+	irq_set_affinity(dev->irq, leon3_cpuid());
 
 	/* XXX should inform scheduler to recalculate any deadline-related
 	 * timeouts of tasks */
@@ -180,7 +185,8 @@ void tick_check_device(struct clock_event_device *dev)
 /**
  * @brief configure the mode of the ticker
  *
- * @returns 0 on success, -EINVAL if mode not available
+ * @returns 0 on success, -EINVAL if mode not available,
+ *	   -ENODEV if no device is available for the current CPU
  */
 
 int tick_set_mode(enum tick_mode mode)
@@ -189,7 +195,9 @@ int tick_set_mode(enum tick_mode mode)
 
 
 	/* XXX need per-cpu selection later */
-	dev = tick_get_device(0);
+	dev = tick_get_device(leon3_cpuid());
+	if (!dev)
+		return -ENODEV;
 
 	switch(mode) {
 		case TICK_MODE_PERIODIC:
@@ -221,7 +229,8 @@ unsigned long tick_get_period_min_ns(void)
 /**
  * @brief configure next tick period in nanoseconds
  *
- * returns 0 on success, 1 if nanoseconds range was clamped to clock range
+ * returns 0 on success, 1 if nanoseconds range was clamped to clock range,
+ *	   -ENODEV if no device is available for the current CPU
  */
 
 
@@ -231,7 +240,9 @@ int tick_set_next_ns(unsigned long nanoseconds)
 
 
 	/* XXX need per-cpu selection later */
-	dev = tick_get_device(0);
+	dev = tick_get_device(leon3_cpuid());
+	if (!dev)
+		return -ENODEV;
 
 	return clockevents_program_timeout_ns(dev, nanoseconds);
 }
@@ -255,7 +266,9 @@ int tick_set_next_ktime(struct timespec expires)
 
 
 	/* XXX need per-cpu selection later */
-	dev = tick_get_device(0);
+	dev = tick_get_device(leon3_cpuid());
+	if (!dev)
+		return -ENODEV;
 
 	return clockevents_program_event(dev, expires);
 }
diff --git a/lib/string.c b/lib/string.c
index 271190181c553240f51a4ae4ef78b24e0c4efc10..d4d52f409e9c09eec85b275f0032013da173807b 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -721,3 +721,118 @@ long int strtol(const char *nptr, char **endptr, int base)
 }
 
 
+/**
+ * @brief convert a string to a long long integer
+ *
+ * @param nptr	the pointer to a string (possibly) representing a number
+ * @param endptr if not NULL, stores the pointer to the first character not part
+ *		 of the number
+ * @param base  the base of the number string
+ *
+ * @return the converted number
+ *
+ * @note A base of 0 defaults to 10 unless the first character after
+ *	 ' ', '+' or '-' is a '0', which will default it to base 8, unless
+ *	 it is followed by 'x' or 'X'  which defaults to base 16.
+ *	 If a number is not preceeded by a sign, it is assumed to be a unsigned
+ *	 type and may therefore assume the size of ULLONG_MAX.
+ *	 If no number has been found, the function will return 0 and
+ *	 nptr == endptr
+ *
+ * @note if the value would over-/underflow, LLONG_MAX/MIN is returned
+ */
+
+long long int strtoll(const char *nptr, char **endptr, int base)
+{
+	int neg = 0;
+
+	unsigned long long res = 0;
+	unsigned long long clamp = (unsigned long) ULONG_LONG_MAX;
+
+
+
+	if (endptr)
+		(*endptr) = (char *) nptr;
+
+	for (; isspace(*nptr); nptr++);
+
+
+	if ((*nptr) == '-') {
+		nptr++;
+		neg = 1;
+		clamp = -(unsigned long long) LONG_LONG_MIN;
+	} else if ((*nptr) == '+') {
+		clamp =  (unsigned long long) LONG_LONG_MAX;
+		nptr++;
+	}
+
+	if (!base || base == 16) {
+		if ((*nptr) == '0') {
+			switch (nptr[1]) {
+			case 'x':
+			case 'X':
+				nptr += 2;
+				base = 16;
+				break;
+			default:
+				nptr++;
+				base = 8;
+				break;
+			}
+		} else {
+			/* default */
+			base = 10;
+		}
+	}
+
+
+	/* Now iterate over the string and add up the digits. We convert
+	 * any A-Z to a-z (offset == 32 in ASCII) to check if the string
+	 * contains letters representing values (A=10...Z=35). We abort if
+	 * the computed digit value exceeds the given base or on overflow.
+	 */
+
+	while (1) {
+		unsigned int c = (*nptr);
+		unsigned int l = c | 0x20;
+		unsigned int val;
+
+		if (isdigit(c))
+			val = c - '0';
+		else if (islower(l))
+		       val = l - 'a' + 10;
+		else
+			break;
+
+		if (val >= base)
+			break;
+
+		/* Check for overflow only if result is approximately within
+		 * range of it, given the base. If we overflow, set result
+		 * to clamp (LLONG_MAX or LLONG_MIN)
+		 */
+
+		if (res & (~0ULL << (BITS_PER_LONG_LONG - fls(base)))) {
+	               if (res > (clamp - val) / base) {
+			       res = clamp;
+			       break;
+		       }
+		}
+
+		res = res * base + val;
+		nptr++;
+	}
+
+
+	/* update endptr if a value was found */
+	if (res)
+		if (endptr)
+			(*endptr) = (char *) nptr;
+
+
+	if (neg)
+		return - (long long int) res;
+
+	return (long long int) res;
+}
+
diff --git a/lib/vsnprintf.c b/lib/vsnprintf.c
index 5bfe4adbd153be73a1da50cf40edb420129a94d6..2f32fabcec79c0d2d7853657a692c33fdf86d564 100644
--- a/lib/vsnprintf.c
+++ b/lib/vsnprintf.c
@@ -1310,7 +1310,7 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap)
 	if (size) {
 		if (str) {
 			if (buf < end)
-				buf[-1] = '\0';
+				buf[0] = '\0';
 			else
 				end[-1] = '\0';
 		}