Index: kernel/arch/sparc64/src/console.c
===================================================================
--- kernel/arch/sparc64/src/console.c	(revision 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/console.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/cpu/cpu.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/ddi/ddi.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/drivers/scr.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
+++ kernel/arch/sparc64/src/drivers/sgcn.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/drivers/tick.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/mm/as.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/mm/cache.S	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/mm/page.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/mm/tlb.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/mm/tsb.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/smp/ipi.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/smp/smp.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/sparc64.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/start.S	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 8d2760fe0365099552ec91e6cee8c5bbd55ed273)
+++ kernel/arch/sparc64/src/trap/interrupt.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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);
