Index: kernel/arch/arm32/src/arm32.c
===================================================================
--- kernel/arch/arm32/src/arm32.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/arm32/src/arm32.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -87,5 +87,13 @@
 
 #ifdef CONFIG_FB
-	fb_init(machine_get_fb_address(), 640, 480, 1920, VISUAL_RGB_8_8_8);
+	fb_properties_t prop = {
+		.addr = machine_get_fb_address(),
+		.offset = 0,
+		.x = 640,
+		.y = 480,
+		.scan = 1920,
+		.visual = VISUAL_RGB_8_8_8,
+	};
+	fb_init(&prop);
 #endif
 }
Index: kernel/arch/ia32/src/drivers/vesa.c
===================================================================
--- kernel/arch/ia32/src/drivers/vesa.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/ia32/src/drivers/vesa.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -87,5 +87,13 @@
 	}
 	
-	fb_init(vesa_ph_addr, vesa_width, vesa_height, vesa_scanline, visual);
+	fb_properties_t vesa_props = {
+		.addr = vesa_ph_addr,
+		.offset = 0,
+		.x = vesa_width,
+		.y = vesa_height,
+		.scan = vesa_scanline,
+		.visual = visual,
+	};
+	fb_init(&vesa_props);
 }
 
Index: kernel/arch/mips32/src/mips32.c
===================================================================
--- kernel/arch/mips32/src/mips32.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/mips32/src/mips32.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -127,5 +127,13 @@
 #ifdef CONFIG_FB
 	/* GXemul framebuffer */
-	fb_init(0x12000000, 640, 480, 1920, VISUAL_RGB_8_8_8);
+	fb_properties_t gxemul_prop = {
+		.addr = 0x12000000,
+		.offset = 0,
+		.x = 640,
+		.y = 480,
+		.scan = 1920,
+		.visual = VISUAL_RGB_8_8_8,
+	};
+	fb_init(&gxemul_prop);
 #endif
 	sysinfo_set_item_val("machine." STRING(MACHINE), NULL, 1);
Index: kernel/arch/ppc32/src/ppc32.c
===================================================================
--- kernel/arch/ppc32/src/ppc32.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/ppc32/src/ppc32.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -95,5 +95,13 @@
 			panic("Unsupported bits per pixel");
 		}
-		fb_init(bootinfo.screen.addr, bootinfo.screen.width, bootinfo.screen.height, bootinfo.screen.scanline, visual);
+		fb_properties_t prop = {
+			.addr = bootinfo.screen.addr,
+			.offset = 0,
+			.x = bootinfo.screen.width,
+			.y = bootinfo.screen.height,
+			.scan = bootinfo.screen.scanline,
+			.visual = visual,
+		};
+		fb_init(&prop);
 		
 		/* Initialize IRQ routing */
@@ -104,5 +112,6 @@
 		
 		/* Initialize I/O controller */
-		cuda_init(device_assign_devno(), bootinfo.keyboard.addr + 0x16000, 2 * PAGE_SIZE);
+		cuda_init(device_assign_devno(),
+		    bootinfo.keyboard.addr + 0x16000, 2 * PAGE_SIZE);
 		
 		/* Merge all zones to 1 big zone */
@@ -129,5 +138,8 @@
 void userspace(uspace_arg_t *kernel_uarg)
 {
-	userspace_asm((uintptr_t) kernel_uarg->uspace_uarg, (uintptr_t) kernel_uarg->uspace_stack + THREAD_STACK_SIZE - SP_DELTA, (uintptr_t) kernel_uarg->uspace_entry);
+	userspace_asm((uintptr_t) kernel_uarg->uspace_uarg,
+	    (uintptr_t) kernel_uarg->uspace_stack +
+	    THREAD_STACK_SIZE - SP_DELTA,
+	    (uintptr_t) kernel_uarg->uspace_entry);
 	
 	/* Unreachable */
Index: kernel/arch/sparc64/Makefile.inc
===================================================================
--- kernel/arch/sparc64/Makefile.inc	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/Makefile.inc	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -81,4 +81,16 @@
 endif
 
+ifeq ($(CONFIG_SGCN),y)
+        DEFS += -DCONFIG_SGCN
+endif
+
+ifeq ($(MACHINE),us)
+    DEFS += -DUS
+endif
+
+ifeq ($(MACHINE),us3)
+	DEFS += -DUS3
+endif
+
 ARCH_SOURCES = \
 	arch/$(ARCH)/src/cpu/cpu.c \
@@ -107,5 +119,7 @@
 	arch/$(ARCH)/src/drivers/kbd.c \
 	arch/$(ARCH)/src/drivers/scr.c \
-	arch/$(ARCH)/src/drivers/pci.c 
+	arch/$(ARCH)/src/drivers/sgcn.c \
+	arch/$(ARCH)/src/drivers/pci.c
+
 
 ifeq ($(CONFIG_SMP),y)
Index: kernel/arch/sparc64/include/arch.h
===================================================================
--- kernel/arch/sparc64/include/arch.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/arch.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -42,5 +42,5 @@
 #define ASI_NUCLEUS_QUAD_LDD	0x24	/** ASI for 16-byte atomic loads. */
 #define ASI_DCACHE_TAG		0x47	/** ASI D-Cache Tag. */
-#define ASI_UPA_CONFIG		0x4a	/** ASI of the UPA_CONFIG register. */
+#define ASI_ICBUS_CONFIG		0x4a	/** ASI of the UPA_CONFIG/FIREPLANE_CONFIG register. */
 
 #define NWINDOWS		8	/** Number of register window sets. */
Index: kernel/arch/sparc64/include/asm.h
===================================================================
--- kernel/arch/sparc64/include/asm.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/asm.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -137,4 +137,26 @@
 }
 
+/** Read STICK_compare Register.
+ *
+ * @return Value of STICK_compare register.
+ */
+static inline uint64_t stick_compare_read(void)
+{
+	uint64_t v;
+	
+	asm volatile ("rd %%asr25, %0\n" : "=r" (v));
+	
+	return v;
+}
+
+/** Write STICK_compare Register.
+ *
+ * @param v New value of STICK_comapre register.
+ */
+static inline void stick_compare_write(uint64_t v)
+{
+	asm volatile ("wr %0, %1, %%asr25\n" : : "r" (v), "i" (0));
+}
+
 /** Read TICK Register.
  *
@@ -408,13 +430,4 @@
 }
 
-/** Read UPA_CONFIG register.
- *
- * @return Value of the UPA_CONFIG register.
- */
-static inline uint64_t upa_config_read(void)
-{
-	return asi_u64_read(ASI_UPA_CONFIG, 0);
-}
-
 extern void cpu_halt(void);
 extern void cpu_sleep(void);
Index: kernel/arch/sparc64/include/cpu.h
===================================================================
--- kernel/arch/sparc64/include/cpu.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/cpu.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -36,13 +36,4 @@
 #define KERN_sparc64_CPU_H_
 
-#include <arch/types.h>
-#include <typedefs.h>
-#include <arch/register.h>
-#include <arch/asm.h>
-
-#ifdef CONFIG_SMP
-#include <arch/mm/cache.h>
-#endif
-
 #define MANUF_FUJITSU		0x04
 #define MANUF_ULTRASPARC	0x17	/**< UltraSPARC I, UltraSPARC II */
@@ -53,12 +44,27 @@
 #define IMPL_ULTRASPARCII_I	0x12
 #define IMPL_ULTRASPARCII_E	0x13
-#define IMPL_ULTRASPARCIII	0x15
+#define IMPL_ULTRASPARCIII	0x14
+#define IMPL_ULTRASPARCIII_PLUS	0x15
+#define IMPL_ULTRASPARCIII_I	0x16
+#define IMPL_ULTRASPARCIV	0x18
 #define IMPL_ULTRASPARCIV_PLUS	0x19
 
 #define IMPL_SPARC64V		0x5
 
+#ifndef __ASM__
+
+#include <arch/types.h>
+#include <typedefs.h>
+#include <arch/register.h>
+#include <arch/regdef.h>
+#include <arch/asm.h>
+
+#ifdef CONFIG_SMP
+#include <arch/mm/cache.h>
+#endif
+
 typedef struct {
 	uint32_t mid;			/**< Processor ID as read from
-					     UPA_CONFIG. */
+					     UPA_CONFIG/FIREPLANE_CONFIG. */
 	ver_reg_t ver;
 	uint32_t clock_frequency;	/**< Processor frequency in Hz. */
@@ -67,5 +73,25 @@
 					     matches this value. */
 } cpu_arch_t;
-	
+
+
+/**
+ * Reads the module ID (agent ID/CPUID) of the current CPU.
+ */
+static inline uint32_t read_mid(void)
+{
+	uint64_t icbus_config = asi_u64_read(ASI_ICBUS_CONFIG, 0);
+	icbus_config = icbus_config >> ICBUS_CONFIG_MID_SHIFT;
+#if defined (US)
+	return icbus_config & 0x1f;
+#elif defined (US3)
+	if (((ver_reg_t) ver_read()).impl == IMPL_ULTRASPARCIII_I)
+		return icbus_config & 0x1f;
+	else
+		return icbus_config & 0x3ff;
+#endif
+}
+
+#endif	
+
 #endif
 
Index: kernel/arch/sparc64/include/cpu_family.h
===================================================================
--- kernel/arch/sparc64/include/cpu_family.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ kernel/arch/sparc64/include/cpu_family.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_sparc64_CPU_FAMILY_H_
+#define KERN_sparc64_CPU_FAMILY_H_
+
+#include <arch.h>
+#include <cpu.h>
+#include <arch/register.h>
+#include <arch/asm.h>
+
+/**
+ * Find the processor (sub)family.
+ * 
+ * @return 	true iff the CPU belongs to the US family
+ */
+static inline bool is_us(void)
+{
+	int impl = ((ver_reg_t) ver_read()).impl;
+	return (impl == IMPL_ULTRASPARCI) || (impl == IMPL_ULTRASPARCII) ||
+	       (impl == IMPL_ULTRASPARCII_I) ||  (impl == IMPL_ULTRASPARCII_E);
+}
+
+/**
+ * Find the processor (sub)family.
+ * 
+ * @return 	true iff the CPU belongs to the US-III subfamily
+ */
+static inline bool is_us_iii(void)
+{
+	int impl = ((ver_reg_t) ver_read()).impl;
+	return (impl == IMPL_ULTRASPARCIII) ||
+	       (impl == IMPL_ULTRASPARCIII_PLUS) ||
+	       (impl == IMPL_ULTRASPARCIII_I);
+}
+
+/**
+ * Find the processor (sub)family.
+ * 
+ * @return 	true iff the CPU belongs to the US-IV subfamily
+ */
+static inline bool is_us_iv(void)
+{
+	int impl = ((ver_reg_t) ver_read()).impl;
+	return (impl == IMPL_ULTRASPARCIV) || (impl == IMPL_ULTRASPARCIV_PLUS);
+}
+	
+#endif
+
+/** @}
+ */
Index: kernel/arch/sparc64/include/cpu_node.h
===================================================================
--- kernel/arch/sparc64/include/cpu_node.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ kernel/arch/sparc64/include/cpu_node.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2005 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_sparc64_CPU_NODE_H_
+#define KERN_sparc64_CPU_NODE_H_
+
+#include <genarch/ofw/ofw_tree.h>
+
+
+/** Finds the parent node of all the CPU nodes (nodes named "cpu" or "cmp").
+ *
+ *  Depending on the machine type (and possibly the OFW version), CPUs can be
+ *  at "/" or at "/ssm@0,0".
+ */ 
+static inline ofw_tree_node_t *cpus_parent(void)
+{
+	ofw_tree_node_t *parent;
+	parent = ofw_tree_find_child(ofw_tree_lookup("/"), "ssm@0,0");
+	if (parent == NULL)
+		parent = ofw_tree_lookup("/");
+	return parent;
+}
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/sparc64/include/drivers/kbd.h
===================================================================
--- kernel/arch/sparc64/include/drivers/kbd.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/drivers/kbd.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -42,5 +42,6 @@
 	KBD_UNKNOWN,
 	KBD_Z8530,
-	KBD_NS16550
+	KBD_NS16550,
+	KBD_SGCN
 } kbd_type_t;
 
Index: kernel/arch/sparc64/include/drivers/scr.h
===================================================================
--- kernel/arch/sparc64/include/drivers/scr.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/drivers/scr.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -43,5 +43,6 @@
 	SCR_ATYFB,
 	SCR_FFB,
-	SCR_CGSIX
+	SCR_CGSIX,
+	SCR_XVR
 } scr_type_t;
 
Index: kernel/arch/sparc64/include/drivers/sgcn.h
===================================================================
--- kernel/arch/sparc64/include/drivers/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ kernel/arch/sparc64/include/drivers/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64	
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_sparc64_SGCN_H_
+#define KERN_sparc64_SGCN_H_
+
+#include <arch/types.h>
+
+/* number of bytes in the TOC magic, including the terminating '\0' */
+#define TOC_MAGIC_BYTES		8
+
+/* number of bytes in the TOC key, including the terminating '\0' */
+#define TOC_KEY_SIZE		8
+
+/* maximum number of entries in the SRAM table of contents */
+#define MAX_TOC_ENTRIES		32
+
+/* number of bytes in the SGCN buffer magic, including the terminating '\0' */
+#define SGCN_MAGIC_BYTES	4
+
+/**
+ * Entry in the SRAM table of contents. Describes one segment of the SRAM
+ * which serves a particular purpose (e.g. OBP serial console, Solaris serial
+ * console, Solaris mailbox,...). 
+ */
+typedef struct {
+	/** key (e.g. "OBPCONS", "SOLCONS", "SOLMBOX",...) */
+	char key[TOC_KEY_SIZE];
+	
+	/** size of the segment in bytes */
+	uint32_t size;
+	
+	/** offset of the segment within SRAM */
+	uint32_t offset;
+} __attribute ((packed)) toc_entry_t;
+
+/**
+ * SRAM table of contents. Describes all segments within the SRAM.
+ */
+typedef struct {
+	/** hard-wired to "TOCSRAM" */
+	char magic[TOC_MAGIC_BYTES];
+	
+	/** we don't need this */
+	char unused[8];
+	
+	/** TOC entries */
+	toc_entry_t keys[MAX_TOC_ENTRIES];
+} __attribute__ ((packed)) iosram_toc_t;
+
+/**
+ * SGCN buffer header. It is placed at the very beginning of the SGCN
+ * buffer. 
+ */
+typedef struct {
+	/** hard-wired to "CON" */
+	char magic[SGCN_MAGIC_BYTES];
+	
+	/** we don't need this */
+	char unused[8];
+	
+	/** offset within the SGCN buffer of the input buffer start */
+	uint32_t in_begin;
+	
+	/** offset within the SGCN buffer of the input buffer end */
+	uint32_t in_end;
+	
+	/** offset within the SGCN buffer of the input buffer read pointer */
+	uint32_t in_rdptr;
+	
+	/** offset within the SGCN buffer of the input buffer write pointer */
+	uint32_t in_wrptr;
+
+	/** offset within the SGCN buffer of the output buffer start */
+	uint32_t out_begin;
+	
+	/** offset within the SGCN buffer of the output buffer end */
+	uint32_t out_end;
+	
+	/** offset within the SGCN buffer of the output buffer read pointer */
+	uint32_t out_rdptr;
+	
+	/** offset within the SGCN buffer of the output buffer write pointer */
+	uint32_t out_wrptr;
+} __attribute__ ((packed)) sgcn_buffer_header_t;
+
+void sgcn_grab(void);
+void sgcn_release(void);
+void sgcn_poll(void);
+void sgcn_init(void);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/sparc64/include/mm/cache.h
===================================================================
--- kernel/arch/sparc64/include/mm/cache.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/mm/cache.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -39,13 +39,4 @@
 #include <mm/frame.h>
 
-#define dcache_flush_page(p) \
-	dcache_flush_color(PAGE_COLOR((p)))
-#define dcache_flush_frame(p, f) \
-	dcache_flush_tag(PAGE_COLOR((p)), ADDR2PFN((f)));
-
-extern void dcache_flush(void);
-extern void dcache_flush_color(int c);
-extern void dcache_flush_tag(int c, pfn_t tag);
-
 #endif
 
Index: kernel/arch/sparc64/include/mm/cache_spec.h
===================================================================
--- kernel/arch/sparc64/include/mm/cache_spec.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/mm/cache_spec.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -39,16 +39,17 @@
  * The following macros are valid for the following processors:
  *
- * 	UltraSPARC, UltraSPARC II, UltraSPARC IIi
+ * 	UltraSPARC, UltraSPARC II, UltraSPARC IIi, UltraSPARC III,
+ * 	UltraSPARC III+, UltraSPARC IV, UltraSPARC IV+
  * 
  * Should we support other UltraSPARC processors, we need to make sure that
  * the macros are defined correctly for them.
  */
-
+ 
+#if defined (US)
 #define DCACHE_SIZE		(16 * 1024)
+#elif defined (US3)
+#define DCACHE_SIZE		(64 * 1024)
+#endif
 #define DCACHE_LINE_SIZE	32	
-
-#define ICACHE_SIZE		(16 * 1024)
-#define ICACHE_WAYS		2
-#define ICACHE_LINE_SIZE	32
 
 #endif
Index: kernel/arch/sparc64/include/mm/frame.h
===================================================================
--- kernel/arch/sparc64/include/mm/frame.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/mm/frame.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -60,6 +60,11 @@
 	uintptr_t address;
 	struct {
+#if defined (US)
 		unsigned : 23;
 		uint64_t pfn : 28;		/**< Physical Frame Number. */
+#elif defined (US3)
+		unsigned : 21;
+		uint64_t pfn : 30;		/**< Physical Frame Number. */
+#endif
 		unsigned offset : 13;		/**< Offset. */
 	} __attribute__ ((packed));
Index: kernel/arch/sparc64/include/mm/mmu.h
===================================================================
--- kernel/arch/sparc64/include/mm/mmu.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/mm/mmu.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -36,6 +36,8 @@
 #define KERN_sparc64_MMU_H_
 
+#if defined(US)
 /* LSU Control Register ASI. */
 #define ASI_LSU_CONTROL_REG		0x45	/**< Load/Store Unit Control Register. */
+#endif
 
 /* I-MMU ASIs. */
@@ -53,4 +55,9 @@
 #define VA_IMMU_TSB_BASE		0x28	/**< IMMU TSB base register. */
 #define VA_IMMU_TAG_ACCESS		0x30	/**< IMMU TLB tag access register. */
+#if defined (US3)
+#define VA_IMMU_PRIMARY_EXTENSION	0x48	/**< IMMU TSB primary extension register */
+#define VA_IMMU_NUCLEUS_EXTENSION	0x58	/**< IMMU TSB nucleus extension register */
+#endif
+
 
 /* D-MMU ASIs. */
@@ -74,4 +81,9 @@
 #define VA_DMMU_VA_WATCHPOINT_REG	0x38	/**< DMMU VA data watchpoint register. */
 #define VA_DMMU_PA_WATCHPOINT_REG	0x40	/**< DMMU PA data watchpoint register. */
+#if defined (US3)
+#define VA_DMMU_PRIMARY_EXTENSION	0x48	/**< DMMU TSB primary extension register */
+#define VA_DMMU_SECONDARY_EXTENSION	0x50	/**< DMMU TSB secondary extension register */
+#define VA_DMMU_NUCLEUS_EXTENSION	0x58	/**< DMMU TSB nucleus extension register */
+#endif
 
 #ifndef __ASM__
@@ -81,4 +93,5 @@
 #include <arch/types.h>
 
+#if defined(US)
 /** LSU Control Register. */
 typedef union {
@@ -101,4 +114,5 @@
 	} __attribute__ ((packed));
 } lsu_cr_reg_t;
+#endif /* US */
 
 #endif /* !def __ASM__ */
Index: kernel/arch/sparc64/include/mm/tlb.h
===================================================================
--- kernel/arch/sparc64/include/mm/tlb.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/mm/tlb.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -36,6 +36,14 @@
 #define KERN_sparc64_TLB_H_
 
+#if defined (US)
 #define ITLB_ENTRY_COUNT		64
 #define DTLB_ENTRY_COUNT		64
+#define DTLB_MAX_LOCKED_ENTRIES		DTLB_ENTRY_COUNT
+#endif
+
+/** TLB_DSMALL is the only of the three DMMUs that can hold locked entries. */
+#if defined (US3)
+#define DTLB_MAX_LOCKED_ENTRIES		16
+#endif
 
 #define MEM_CONTEXT_KERNEL		0
@@ -54,4 +62,7 @@
 #define TLB_DEMAP_PAGE		0
 #define TLB_DEMAP_CONTEXT	1
+#if defined (US3)
+#define TLB_DEMAP_ALL		2
+#endif
 
 #define TLB_DEMAP_TYPE_SHIFT	6
@@ -61,4 +72,16 @@
 #define TLB_DEMAP_SECONDARY	1
 #define TLB_DEMAP_NUCLEUS	2
+
+/* There are more TLBs in one MMU in US3, their codes are defined here. */
+#if defined (US3)
+/* D-MMU: one small (16-entry) TLB and two big (512-entry) TLBs */
+#define TLB_DSMALL	0
+#define TLB_DBIG_0	2
+#define TLB_DBIG_1	3
+	
+/* I-MMU: one small (16-entry) TLB and one big TLB */
+#define TLB_ISMALL	0
+#define TLB_IBIG	2
+#endif
 
 #define TLB_DEMAP_CONTEXT_SHIFT	4
@@ -77,4 +100,6 @@
 #include <arch/barrier.h>
 #include <arch/types.h>
+#include <arch/register.h>
+#include <arch/cpu.h>
 
 union tlb_context_reg {
@@ -91,4 +116,7 @@
 
 /** I-/D-TLB Data Access Address in Alternate Space. */
+
+#if defined (US)
+
 union tlb_data_access_addr {
 	uint64_t value;
@@ -99,6 +127,51 @@
 	} __attribute__ ((packed));
 };
-typedef union tlb_data_access_addr tlb_data_access_addr_t;
-typedef union tlb_data_access_addr tlb_tag_read_addr_t;
+typedef union tlb_data_access_addr dtlb_data_access_addr_t;
+typedef union tlb_data_access_addr dtlb_tag_read_addr_t;
+typedef union tlb_data_access_addr itlb_data_access_addr_t;
+typedef union tlb_data_access_addr itlb_tag_read_addr_t;
+
+#elif defined (US3)
+
+/*
+ * In US3, I-MMU and D-MMU have different formats of the data
+ * access register virtual address. In the corresponding
+ * structures the member variable for the entry number is
+ * called "local_tlb_entry" - it contrasts with the "tlb_entry"
+ * for the US data access register VA structure. The rationale
+ * behind this is to prevent careless mistakes in the code
+ * caused by setting only the entry number and not the TLB
+ * number in the US3 code (when taking the code from US). 
+ */
+
+union dtlb_data_access_addr {
+	uint64_t value;
+	struct {
+		uint64_t : 45;
+		unsigned : 1;
+		unsigned tlb_number : 2;
+		unsigned : 4;
+		unsigned local_tlb_entry : 9;
+		unsigned : 3;
+	} __attribute__ ((packed));
+};
+typedef union dtlb_data_access_addr dtlb_data_access_addr_t;
+typedef union dtlb_data_access_addr dtlb_tag_read_addr_t;
+
+union itlb_data_access_addr {
+	uint64_t value;
+	struct {
+		uint64_t : 45;
+		unsigned : 1;
+		unsigned tlb_number : 2;
+		unsigned : 6;
+		unsigned local_tlb_entry : 7;
+		unsigned : 3;
+	} __attribute__ ((packed));
+};
+typedef union itlb_data_access_addr itlb_data_access_addr_t;
+typedef union itlb_data_access_addr itlb_tag_read_addr_t;
+
+#endif
 
 /** I-/D-TLB Tag Read Register. */
@@ -119,6 +192,11 @@
 	struct {
 		uint64_t vpn: 51;	/**< Virtual Address bits 63:13. */
+#if defined (US)
 		unsigned : 6;		/**< Ignored. */
 		unsigned type : 1;	/**< The type of demap operation. */
+#elif defined (US3)
+		unsigned : 5;		/**< Ignored. */
+		unsigned type: 2;	/**< The type of demap operation. */
+#endif
 		unsigned context : 2;	/**< Context register selection. */
 		unsigned : 4;		/**< Zero. */
@@ -131,8 +209,17 @@
 	uint64_t value;
 	struct {
+#if defined (US)
 		unsigned long : 40;	/**< Implementation dependent. */
 		unsigned asi : 8;	/**< ASI. */
 		unsigned : 2;
 		unsigned ft : 7;	/**< Fault type. */
+#elif defined (US3)
+		unsigned long : 39;	/**< Implementation dependent. */
+		unsigned nf : 1;	/**< Non-faulting load. */
+		unsigned asi : 8;	/**< ASI. */
+		unsigned tm : 1;	/**< I-TLB miss. */
+		unsigned : 3;		/**< Reserved. */
+		unsigned ft : 5;	/**< Fault type. */
+#endif
 		unsigned e : 1;		/**< Side-effect bit. */
 		unsigned ct : 2;	/**< Context Register selection. */
@@ -145,7 +232,51 @@
 typedef union tlb_sfsr_reg tlb_sfsr_reg_t;
 
+#if defined (US3)
+
+/*
+ * Functions for determining the number of entries in TLBs. They either return
+ * a constant value or a value based on the CPU autodetection.
+ */
+
+/**
+ * Determine the number of entries in the DMMU's small TLB. 
+ */
+static inline uint16_t tlb_dsmall_size(void)
+{
+	return 16;
+}
+
+/**
+ * Determine the number of entries in each DMMU's big TLB. 
+ */
+static inline uint16_t tlb_dbig_size(void)
+{
+	return 512;
+}
+
+/**
+ * Determine the number of entries in the IMMU's small TLB. 
+ */
+static inline uint16_t tlb_ismall_size(void)
+{
+	return 16;
+}
+
+/**
+ * Determine the number of entries in the IMMU's big TLB. 
+ */
+static inline uint16_t tlb_ibig_size(void)
+{
+	if (((ver_reg_t) ver_read()).impl == IMPL_ULTRASPARCIV_PLUS)
+		return 512;
+	else
+		return 128;
+}
+
+#endif
+
 /** Read MMU Primary Context Register.
  *
- * @return Current value of Primary Context Register.
+ * @return		Current value of Primary Context Register.
  */
 static inline uint64_t mmu_primary_context_read(void)
@@ -156,5 +287,5 @@
 /** Write MMU Primary Context Register.
  *
- * @param v New value of Primary Context Register.
+ * @param v		New value of Primary Context Register.
  */
 static inline void mmu_primary_context_write(uint64_t v)
@@ -166,5 +297,5 @@
 /** Read MMU Secondary Context Register.
  *
- * @return Current value of Secondary Context Register.
+ * @return		Current value of Secondary Context Register.
  */
 static inline uint64_t mmu_secondary_context_read(void)
@@ -175,5 +306,5 @@
 /** Write MMU Primary Context Register.
  *
- * @param v New value of Primary Context Register.
+ * @param v		New value of Primary Context Register.
  */
 static inline void mmu_secondary_context_write(uint64_t v)
@@ -183,13 +314,16 @@
 }
 
+#if defined (US)
+
 /** Read IMMU TLB Data Access Register.
  *
- * @param entry TLB Entry index.
- *
- * @return Current value of specified IMMU TLB Data Access Register.
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified IMMU TLB Data Access
+ * 			Register.
  */
 static inline uint64_t itlb_data_access_read(index_t entry)
 {
-	tlb_data_access_addr_t reg;
+	itlb_data_access_addr_t reg;
 	
 	reg.value = 0;
@@ -200,10 +334,10 @@
 /** Write IMMU TLB Data Access Register.
  *
- * @param entry TLB Entry index.
- * @param value Value to be written.
+ * @param entry		TLB Entry index.
+ * @param value		Value to be written.
  */
 static inline void itlb_data_access_write(index_t entry, uint64_t value)
 {
-	tlb_data_access_addr_t reg;
+	itlb_data_access_addr_t reg;
 	
 	reg.value = 0;
@@ -215,11 +349,12 @@
 /** Read DMMU TLB Data Access Register.
  *
- * @param entry TLB Entry index.
- *
- * @return Current value of specified DMMU TLB Data Access Register.
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified DMMU TLB Data Access
+ * 			Register.
  */
 static inline uint64_t dtlb_data_access_read(index_t entry)
 {
-	tlb_data_access_addr_t reg;
+	dtlb_data_access_addr_t reg;
 	
 	reg.value = 0;
@@ -230,10 +365,10 @@
 /** Write DMMU TLB Data Access Register.
  *
- * @param entry TLB Entry index.
- * @param value Value to be written.
+ * @param entry		TLB Entry index.
+ * @param value		Value to be written.
  */
 static inline void dtlb_data_access_write(index_t entry, uint64_t value)
 {
-	tlb_data_access_addr_t reg;
+	dtlb_data_access_addr_t reg;
 	
 	reg.value = 0;
@@ -245,11 +380,11 @@
 /** Read IMMU TLB Tag Read Register.
  *
- * @param entry TLB Entry index.
- *
- * @return Current value of specified IMMU TLB Tag Read Register.
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified IMMU TLB Tag Read Register.
  */
 static inline uint64_t itlb_tag_read_read(index_t entry)
 {
-	tlb_tag_read_addr_t tag;
+	itlb_tag_read_addr_t tag;
 
 	tag.value = 0;
@@ -260,11 +395,11 @@
 /** Read DMMU TLB Tag Read Register.
  *
- * @param entry TLB Entry index.
- *
- * @return Current value of specified DMMU TLB Tag Read Register.
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified DMMU TLB Tag Read Register.
  */
 static inline uint64_t dtlb_tag_read_read(index_t entry)
 {
-	tlb_tag_read_addr_t tag;
+	dtlb_tag_read_addr_t tag;
 
 	tag.value = 0;
@@ -273,7 +408,118 @@
 }
 
+#elif defined (US3)
+
+
+/** Read IMMU TLB Data Access Register.
+ *
+ * @param tlb		TLB number (one of TLB_ISMALL or TLB_IBIG)
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified IMMU TLB Data Access
+ * 			Register.
+ */
+static inline uint64_t itlb_data_access_read(int tlb, index_t entry)
+{
+	itlb_data_access_addr_t reg;
+	
+	reg.value = 0;
+	reg.tlb_number = tlb;
+	reg.local_tlb_entry = entry;
+	return asi_u64_read(ASI_ITLB_DATA_ACCESS_REG, reg.value);
+}
+
+/** Write IMMU TLB Data Access Register.
+ * @param tlb		TLB number (one of TLB_ISMALL or TLB_IBIG)
+ * @param entry		TLB Entry index.
+ * @param value		Value to be written.
+ */
+static inline void itlb_data_access_write(int tlb, index_t entry,
+	uint64_t value)
+{
+	itlb_data_access_addr_t reg;
+	
+	reg.value = 0;
+	reg.tlb_number = tlb;
+	reg.local_tlb_entry = entry;
+	asi_u64_write(ASI_ITLB_DATA_ACCESS_REG, reg.value, value);
+	flush_pipeline();
+}
+
+/** Read DMMU TLB Data Access Register.
+ *
+ * @param tlb		TLB number (one of TLB_DSMALL, TLB_DBIG, TLB_DBIG) 
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified DMMU TLB Data Access
+ * 			Register.
+ */
+static inline uint64_t dtlb_data_access_read(int tlb, index_t entry)
+{
+	dtlb_data_access_addr_t reg;
+	
+	reg.value = 0;
+	reg.tlb_number = tlb;
+	reg.local_tlb_entry = entry;
+	return asi_u64_read(ASI_DTLB_DATA_ACCESS_REG, reg.value);
+}
+
+/** Write DMMU TLB Data Access Register.
+ *
+ * @param tlb		TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1)  
+ * @param entry		TLB Entry index.
+ * @param value		Value to be written.
+ */
+static inline void dtlb_data_access_write(int tlb, index_t entry,
+	uint64_t value)
+{
+	dtlb_data_access_addr_t reg;
+	
+	reg.value = 0;
+	reg.tlb_number = tlb;
+	reg.local_tlb_entry = entry;
+	asi_u64_write(ASI_DTLB_DATA_ACCESS_REG, reg.value, value);
+	membar();
+}
+
+/** Read IMMU TLB Tag Read Register.
+ *
+ * @param tlb		TLB number (one of TLB_ISMALL or TLB_IBIG) 
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified IMMU TLB Tag Read Register.
+ */
+static inline uint64_t itlb_tag_read_read(int tlb, index_t entry)
+{
+	itlb_tag_read_addr_t tag;
+
+	tag.value = 0;
+	tag.tlb_number = tlb;
+	tag.local_tlb_entry = entry;
+	return asi_u64_read(ASI_ITLB_TAG_READ_REG, tag.value);
+}
+
+/** Read DMMU TLB Tag Read Register.
+ *
+ * @param tlb		TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1)
+ * @param entry		TLB Entry index.
+ *
+ * @return		Current value of specified DMMU TLB Tag Read Register.
+ */
+static inline uint64_t dtlb_tag_read_read(int tlb, index_t entry)
+{
+	dtlb_tag_read_addr_t tag;
+
+	tag.value = 0;
+	tag.tlb_number = tlb;
+	tag.local_tlb_entry = entry;
+	return asi_u64_read(ASI_DTLB_TAG_READ_REG, tag.value);
+}
+
+#endif
+
+
 /** Write IMMU TLB Tag Access Register.
  *
- * @param v Value to be written.
+ * @param v		Value to be written.
  */
 static inline void itlb_tag_access_write(uint64_t v)
@@ -285,5 +531,5 @@
 /** Read IMMU TLB Tag Access Register.
  *
- * @return Current value of IMMU TLB Tag Access Register.
+ * @return		Current value of IMMU TLB Tag Access Register.
  */
 static inline uint64_t itlb_tag_access_read(void)
@@ -294,5 +540,5 @@
 /** Write DMMU TLB Tag Access Register.
  *
- * @param v Value to be written.
+ * @param v		Value to be written.
  */
 static inline void dtlb_tag_access_write(uint64_t v)
@@ -304,5 +550,5 @@
 /** Read DMMU TLB Tag Access Register.
  *
- * @return Current value of DMMU TLB Tag Access Register.
+ * @return 		Current value of DMMU TLB Tag Access Register.
  */
 static inline uint64_t dtlb_tag_access_read(void)
@@ -314,5 +560,5 @@
 /** Write IMMU TLB Data in Register.
  *
- * @param v Value to be written.
+ * @param v		Value to be written.
  */
 static inline void itlb_data_in_write(uint64_t v)
@@ -324,5 +570,5 @@
 /** Write DMMU TLB Data in Register.
  *
- * @param v Value to be written.
+ * @param v		Value to be written.
  */
 static inline void dtlb_data_in_write(uint64_t v)
@@ -334,5 +580,5 @@
 /** Read ITLB Synchronous Fault Status Register.
  *
- * @return Current content of I-SFSR register.
+ * @return		Current content of I-SFSR register.
  */
 static inline uint64_t itlb_sfsr_read(void)
@@ -343,5 +589,5 @@
 /** Write ITLB Synchronous Fault Status Register.
  *
- * @param v New value of I-SFSR register.
+ * @param v		New value of I-SFSR register.
  */
 static inline void itlb_sfsr_write(uint64_t v)
@@ -353,5 +599,5 @@
 /** Read DTLB Synchronous Fault Status Register.
  *
- * @return Current content of D-SFSR register.
+ * @return		Current content of D-SFSR register.
  */
 static inline uint64_t dtlb_sfsr_read(void)
@@ -362,5 +608,5 @@
 /** Write DTLB Synchronous Fault Status Register.
  *
- * @param v New value of D-SFSR register.
+ * @param v		New value of D-SFSR register.
  */
 static inline void dtlb_sfsr_write(uint64_t v)
@@ -372,5 +618,5 @@
 /** Read DTLB Synchronous Fault Address Register.
  *
- * @return Current content of D-SFAR register.
+ * @return		Current content of D-SFAR register.
  */
 static inline uint64_t dtlb_sfar_read(void)
@@ -381,8 +627,9 @@
 /** Perform IMMU TLB Demap Operation.
  *
- * @param type Selects between context and page demap.
+ * @param type		Selects between context and page demap (and entire MMU
+ * 			demap on US3).
  * @param context_encoding Specifies which Context register has Context ID for
- * 	demap.
- * @param page Address which is on the page to be demapped.
+ * 			demap.
+ * @param page		Address which is on the page to be demapped.
  */
 static inline void itlb_demap(int type, int context_encoding, uintptr_t page)
@@ -398,7 +645,7 @@
 	da.vpn = pg.vpn;
 	
-	asi_u64_write(ASI_IMMU_DEMAP, da.value, 0);	/* da.value is the
-							 * address within the
-							 * ASI */ 
+	/* da.value is the address within the ASI */ 
+	asi_u64_write(ASI_IMMU_DEMAP, da.value, 0);
+
 	flush_pipeline();
 }
@@ -406,8 +653,9 @@
 /** Perform DMMU TLB Demap Operation.
  *
- * @param type Selects between context and page demap.
+ * @param type		Selects between context and page demap (and entire MMU
+ * 			demap on US3).
  * @param context_encoding Specifies which Context register has Context ID for
- *	 demap.
- * @param page Address which is on the page to be demapped.
+ * 			demap.
+ * @param page		Address which is on the page to be demapped.
  */
 static inline void dtlb_demap(int type, int context_encoding, uintptr_t page)
@@ -423,15 +671,15 @@
 	da.vpn = pg.vpn;
 	
-	asi_u64_write(ASI_DMMU_DEMAP, da.value, 0);	/* da.value is the
-							 * address within the
-							 * ASI */ 
+	/* da.value is the address within the ASI */ 
+	asi_u64_write(ASI_DMMU_DEMAP, da.value, 0);
+
 	membar();
 }
 
-extern void fast_instruction_access_mmu_miss(unative_t unused, istate_t *istate);
-extern void fast_data_access_mmu_miss(tlb_tag_access_reg_t tag, istate_t *istate);
-extern void fast_data_access_protection(tlb_tag_access_reg_t tag , istate_t *istate);
-
-extern void dtlb_insert_mapping(uintptr_t page, uintptr_t frame, int pagesize, bool locked, bool cacheable);
+extern void fast_instruction_access_mmu_miss(unative_t, istate_t *);
+extern void fast_data_access_mmu_miss(tlb_tag_access_reg_t, istate_t *);
+extern void fast_data_access_protection(tlb_tag_access_reg_t , istate_t *);
+
+extern void dtlb_insert_mapping(uintptr_t, uintptr_t, int, bool, bool);
 
 extern void dump_sfsr_and_sfar(void);
Index: kernel/arch/sparc64/include/mm/tsb.h
===================================================================
--- kernel/arch/sparc64/include/mm/tsb.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/mm/tsb.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -108,4 +108,53 @@
 }
 
+#if defined (US3)
+
+/** Write DTSB Primary Extension register.
+ *
+ * @param v New content of the DTSB Primary Extension register.
+ */
+static inline void dtsb_primary_extension_write(uint64_t v)
+{
+	asi_u64_write(ASI_DMMU, VA_DMMU_PRIMARY_EXTENSION, v);
+}
+
+/** Write DTSB Secondary Extension register.
+ *
+ * @param v New content of the DTSB Secondary Extension register.
+ */
+static inline void dtsb_secondary_extension_write(uint64_t v)
+{
+	asi_u64_write(ASI_DMMU, VA_DMMU_SECONDARY_EXTENSION, v);
+}
+
+/** Write DTSB Nucleus Extension register.
+ *
+ * @param v New content of the DTSB Nucleus Extension register.
+ */
+static inline void dtsb_nucleus_extension_write(uint64_t v)
+{
+	asi_u64_write(ASI_DMMU, VA_DMMU_NUCLEUS_EXTENSION, v);
+}
+
+/** Write ITSB Primary Extension register.
+ *
+ * @param v New content of the ITSB Primary Extension register.
+ */
+static inline void itsb_primary_extension_write(uint64_t v)
+{
+	asi_u64_write(ASI_IMMU, VA_IMMU_PRIMARY_EXTENSION, v);
+}
+
+/** Write ITSB Nucleus Extension register.
+ *
+ * @param v New content of the ITSB Nucleus Extension register.
+ */
+static inline void itsb_nucleus_extension_write(uint64_t v)
+{
+	asi_u64_write(ASI_IMMU, VA_IMMU_NUCLEUS_EXTENSION, v);
+}
+
+#endif
+
 /* Forward declarations. */
 struct as;
Index: kernel/arch/sparc64/include/mm/tte.h
===================================================================
--- kernel/arch/sparc64/include/mm/tte.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/mm/tte.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -51,4 +51,5 @@
 #include <arch/types.h>
 
+/* TTE tag's VA_tag field contains bits <63:VA_TAG_PAGE_SHIFT> of the VA */
 #define VA_TAG_PAGE_SHIFT	22
 
@@ -76,6 +77,11 @@
 		unsigned ie : 1;	/**< Invert Endianness. */
 		unsigned soft2 : 9;	/**< Software defined field. */
+#if defined (US)
 		unsigned diag : 9;	/**< Diagnostic data. */
 		unsigned pfn : 28;	/**< Physical Address bits, bits 40:13. */
+#elif defined (US3)
+		unsigned : 7;		/**< Reserved. */
+		unsigned pfn : 30;	/**< Physical Address bits, bits 42:13 */
+#endif
 		unsigned soft : 6;	/**< Software defined field. */
 		unsigned l : 1;		/**< Lock. */
Index: kernel/arch/sparc64/include/regdef.h
===================================================================
--- kernel/arch/sparc64/include/regdef.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/regdef.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -56,6 +56,9 @@
 #define WSTATE_OTHER(n)		((n) << 3)
 
-#define UPA_CONFIG_MID_SHIFT    17
-#define UPA_CONFIG_MID_MASK     0x1f
+/*
+ * The following definitions concern the UPA_CONFIG register on US and the
+ * FIREPLANE_CONFIG register on US3. 
+ */
+#define ICBUS_CONFIG_MID_SHIFT    17
 
 #endif
Index: kernel/arch/sparc64/include/register.h
===================================================================
--- kernel/arch/sparc64/include/register.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/register.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -118,21 +118,4 @@
 typedef union fprs_reg fprs_reg_t;
 
-/** UPA_CONFIG register.
- *
- * Note that format of this register differs significantly from
- * processor version to version. The format defined here
- * is the common subset for all supported processor versions.
- */
-union upa_config {
-	uint64_t value;
-	struct {
-		uint64_t : 34;
-		unsigned pcon : 8;	/**< Processor configuration. */
-		unsigned mid : 5;	/**< Module (processor) ID register. */
-		unsigned pcap : 17;	/**< Processor capabilities. */
-	} __attribute__ ((packed));
-};
-typedef union upa_config upa_config_t;
-
 #endif
 
Index: kernel/arch/sparc64/include/trap/interrupt.h
===================================================================
--- kernel/arch/sparc64/include/trap/interrupt.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/include/trap/interrupt.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -50,19 +50,41 @@
 
 /* Interrupt ASI registers. */
-#define ASI_UDB_INTR_W			0x77
+#define ASI_INTR_W			0x77
 #define ASI_INTR_DISPATCH_STATUS	0x48
-#define ASI_UDB_INTR_R			0x7f
+#define ASI_INTR_R			0x7f
 #define ASI_INTR_RECEIVE		0x49
 
-/* VA's used with ASI_UDB_INTR_W register. */
+/* VA's used with ASI_INTR_W register. */
+#if defined (US)
 #define ASI_UDB_INTR_W_DATA_0	0x40
 #define ASI_UDB_INTR_W_DATA_1	0x50
 #define ASI_UDB_INTR_W_DATA_2	0x60
-#define ASI_UDB_INTR_W_DISPATCH	0x70
+#elif defined (US3)
+#define VA_INTR_W_DATA_0	0x40
+#define VA_INTR_W_DATA_1	0x48
+#define VA_INTR_W_DATA_2	0x50
+#define VA_INTR_W_DATA_3	0x58
+#define VA_INTR_W_DATA_4	0x60
+#define VA_INTR_W_DATA_5	0x68
+#define VA_INTR_W_DATA_6	0x80
+#define VA_INTR_W_DATA_7	0x88
+#endif
+#define VA_INTR_W_DISPATCH	0x70
 
-/* VA's used with ASI_UDB_INTR_R register. */
+/* VA's used with ASI_INTR_R register. */
+#if defined(US)
 #define ASI_UDB_INTR_R_DATA_0	0x40
 #define ASI_UDB_INTR_R_DATA_1	0x50
 #define ASI_UDB_INTR_R_DATA_2	0x60
+#elif defined (US3)
+#define VA_INTR_R_DATA_0	0x40
+#define VA_INTR_R_DATA_1	0x48
+#define VA_INTR_R_DATA_2	0x50
+#define VA_INTR_R_DATA_3	0x58
+#define VA_INTR_R_DATA_4	0x60
+#define VA_INTR_R_DATA_5	0x68
+#define VA_INTR_R_DATA_6	0x80
+#define VA_INTR_R_DATA_7	0x88
+#endif
 
 /* Shifts in the Interrupt Vector Dispatch virtual address. */
Index: kernel/arch/sparc64/src/console.c
===================================================================
--- kernel/arch/sparc64/src/console.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/console.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -39,4 +39,6 @@
 #include <arch/drivers/kbd.h>
 
+#include <arch/drivers/sgcn.h>
+
 #ifdef CONFIG_Z8530
 #include <genarch/kbd/z8530.h>
@@ -55,21 +57,22 @@
 #include <arch.h>
 #include <panic.h>
+#include <func.h>
 #include <print.h>
 
 #define KEYBOARD_POLL_PAUSE	50000	/* 50ms */
 
-/** Initialize kernel console to use framebuffer and keyboard directly. */
-void standalone_sparc64_console_init(void)
+/**
+ * Initialize kernel console to use framebuffer and keyboard directly.
+ * Called on UltraSPARC machines with standard keyboard and framebuffer.
+ *
+ * @param aliases	the "/aliases" OBP node 
+ */
+static void standard_console_init(ofw_tree_node_t *aliases)
 {
 	stdin = NULL;
 
-	ofw_tree_node_t *aliases;
 	ofw_tree_property_t *prop;
 	ofw_tree_node_t *screen;
 	ofw_tree_node_t *keyboard;
-	
-	aliases = ofw_tree_lookup("/aliases");
-	if (!aliases)
-		panic("Can't find /aliases.\n");
 	
 	prop = ofw_tree_getprop(aliases, "screen");
@@ -96,4 +99,34 @@
 }
 
+/** Initilize I/O on the Serengeti machine. */
+static void serengeti_init(void)
+{
+	sgcn_init();
+}
+
+/**
+ * Initialize input/output. Auto-detects the type of machine
+ * and calls the appropriate I/O init routine. 
+ */
+void standalone_sparc64_console_init(void)
+{
+	ofw_tree_node_t *aliases;
+	ofw_tree_property_t *prop;
+	
+	aliases = ofw_tree_lookup("/aliases");
+	if (!aliases)
+		panic("Can't find /aliases.\n");
+	
+	/* "def-cn" = "default console" */
+	prop = ofw_tree_getprop(aliases, "def-cn");
+	
+	if ((!prop) || (!prop->value) || (strcmp(prop->value, "/sgcn") != 0)) {
+		standard_console_init(aliases);
+	} else {
+		serengeti_init();
+	}
+}
+
+
 /** Kernel thread for polling keyboard.
  *
@@ -130,4 +163,8 @@
 #endif
 #endif
+#ifdef CONFIG_SGCN
+		if (kbd_type == KBD_SGCN)
+			sgcn_poll();
+#endif
 		thread_usleep(KEYBOARD_POLL_PAUSE);
 	}
@@ -150,4 +187,9 @@
 		break;
 #endif
+#ifdef CONFIG_SGCN
+	case KBD_SGCN:
+		sgcn_grab();
+		break;
+#endif
 	default:
 		break;
@@ -171,4 +213,9 @@
 		break;
 #endif
+#ifdef CONFIG_SGCN
+	case KBD_SGCN:
+		sgcn_release();
+		break;
+#endif
 	default:
 		break;
Index: kernel/arch/sparc64/src/cpu/cpu.c
===================================================================
--- kernel/arch/sparc64/src/cpu/cpu.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/cpu/cpu.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -33,4 +33,5 @@
  */
 
+#include <arch/cpu_family.h>
 #include <cpu.h>
 #include <arch.h>
@@ -38,4 +39,37 @@
 #include <arch/drivers/tick.h>
 #include <print.h>
+#include <arch/cpu_node.h>
+
+/**
+ * Finds out the clock frequency of the current CPU.
+ *
+ * @param node	node representing the current CPU in the OFW tree
+ * @return 	clock frequency if "node" is the current CPU and no error
+ *		occurs,	-1 if "node" is not the current CPU or on error
+ */
+static int find_cpu_frequency(ofw_tree_node_t *node)
+{
+	ofw_tree_property_t *prop;
+	uint32_t mid;
+
+	/* 'upa-portid' for US, 'portid' for US-III, 'cpuid' for US-IV */
+	prop = ofw_tree_getprop(node, "upa-portid");
+	if ((!prop) || (!prop->value))
+		prop = ofw_tree_getprop(node, "portid");
+	if ((!prop) || (!prop->value))
+		prop = ofw_tree_getprop(node, "cpuid");
+	
+	if (prop && prop->value) {
+		mid = *((uint32_t *) prop->value);
+		if (mid == CPU->arch.mid) {
+			prop = ofw_tree_getprop(node, "clock-frequency");
+			if (prop && prop->value) {
+				return *((uint32_t *) prop->value);
+			}
+		}
+	}
+	
+	return -1;
+}
 
 /** Perform sparc64 specific initialization of the processor structure for the
@@ -45,32 +79,35 @@
 {
 	ofw_tree_node_t *node;
-	uint32_t mid;
 	uint32_t clock_frequency = 0;
-	upa_config_t upa_config;
 	
-	upa_config.value = upa_config_read();
-	CPU->arch.mid = upa_config.mid;
+	CPU->arch.mid = read_mid();
 	
 	/*
 	 * Detect processor frequency.
 	 */
-	node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
-	while (node) {
-		ofw_tree_property_t *prop;
+	if (is_us() || is_us_iii()) { 
+		node = ofw_tree_find_child_by_device_type(cpus_parent(), "cpu");
+		while (node) {
+			int f = find_cpu_frequency(node);
+			if (f != -1) 
+				clock_frequency = (uint32_t) f;
+			node = ofw_tree_find_peer_by_device_type(node, "cpu");
+		}
+	} else if (is_us_iv()) {
+		node = ofw_tree_find_child(cpus_parent(), "cmp");
+		while (node) {
+			int f;
+			f = find_cpu_frequency(
+				ofw_tree_find_child(node, "cpu@0"));
+			if (f != -1) 
+				clock_frequency = (uint32_t) f;
+			f = find_cpu_frequency(
+				ofw_tree_find_child(node, "cpu@1"));
+			if (f != -1) 
+				clock_frequency = (uint32_t) f;
+			node = ofw_tree_find_peer_by_name(node, "cmp");
+		}
+	}
 		
-		prop = ofw_tree_getprop(node, "upa-portid");
-		if (prop && prop->value) {
-			mid = *((uint32_t *) prop->value);
-			if (mid == CPU->arch.mid) {
-				prop = ofw_tree_getprop(node,
-				    "clock-frequency");
-				if (prop && prop->value)
-					clock_frequency = *((uint32_t *)
-					    prop->value);
-			}
-		}
-		node = ofw_tree_find_peer_by_device_type(node, "cpu");
-	}
-
 	CPU->arch.clock_frequency = clock_frequency;
 	tick_init();
@@ -125,4 +162,13 @@
 		impl = "UltraSPARC III";
 		break;
+	case IMPL_ULTRASPARCIII_PLUS:
+		impl = "UltraSPARC III+";
+		break;
+	case IMPL_ULTRASPARCIII_I:
+		impl = "UltraSPARC IIIi";
+		break;
+	case IMPL_ULTRASPARCIV:
+		impl = "UltraSPARC IV";
+		break;
 	case IMPL_ULTRASPARCIV_PLUS:
 		impl = "UltraSPARC IV+";
Index: kernel/arch/sparc64/src/ddi/ddi.c
===================================================================
--- kernel/arch/sparc64/src/ddi/ddi.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/ddi/ddi.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -42,5 +42,5 @@
  *
  * @param task Task.
- * @param ioaddr Startign I/O space address.
+ * @param ioaddr Starting I/O space address.
  * @param size Size of the enabled I/O range.
  *
Index: kernel/arch/sparc64/src/drivers/scr.c
===================================================================
--- kernel/arch/sparc64/src/drivers/scr.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/drivers/scr.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -56,4 +56,8 @@
 {
 	ofw_tree_property_t *prop;
+	ofw_pci_reg_t *pci_reg;
+	ofw_pci_reg_t pci_abs_reg;
+	ofw_upa_reg_t *upa_reg;
+	ofw_sbus_reg_t *sbus_reg;
 	const char *name;
 	
@@ -62,4 +66,6 @@
 	if (strcmp(name, "SUNW,m64B") == 0)
 		scr_type = SCR_ATYFB;
+	else if (strcmp(name, "SUNW,XVR-100") == 0)
+		scr_type = SCR_XVR;
 	else if (strcmp(name, "SUNW,ffb") == 0)
 		scr_type = SCR_FFB;
@@ -68,5 +74,5 @@
 	
 	if (scr_type == SCR_UNKNOWN) {
-		printf("Unknown keyboard device.\n");
+		printf("Unknown screen device.\n");
 		return;
 	}
@@ -107,13 +113,13 @@
 		}
 	
-		ofw_pci_reg_t *fb_reg = &((ofw_pci_reg_t *) prop->value)[1];
-		ofw_pci_reg_t abs_reg;
-		
-		if (!ofw_pci_reg_absolutize(node, fb_reg, &abs_reg)) {
+		pci_reg = &((ofw_pci_reg_t *) prop->value)[1];
+		
+		if (!ofw_pci_reg_absolutize(node, pci_reg, &pci_abs_reg)) {
 			printf("Failed to absolutize fb register.\n");
 			return;
 		}
 	
-		if (!ofw_pci_apply_ranges(node->parent, &abs_reg , &fb_addr)) {
+		if (!ofw_pci_apply_ranges(node->parent, &pci_abs_reg,
+		    &fb_addr)) {
 			printf("Failed to determine screen address.\n");
 			return;
@@ -143,10 +149,52 @@
 		
 		break;
+	case SCR_XVR:
+		if (prop->size / sizeof(ofw_pci_reg_t) < 2) {
+			printf("Too few screen registers.\n");
+			return;
+		}
+	
+		pci_reg = &((ofw_pci_reg_t *) prop->value)[1];
+		
+		if (!ofw_pci_reg_absolutize(node, pci_reg, &pci_abs_reg)) {
+			printf("Failed to absolutize fb register.\n");
+			return;
+		}
+	
+		if (!ofw_pci_apply_ranges(node->parent, &pci_abs_reg,
+		    &fb_addr)) {
+			printf("Failed to determine screen address.\n");
+			return;
+		}
+
+		switch (fb_depth) {
+		case 8:
+			fb_scanline = fb_linebytes * (fb_depth >> 3);
+			visual = VISUAL_SB1500_PALETTE;
+			break;
+		case 16:
+			fb_scanline = fb_linebytes * (fb_depth >> 3);
+			visual = VISUAL_RGB_5_6_5;
+			break;
+		case 24:
+			fb_scanline = fb_linebytes * 4;
+			visual = VISUAL_RGB_8_8_8_0;
+			break;
+		case 32:
+			fb_scanline = fb_linebytes * (fb_depth >> 3);
+			visual = VISUAL_RGB_0_8_8_8;
+			break;
+		default:
+			printf("Unsupported bits per pixel.\n");
+			return;
+		}
+		
+		break;
 	case SCR_FFB:	
 		fb_scanline = 8192;
 		visual = VISUAL_BGR_0_8_8_8;
 
-		ofw_upa_reg_t *reg = &((ofw_upa_reg_t *) prop->value)[FFB_REG_24BPP];
-		if (!ofw_upa_apply_ranges(node->parent, reg, &fb_addr)) {
+		upa_reg = &((ofw_upa_reg_t *) prop->value)[FFB_REG_24BPP];
+		if (!ofw_upa_apply_ranges(node->parent, upa_reg, &fb_addr)) {
 			printf("Failed to determine screen address.\n");
 			return;
@@ -165,6 +213,6 @@
 		}
 		
-		ofw_sbus_reg_t *cg6_reg = &((ofw_sbus_reg_t *) prop->value)[0];
-		if (!ofw_sbus_apply_ranges(node->parent, cg6_reg, &fb_addr)) {
+		sbus_reg = &((ofw_sbus_reg_t *) prop->value)[0];
+		if (!ofw_sbus_apply_ranges(node->parent, sbus_reg, &fb_addr)) {
 			printf("Failed to determine screen address.\n");
 			return;
@@ -176,5 +224,13 @@
 	}
 
-	fb_init(fb_addr, fb_width, fb_height, fb_scanline, visual);
+	fb_properties_t props = {
+		.addr = fb_addr,
+		.offset = 0,
+		.x = fb_width,
+		.y = fb_height,
+		.scan = fb_scanline,
+		.visual = visual,
+	};
+	fb_init(&props);
 }
 
Index: kernel/arch/sparc64/src/drivers/sgcn.c
===================================================================
--- kernel/arch/sparc64/src/drivers/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ kernel/arch/sparc64/src/drivers/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64
+ * @{
+ */
+/**
+ * @file
+ * @brief	SGCN driver.
+ */
+
+#include <arch/drivers/sgcn.h>
+#include <arch/drivers/kbd.h>
+#include <genarch/ofw/ofw_tree.h>
+#include <debug.h>
+#include <func.h>
+#include <print.h>
+#include <mm/page.h>
+#include <ipc/irq.h>
+#include <ddi/ddi.h>
+#include <ddi/device.h>
+#include <console/chardev.h>
+#include <console/console.h>
+#include <ddi/device.h>
+#include <sysinfo/sysinfo.h>
+#include <synch/spinlock.h>
+
+/*
+ * Physical address at which the SBBC starts. This value has been obtained
+ * by inspecting (using Simics) memory accesses made by OBP. It is valid
+ * for the Simics-simulated Serengeti machine. The author of this code is
+ * not sure whether this value is valid generally. 
+ */
+#define SBBC_START		0x63000000000
+
+/* offset of SRAM within the SBBC memory */
+#define SBBC_SRAM_OFFSET	0x900000
+
+/* size (in bytes) of the physical memory area which will be mapped */
+#define MAPPED_AREA_SIZE	(128 * 1024)
+
+/* magic string contained at the beginning of SRAM */
+#define SRAM_TOC_MAGIC		"TOCSRAM"
+
+/*
+ * Key into the SRAM table of contents which identifies the entry
+ * describing the OBP console buffer. It is worth mentioning
+ * that the OBP console buffer is not the only console buffer
+ * which can be used. It is, however, used because when the kernel
+ * is running, the OBP buffer is not used by OBP any more but OBP
+ * has already made neccessary arangements so that the output will
+ * be read from the OBP buffer and input will go to the OBP buffer.
+ * Therefore HelenOS needs to make no such arrangements any more.
+ */
+#define CONSOLE_KEY		"OBPCONS"
+
+/* magic string contained at the beginning of the console buffer */
+#define SGCN_BUFFER_MAGIC	"CON"
+
+/**
+ * The driver is polling based, but in order to notify the userspace
+ * of a key being pressed, we need to supply the interface with some
+ * interrupt number. The interrupt number can be arbitrary as it it
+ * will never be used for identifying HW interrupts, but only in
+ * notifying the userspace. 
+ */
+#define FICTIONAL_INR		1
+
+
+/*
+ * Returns a pointer to the object of a given type which is placed at the given
+ * offset from the SRAM beginning.
+ */
+#define SRAM(type, offset)	((type *) (sram_begin + (offset)))
+
+/* Returns a pointer to the SRAM table of contents. */
+#define SRAM_TOC		(SRAM(iosram_toc_t, 0))
+
+/*
+ * Returns a pointer to the object of a given type which is placed at the given
+ * offset from the console buffer beginning.
+ */
+#define SGCN_BUFFER(type, offset) \
+				((type *) (sgcn_buffer_begin + (offset)))
+
+/** Returns a pointer to the console buffer header. */
+#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
+/** defined in drivers/kbd.c */
+extern kbd_type_t kbd_type;
+
+/** starting address of SRAM, will be set by the init_sram_begin function */
+static uintptr_t sram_begin;
+
+/**
+ * starting address of the SGCN buffer, will be set by the
+ * init_sgcn_buffer_begin function
+ */
+static uintptr_t sgcn_buffer_begin;
+
+/**
+ * SGCN IRQ structure. So far used only for notifying the userspace of the
+ * key being pressed, not for kernel being informed about keyboard interrupts.
+ */ 
+static irq_t sgcn_irq;
+
+// TODO think of a way how to synchronize accesses to SGCN buffer between the kernel and the userspace
+
+/* 
+ * Ensures that writing to the buffer and consequent update of the write pointer
+ * are together one atomic operation.
+ */
+SPINLOCK_INITIALIZE(sgcn_output_lock);
+
+/* 
+ * Prevents the input buffer read/write pointers from getting to inconsistent
+ * state. 
+ */
+SPINLOCK_INITIALIZE(sgcn_input_lock);
+
+
+/* functions referenced from definitions of I/O operations structures */
+static void sgcn_noop(chardev_t *);
+static void sgcn_putchar(chardev_t *, const char);
+static char sgcn_key_read(chardev_t *);
+
+/** character device operations */
+static chardev_operations_t sgcn_ops = {
+	.suspend = sgcn_noop,
+	.resume = sgcn_noop,
+	.read = sgcn_key_read,
+	.write = sgcn_putchar
+};
+
+/** SGCN character device */
+chardev_t sgcn_io;
+
+/**
+ * Registers the physical area of the SRAM so that the userspace SGCN
+ * driver can map it. Moreover, it sets some sysinfo values (SRAM address
+ * and SRAM size).
+ */
+static void register_sram_parea(uintptr_t sram_begin_physical)
+{
+	static parea_t sram_parea;
+	sram_parea.pbase = sram_begin_physical;
+	sram_parea.vbase = (uintptr_t) sram_begin;
+	sram_parea.frames = MAPPED_AREA_SIZE / FRAME_SIZE;
+	sram_parea.cacheable = false;
+	ddi_parea_register(&sram_parea);
+	
+	sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
+	sysinfo_set_item_val("sram.address.physical", NULL,
+		sram_begin_physical);
+}
+
+/**
+ * Initializes the starting address of SRAM.
+ *
+ * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
+ * physical memory, where C is the value read from the "iosram-toc"
+ * property of the "/chosen" OBP node. The sram_begin variable will
+ * be set to the virtual address which maps to the SRAM physical
+ * address.
+ *
+ * It also registers the physical area of SRAM and sets some sysinfo
+ * values (SRAM address and SRAM size).
+ */
+static void init_sram_begin(void)
+{
+	ofw_tree_node_t *chosen;
+	ofw_tree_property_t *iosram_toc;
+	uintptr_t sram_begin_physical;
+
+	chosen = ofw_tree_lookup("/chosen");
+	if (!chosen)
+		panic("Can't find /chosen.\n");
+
+	iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
+	if (!iosram_toc)
+		panic("Can't find property \"iosram-toc\".\n");
+	if (!iosram_toc->value)
+		panic("Can't find SRAM TOC.\n");
+
+	sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
+		+ *((uint32_t *) iosram_toc->value);
+	sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
+	
+	register_sram_parea(sram_begin_physical);
+}
+
+/**
+ * Initializes the starting address of the SGCN buffer.
+ *
+ * The offset of the SGCN buffer within SRAM is obtained from the
+ * SRAM table of contents. The table of contents contains
+ * information about several buffers, among which there is an OBP
+ * console buffer - this one will be used as the SGCN buffer. 
+ *
+ * This function also writes the offset of the SGCN buffer within SRAM
+ * under the sram.buffer.offset sysinfo key.
+ */
+static void sgcn_buffer_begin_init(void)
+{
+	init_sram_begin();
+		
+	ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
+	
+	/* lookup TOC entry with the correct key */
+	uint32_t i;
+	for (i = 0; i < MAX_TOC_ENTRIES; i++) {
+		if (strcmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
+			break;
+	}
+	ASSERT(i < MAX_TOC_ENTRIES);
+	
+	sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
+	
+	sysinfo_set_item_val("sram.buffer.offset", NULL,
+		SRAM_TOC->keys[i].offset);
+}
+
+/**
+ * Default suspend/resume operation for the input device.
+ */
+static void sgcn_noop(chardev_t *d)
+{
+}
+
+/**
+ * Writes a single character to the SGCN (circular) output buffer
+ * and updates the output write pointer so that SGCN gets to know
+ * that the character has been written.
+ */
+static void sgcn_do_putchar(const char c)
+{
+	uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->out_end;
+	uint32_t size = end - begin;
+	
+	/* we need pointers to volatile variables */
+	volatile char *buf_ptr = (volatile char *)
+		SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
+	volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
+	volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
+
+	/*
+	 * Write the character and increment the write pointer modulo the
+	 * output buffer size. Note that if we are to rewrite a character
+	 * which has not been read by the SGCN controller yet (i.e. the output
+	 * buffer is full), we need to wait until the controller reads some more
+	 * characters. We wait actively, which means that all threads waiting
+	 * for the lock are blocked. However, this situation is
+	 *   1) rare - the output buffer is big, so filling the whole
+	 *             output buffer is improbable
+	 *   2) short-lasting - it will take the controller only a fraction
+	 *             of millisecond to pick the unread characters up
+	 *   3) not serious - the blocked threads are those that print something
+	 *             to user console, which is not a time-critical operation
+	 */
+	uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
+	while (*out_rdptr_ptr == new_wrptr)
+		;
+	*buf_ptr = c;
+	*out_wrptr_ptr = new_wrptr;
+}
+
+/**
+ * SGCN output operation. Prints a single character to the SGCN. If the line
+ * feed character is written ('\n'), the carriage return character ('\r') is
+ * written straight away. 
+ */
+static void sgcn_putchar(struct chardev * cd, const char c)
+{
+	spinlock_lock(&sgcn_output_lock);
+	
+	sgcn_do_putchar(c);
+	if (c == '\n') {
+		sgcn_do_putchar('\r');
+	}
+	
+	spinlock_unlock(&sgcn_output_lock);
+}
+
+/**
+ * Called when actively reading the character. Not implemented yet.
+ */
+static char sgcn_key_read(chardev_t *d)
+{
+	return (char) 0;
+}
+
+/**
+ * The driver works in polled mode, so no interrupt should be handled by it.
+ */
+static irq_ownership_t sgcn_claim(void)
+{
+	return IRQ_DECLINE;
+}
+
+/**
+ * The driver works in polled mode, so no interrupt should be handled by it.
+ */
+static void sgcn_irq_handler(irq_t *irq, void *arg, ...)
+{
+	panic("Not yet implemented, SGCN works in polled mode.\n");
+}
+
+/**
+ * Grabs the input for kernel.
+ */
+void sgcn_grab(void)
+{
+	ipl_t ipl = interrupts_disable();
+	
+	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
+	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
+	
+	/* skip all the user typed before the grab and hasn't been processed */
+	spinlock_lock(&sgcn_input_lock);
+	*in_rdptr_ptr = *in_wrptr_ptr;
+	spinlock_unlock(&sgcn_input_lock);
+
+	spinlock_lock(&sgcn_irq.lock);
+	sgcn_irq.notif_cfg.notify = false;
+	spinlock_unlock(&sgcn_irq.lock);
+	
+	interrupts_restore(ipl);
+}
+
+/**
+ * Releases the input so that userspace can use it.
+ */
+void sgcn_release(void)
+{
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sgcn_irq.lock);
+	if (sgcn_irq.notif_cfg.answerbox)
+		sgcn_irq.notif_cfg.notify = true;
+	spinlock_unlock(&sgcn_irq.lock);
+	interrupts_restore(ipl);
+}
+
+/**
+ * Function regularly called by the keyboard polling thread. Finds out whether
+ * there are some unread characters in the input queue. If so, it picks them up
+ * and sends them to the upper layers of HelenOS.
+ */
+void sgcn_poll(void)
+{
+	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->in_end;
+	uint32_t size = end - begin;
+	
+	spinlock_lock(&sgcn_input_lock);
+	
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&sgcn_irq.lock);
+	
+	/* we need pointers to volatile variables */
+	volatile char *buf_ptr = (volatile char *)
+		SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
+	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
+	
+	if (*in_rdptr_ptr != *in_wrptr_ptr) {
+		if (sgcn_irq.notif_cfg.notify && sgcn_irq.notif_cfg.answerbox) {
+			ipc_irq_send_notif(&sgcn_irq);
+			spinlock_unlock(&sgcn_irq.lock);
+			interrupts_restore(ipl);
+			spinlock_unlock(&sgcn_input_lock);
+			return;
+		}
+	}
+	
+	spinlock_unlock(&sgcn_irq.lock);
+	interrupts_restore(ipl);	
+
+	while (*in_rdptr_ptr != *in_wrptr_ptr) {
+		
+		buf_ptr = (volatile char *)
+			SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+		char c = *buf_ptr;
+		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
+			
+		if (c == '\r') {
+			c = '\n';
+		}
+		chardev_push_character(&sgcn_io, c);	
+	}	
+	
+	spinlock_unlock(&sgcn_input_lock);
+}
+
+/**
+ * A public function which initializes I/O from/to Serengeti console
+ * and sets it as a default input/output. 
+ */
+void sgcn_init(void)
+{
+	sgcn_buffer_begin_init();
+
+	kbd_type = KBD_SGCN;
+
+	devno_t devno = device_assign_devno();
+	irq_initialize(&sgcn_irq);
+	sgcn_irq.devno = devno;
+	sgcn_irq.inr = FICTIONAL_INR;
+	sgcn_irq.claim = sgcn_claim;
+	sgcn_irq.handler = sgcn_irq_handler;
+	irq_register(&sgcn_irq);
+	
+	sysinfo_set_item_val("kbd", NULL, true);
+	sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
+	sysinfo_set_item_val("kbd.devno", NULL, devno);
+	sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
+	sysinfo_set_item_val("fb.kind", NULL, 4);
+	
+	chardev_initialize("sgcn_io", &sgcn_io, &sgcn_ops);
+	stdin = &sgcn_io;
+	stdout = &sgcn_io;
+}
+
+/** @}
+ */
Index: kernel/arch/sparc64/src/drivers/tick.c
===================================================================
--- kernel/arch/sparc64/src/drivers/tick.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/drivers/tick.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -46,9 +46,10 @@
 #define TICK_RESTART_TIME	50	/* Worst case estimate. */
 
-/** Initialize tick interrupt. */
+/** Initialize tick and stick interrupt. */
 void tick_init(void)
 {
+	/* initialize TICK interrupt */
 	tick_compare_reg_t compare;
-	
+
 	interrupt_register(14, "tick_int", tick_interrupt);
 	compare.int_dis = false;
@@ -57,4 +58,19 @@
 	tick_compare_write(compare.value);
 	tick_write(0);
+
+#if defined (US3)
+	/* disable STICK interrupts and clear any pending ones */
+	tick_compare_reg_t stick_compare;
+	softint_reg_t clear;
+
+	stick_compare.value = stick_compare_read();
+	stick_compare.int_dis = true;
+	stick_compare.tick_cmpr = 0;
+	stick_compare_write(stick_compare.value);
+
+	clear.value = 0;
+	clear.stick_int = 1;
+	clear_softint_write(clear.value);
+#endif
 }
 
@@ -68,5 +84,5 @@
 	softint_reg_t softint, clear;
 	uint64_t drift;
-	
+
 	softint.value = softint_read();
 	
Index: kernel/arch/sparc64/src/mm/as.c
===================================================================
--- kernel/arch/sparc64/src/mm/as.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/mm/as.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -165,4 +165,22 @@
 	tsb_base.base = ((uintptr_t) as->arch.dtsb) >> MMU_PAGE_WIDTH;
 	dtsb_base_write(tsb_base.value);
+	
+#if defined (US3)
+	/*
+	 * Clear the extension registers.
+	 * In HelenOS, primary and secondary context registers contain
+	 * equal values and kernel misses (context 0, ie. the nucleus context)
+	 * are excluded from the TSB miss handler, so it makes no sense
+	 * to have separate TSBs for primary, secondary and nucleus contexts.
+	 * Clearing the extension registers will ensure that the value of the
+	 * TSB Base register will be used as an address of TSB, making the code
+	 * compatible with the US port. 
+	 */
+	itsb_primary_extension_write(0);
+	itsb_nucleus_extension_write(0);
+	dtsb_primary_extension_write(0);
+	dtsb_secondary_extension_write(0);
+	dtsb_nucleus_extension_write(0);
+#endif
 #endif
 }
Index: kernel/arch/sparc64/src/mm/cache.S
===================================================================
--- kernel/arch/sparc64/src/mm/cache.S	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/mm/cache.S	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -48,44 +48,2 @@
 	! beware SF Erratum #51, do not put the MEMBAR here
 	nop				
-
-/** Flush only D-cache lines of one virtual color.
- *
- * @param o0	Virtual color to be flushed.
- */
-.global dcache_flush_color
-dcache_flush_color:
-	mov (DCACHE_SIZE / DCACHE_LINE_SIZE) / 2, %g1
-	set DCACHE_SIZE / 2, %g2
-	sllx %g2, %o0, %g2
-	sub %g2, DCACHE_LINE_SIZE, %g2
-0:	stxa %g0, [%g2] ASI_DCACHE_TAG
-	membar #Sync
-	subcc %g1, 1, %g1
-	bnz,pt %xcc, 0b
-	sub %g2, DCACHE_LINE_SIZE, %g2
-	retl
-	nop
-
-/** Flush only D-cache lines of one virtual color and one tag.
- *
- * @param o0	Virtual color to lookup the tag.
- * @param o1	Tag of the cachelines to be flushed.
- */
-.global dcache_flush_tag
-dcache_flush_tag:
-	mov (DCACHE_SIZE / DCACHE_LINE_SIZE) / 2, %g1
-	set DCACHE_SIZE / 2, %g2
-	sllx %g2, %o0, %g2
-	sub %g2, DCACHE_LINE_SIZE, %g2
-0:	ldxa [%g2] ASI_DCACHE_TAG, %g3
-	srlx %g3, DCACHE_TAG_SHIFT, %g3
-	cmp %g3, %o1
-	bnz 1f
-	nop
-	stxa %g0, [%g2] ASI_DCACHE_TAG
-	membar #Sync
-1:	subcc %g1, 1, %g1
-	bnz,pt %xcc, 0b
-	sub %g2, DCACHE_LINE_SIZE, %g2
-	retl
-	nop
Index: kernel/arch/sparc64/src/mm/page.c
===================================================================
--- kernel/arch/sparc64/src/mm/page.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/mm/page.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -53,5 +53,5 @@
 	uintptr_t phys_page;
 	int pagesize_code;
-} bsp_locked_dtlb_entry[DTLB_ENTRY_COUNT];
+} bsp_locked_dtlb_entry[DTLB_MAX_LOCKED_ENTRIES];
 
 /** Number of entries in bsp_locked_dtlb_entry array. */
@@ -167,2 +167,3 @@
 /** @}
  */
+
Index: kernel/arch/sparc64/src/mm/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/tlb.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/mm/tlb.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -55,12 +55,11 @@
 #endif
 
-static void dtlb_pte_copy(pte_t *t, index_t index, bool ro);
-static void itlb_pte_copy(pte_t *t, index_t index);
-static void do_fast_instruction_access_mmu_miss_fault(istate_t *istate,
-    const char *str);
-static void do_fast_data_access_mmu_miss_fault(istate_t *istate,
-    tlb_tag_access_reg_t tag, const char *str);
-static void do_fast_data_access_protection_fault(istate_t *istate,
-    tlb_tag_access_reg_t tag, const char *str);
+static void dtlb_pte_copy(pte_t *, index_t, bool);
+static void itlb_pte_copy(pte_t *, index_t);
+static void do_fast_instruction_access_mmu_miss_fault(istate_t *, const char *);
+static void do_fast_data_access_mmu_miss_fault(istate_t *, tlb_tag_access_reg_t,
+    const char *);
+static void do_fast_data_access_protection_fault(istate_t *,
+    tlb_tag_access_reg_t, const char *);
 
 char *context_encoding[] = {
@@ -87,9 +86,9 @@
 /** Insert privileged mapping into DMMU TLB.
  *
- * @param page Virtual page address.
- * @param frame Physical frame address.
- * @param pagesize Page size.
- * @param locked True for permanent mappings, false otherwise.
- * @param cacheable True if the mapping is cacheable, false otherwise.
+ * @param page		Virtual page address.
+ * @param frame		Physical frame address.
+ * @param pagesize	Page size.
+ * @param locked	True for permanent mappings, false otherwise.
+ * @param cacheable	True if the mapping is cacheable, false otherwise.
  */
 void dtlb_insert_mapping(uintptr_t page, uintptr_t frame, int pagesize,
@@ -104,5 +103,5 @@
 	fr.address = frame;
 
-	tag.value = ASID_KERNEL;
+	tag.context = ASID_KERNEL;
 	tag.vpn = pg.vpn;
 
@@ -127,8 +126,8 @@
 /** Copy PTE to TLB.
  *
- * @param t 	Page Table Entry to be copied.
- * @param index	Zero if lower 8K-subpage, one if higher 8K-subpage.
- * @param ro 	If true, the entry will be created read-only, regardless of its
- * 		w field.
+ * @param t 		Page Table Entry to be copied.
+ * @param index		Zero if lower 8K-subpage, one if higher 8K-subpage.
+ * @param ro		If true, the entry will be created read-only, regardless
+ * 			of its w field.
  */
 void dtlb_pte_copy(pte_t *t, index_t index, bool ro)
@@ -166,6 +165,6 @@
 /** Copy PTE to ITLB.
  *
- * @param t 	Page Table Entry to be copied.
- * @param index	Zero if lower 8K-subpage, one if higher 8K-subpage.
+ * @param t		Page Table Entry to be copied.
+ * @param index		Zero if lower 8K-subpage, one if higher 8K-subpage.
  */
 void itlb_pte_copy(pte_t *t, index_t index)
@@ -236,8 +235,9 @@
  * low-level, assembly language part of the fast_data_access_mmu_miss handler.
  *
- * @param tag Content of the TLB Tag Access register as it existed when the
- *    trap happened. This is to prevent confusion created by clobbered
- *    Tag Access register during a nested DTLB miss.
- * @param istate Interrupted state saved on the stack.
+ * @param tag		Content of the TLB Tag Access register as it existed
+ * 			when the trap happened. This is to prevent confusion
+ * 			created by clobbered Tag Access register during a nested
+ * 			DTLB miss.
+ * @param istate	Interrupted state saved on the stack.
  */
 void fast_data_access_mmu_miss(tlb_tag_access_reg_t tag, istate_t *istate)
@@ -288,8 +288,9 @@
 /** DTLB protection fault handler.
  *
- * @param tag Content of the TLB Tag Access register as it existed when the
- *    trap happened. This is to prevent confusion created by clobbered
- *    Tag Access register during a nested DTLB miss.
- * @param istate Interrupted state saved on the stack.
+ * @param tag		Content of the TLB Tag Access register as it existed
+ * 			when the trap happened. This is to prevent confusion
+ * 			created by clobbered Tag Access register during a nested
+ * 			DTLB miss.
+ * @param istate	Interrupted state saved on the stack.
  */
 void fast_data_access_protection(tlb_tag_access_reg_t tag, istate_t *istate)
@@ -332,4 +333,24 @@
 }
 
+/** Print TLB entry (for debugging purposes).
+ *
+ * The diag field has been left out in order to make this function more generic
+ * (there is no diag field in US3 architeture). 
+ *
+ * @param i		TLB entry number 
+ * @param t		TLB entry tag
+ * @param d		TLB entry data 
+ */
+static void print_tlb_entry(int i, tlb_tag_read_reg_t t, tlb_data_t d)
+{
+	printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, "
+	    "ie=%d, soft2=%#x, pfn=%#x, soft=%#x, l=%d, "
+	    "cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n", i, t.vpn,
+	    t.context, d.v, d.size, d.nfo, d.ie, d.soft2,
+	    d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
+}
+
+#if defined (US)
+
 /** Print contents of both TLBs. */
 void tlb_print(void)
@@ -343,10 +364,5 @@
 		d.value = itlb_data_access_read(i);
 		t.value = itlb_tag_read_read(i);
-
-		printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, "
-		    "ie=%d, soft2=%#x, diag=%#x, pfn=%#x, soft=%#x, l=%d, "
-		    "cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n", i, t.vpn,
-		    t.context, d.v, d.size, d.nfo, d.ie, d.soft2, d.diag,
-		    d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
+		print_tlb_entry(i, t, d);
 	}
 
@@ -355,13 +371,54 @@
 		d.value = dtlb_data_access_read(i);
 		t.value = dtlb_tag_read_read(i);
-		
-		printf("%d: vpn=%#llx, context=%d, v=%d, size=%d, nfo=%d, "
-		    "ie=%d, soft2=%#x, diag=%#x, pfn=%#x, soft=%#x, l=%d, "
-		    "cp=%d, cv=%d, e=%d, p=%d, w=%d, g=%d\n", i, t.vpn,
-		    t.context, d.v, d.size, d.nfo, d.ie, d.soft2, d.diag,
-		    d.pfn, d.soft, d.l, d.cp, d.cv, d.e, d.p, d.w, d.g);
-	}
-
-}
+		print_tlb_entry(i, t, d);
+	}
+}
+
+#elif defined (US3)
+
+/** Print contents of all TLBs. */
+void tlb_print(void)
+{
+	int i;
+	tlb_data_t d;
+	tlb_tag_read_reg_t t;
+	
+	printf("TLB_ISMALL contents:\n");
+	for (i = 0; i < tlb_ismall_size(); i++) {
+		d.value = dtlb_data_access_read(TLB_ISMALL, i);
+		t.value = dtlb_tag_read_read(TLB_ISMALL, i);
+		print_tlb_entry(i, t, d);
+	}
+	
+	printf("TLB_IBIG contents:\n");
+	for (i = 0; i < tlb_ibig_size(); i++) {
+		d.value = dtlb_data_access_read(TLB_IBIG, i);
+		t.value = dtlb_tag_read_read(TLB_IBIG, i);
+		print_tlb_entry(i, t, d);
+	}
+	
+	printf("TLB_DSMALL contents:\n");
+	for (i = 0; i < tlb_dsmall_size(); i++) {
+		d.value = dtlb_data_access_read(TLB_DSMALL, i);
+		t.value = dtlb_tag_read_read(TLB_DSMALL, i);
+		print_tlb_entry(i, t, d);
+	}
+	
+	printf("TLB_DBIG_1 contents:\n");
+	for (i = 0; i < tlb_dbig_size(); i++) {
+		d.value = dtlb_data_access_read(TLB_DBIG_0, i);
+		t.value = dtlb_tag_read_read(TLB_DBIG_0, i);
+		print_tlb_entry(i, t, d);
+	}
+	
+	printf("TLB_DBIG_2 contents:\n");
+	for (i = 0; i < tlb_dbig_size(); i++) {
+		d.value = dtlb_data_access_read(TLB_DBIG_1, i);
+		t.value = dtlb_tag_read_read(TLB_DBIG_1, i);
+		print_tlb_entry(i, t, d);
+	}
+}
+
+#endif
 
 void do_fast_instruction_access_mmu_miss_fault(istate_t *istate,
@@ -412,11 +469,50 @@
 	sfar = dtlb_sfar_read();
 	
+#if defined (US)
 	printf("DTLB SFSR: asi=%#x, ft=%#x, e=%d, ct=%d, pr=%d, w=%d, ow=%d, "
 	    "fv=%d\n", sfsr.asi, sfsr.ft, sfsr.e, sfsr.ct, sfsr.pr, sfsr.w,
 	    sfsr.ow, sfsr.fv);
+#elif defined (US3)
+	printf("DTLB SFSR: nf=%d, asi=%#x, tm=%d, ft=%#x, e=%d, ct=%d, pr=%d, "
+	    "w=%d, ow=%d, fv=%d\n", sfsr.nf, sfsr.asi, sfsr.tm, sfsr.ft,
+	    sfsr.e, sfsr.ct, sfsr.pr, sfsr.w, sfsr.ow, sfsr.fv);
+#endif
+	    
 	printf("DTLB SFAR: address=%p\n", sfar);
 	
 	dtlb_sfsr_write(0);
 }
+
+#if defined (US3)
+/** Invalidates given TLB entry if and only if it is non-locked or global.
+ * 
+ * @param tlb		TLB number (one of TLB_DSMALL, TLB_DBIG_0, TLB_DBIG_1,
+ *			TLB_ISMALL, TLB_IBIG).
+ * @param entry		Entry index within the given TLB.
+ */
+static void tlb_invalidate_entry(int tlb, index_t entry)
+{
+	tlb_data_t d;
+	tlb_tag_read_reg_t t;
+	
+	if (tlb == TLB_DSMALL || tlb == TLB_DBIG_0 || tlb == TLB_DBIG_1) {
+		d.value = dtlb_data_access_read(tlb, entry);
+		if (!d.l || d.g) {
+			t.value = dtlb_tag_read_read(tlb, entry);
+			d.v = false;
+			dtlb_tag_access_write(t.value);
+			dtlb_data_access_write(tlb, entry, d.value);
+		}
+	} else if (tlb == TLB_ISMALL || tlb == TLB_IBIG) {
+		d.value = itlb_data_access_read(tlb, entry);
+		if (!d.l || d.g) {
+			t.value = itlb_tag_read_read(tlb, entry);
+			d.v = false;
+			itlb_tag_access_write(t.value);
+			itlb_data_access_write(tlb, entry, d.value);
+		}
+	}
+}
+#endif
 
 /** Invalidate all unlocked ITLB and DTLB entries. */
@@ -424,15 +520,17 @@
 {
 	int i;
-	tlb_data_t d;
-	tlb_tag_read_reg_t t;
-
+	
 	/*
 	 * Walk all ITLB and DTLB entries and remove all unlocked mappings.
 	 *
 	 * The kernel doesn't use global mappings so any locked global mappings
-	 * found  must have been created by someone else. Their only purpose now
+	 * found must have been created by someone else. Their only purpose now
 	 * is to collide with proper mappings. Invalidate immediately. It should
 	 * be safe to invalidate them as late as now.
 	 */
+
+#if defined (US)
+	tlb_data_t d;
+	tlb_tag_read_reg_t t;
 
 	for (i = 0; i < ITLB_ENTRY_COUNT; i++) {
@@ -445,5 +543,5 @@
 		}
 	}
-	
+
 	for (i = 0; i < DTLB_ENTRY_COUNT; i++) {
 		d.value = dtlb_data_access_read(i);
@@ -455,5 +553,19 @@
 		}
 	}
-	
+
+#elif defined (US3)
+
+	for (i = 0; i < tlb_ismall_size(); i++)
+		tlb_invalidate_entry(TLB_ISMALL, i);
+	for (i = 0; i < tlb_ibig_size(); i++)
+		tlb_invalidate_entry(TLB_IBIG, i);
+	for (i = 0; i < tlb_dsmall_size(); i++)
+		tlb_invalidate_entry(TLB_DSMALL, i);
+	for (i = 0; i < tlb_dbig_size(); i++)
+		tlb_invalidate_entry(TLB_DBIG_0, i);
+	for (i = 0; i < tlb_dbig_size(); i++)
+		tlb_invalidate_entry(TLB_DBIG_1, i);
+#endif
+
 }
 
@@ -485,7 +597,7 @@
  * address space.
  *
- * @param asid Address Space ID.
- * @param page First page which to sweep out from ITLB and DTLB.
- * @param cnt Number of ITLB and DTLB entries to invalidate.
+ * @param asid		Address Space ID.
+ * @param page		First page which to sweep out from ITLB and DTLB.
+ * @param cnt		Number of ITLB and DTLB entries to invalidate.
  */
 void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt)
Index: kernel/arch/sparc64/src/mm/tsb.c
===================================================================
--- kernel/arch/sparc64/src/mm/tsb.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/mm/tsb.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -113,7 +113,7 @@
 	tsb->data.size = PAGESIZE_8K;
 	tsb->data.pfn = (t->frame >> MMU_FRAME_WIDTH) + index;
-	tsb->data.cp = t->c;
-	tsb->data.p = t->k;		/* p as privileged */
-	tsb->data.v = t->p;
+	tsb->data.cp = t->c;	/* cp as cache in phys.-idxed, c as cacheable */
+	tsb->data.p = t->k;	/* p as privileged, k as kernel */
+	tsb->data.v = t->p;	/* v as valid, p as present */
 	
 	write_barrier();
@@ -174,2 +174,3 @@
 /** @}
  */
+
Index: kernel/arch/sparc64/src/smp/ipi.c
===================================================================
--- kernel/arch/sparc64/src/smp/ipi.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/smp/ipi.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -47,4 +47,31 @@
 #include <panic.h>
 
+/** Set the contents of the outgoing interrupt vector data.
+ *
+ * The first data item (data 0) will be set to the value of func, the
+ * rest of the vector will contain zeros.
+ *
+ * This is a helper function used from within the cross_call function.
+ *
+ * @param func value the first data item of the vector will be set to
+ */
+static inline void set_intr_w_data(void (* func)(void))
+{
+#if defined (US)
+	asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_0, (uintptr_t) func);
+	asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_1, 0);
+	asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_2, 0);
+#elif defined (US3)
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_0, (uintptr_t)	func);
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_1, 0);
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_2, 0);
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_3, 0);
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_4, 0);
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_5, 0);
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_6, 0);
+	asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_7, 0);
+#endif
+}
+
 /** Invoke function on another processor.
  *
@@ -74,12 +101,11 @@
 		panic("Interrupt Dispatch Status busy bit set\n");
 	
+	ASSERT(!(pstate_read() & PSTATE_IE_BIT));
+	
 	do {
-		asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_0,
-		    (uintptr_t)	func);
-		asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_1, 0);
-		asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_2, 0);
-		asi_u64_write(ASI_UDB_INTR_W,
+		set_intr_w_data(func);
+		asi_u64_write(ASI_INTR_W,
 		    (mid << INTR_VEC_DISPATCH_MID_SHIFT) |
-		    ASI_UDB_INTR_W_DISPATCH, 0);
+		    VA_INTR_W_DISPATCH, 0);
 	
 		membar();
Index: kernel/arch/sparc64/src/smp/smp.c
===================================================================
--- kernel/arch/sparc64/src/smp/smp.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/smp/smp.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -36,4 +36,5 @@
 #include <genarch/ofw/ofw_tree.h>
 #include <cpu.h>
+#include <arch/cpu_family.h>
 #include <arch/cpu.h>
 #include <arch.h>
@@ -44,4 +45,5 @@
 #include <synch/waitq.h>
 #include <print.h>
+#include <arch/cpu_node.h>
 
 /**
@@ -62,11 +64,51 @@
 	count_t cnt = 0;
 	
-	node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
-	while (node) {
-		cnt++;
-		node = ofw_tree_find_peer_by_device_type(node, "cpu");
+	if (is_us() || is_us_iii()) {
+		node = ofw_tree_find_child_by_device_type(cpus_parent(), "cpu");
+		while (node) {
+			cnt++;
+			node = ofw_tree_find_peer_by_device_type(node, "cpu");
+		}
+	} else if (is_us_iv()) {
+		node = ofw_tree_find_child(cpus_parent(), "cmp");
+		while (node) {
+			cnt += 2;
+			node = ofw_tree_find_peer_by_name(node, "cmp");
+		}
 	}
 	
 	config.cpu_count = max(1, cnt);
+}
+
+/**
+ * Wakes up the CPU which is represented by the "node" OFW tree node.
+ * If "node" represents the current CPU, calling the function has
+ * no effect. 
+ */
+static void wakeup_cpu(ofw_tree_node_t *node)
+{
+	uint32_t mid;
+	ofw_tree_property_t *prop;
+		
+	/* 'upa-portid' for US, 'portid' for US-III, 'cpuid' for US-IV */
+	prop = ofw_tree_getprop(node, "upa-portid");
+	if ((!prop) || (!prop->value))
+		prop = ofw_tree_getprop(node, "portid");
+	if ((!prop) || (!prop->value))
+		prop = ofw_tree_getprop(node, "cpuid");
+		
+	if (!prop || prop->value == NULL)
+		return;
+		
+	mid = *((uint32_t *) prop->value);
+	if (CPU->arch.mid == mid)
+		return;
+
+	waking_up_mid = mid;
+		
+	if (waitq_sleep_timeout(&ap_completion_wq, 1000000, SYNCH_FLAGS_NONE) ==
+	    ESYNCH_TIMEOUT)
+		printf("%s: waiting for processor (mid = %" PRIu32
+		    ") timed out\n", __func__, mid);
 }
 
@@ -77,29 +119,16 @@
 	int i;
 	
-	node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
-	for (i = 0; node; node = ofw_tree_find_peer_by_device_type(node, "cpu"), i++) {
-		uint32_t mid;
-		ofw_tree_property_t *prop;
-		
-		prop = ofw_tree_getprop(node, "upa-portid");
-		if (!prop || !prop->value)
-			continue;
-		
-		mid = *((uint32_t *) prop->value);
-		if (CPU->arch.mid == mid) {
-			/*
-			 * Skip the current CPU.
-			 */
-			continue;
+	if (is_us() || is_us_iii()) {
+		node = ofw_tree_find_child_by_device_type(cpus_parent(), "cpu");
+		for (i = 0; node;
+                     node = ofw_tree_find_peer_by_device_type(node, "cpu"), i++)
+			wakeup_cpu(node);
+	} else if (is_us_iv()) {
+		node = ofw_tree_find_child(cpus_parent(), "cmp");
+		while (node) {
+			wakeup_cpu(ofw_tree_find_child(node, "cpu@0"));
+			wakeup_cpu(ofw_tree_find_child(node, "cpu@1"));
+			node = ofw_tree_find_peer_by_name(node, "cmp");
 		}
-
-		/*
-		 * Processor with ID == mid can proceed with its initialization.
-		 */
-		waking_up_mid = mid;
-		
-		if (waitq_sleep_timeout(&ap_completion_wq, 1000000, SYNCH_FLAGS_NONE) == ESYNCH_TIMEOUT)
-			printf("%s: waiting for processor (mid = %" PRIu32 ") timed out\n",
-			    __func__, mid);
 	}
 }
Index: kernel/arch/sparc64/src/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sparc64.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/sparc64.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -87,5 +87,5 @@
 		 */
 		irq_init(1 << 11, 128);
-		
+
 		standalone_sparc64_console_init();
 	}
Index: kernel/arch/sparc64/src/start.S
===================================================================
--- kernel/arch/sparc64/src/start.S	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/start.S	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -28,4 +28,5 @@
 
 #include <arch/arch.h>
+#include <arch/cpu.h>
 #include <arch/regdef.h>
 #include <arch/boot/boot.h>
@@ -46,4 +47,14 @@
 
 #define BSP_FLAG	1
+
+/*
+ * 2^PHYSMEM_ADDR_SIZE is the size of the physical address space on
+ * a given processor.
+ */
+#if defined (US)
+    #define PHYSMEM_ADDR_SIZE	41
+#elif defined (US3)
+    #define PHYSMEM_ADDR_SIZE	43
+#endif
 
 /*
@@ -68,8 +79,10 @@
 	andn %o0, %l0, %l6			! l6 <= start of physical memory
 
-	! Get bits 40:13 of physmem_base.
+	! Get bits (PHYSMEM_ADDR_SIZE - 1):13 of physmem_base.
 	srlx %l6, 13, %l5
-	sllx %l5, 13 + (63 - 40), %l5
-	srlx %l5, 63 - 40, %l5			! l5 <= physmem_base[40:13]
+	
+	! l5 <= physmem_base[(PHYSMEM_ADDR_SIZE - 1):13]
+	sllx %l5, 13 + (63 - (PHYSMEM_ADDR_SIZE - 1)), %l5
+	srlx %l5, 63 - (PHYSMEM_ADDR_SIZE - 1), %l5	
 	
 	/*
@@ -84,4 +97,6 @@
 	wrpr %g0, NWINDOWS - 1, %cleanwin	! prevent needless clean_window
 						! traps for kernel
+						
+	wrpr %g0, 0, %wstate			! use default spill/fill trap
 
 	wrpr %g0, 0, %tl			! TL = 0, primary context
@@ -245,5 +260,6 @@
 	/*
 	 * Precompute kernel 8K TLB data template.
-	 * %l5 contains starting physical address bits [40:13]
+	 * %l5 contains starting physical address
+	 * bits [(PHYSMEM_ADDR_SIZE - 1):13]
 	 */
 	sethi %hi(kernel_8k_tlb_data_template), %l4
@@ -283,13 +299,30 @@
 
 
+1:
+#ifdef CONFIG_SMP
+	/*
+	 * Determine the width of the MID and save its mask to %g3. The width
+	 * is
+	 * 	* 5 for US and US-IIIi,
+	 * 	* 10 for US3 except US-IIIi.
+	 */
+#if defined(US)
+	mov 0x1f, %g3
+#elif defined(US3)
+	mov 0x3ff, %g3
+	rdpr %ver, %g2
+	sllx %g2, 16, %g2
+	srlx %g2, 48, %g2
+	cmp %g2, IMPL_ULTRASPARCIII_I
+	move %xcc, 0x1f, %g3
+#endif
+
 	/*
 	 * Read MID from the processor.
 	 */
-1:
-	ldxa [%g0] ASI_UPA_CONFIG, %g1
-	srlx %g1, UPA_CONFIG_MID_SHIFT, %g1
-	and %g1, UPA_CONFIG_MID_MASK, %g1
-
-#ifdef CONFIG_SMP
+	ldxa [%g0] ASI_ICBUS_CONFIG, %g1
+	srlx %g1, ICBUS_CONFIG_MID_SHIFT, %g1
+	and %g1, %g3, %g1
+
 	/*
 	 * Active loop for APs until the BSP picks them up. A processor cannot
Index: kernel/arch/sparc64/src/trap/interrupt.c
===================================================================
--- kernel/arch/sparc64/src/trap/interrupt.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/arch/sparc64/src/trap/interrupt.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -68,9 +68,17 @@
 void interrupt(int n, istate_t *istate)
 {
+	uint64_t status;
 	uint64_t intrcv;
 	uint64_t data0;
+	status = asi_u64_read(ASI_INTR_DISPATCH_STATUS, 0);
+	if (status & (!INTR_DISPATCH_STATUS_BUSY))
+		panic("Interrupt Dispatch Status busy bit not set\n");
 
 	intrcv = asi_u64_read(ASI_INTR_RECEIVE, 0);
-	data0 = asi_u64_read(ASI_UDB_INTR_R, ASI_UDB_INTR_R_DATA_0);
+#if defined (US)
+	data0 = asi_u64_read(ASI_INTR_R, ASI_UDB_INTR_R_DATA_0);
+#elif defined (US3)
+	data0 = asi_u64_read(ASI_INTR_R, VA_INTR_R_DATA_0);
+#endif
 
 	irq_t *irq = irq_dispatch_and_lock(data0);
Index: kernel/genarch/include/fb/fb.h
===================================================================
--- kernel/genarch/include/fb/fb.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/genarch/include/fb/fb.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -39,6 +39,32 @@
 #include <synch/spinlock.h>
 
+/**
+ * Properties of the framebuffer device.
+ */
+typedef struct fb_properties {
+	/** Physical address of the framebuffer device. */
+	uintptr_t addr;
+
+	/**
+	 * Address where the first (top left) pixel is mapped,
+	 * relative to "addr".
+	 */
+	unsigned int offset;	
+
+	/** Screen width in pixels. */
+	unsigned int x;
+
+	/** Screen height in pixels. */
+	unsigned int y;
+
+	/** Bytes per one scanline. */
+	unsigned int scan;
+
+	/** Color model. */
+	unsigned int visual;
+} fb_properties_t;
+
 SPINLOCK_EXTERN(fb_lock);
-void fb_init(uintptr_t addr, unsigned int x, unsigned int y, unsigned int scan, unsigned int visual);
+void fb_init(fb_properties_t *props);
 
 #endif
Index: kernel/genarch/include/fb/visuals.h
===================================================================
--- kernel/genarch/include/fb/visuals.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/genarch/include/fb/visuals.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -45,4 +45,5 @@
 
 #define VISUAL_BGR_0_8_8_8	6
+#define VISUAL_SB1500_PALETTE	7
 
 #endif
Index: kernel/genarch/include/ofw/ofw_tree.h
===================================================================
--- kernel/genarch/include/ofw/ofw_tree.h	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/genarch/include/ofw/ofw_tree.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -173,4 +173,6 @@
 extern ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *,
     const char *);
+extern ofw_tree_node_t *ofw_tree_find_peer_by_name(ofw_tree_node_t *node,
+    const char *name);
 extern ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *,
     uint32_t);
Index: kernel/genarch/src/fb/fb.c
===================================================================
--- kernel/genarch/src/fb/fb.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/genarch/src/fb/fb.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -190,4 +190,24 @@
 	*((uint8_t *) dst) = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 |
 	    BLUE(rgb, 3);
+}
+
+static void sb1500rgb_byte8(void *dst, int rgb)
+{
+	if (RED(rgb, 1) && GREEN(rgb, 1) && BLUE(rgb, 1))
+		*((uint8_t *) dst) = 255;
+	else if (RED(rgb, 1) && GREEN(rgb, 1))
+		*((uint8_t *) dst) = 150;
+	else if (GREEN(rgb, 1) && BLUE(rgb, 1))
+		*((uint8_t *) dst) = 47;
+	else if (RED(rgb, 1) && BLUE(rgb, 1))
+		*((uint8_t *) dst) = 48;
+	else if (RED(rgb, 1))
+		*((uint8_t *) dst) = 32;
+	else if (GREEN(rgb, 1))
+		*((uint8_t *) dst) = 47;
+	else if (BLUE(rgb, 1))
+		*((uint8_t *) dst) = 2;
+	else 
+		*((uint8_t *) dst) = 1;
 }
 
@@ -437,15 +457,9 @@
 /** Initialize framebuffer as a chardev output device
  *
- * @param addr   Physical address of the framebuffer
- * @param x      Screen width in pixels
- * @param y      Screen height in pixels
- * @param scan   Bytes per one scanline
- * @param visual Color model
- *
- */
-void fb_init(uintptr_t addr, unsigned int x, unsigned int y, unsigned int scan,
-    unsigned int visual)
-{
-	switch (visual) {
+ * @param props  	Properties of the framebuffer device.
+ */
+void fb_init(fb_properties_t *props)
+{
+	switch (props->visual) {
 	case VISUAL_INDIRECT_8:
 		rgb2scr = rgb_byte8;
@@ -453,4 +467,9 @@
 		pixelbytes = 1;
 		break;
+	case VISUAL_SB1500_PALETTE:
+		rgb2scr = sb1500rgb_byte8;
+		scr2rgb = byte8_rgb;
+		pixelbytes = 1;
+		break;
 	case VISUAL_RGB_5_5_5:
 		rgb2scr = rgb_byte555;
@@ -487,17 +506,18 @@
 	}
 	
-	unsigned int fbsize = scan * y;
+	unsigned int fbsize = props->scan * props->y + props->offset;
 	
 	/* Map the framebuffer */
-	fbaddress = (uint8_t *) hw_map((uintptr_t) addr, fbsize);
-	
-	xres = x;
-	yres = y;
-	scanline = scan;
-	
-	rows = y / FONT_SCANLINES;
-	columns = x / COL_WIDTH;
-
-	fb_parea.pbase = (uintptr_t) addr;
+	fbaddress = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
+	fbaddress += props->offset;
+	
+	xres = props->x;
+	yres = props->y;
+	scanline = props->scan;
+	
+	rows = props->y / FONT_SCANLINES;
+	columns = props->x / COL_WIDTH;
+
+	fb_parea.pbase = (uintptr_t) props->addr;
 	fb_parea.vbase = (uintptr_t) fbaddress;
 	fb_parea.frames = SIZE2FRAMES(fbsize);
@@ -509,7 +529,7 @@
 	sysinfo_set_item_val("fb.width", NULL, xres);
 	sysinfo_set_item_val("fb.height", NULL, yres);
-	sysinfo_set_item_val("fb.scanline", NULL, scan);
-	sysinfo_set_item_val("fb.visual", NULL, visual);
-	sysinfo_set_item_val("fb.address.physical", NULL, addr);
+	sysinfo_set_item_val("fb.scanline", NULL, props->scan);
+	sysinfo_set_item_val("fb.visual", NULL, props->visual);
+	sysinfo_set_item_val("fb.address.physical", NULL, props->addr);
 	sysinfo_set_item_val("fb.invert-colors", NULL, invert_colors);
 
@@ -525,4 +545,5 @@
 	if (!blankline)
 		panic("Failed to allocate blank line for framebuffer.");
+	unsigned int x, y;
 	for (y = 0; y < FONT_SCANLINES; y++)
 		for (x = 0; x < xres; x++)
Index: kernel/genarch/src/ofw/ofw_tree.c
===================================================================
--- kernel/genarch/src/ofw/ofw_tree.c	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/genarch/src/ofw/ofw_tree.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -55,10 +55,12 @@
 /** Get OpenFirmware node property.
  *
- * @param node Node in which to lookup the property.
- * @param name Name of the property.
- *
- * @return Pointer to the property structure or NULL if no such property.
- */
-ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node, const char *name)
+ * @param node		Node in which to lookup the property.
+ * @param name		Name of the property.
+ *
+ * @return		Pointer to the property structure or NULL if no such
+ * 			property.
+ */
+ofw_tree_property_t *
+ofw_tree_getprop(const ofw_tree_node_t *node, const char *name)
 {
 	unsigned int i;
@@ -74,7 +76,7 @@
 /** Return value of the 'name' property.
  *
- * @param node Node of interest.
- *
- * @return Value of the 'name' property belonging to the node.
+ * @param node		Node of interest.
+ *
+ * @return		Value of the 'name' property belonging to the node.
  */
 const char *ofw_tree_node_name(const ofw_tree_node_t *node)
@@ -94,8 +96,9 @@
 /** Lookup child of given name.
  *
- * @param node Node whose child is being looked up.
- * @param name Name of the child being looked up.
- *
- * @return NULL if there is no such child or pointer to the matching child node.
+ * @param node		Node whose child is being looked up.
+ * @param name		Name of the child being looked up.
+ *
+ * @return		NULL if there is no such child or pointer to the
+ * 			matching child node.
  */
 ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name)
@@ -128,10 +131,12 @@
 /** Lookup first child of given device type.
  *
- * @param node Node whose child is being looked up.
- * @param name Device type of the child being looked up.
- *
- * @return NULL if there is no such child or pointer to the matching child node.
- */
-ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node, const char *name)
+ * @param node		Node whose child is being looked up.
+ * @param name		Device type of the child being looked up.
+ *
+ * @return		NULL if there is no such child or pointer to the
+ * 			matching child node.
+ */
+ofw_tree_node_t *
+ofw_tree_find_child_by_device_type(ofw_tree_node_t *node, const char *name)
 {
 	ofw_tree_node_t *cur;
@@ -154,10 +159,12 @@
  * are looked up iteratively to avoid stack overflow.
  *
- * @param root Root of the searched subtree.
- * @param handle OpenFirmware handle.
- *
- * @return NULL if there is no such node or pointer to the matching node.
- */
-ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *root, uint32_t handle)
+ * @param root		Root of the searched subtree.
+ * @param handle	OpenFirmware handle.
+ *
+ * @return		NULL if there is no such node or pointer to the matching
+ * 			node.
+ */
+ofw_tree_node_t *
+ofw_tree_find_node_by_handle(ofw_tree_node_t *root, uint32_t handle)
 {
 	ofw_tree_node_t *cur;
@@ -181,10 +188,12 @@
 /** Lookup first peer of given device type.
  *
- * @param node Node whose peer is being looked up.
- * @param name Device type of the child being looked up.
- *
- * @return NULL if there is no such child or pointer to the matching child node.
- */
-ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node, const char *name)
+ * @param node		Node whose peer is being looked up.
+ * @param name		Device type of the child being looked up.
+ *
+ * @return		NULL if there is no such child or pointer to the
+ * 			matching child node.
+ */
+ofw_tree_node_t *
+ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node, const char *name)
 {
 	ofw_tree_node_t *cur;
@@ -203,13 +212,39 @@
 
 
+/** Lookup first peer of given name.
+ *
+ * @param node		Node whose peer is being looked up.
+ * @param name		Name of the child being looked up.
+ *
+ * @return		NULL if there is no such peer or pointer to the matching
+ * 			peer node.
+ */
+ofw_tree_node_t *
+ofw_tree_find_peer_by_name(ofw_tree_node_t *node, const char *name)
+{
+	ofw_tree_node_t *cur;
+	ofw_tree_property_t *prop;
+	
+	for (cur = node->peer; cur; cur = cur->peer) {
+		prop = ofw_tree_getprop(cur, "name");
+		if (!prop || !prop->value)
+			continue;
+		if (strcmp(prop->value, name) == 0)
+			return cur;
+	}
+			
+	return NULL;
+}
+
 /** Lookup OpenFirmware node by its path.
  *
- * @param path Path to the node.
- *
- * @return NULL if there is no such node or pointer to the leaf node.
+ * @param path		Path to the node.
+ *
+ * @return		NULL if there is no such node or pointer to the leaf
+ * 			node.
  */
 ofw_tree_node_t *ofw_tree_lookup(const char *path)
 {
-	char buf[NAME_BUF_LEN+1];
+	char buf[NAME_BUF_LEN + 1];
 	ofw_tree_node_t *node = ofw_root;
 	index_t i, j;
@@ -237,6 +272,6 @@
  * iteratively in order to avoid stack overflow.
  *
- * @param node Root of the subtree.
- * @param path Current path, NULL for the very root of the entire tree.
+ * @param node		Root of the subtree.
+ * @param path		Current path, NULL for the very root of the entire tree.
  */
 static void ofw_tree_node_print(const ofw_tree_node_t *node, const char *path)
Index: kernel/kernel.config
===================================================================
--- kernel/kernel.config	(revision 405e13aa248226e6f7612790ebd85070e3c4cd09)
+++ kernel/kernel.config	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -77,4 +77,9 @@
 ! [ARCH=amd64] MACHINE (choice)
 
+# CPU type
+@ "us" UltraSPARC I-II subarchitecture
+@ "us3" UltraSPARC III-IV subarchitecture
+! [ARCH=sparc64] MACHINE (choice)
+
 # Machine type
 @ "msim" MSIM Simulator
@@ -139,11 +144,11 @@
 ! [ARCH=sparc64] CONFIG_Z8530 (y/n)
 
-# Support for NS16550 serial port (On IA64 as a console instead legacy keyboard)
-! [ARCH=sparc64] CONFIG_NS16550 (y/n)
+# Support for NS16550 serial port 
+! [ARCH=sparc64|(ARCH=ia64&MACHINE!=ski)] CONFIG_NS16550 (n/y)
 
-# Support for NS16550 serial port (On IA64 as a console instead legacy keyboard)
-! [ARCH=ia64&MACHINE!=ski] CONFIG_NS16550 (n/y)
+# Support for Serengeti console
+! [ARCH=sparc64] CONFIG_SGCN (y/n)
 
-# IOSapic on default address support (including legacy IRQ)
+# IOSapic on default address support
 ! [ARCH=ia64&MACHINE!=ski] CONFIG_IOSAPIC (y/n)
 
