diff --git a/Makefile b/Makefile
index fa72d66aa6f61346e6baaabb0941784d6e056a32..60f85f56a6b6e15ad22ab3d1b077eeb40ca1053c 100644
--- a/Makefile
+++ b/Makefile
@@ -263,13 +263,14 @@ NOSTDINC_FLAGS  =
 CFLAGS_KERNEL	=
 AFLAGS_KERNEL	=
 
-# Use MYAPPINCLUDE when you must reference the include/ directory.
+# Use KERNELINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
-MYAPPINCLUDE    := \
+KERNELINCLUDE    := \
+                -I$(srctree)/arch/$(SRCARCH)/include \
 		$(if $(KBUILD_SRC), -I$(srctree)/include) \
 		-Iinclude -include include/generated/autoconf.h
 
-KBUILD_CPPFLAGS := -D__MYAPP__
+KBUILD_CPPFLAGS := -D__KERNEL__
 
 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
 		   -fno-strict-aliasing -fno-common \
@@ -289,7 +290,7 @@ export CPP AR NM STRIP OBJCOPY OBJDUMP
 export MAKE AWK PERL PYTHON
 export HOSTCXX HOSTCXXFLAGS CHECK CHECKFLAGS
 
-export KBUILD_CPPFLAGS NOSTDINC_FLAGS MYAPPINCLUDE OBJCOPYFLAGS LDFLAGS
+export KBUILD_CPPFLAGS NOSTDINC_FLAGS KERNELINCLUDE OBJCOPYFLAGS LDFLAGS
 export KBUILD_CFLAGS CFLAGS_KERNEL
 export KBUILD_AFLAGS AFLAGS_KERNEL
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
@@ -569,7 +570,8 @@ export KBUILD_IMAGE ?= leanos
 export	INSTALL_PATH ?= ./install
 
 
-core-y		:= arch/sparc/
+core-y		:= arch/$(SRCARCH)/
+kernel-y	:= kernel/
 init-y		:= init/
 libs-y		:= lib/
 
@@ -578,13 +580,15 @@ libs-y		:= lib/
 leanos-dirs	:= $(patsubst %/,%,$(filter %/, \
 		     $(init-y) \
 		     $(core-y) \
+		     $(kernel-y) \
 		     $(libs-y)))
 #
 leanos-core	:= $(patsubst %/, %/built-in.o, $(core-y))
+leanos-kernel	:= $(patsubst %/, %/built-in.o, $(kernel-y))
 leanos-init	:= $(patsubst %/, %/built-in.o, $(init-y))
 leanos-libs	:= $(patsubst %/, %/lib.a, $(libs-y))
 
-leanos-deps	:= $(leanos-init) $(leanos-core) $(leanos-libs)
+leanos-deps	:= $(leanos-init) $(leanos-core) $(leanos-kernel) $(leanos-libs)
 
 quiet_cmd_leanos = LD      $@
       cmd_leanos = $(CC) $(LDFLAGS) -o $@                          \
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 0bdb2c87352c6285014e4b1ccf53358a9c2e2ce8..f6c89ab6dfdcf49d7e3ba07f864ebacd78330000 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -1,7 +1,22 @@
-
+menu "SPARC Configuration"
 
 ### Arch specific settings
 
+config PAGE_OFFSET
+	bool "Use an offset in physical/virtual page address conversion"
+	default n
+	help
+	  Use a fixed offset when computing the virtual and physical page
+	  addresses.
+
+config EXTRA_SPARC_PHYS_BANKS
+	int "Number of extra physical memory banks"
+	default 0
+	range 0 31
+	help
+	 Set number of additional physical memory banks if the machine has more
+	 than one.
+endmenu
 
 
 
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 0857c4b52a0c5ade3b8226c59bc1ee4b59539d71..d91ba92498f984fa9ac95c7165e31f4ffcb32975 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -3,5 +3,9 @@ CHECKFLAGS     += -D__sparc__
 
 
 obj-y += setup.o
+obj-y += init.o
+obj-y += page.o
+obj-y += bootmem.o
+obj-y += mm.o
 
 #libs-y                 += lib/
diff --git a/arch/sparc/kernel/bootmem.c b/arch/sparc/kernel/bootmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..28e0a5155a25558d3695fa641af714de47769a5e
--- /dev/null
+++ b/arch/sparc/kernel/bootmem.c
@@ -0,0 +1,68 @@
+/**
+ * @file arch/sparc/kernel/bootmem.c
+ */
+
+#include <page.h>
+
+#include <kernel/printk.h>
+
+
+void bootmem_init(void)
+{
+	int i;
+
+	unsigned long start_pfn;
+	unsigned long end_pfn = 0UL;
+
+
+	pr_notice("End of program at: %lx\n", (unsigned long) _end);
+
+	/* start allocatable memory with page aligned address of last symbol in
+	 * image
+	 */
+	start_pfn  = (unsigned long) PAGE_ALIGN((unsigned long) &_end);
+
+	/* locate the memory bank we're in and start the mapping from
+	 * the first free page after the image.
+	 */
+	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+
+		if (start_pfn < sp_banks[i].base_addr)
+			continue;
+
+		end_pfn = sp_banks[i].base_addr + sp_banks[i].num_bytes;
+
+		if (start_pfn < end_pfn)
+			break;
+		
+		end_pfn = 0UL;
+	}
+
+	BUG_ON(!end_pfn);	/* found no suitable memory, we're boned */
+
+	/* Map what is not used for the kernel code to the virtual page start.
+	 * Since we don't have a bootstrap process for remapping the kernel,
+	 * for now, we will run the code from the 1:1 mapping of our physical
+	 * base and move everything else into high memory.
+	 */
+
+	start_pfn = (unsigned long) __pa(start_pfn);
+	
+	/* Now shift down to get the real physical page frame number. */
+	start_pfn >>= PAGE_SHIFT;
+	
+	end_pfn = (unsigned long) __pa(end_pfn);
+
+	end_pfn = end_pfn >> PAGE_SHIFT;
+	
+	pr_notice("start_pfn: %lx\n", start_pfn);
+	pr_notice("end_pfn:   %lx\n", end_pfn);
+
+
+	init_page_map(MEM_PAGE_NODE(0), start_pfn, end_pfn);
+
+
+
+
+
+}
diff --git a/arch/sparc/kernel/init.c b/arch/sparc/kernel/init.c
new file mode 100644
index 0000000000000000000000000000000000000000..faf296604e7e0175c678b14368947c7df85a5699
--- /dev/null
+++ b/arch/sparc/kernel/init.c
@@ -0,0 +1,10 @@
+/**
+ * @file arch/sparc/kernel/init.c
+ */
+
+#include <mm.h>
+
+void paging_init(void)
+{
+	bootmem_init();
+}
diff --git a/arch/sparc/kernel/mm.c b/arch/sparc/kernel/mm.c
new file mode 100644
index 0000000000000000000000000000000000000000..e9e3cc8373dee00c9c2148a37a21b5f9dcc3e173
--- /dev/null
+++ b/arch/sparc/kernel/mm.c
@@ -0,0 +1,11 @@
+/**
+ * @file arch/sparc/kernel/mm.c
+ */
+
+#include <mm.h>
+
+
+unsigned long phys_base;
+unsigned long pfn_base;
+
+struct sparc_physical_banks sp_banks[SPARC_PHYS_BANKS+1];
diff --git a/arch/sparc/kernel/page.c b/arch/sparc/kernel/page.c
new file mode 100644
index 0000000000000000000000000000000000000000..4dfd728791b07589d2388529cc63e0e8ebb809b2
--- /dev/null
+++ b/arch/sparc/kernel/page.c
@@ -0,0 +1,36 @@
+/**
+ * @file arch/sparc/kernel/page.c
+ */
+
+#include <page.h>
+
+struct pg_data page_mem[SPARC_PHYS_BANKS+1];
+
+
+
+unsigned long init_page_map(struct pg_data *pg,
+			    unsigned long start_pfn,
+			    unsigned long end_pfn)
+{
+	unsigned long mapsize = 0;
+#if 0
+	pg->bdata->node_map_mem = __va(PFN_PHYS(start_pfn));
+	pg->bdata->node_mem_map = __va(PFN_PHYS(start_pfn));
+	pg->bdata->node_min_pfn = start_pfn;
+	pg->bdata->node_low_pfn = end_pfn;
+	link_bootmem(pg->bdata);
+
+	/*
+	 * Initially all pages are reserved - setup_arch() has to
+	 * register free RAM areas explicitly.
+	 */
+	mapsize = bootmap_bytes(end - start);
+	memset(bdata->node_bootmem_map, 0xff, mapsize);
+
+	bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx\n",
+		bdata - bootmem_node_data, start, mapstart, end, mapsize);
+
+#endif
+	return mapsize;
+}
+
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 828c709066da354fc049a8d8413f026b1dbae49f..ca335e448faa80e14f001049d8f2e86fc0a2297a 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -2,6 +2,40 @@
  * @file arch/sparc/kernel/setup.c
  */
 
+#include <string.h> /* memset() */
+
+#include <init.h>
+#include <mm.h>
+#include <compiler.h>
+
+
+/**
+ * @brief configure available memory banks
+ * 
+ * TODO the memory layout should either be presented in a separate
+ *	board configuration file or, preferably, be derived from an AMBA
+ *	bus scan.
+ */
+
+static void mem_init(void)
+{
+	memset(&sp_banks, 0x0, ARRAY_SIZE(sp_banks));
+
+	sp_banks[0].base_addr = 0x40000000; 
+	sp_banks[0].num_bytes = 0x00800000;
+#if 0	
+	sp_banks[1].base_addr = 0x60000000; 
+	sp_banks[1].num_bytes = 0x04000000;
+#endif
+}
+
+
+/**
+ * @brief architecture setup entry point
+ */
+
 void setup_arch(void)
 {
+	mem_init();
+	paging_init();
 }
diff --git a/include/compiler.h b/include/compiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..ae05cf64f5c2eb7b12bb7049d75d975cae35ff1f
--- /dev/null
+++ b/include/compiler.h
@@ -0,0 +1,44 @@
+/**
+ * @file   compiler.h
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2015
+ *
+ * @copyright GPLv2
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ * 
+ * @brief a collection of preprocessor macros
+ */
+
+
+#ifndef COMPILER_H
+#define COMPILER_H
+
+
+/**
+ * Compile time check usable outside of function scope.
+ * Stolen from Linux (hpi_internal.h)
+ */
+#define compile_time_assert(cond, msg) typedef char ASSERT_##msg[(cond) ? 1 : -1]
+
+
+/**
+ * same with the stuff below
+ */
+
+#define likely(x)      __builtin_expect(!!(x), 1)
+#define unlikely(x)    __builtin_expect(!!(x), 0)
+
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 
+
+/* optimisation barrier */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#endif
diff --git a/include/kernel/kernel.h b/include/kernel/kernel.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b5892a7e41f8eea478351be4901a21dba42eb8f
--- /dev/null
+++ b/include/kernel/kernel.h
@@ -0,0 +1,23 @@
+#ifndef _KERNEL_H_
+#define _KERNEL_H_
+
+#include <compiler.h>
+
+
+#define ALIGN_MASK(x, mask)    (((x) + (mask)) & ~(mask))
+#define ALIGN(x, a)            ALIGN_MASK(x, (typeof(x))(a) - 1)
+
+
+/* this is a bit crude, but must do for now */
+#define panic(x) {}while(1)
+
+#include <stdio.h>
+#define BUG() do { \
+        printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+        panic("BUG!"); \
+} while (0)
+
+#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
+
+
+#endif /* _KERNEL_H_ */
diff --git a/include/kernel/kernel_levels.h b/include/kernel/kernel_levels.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2205fff76838f7f4e16cadb91471c5f74c5aee5
--- /dev/null
+++ b/include/kernel/kernel_levels.h
@@ -0,0 +1,60 @@
+#ifndef _KERNEL_LEVELS_H_
+#define _KERNEL_LEVELS_H_
+
+/* stole that from linux/kern_levels.h */
+
+#define KERN_SOH        "\001"          /* ASCII Start Of Header */
+#define KERN_SOH_ASCII  '\001'
+
+#define KERN_EMERG      KERN_SOH "0"    /* system is unusable */
+#define KERN_ALERT      KERN_SOH "1"    /* action must be taken immediately */
+#define KERN_CRIT       KERN_SOH "2"    /* critical conditions */
+#define KERN_ERR        KERN_SOH "3"    /* error conditions */
+#define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
+#define KERN_NOTICE     KERN_SOH "5"    /* normal but significant condition */
+#define KERN_INFO       KERN_SOH "6"    /* informational */
+#define KERN_DEBUG      KERN_SOH "7"    /* debug-level messages */
+
+#define KERN_DEFAULT    KERN_SOH "d"    /* the default kernel loglevel */
+
+
+
+/* we're boned */
+#define pr_emerg(fmt, ...) \
+        printk(KERN_EMERG fmt, ##__VA_ARGS__)
+
+/* immediate action required, we are likely boned*/
+#define pr_alert(fmt, ...) \
+        printk(KERN_ALERT fmt, ##__VA_ARGS__)
+
+/* critical condition occured, we are probably boned */
+#define pr_crit(fmt, ...) \
+        printk(KERN_CRIT fmt, ##__VA_ARGS__)
+
+/* some error occured, we are probably fine */
+#define pr_err(fmt, ...) \
+        printk(KERN_ERR fmt, ##__VA_ARGS__)
+
+/* outlook not so good */
+#define pr_warning(fmt, ...) \
+        printk(KERN_WARNING fmt, ##__VA_ARGS__)
+
+#define pr_warn pr_warning
+
+/* something worth knowing */
+#define pr_notice(fmt, ...) \
+        printk(KERN_NOTICE fmt, ##__VA_ARGS__)
+
+/* still interesting */
+#define pr_info(fmt, ...) \
+        printk(KERN_INFO fmt, ##__VA_ARGS__)
+
+/* Quite correct, sir, blabber on. */
+#define pr_debug(fmt, ...) \
+        printk(KERN_DEBUG fmt, ##__VA_ARGS__)
+
+
+void printk_set_level(int lvl);
+
+
+#endif /* _KERNEL_LEVELS_H_ */
diff --git a/include/kernel/printk.h b/include/kernel/printk.h
new file mode 100644
index 0000000000000000000000000000000000000000..e9a3a039298ef6579cbea09526beb8c58be818da
--- /dev/null
+++ b/include/kernel/printk.h
@@ -0,0 +1,12 @@
+/**
+ * @file include/kernel/printk.h
+ */
+
+#ifndef _KERNEL_KERNEL_LEVELS_H_
+#define _KERNEL_KERNEL_LEVELS_H_
+
+#include <kernel/kernel_levels.h>
+
+int printk(const char *fmt, ...);
+
+#endif /* _KERNEL_KERNEL_LEVELS_H_ */
diff --git a/kernel/Kconfig b/kernel/Kconfig
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..64afbec3289e3f730cb91eb33d97b45295918f09 100644
--- a/kernel/Kconfig
+++ b/kernel/Kconfig
@@ -0,0 +1,13 @@
+config KERNEL_LEVEL
+	int "Kernel debug level"
+	default "7"
+	help
+	 Limit the kernel's debug message level:
+	 0: emergency
+	 1: alerts
+	 2: critical conditions
+	 3: error conditions
+	 4: warnings
+	 5: notices
+	 6: informational
+	 7: debug
diff --git a/kernel/Makefile b/kernel/Makefile
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c0728ac094f9b069bb49141f3a1b4439e42a505e 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -0,0 +1 @@
+obj-y += printk.o
diff --git a/kernel/printk.c b/kernel/printk.c
new file mode 100644
index 0000000000000000000000000000000000000000..a87779df7710b74b9eb59a6e0360989a08c744b3
--- /dev/null
+++ b/kernel/printk.c
@@ -0,0 +1,70 @@
+/**
+ * @file kernel/printk.c
+ *
+ * @note printk levels obviously stolen from linux (include/linux/printk.h)
+ * @copyright Linus Torvalds et. al.
+ *
+ * TODO this obviously needs custom support when not using newlib/bcc
+ */
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <kernel/kernel_levels.h>
+
+#if defined(CONFIG_KERNEL_LEVEL)
+#define KERNEL_LEVEL (CONFIG_KERNEL_LEVEL + '0')
+#else
+#define KERNEL_LEVEL '7'
+#endif
+
+static int printk_get_level(const char *buffer)
+{
+	if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
+		switch (buffer[1]) {
+		case '0' ... '7':
+		case 'd':       /* KERN_DEFAULT */
+			return buffer[1];
+		}
+	}
+	return 0;
+}
+
+
+static inline const char *printk_skip_level(const char *buffer)
+{
+	if (printk_get_level(buffer))
+		return buffer + 2;
+
+	return buffer;
+}
+
+/**
+ * @brief see printf(3)
+ *
+ */
+
+int printk(const char *fmt, ...)
+{
+	int ret = 0;
+	int level;
+
+	va_list args;
+
+	
+	level = printk_get_level(fmt); 
+
+	va_start(args, fmt);
+
+	if (level) {
+		if (level < KERNEL_LEVEL) 
+			ret = vprintf(printk_skip_level(fmt), args);
+	} else {
+		ret = vprintf(fmt, args);
+	}
+
+	va_end(args);
+
+	return ret;
+}
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 1d1bc293749cb88c8d2fefa1619f2fb192bef479..ffb5639bb0be400ce18f5ebe92d1cf190bb39af5 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -91,13 +91,13 @@ __a_flags	=                          $(call flags,_a_flags)
 __cpp_flags     =                          $(call flags,_cpp_flags)
 endif
 
-c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(MYAPPINCLUDE)     \
+c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KERNELINCLUDE)     \
 		 $(__c_flags) $(modkern_cflags)
 
-a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(MYAPPINCLUDE)     \
+a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KERNELINCLUDE)     \
 		 $(__a_flags) $(modkern_aflags)
 
-cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(MYAPPINCLUDE)     \
+cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KERNELINCLUDE)     \
 		 $(__cpp_flags)
 
 ld_flags       = $(LDFLAGS) $(ldflags-y)