Index: boot/arch/ppc64/Makefile.inc
===================================================================
--- boot/arch/ppc64/Makefile.inc	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/arch/ppc64/Makefile.inc	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -27,4 +27,6 @@
 #
 
+DEFS += -DOPEN_BOOT
+
 build: $(BASE)/image.boot
 
@@ -36,5 +38,5 @@
 
 arch/$(ARCH)/loader/image.boot:
-	make -C arch/$(ARCH)/loader COMPILER=$(COMPILER) KERNELDIR=../../../$(KERNELDIR) USPACEDIR=../../../$(USPACEDIR)
+	make -C arch/$(ARCH)/loader COMPILER=$(COMPILER) KERNELDIR=../../../$(KERNELDIR) USPACEDIR=../../../$(USPACEDIR) "DEFS=$(DEFS)"
 
 clean: generic_clean
Index: boot/arch/sparc64/Makefile.inc
===================================================================
--- boot/arch/sparc64/Makefile.inc	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/arch/sparc64/Makefile.inc	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -29,4 +29,12 @@
 TMP = distroot
 
+ifeq ($(CONFIG_AOUT_ISOFS_B),n)
+	SILO_PACKAGE=silo.patched.tar.gz
+endif
+
+ifeq ($(CONFIG_AOUT_ISOFS_B),y)
+	SILO_PACKAGE=silo.tar.gz
+endif
+
 build: $(BASE)/image.iso
 
@@ -40,5 +48,5 @@
 	mkdir -p $(TMP)/boot
 	mkdir -p $(TMP)/HelenOS
-	cat arch/$(ARCH)/silo/silo.tar.gz | (cd $(TMP)/boot; tar xvfz -)
+	cat arch/$(ARCH)/silo/$(SILO_PACKAGE) | (cd $(TMP)/boot; tar xvfz -)
 	cp arch/$(ARCH)/silo/README arch/$(ARCH)/silo/COPYING $(TMP)/boot
 	cat arch/$(ARCH)/silo/silo.conf | $(SILO_CONF_FILTER) >$(TMP)/boot/silo.conf
Index: boot/arch/sparc64/loader/asm.S
===================================================================
--- boot/arch/sparc64/loader/asm.S	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/arch/sparc64/loader/asm.S	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -106,7 +106,26 @@
 	 * 2. Invalidate I-cache.
 	 * 3. Flush instruction pipeline.
-	 */ 
-	call	icache_flush
-	membar	#StoreStore
+	 */
+
+	/*
+	 * US3 processors have a write-invalidate cache, so explicitly
+	 * invalidating it is not required. Whether to invalidate I-cache
+	 * or not is decided according to the value of the global
+	 * "subarchitecture" variable (set in the bootstrap).
+	 */
+	set subarchitecture, %g2
+	ldub [%g2], %g2
+	cmp %g2, 3
+	be 1f
+	nop
+0:
+	call icache_flush
+	nop
+1:
+	membar #StoreStore
+	
+	/*
+	 * Flush the instruction pipeline.
+	 */
 	flush	%i7
 
@@ -135,5 +154,4 @@
 	! SF Erratum #51
 	nop
-
 .global ofw
 ofw:
Index: boot/arch/sparc64/loader/main.c
===================================================================
--- boot/arch/sparc64/loader/main.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/arch/sparc64/loader/main.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -40,4 +40,5 @@
 
 bootinfo_t bootinfo;
+
 component_t components[COMPONENTS];
 
@@ -55,4 +56,13 @@
 	char *timestamp = "";
 #endif
+
+/** UltraSPARC subarchitecture - 1 for US, 3 for US3 */
+uint8_t subarchitecture;
+
+/**
+ * mask of the MID field inside the ICBUS_CONFIG register shifted by
+ * MID_SHIFT bits to the right
+ */
+uint16_t mid_mask;
 
 /** Print version information. */
@@ -64,4 +74,37 @@
 }
 
+/* the lowest ID (read from the VER register) of some US3 CPU model */
+#define FIRST_US3_CPU 	0x14
+
+/* the greatest ID (read from the VER register) of some US3 CPU model */
+#define LAST_US3_CPU 	0x19
+
+/* UltraSPARC IIIi processor implementation code */
+#define US_IIIi_CODE	0x15
+
+/**
+ * Sets the global variables "subarchitecture" and "mid_mask" to
+ * correct values.
+ */
+static void detect_subarchitecture(void)
+{
+	uint64_t v;
+	asm volatile ("rdpr %%ver, %0\n" : "=r" (v));
+	
+	v = (v << 16) >> 48;
+	if ((v >= FIRST_US3_CPU) && (v <= LAST_US3_CPU)) {
+		subarchitecture = SUBARCH_US3;
+		if (v == US_IIIi_CODE)
+			mid_mask = (1 << 5) - 1;
+		else
+			mid_mask = (1 << 10) - 1;
+	} else if (v < FIRST_US3_CPU) {
+		subarchitecture = SUBARCH_US;
+		mid_mask = (1 << 5) - 1;
+	} else {
+		printf("\nThis CPU is not supported by HelenOS.");
+	}
+}
+
 void bootstrap(void)
 {
@@ -73,4 +116,5 @@
 	version_print();
 	
+	detect_subarchitecture();
 	init_components(components);
 
@@ -84,5 +128,5 @@
 		halt();
 	}
-	
+
 	if (bootinfo.memmap.total == 0) {
 		printf("Error: no memory detected, halting.\n");
Index: boot/arch/sparc64/loader/main.h
===================================================================
--- boot/arch/sparc64/loader/main.h	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/arch/sparc64/loader/main.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -42,4 +42,7 @@
 #define AP_PROCESSOR	0
 
+#define SUBARCH_US	1
+#define SUBARCH_US3	3
+
 typedef struct {
 	void *addr;
Index: boot/arch/sparc64/loader/ofwarch.c
===================================================================
--- boot/arch/sparc64/loader/ofwarch.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/arch/sparc64/loader/ofwarch.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -41,4 +41,8 @@
 #include "asm.h"
 
+/* these tho variables will be set by the detect_subarchitecture function */
+extern uint8_t subarchitecture;
+extern uint16_t mid_mask;
+
 void write(const char *str, const int len)
 {
@@ -57,34 +61,38 @@
 }
 
-int ofw_cpu(void)
+/**
+ * Starts all CPUs represented by following siblings of the given node,
+ * except for the current CPU.
+ *
+ * @param child		The first child of the OFW tree node whose children
+ * 			represent CPUs to be woken up.
+ * @param current_mid	MID of the current CPU, the current CPU will
+ *			(of course) not be woken up.
+ * @return		Number of CPUs which have the same parent node as
+ * 			"child".
+ */
+static int wake_cpus_in_node(phandle child, uint64_t current_mid)
 {
+	int cpus;
 	char type_name[BUF_SIZE];
-
-	phandle node;
-	node = ofw_get_child_node(ofw_root);
-	if (node == 0 || node == -1) {
-		printf("Could not find any child nodes of the root node.\n");
-		return 0;
-	}
 	
-	uint64_t current_mid;
-	
-	asm volatile ("ldxa [%1] %2, %0\n"
-	    : "=r" (current_mid)
-	    : "r" (0), "i" (ASI_UPA_CONFIG));
-	current_mid >>= UPA_CONFIG_MID_SHIFT;
-	current_mid &= UPA_CONFIG_MID_MASK;
-
-	int cpus;
-	
-	for (cpus = 0; node != 0 && node != -1; node = ofw_get_peer_node(node),
-	    cpus++) {
-		if (ofw_get_property(node, "device_type", type_name,
+	for (cpus = 0; child != 0 && child != -1;
+	    child = ofw_get_peer_node(child), cpus++) {
+		if (ofw_get_property(child, "device_type", type_name,
 		    sizeof(type_name)) > 0) {
 			if (strcmp(type_name, "cpu") == 0) {
 				uint32_t mid;
 				
-				if (ofw_get_property(node, "upa-portid", &mid,
-				    sizeof(mid)) <= 0)
+				/*
+				 * "upa-portid" for US, "portid" for US-III,
+				 * "cpuid" for US-IV
+				 */
+				if (ofw_get_property(
+				    child, "upa-portid",
+				    &mid, sizeof(mid)) <= 0
+				    && ofw_get_property(child, "portid",
+				    &mid, sizeof(mid)) <= 0
+				    && ofw_get_property(child, "cpuid",
+				    &mid, sizeof(mid)) <= 0)
 					continue;
 					
@@ -94,5 +102,5 @@
 					 */
 					(void) ofw_call("SUNW,start-cpu", 3, 1,
-					    NULL, node, KERNEL_VIRTUAL_ADDRESS,
+					    NULL, child, KERNEL_VIRTUAL_ADDRESS,
 					    bootinfo.physmem_start |
 					    AP_PROCESSOR);
@@ -105,10 +113,57 @@
 }
 
+/**
+ * Finds out the current CPU's MID and wakes up all AP processors.
+ */
+int ofw_cpu(void)
+{
+	int cpus;
+	phandle node;
+	phandle subnode;
+	phandle cpus_parent;
+	phandle cmp;
+	char name[BUF_SIZE];
+
+	/* get the current CPU MID */
+	uint64_t current_mid;
+	
+	asm volatile ("ldxa [%1] %2, %0\n"
+	    : "=r" (current_mid)
+	    : "r" (0), "i" (ASI_ICBUS_CONFIG));
+	current_mid >>= ICBUS_CONFIG_MID_SHIFT;
+
+	current_mid &= mid_mask;
+
+	/* wake up CPUs */
+	
+	cpus_parent = ofw_find_device("/ssm@0,0");
+	if (cpus_parent == 0 || cpus_parent == -1) {
+		cpus_parent = ofw_find_device("/");
+	}
+
+	node = ofw_get_child_node(cpus_parent);
+	cpus = wake_cpus_in_node(node, current_mid);
+	while (node != 0 && node != -1) {
+		if (ofw_get_property(node, "name", name,
+			sizeof(name)) > 0) {
+			if (strcmp(name, "cmp") == 0) {
+				subnode = ofw_get_child_node(node);
+				cpus += wake_cpus_in_node(subnode,
+					current_mid);
+			}
+		}
+		node = ofw_get_peer_node(node);
+	}
+	
+	return cpus;
+	
+}
+
 /** Get physical memory starting address.
  *
- * @param start Pointer to variable where the physical memory starting
- * 		address will be stored.
+ * @param start		Pointer to variable where the physical memory starting
+ *			address will be stored.
  *
- * @return Non-zero on succes, zero on failure.
+ * @return		Non-zero on succes, zero on failure.
  */
 int ofw_get_physmem_start(uintptr_t *start)
Index: boot/arch/sparc64/loader/register.h
===================================================================
--- boot/arch/sparc64/loader/register.h	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/arch/sparc64/loader/register.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -34,7 +34,6 @@
 #define PSTATE_AM_BIT   8
 
-#define ASI_UPA_CONFIG          0x4a
-#define UPA_CONFIG_MID_SHIFT    17
-#define UPA_CONFIG_MID_MASK     0x1f
+#define ASI_ICBUS_CONFIG		0x4a
+#define ICBUS_CONFIG_MID_SHIFT		17
 
 #endif
Index: boot/boot.config
===================================================================
--- boot/boot.config	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/boot.config	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -84,4 +84,7 @@
 ! RDFMT (choice)
 
+# Preserve A.OUT header in isofs.b
+! [ARCH=sparc64] CONFIG_AOUT_ISOFS_B (y/n)
+
 # External ramdisk 
 ! [ARCH=sparc64] CONFIG_RD_EXTERNAL (y/n)
Index: boot/genarch/balloc.h
===================================================================
--- boot/genarch/balloc.h	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/genarch/balloc.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -32,5 +32,5 @@
 #include <types.h>
 
-#define BALLOC_MAX_SIZE		(1024 * 1024)
+#define BALLOC_MAX_SIZE		(128 * 1024)
 
 typedef struct {
Index: boot/genarch/ofw.c
===================================================================
--- boot/genarch/ofw.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/genarch/ofw.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -49,5 +49,6 @@
 		halt();
 	
-	if (ofw_get_property(ofw_chosen, "stdout", &ofw_stdout, sizeof(ofw_stdout)) <= 0)
+	if (ofw_get_property(ofw_chosen, "stdout", &ofw_stdout,
+	    sizeof(ofw_stdout)) <= 0)
 		ofw_stdout = 0;
 	
@@ -58,9 +59,11 @@
 	}
 	
-	if (ofw_get_property(ofw_chosen, "mmu", &ofw_mmu, sizeof(ofw_mmu)) <= 0) {
+	if (ofw_get_property(ofw_chosen, "mmu", &ofw_mmu,
+	    sizeof(ofw_mmu)) <= 0) {
 		puts("\r\nError: Unable to get mmu property, halted.\r\n");
 		halt();
 	}
-	if (ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop, sizeof(ofw_memory_prop)) <= 0) {
+	if (ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop,
+	    sizeof(ofw_memory_prop)) <= 0) {
 		puts("\r\nError: Unable to get memory property, halted.\r\n");
 		halt();
@@ -82,12 +85,16 @@
 /** Perform a call to OpenFirmware client interface.
  *
- * @param service String identifying the service requested.
- * @param nargs Number of input arguments.
- * @param nret Number of output arguments. This includes the return value.
- * @param rets Buffer for output arguments or NULL. The buffer must accommodate nret - 1 items.
- *
- * @return Return value returned by the client interface.
+ * @param service	String identifying the service requested.
+ * @param nargs		Number of input arguments.
+ * @param nret		Number of output arguments. This includes the return
+ * 			value.
+ * @param rets		Buffer for output arguments or NULL. The buffer must
+ * 			accommodate nret - 1 items.
+ *
+ * @return		Return value returned by the client interface.
  */
-unsigned long ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets, ...)
+unsigned long
+ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets,
+    ...)
 {
 	va_list list;
@@ -120,5 +127,7 @@
 }
 
-int ofw_get_property(const phandle device, const char *name, void *buf, const int buflen)
+int
+ofw_get_property(const phandle device, const char *name, void *buf,
+    const int buflen)
 {
 	return ofw_call("getprop", 4, 1, NULL, device, name, buf, buflen);
@@ -145,5 +154,6 @@
 	
 	if (ofw_get_property(device, "#address-cells", &ret, sizeof(ret)) <= 0)
-		if (ofw_get_property(ofw_root, "#address-cells", &ret, sizeof(ret)) <= 0)
+		if (ofw_get_property(ofw_root, "#address-cells", &ret,
+		    sizeof(ret)) <= 0)
 			ret = OFW_ADDRESS_CELLS;
 	
@@ -157,5 +167,6 @@
 	
 	if (ofw_get_property(device, "#size-cells", &ret, sizeof(ret)) <= 0)
-		if (ofw_get_property(ofw_root, "#size-cells", &ret, sizeof(ret)) <= 0)
+		if (ofw_get_property(ofw_root, "#size-cells", &ret,
+		    sizeof(ret)) <= 0)
 			ret = OFW_SIZE_CELLS;
 	
@@ -193,5 +204,6 @@
 	int shift;
 
-	if (ofw_call("call-method", 3, 5, result, "translate", ofw_mmu, virt) != 0) {
+	if (ofw_call("call-method", 3, 5, result, "translate", ofw_mmu,
+	    virt) != 0) {
 		puts("Error: MMU method translate() failed, halting.\n");
 		halt();
@@ -213,5 +225,6 @@
 	ofw_arg_t retaddr;
 
-	if (ofw_call("call-method", 5, 2, &retaddr, "claim", ofw_mmu, 0, len, virt) != 0) {
+	if (ofw_call("call-method", 5, 2, &retaddr, "claim", ofw_mmu, 0, len,
+	    virt) != 0) {
 		puts("Error: MMU method claim() failed, halting.\n");
 		halt();
@@ -270,6 +283,6 @@
 	}
 
-	return ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode, size, virt,
-	    phys_hi, phys_lo);
+	return ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode, size,
+	    virt, phys_hi, phys_lo);
 }
 
@@ -282,8 +295,11 @@
 int ofw_memmap(memmap_t *map)
 {
-	unsigned int ac = ofw_get_address_cells(ofw_memory);
-	unsigned int sc = ofw_get_size_cells(ofw_memory);
-
-	uint32_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)];
+	unsigned int ac = ofw_get_address_cells(ofw_memory) /
+	    (sizeof(uintptr_t) / sizeof(uint32_t));
+	unsigned int sc = ofw_get_size_cells(ofw_memory) /
+	    (sizeof(uintptr_t) / sizeof(uint32_t));
+	printf("address cells: %d, size cells: %d. ", ac, sc);
+
+	uintptr_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)];
 	int ret = ofw_get_property(ofw_memory, "reg", buf, sizeof(buf));
 	if (ret <= 0)		/* ret is the number of written bytes */
@@ -293,9 +309,20 @@
 	map->total = 0;
 	map->count = 0;
-	for (pos = 0; (pos < ret / sizeof(uint32_t)) &&
+	for (pos = 0; (pos < ret / sizeof(uintptr_t)) &&
 	    (map->count < MEMMAP_MAX_RECORDS); pos += ac + sc) {
-		void * start = (void *) ((uintptr_t) buf[pos + ac - 1]);
+		void *start = (void *) (buf[pos + ac - 1]);
 		unsigned int size = buf[pos + ac + sc - 1];
-		
+
+		/*
+ 		 * This is a hot fix of the issue which occurs on machines
+ 		 * where there are holes in the physical memory (such as
+ 		 * SunBlade 1500). Should we detect a hole in the physical
+ 		 * memory, we will ignore any memory detected behind
+ 		 * the hole and pretend the hole does not exist.
+		 */
+		if ((map->count > 0) && (map->zones[map->count - 1].start +
+		    map->zones[map->count - 1].size < start))
+			break;
+
 		if (size > 0) {
 			map->zones[map->count].start = start;
@@ -309,5 +336,4 @@
 }
 
-
 int ofw_screen(screen_t *screen)
 {
@@ -315,5 +341,6 @@
 	uint32_t virtaddr;
 	
-	if (ofw_get_property(ofw_aliases, "screen", device_name, sizeof(device_name)) <= 0)
+	if (ofw_get_property(ofw_aliases, "screen", device_name,
+	    sizeof(device_name)) <= 0)
 		return false;
 	
@@ -322,19 +349,24 @@
 		return false;
 	
-	if (ofw_get_property(device, "address", &virtaddr, sizeof(virtaddr)) <= 0)
+	if (ofw_get_property(device, "address", &virtaddr,
+	    sizeof(virtaddr)) <= 0)
 		return false;
 
 	screen->addr = (void *) ((uintptr_t) virtaddr);
 
-	if (ofw_get_property(device, "width", &screen->width, sizeof(screen->width)) <= 0)
-		return false;
-	
-	if (ofw_get_property(device, "height", &screen->height, sizeof(screen->height)) <= 0)
-		return false;
-	
-	if (ofw_get_property(device, "depth", &screen->bpp, sizeof(screen->bpp)) <= 0)
-		return false;
-	
-	if (ofw_get_property(device, "linebytes", &screen->scanline, sizeof(screen->scanline)) <= 0)
+	if (ofw_get_property(device, "width", &screen->width,
+	    sizeof(screen->width)) <= 0)
+		return false;
+	
+	if (ofw_get_property(device, "height", &screen->height,
+	    sizeof(screen->height)) <= 0)
+		return false;
+	
+	if (ofw_get_property(device, "depth", &screen->bpp,
+	    sizeof(screen->bpp)) <= 0)
+		return false;
+	
+	if (ofw_get_property(device, "linebytes", &screen->scanline,
+	    sizeof(screen->scanline)) <= 0)
 		return false;
 	
Index: boot/genarch/ofw_tree.c
===================================================================
--- boot/genarch/ofw_tree.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ boot/genarch/ofw_tree.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -121,5 +121,4 @@
 		memcpy(current_node->da_name, &path[i], len);
 		current_node->da_name[len] = '\0';
-	
 	
 		/*
@@ -220,8 +219,26 @@
 {
 	ofw_tree_node_t *root;
+	phandle ssm_node;
+	ofw_tree_node_t *ssm;
 	
 	root = ofw_tree_node_alloc();
 	if (root)
 		ofw_tree_node_process(root, NULL, ofw_root);
+
+	/*
+	 * The firmware client interface does not automatically include the
+	 * "ssm" node in the list of children of "/". A nasty yet working
+	 * solution is to explicitly stick "ssm" to the OFW tree.
+	 */
+	ssm_node = ofw_find_device("/ssm@0,0");
+	if (ssm_node != -1) {
+		ssm = ofw_tree_node_alloc();
+		if (ssm) {
+			ofw_tree_node_process(
+				ssm, root, ofw_find_device("/ssm@0,0"));
+			ssm->peer = root->child;
+			root->child = ssm;
+		}
+	}
 	
 	return root;
Index: contrib/util/DownloadAndPatchSILO.sh
===================================================================
--- contrib/util/DownloadAndPatchSILO.sh	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ contrib/util/DownloadAndPatchSILO.sh	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+# Download SILO and patch it so that it can be used to create a bootable CD
+# for the Serengeti machine
+#  by Pavel Rimsky <rimskyp@seznam.cz>
+#  portions by Martin Decky <martin@decky.cz>
+#
+#  GPL'ed, copyleft
+#
+
+# stuff to be downloaded
+SILO_DOWNLOAD_FILE='silo-loaders-1.4.11.tar.gz'
+SILO_DOWNLOAD_URL='http://silo.auxio.org/pub/silo/old/'$SILO_DOWNLOAD_FILE
+
+# check whether the last command failed, if so, write an error message and exit
+check_error() {
+    if [ "$1" -ne "0" ]; then
+        echo
+        echo "Script failed: $2"
+        exit
+    fi
+}
+
+# temporary files are to be stored in /tmp
+# the resulting file in the current directory
+WD=`pwd`
+cd /tmp
+
+# download SILO from its official website
+echo ">>> Downloading SILO"
+wget $SILO_DOWNLOAD_URL
+check_error $? "Error downloading SILO."
+
+# unpack the downloaded file
+echo ">>> Unpacking tarball"
+tar xvzf $SILO_DOWNLOAD_FILE
+check_error $? "Error unpacking tarball."
+
+# CD to the unpacked directory
+echo ">>> Changing to the unpacked SILO directory"
+cd boot
+check_error $? "Changing directory failed."
+
+# patch it - remove bytes 512 to 512 + 32 (counted from 0), which belong to
+# the ELF header which is not recognized by the Serengeti firmware
+echo ">>> Patching SILO"
+(((xxd -p -l 512 isofs.b) && (xxd -p -s 544 isofs.b)) | xxd -r -p) \
+	 > isofs.b.patched
+check_error $? "Patching SILO failed"
+mv isofs.b.patched isofs.b
+
+# get rid of files which are not needed for creating the bootable CD
+echo ">>> Purging SILO directory"
+for file in `ls`; do
+	if [ \( -f $file \) -a \( $file != "isofs.b" \) -a \( $file != "second.b" \) ];
+		then
+		rm -fr $file;
+	fi
+done
+check_error $? "Purging SILO directory failed"
+
+# create the gzipped tarball with patched SILO
+echo ">>> Creating tarball with patched SILO"
+tar cvzf silo.patched.tar.gz *.b
+check_error $? "Creating tarball with patched SILO failed"
+
+# and move it to the directory where the user expects it to be
+echo ">>> Moving the tarball with patched SILO to the current directory"
+mv silo.patched.tar.gz $WD
+check_error $? "Moving the tarball with patched SILO failed"
+
+# move back to the working directory from /tmp
+cd $WD
+
Index: kernel/arch/arm32/src/arm32.c
===================================================================
--- kernel/arch/arm32/src/arm32.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ 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)
 
Index: uspace/srv/console/console.c
===================================================================
--- uspace/srv/console/console.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/console/console.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -328,5 +328,4 @@
 		case KBD_PUSHCHAR:
 			/* got key from keyboard driver */
-			
 			retval = 0;
 			c = IPC_GET_ARG1(call);
Index: uspace/srv/fb/Makefile
===================================================================
--- uspace/srv/fb/Makefile	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/fb/Makefile	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -66,6 +66,12 @@
 endif
 ifeq ($(ARCH), mips32)
-	SOURCES += msim.c
+	SOURCES += msim.c \
+                   serial_console.c
 	CFLAGS += -DMSIM_ENABLED -DFB_INVERT_ENDIAN
+endif
+ifeq ($(ARCH), sparc64)
+	SOURCES += sgcn.c \
+	           serial_console.c
+	CFLAGS += -DSGCN_ENABLED
 endif
 
Index: uspace/srv/fb/main.c
===================================================================
--- uspace/srv/fb/main.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/fb/main.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -39,4 +39,5 @@
 #include "ega.h"
 #include "msim.h"
+#include "sgcn.h"
 #include "main.h"
 
@@ -80,4 +81,10 @@
 	}
 #endif
+#ifdef SGCN_ENABLED
+	if ((!initialized) && (sysinfo_value("fb.kind") == 4)) {
+		if (sgcn_init() == 0)
+			initialized = true;
+	}
+#endif
 
 	if (!initialized)
Index: uspace/srv/fb/msim.c
===================================================================
--- uspace/srv/fb/msim.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/fb/msim.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -50,4 +50,5 @@
 #include <ddi.h>
 
+#include "serial_console.h"
 #include "msim.h"
 
@@ -65,55 +66,4 @@
 {
 	*virt_addr = c;
-}
-
-static void msim_puts(char *str)
-{
-	while (*str)
-		*virt_addr = *(str++);
-}
-
-static void msim_clrscr(void)
-{
-	msim_puts("\033[2J");
-}
-
-static void msim_goto(const unsigned int row, const unsigned int col)
-{
-	if ((row > HEIGHT) || (col > WIDTH))
-		return;
-	
-	char control[MAX_CONTROL];
-	snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
-	msim_puts(control);
-}
-
-static void msim_set_style(const unsigned int mode)
-{
-	char control[MAX_CONTROL];
-	snprintf(control, MAX_CONTROL, "\033[%um", mode);
-	msim_puts(control);
-}
-
-static void msim_cursor_disable(void)
-{
-	msim_puts("\033[?25l");
-}
-
-static void msim_cursor_enable(void)
-{
-	msim_puts("\033[?25h");
-}
-
-static void msim_scroll(int i)
-{
-	if (i > 0) {
-		msim_goto(HEIGHT - 1, 0);
-		while (i--)
-			msim_puts("\033D");
-	} else if (i < 0) {
-		msim_goto(0, 0);
-		while (i++)
-			msim_puts("\033M");
-	}
 }
 
@@ -142,7 +92,7 @@
 	/* Clear the terminal, set scrolling region
 	   to 0 - 25 lines */
-	msim_clrscr();
-	msim_goto(0, 0);
-	msim_puts("\033[0;25r");
+	serial_clrscr();
+	serial_goto(0, 0);
+	serial_puts("\033[0;25r");
 	
 	while (true) {
@@ -158,5 +108,5 @@
 			newcol = IPC_GET_ARG3(call);
 			if ((lastcol != newcol) || (lastrow != newrow))
-				msim_goto(newrow, newcol);
+				serial_goto(newrow, newcol);
 			lastcol = newcol + 1;
 			lastrow = newrow;
@@ -167,5 +117,5 @@
 			newrow = IPC_GET_ARG1(call);
 			newcol = IPC_GET_ARG2(call);
-			msim_goto(newrow, newcol);
+			serial_goto(newrow, newcol);
 			lastrow = newrow;
 			lastcol = newcol;
@@ -176,5 +126,5 @@
 			continue;
 		case FB_CLEAR:
-			msim_clrscr();
+			serial_clrscr();
 			retval = 0;
 			break;
@@ -183,7 +133,7 @@
 			bgcolor = IPC_GET_ARG2(call);
 			if (fgcolor < bgcolor)
-				msim_set_style(0);
+				serial_set_style(0);
 			else
-				msim_set_style(7);
+				serial_set_style(7);
 			retval = 0;
 			break;
@@ -194,13 +144,13 @@
 				break;
 			}
-			msim_scroll(i);
-			msim_goto(lastrow, lastcol);
+			serial_scroll(i);
+			serial_goto(lastrow, lastcol);
 			retval = 0;
 			break;
 		case FB_CURSOR_VISIBILITY:
 			if(IPC_GET_ARG1(call))
-				msim_cursor_enable();
+				serial_cursor_enable();
 			else
-				msim_cursor_disable();
+				serial_cursor_disable();
 			retval = 0;
 			break;
@@ -219,4 +169,6 @@
 	physmem_map(phys_addr, virt_addr, 1, AS_AREA_READ | AS_AREA_WRITE);
 	
+	serial_console_init(msim_putc, WIDTH, HEIGHT);
+	
 	async_set_client_connection(msim_client_connection);
 	return 0;
Index: uspace/srv/fb/serial_console.c
===================================================================
--- uspace/srv/fb/serial_console.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/serial_console.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2008 Martin Decky
+ * 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.
+ */
+
+/**
+ * @defgroup serial Serial console
+ * @brief    Serial console services (putc, puts, clear screen, cursor goto,...)
+ * @{
+ */ 
+
+/** @file
+ */
+
+#include <stdio.h>
+
+#include "serial_console.h"
+
+#define MAX_CONTROL 20
+
+static uint32_t width;
+static uint32_t height;
+static putc_function_t putc_function;
+
+void serial_puts(char *str)
+{
+	while (*str)
+		putc_function(*(str++));
+}
+
+void serial_goto(const unsigned int row, const unsigned int col)
+{
+	if ((row > height) || (col > width))
+		return;
+	
+	char control[20];
+	snprintf(control, 20, "\033[%u;%uf", row + 1, col + 1);
+	serial_puts(control);
+}
+
+void serial_clrscr(void)
+{
+	serial_puts("\033[2J");
+}
+
+void serial_scroll(int i)
+{
+	if (i > 0) {
+		serial_goto(height - 1, 0);
+		while (i--)
+			serial_puts("\033D");
+	} else if (i < 0) {
+		serial_goto(0, 0);
+		while (i++)
+			serial_puts("\033M");
+	}
+}
+
+void serial_set_style(const unsigned int mode)
+{
+	char control[MAX_CONTROL];
+	snprintf(control, MAX_CONTROL, "\033[%um", mode);
+	serial_puts(control);
+}
+
+void serial_cursor_disable(void)
+{
+	serial_puts("\033[?25l");
+}
+
+void serial_cursor_enable(void)
+{
+	serial_puts("\033[?25h");
+}
+
+void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h)
+{
+	width = w;
+	height = h;
+	putc_function = putc_fn;
+}
+
+/** 
+ * @}
+ */
Index: uspace/srv/fb/serial_console.h
===================================================================
--- uspace/srv/fb/serial_console.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/serial_console.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup serial Serial console
+ * @brief    Serial console services (putc, puts, clear screen, cursor goto,...)
+ * @{
+ */ 
+
+/** @file
+ */
+
+#ifndef FB_SERIAL_CONSOLE_H_
+#define FB_SERIAL_CONSOLE_H_
+
+typedef void (*putc_function_t)(char);
+
+void serial_puts(char *str);
+void serial_goto(const unsigned int row, const unsigned int col);
+void serial_clrscr(void);
+void serial_scroll(int i);
+void serial_set_style(const unsigned int mode);
+void serial_cursor_disable(void);
+void serial_cursor_enable(void);
+void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h);
+
+#endif
Index: uspace/srv/fb/sgcn.c
===================================================================
--- uspace/srv/fb/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2008 Martin Decky
+ * 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.
+ */
+
+/** @defgroup sgcnfb SGCN
+ * @brief	userland driver of the Serengeti console output
+ * @{
+ */ 
+/** @file
+ */
+
+#include <async.h>
+#include <ipc/ipc.h>
+#include <ipc/fb.h>
+#include <sysinfo.h>
+#include <as.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ddi.h>
+
+#include "serial_console.h"
+#include "sgcn.h"
+
+#define WIDTH 80
+#define HEIGHT 24
+
+/**
+ * Virtual address mapped to SRAM.
+ */
+static uintptr_t sram_virt_addr;
+
+/**
+ * SGCN buffer offset within SGCN.
+ */
+static uintptr_t sram_buffer_offset;
+
+/* Allow only 1 connection */
+static int client_connected = 0;
+
+/**
+ * SGCN buffer header. It is placed at the very beginning of the SGCN
+ * buffer. 
+ */
+typedef struct {
+	/** hard-wired to "CON" */
+	char magic[4];
+	
+	/** we don't need this */
+	char unused[24];
+
+	/** 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;
+
+
+/*
+ * 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 *) (sram_virt_addr + sram_buffer_offset + (offset)))
+
+/** Returns a pointer to the console buffer header. */
+#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
+/**
+ * Pushes the character to the SGCN serial.
+ * @param c	character to be pushed
+ */
+static void sgcn_putc(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);
+
+	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;
+}
+
+/**
+ * Main function of the thread serving client connections.
+ */
+static void sgcn_client_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	int retval;
+	ipc_callid_t callid;
+	ipc_call_t call;
+	char c;
+	int lastcol = 0;
+	int lastrow = 0;
+	int newcol;
+	int newrow;
+	int fgcolor;
+	int bgcolor;
+	int i;
+	
+	if (client_connected) {
+		ipc_answer_0(iid, ELIMIT);
+		return;
+	}
+	
+	client_connected = 1;
+	ipc_answer_0(iid, EOK);
+	
+	/* Clear the terminal, set scrolling region
+	   to 0 - 24 lines */
+	serial_clrscr();
+	serial_goto(0, 0);
+	serial_puts("\033[0;24r");
+	
+	while (true) {
+		callid = async_get_call(&call);
+		switch (IPC_GET_METHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			client_connected = 0;
+			ipc_answer_0(callid, EOK);
+			return;
+		case FB_PUTCHAR:
+			c = IPC_GET_ARG1(call);
+			newrow = IPC_GET_ARG2(call);
+			newcol = IPC_GET_ARG3(call);
+			if ((lastcol != newcol) || (lastrow != newrow))
+				serial_goto(newrow, newcol);
+			lastcol = newcol + 1;
+			lastrow = newrow;
+			sgcn_putc(c);
+			retval = 0;
+			break;
+		case FB_CURSOR_GOTO:
+			newrow = IPC_GET_ARG1(call);
+			newcol = IPC_GET_ARG2(call);
+			serial_goto(newrow, newcol);
+			lastrow = newrow;
+			lastcol = newcol;
+			retval = 0;
+			break;
+		case FB_GET_CSIZE:
+			ipc_answer_2(callid, EOK, HEIGHT, WIDTH);
+			continue;
+		case FB_CLEAR:
+			serial_clrscr();
+			retval = 0;
+			break;
+		case FB_SET_STYLE:
+			fgcolor = IPC_GET_ARG1(call);
+			bgcolor = IPC_GET_ARG2(call);
+			if (fgcolor < bgcolor)
+				serial_set_style(0);
+			else
+				serial_set_style(7);
+			retval = 0;
+			break;
+		case FB_SCROLL:
+			i = IPC_GET_ARG1(call);
+			if ((i > HEIGHT) || (i < -HEIGHT)) {
+				retval = EINVAL;
+				break;
+			}
+			serial_scroll(i);
+			serial_goto(lastrow, lastcol);
+			retval = 0;
+			break;
+		case FB_CURSOR_VISIBILITY:
+			if(IPC_GET_ARG1(call))
+				serial_cursor_enable();
+			else
+				serial_cursor_disable();
+			retval = 0;
+			break;
+		default:
+			retval = ENOENT;
+		}
+		ipc_answer_0(callid, retval);
+	}
+}
+
+/**
+ * Initializes the SGCN serial driver.
+ */
+int sgcn_init(void)
+{
+	sram_virt_addr = (uintptr_t) as_get_mappable_page(
+		sysinfo_value("sram.area.size"));
+	int result = physmem_map(
+		(void *) sysinfo_value("sram.address.physical"),
+		(void *) sram_virt_addr,
+		sysinfo_value("sram.area.size") / PAGE_SIZE,
+		AS_AREA_READ | AS_AREA_WRITE
+		);
+	if (result != 0) {
+		printf("SGCN: uspace driver couldn't map physical memory: %d\n",
+			result);
+	}
+	
+	serial_console_init(sgcn_putc, WIDTH, HEIGHT);
+	
+	sram_buffer_offset = sysinfo_value("sram.buffer.offset");
+	
+	async_set_client_connection(sgcn_client_connection);
+	return 0;
+}
+
+/** 
+ * @}
+ */
+ 
Index: uspace/srv/fb/sgcn.h
===================================================================
--- uspace/srv/fb/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/** @defgroup sgcnfb SGCN
+ * @brief	userland driver of the Serengeti console output
+ * @{
+ */
+ 
+/** @file
+ */
+
+#ifndef FB_SGCN_H_
+#define FB_SGCN_H_
+
+int sgcn_init(void);
+
+#endif
+
+/** 
+ * @}
+ */
Index: uspace/srv/kbd/Makefile
===================================================================
--- uspace/srv/kbd/Makefile	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/kbd/Makefile	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -79,7 +79,9 @@
 ifeq ($(ARCH), sparc64)
 	ARCH_SOURCES += \
-		arch/$(ARCH)/src/scanc.c
+		arch/$(ARCH)/src/scanc.c \
+		arch/$(ARCH)/src/sgcn.c
 	GENARCH_SOURCES = \
-		genarch/src/kbd.c
+		genarch/src/kbd.c \
+		genarch/src/nofb.c
 endif
 ifeq ($(ARCH), arm32)
@@ -87,5 +89,8 @@
 		arch/$(ARCH)/src/kbd_gxemul.c
 endif
-
+ifeq ($(ARCH), mips32)
+	GENARCH_SOURCES += \
+	    genarch/src/nofb.c
+endif
 
 GENERIC_OBJECTS := $(addsuffix .o,$(basename $(GENERIC_SOURCES)))
Index: uspace/srv/kbd/arch/mips32/src/kbd.c
===================================================================
--- uspace/srv/kbd/arch/mips32/src/kbd.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/kbd/arch/mips32/src/kbd.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -35,4 +35,5 @@
  */
 #include <arch/kbd.h>
+#include <genarch/nofb.h>
 #include <ipc/ipc.h>
 #include <sysinfo.h>
@@ -100,144 +101,4 @@
 */
 
-static int kbd_arch_process_no_fb(keybuffer_t *keybuffer, int scan_code)
-{
-
-	static unsigned long buf = 0;
-	static int count = 0;	
-
-	/* Please preserve this code (it can be used to determine scancodes)
-	
-	keybuffer_push(keybuffer, to_hex((scan_code>>4)&0xf));
-	keybuffer_push(keybuffer, to_hex(scan_code&0xf));
-	keybuffer_push(keybuffer, ' ');
-	keybuffer_push(keybuffer, ' ');
-	
-	return 1;
-	*/
-	
-	if(scan_code == 0x7e) {
-		switch (buf) {
-		case MSIM_KEY_F5:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 5);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F6:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 6);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F7:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 7);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F8:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 8);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F9:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 9);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F10:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 10);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F11:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 11);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F12:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 12);
-			buf = count = 0;
-			return 1;
-		default:
-			keybuffer_push(keybuffer, buf & 0xff);
-			keybuffer_push(keybuffer, (buf >> 8) &0xff);
-			keybuffer_push(keybuffer, (buf >> 16) &0xff);
-			keybuffer_push(keybuffer, (buf >> 24) &0xff);
-			keybuffer_push(keybuffer, scan_code);
-			buf = count = 0;
-			return 1;
-		}
-	}
-
-	buf |= ((unsigned long) scan_code)<<(8*(count++));
-	
-	if((buf & 0xff) != (MSIM_KEY_F1 & 0xff)) {
-		keybuffer_push(keybuffer, buf);
-		buf = count = 0;
-		return 1;
-	}
-
-	if (count <= 1) 
-		return 1;
-
-	if ((buf & 0xffff) != (MSIM_KEY_F1 & 0xffff) 
-		&& (buf & 0xffff) != (MSIM_KEY_F5 & 0xffff) ) {
-
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
-		buf = count = 0;
-		return 1;
-	}
-
-	if (count <= 2) 
-		return 1;
-
-	switch (buf) {
-	case MSIM_KEY_F1:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 1);
-		buf = count = 0;
-		return 1;
-	case MSIM_KEY_F2:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 2);
-		buf = count = 0;
-		return 1;
-	case MSIM_KEY_F3:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 3);
-		buf = count = 0;
-		return 1;
-	case MSIM_KEY_F4:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 4);
-		buf = count = 0;
-		return 1;
-	}
-
-
-	if((buf & 0xffffff) != (MSIM_KEY_F5 & 0xffffff)
-		&& (buf & 0xffffff) != (MSIM_KEY_F9 & 0xffffff)) {
-
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
-		buf=count=0;
-		return 1;
-	}
-
-	if (count <= 3)
-		return 1;
-	
-	switch (buf) {
-	case MSIM_KEY_F5:
-	case MSIM_KEY_F6:
-	case MSIM_KEY_F7:
-	case MSIM_KEY_F8:
-	case MSIM_KEY_F9:
-	case MSIM_KEY_F10:
-	case MSIM_KEY_F11:
-	case MSIM_KEY_F12:
-		return 1;
-	default:
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
-		keybuffer_push(keybuffer, (buf >> 16) &0xff);
-		keybuffer_push(keybuffer, (buf >> 24) &0xff);
-		buf = count = 0;
-		return 1;
-	}
-	return 1;
-}
-
-
-
 static int kbd_arch_process_fb(keybuffer_t *keybuffer, int scan_code)
 {
@@ -372,5 +233,5 @@
 		return kbd_arch_process_fb(keybuffer, scan_code);
 
-	return kbd_arch_process_no_fb(keybuffer, scan_code);
+	return kbd_process_no_fb(keybuffer, scan_code);
 }
 /** @}
Index: uspace/srv/kbd/arch/sparc64/include/sgcn.h
===================================================================
--- uspace/srv/kbd/arch/sparc64/include/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/arch/sparc64/include/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,46 @@
+/*
+ * 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 kbdsparc64 sparc64
+ * @brief	Serengeti-specific parts of uspace keyboard handler.
+ * @ingroup  kbd
+ * @{
+ */ 
+/** @file
+ */
+
+#ifndef KBD_sparc64_SGCN_H_
+#define KBD_sparc64_SGCN_H_
+
+void sgcn_init(void);
+void sgcn_key_pressed(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/kbd/arch/sparc64/src/kbd.c
===================================================================
--- uspace/srv/kbd/arch/sparc64/src/kbd.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/kbd/arch/sparc64/src/kbd.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -36,4 +36,5 @@
 
 #include <arch/kbd.h>
+#include <arch/sgcn.h>
 #include <ipc/ipc.h>
 #include <sysinfo.h>
@@ -79,4 +80,5 @@
 #define KBD_Z8530	1
 #define KBD_NS16550	2
+#define KBD_SGCN	3
 
 int kbd_arch_init(void)
@@ -92,4 +94,7 @@
 		ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), 0, &ns16550_kbd);
 		break;
+	case KBD_SGCN:
+		sgcn_init();
+		break;
 	default:
 		break;
@@ -101,4 +106,9 @@
 int kbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call)
 {
+	if (sysinfo_value("kbd.type") == KBD_SGCN) {
+		sgcn_key_pressed();
+		return 1;
+	}
+	
 	int scan_code = IPC_GET_ARG1(*call);
 
Index: uspace/srv/kbd/arch/sparc64/src/sgcn.c
===================================================================
--- uspace/srv/kbd/arch/sparc64/src/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/arch/sparc64/src/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,147 @@
+/*
+ * 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 kbdsparc64 sparc64
+ * @brief	Serengeti-specific parts of uspace keyboard handler.
+ * @ingroup  kbd
+ * @{
+ */ 
+/** @file
+ */
+
+#include <arch/sgcn.h>
+#include <as.h>
+#include <ddi.h>
+#include <ipc/ipc.h>
+#include <kbd.h>
+#include <genarch/nofb.h>
+#include <genarch/kbd.h>
+#include <sysinfo.h>
+#include <stdio.h>
+#include <futex.h>
+
+/**
+ * SGCN buffer header. It is placed at the very beginning of the SGCN
+ * buffer. 
+ */
+typedef struct {
+	/** hard-wired to "CON" */
+	char magic[4];
+	
+	/** 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;
+} __attribute__ ((packed)) sgcn_buffer_header_t;
+
+/*
+ * 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 *) (sram_virt_addr + sram_buffer_offset + (offset)))
+
+/** Returns a pointer to the console buffer header. */
+#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
+extern keybuffer_t keybuffer;
+
+/**
+ * Virtual address mapped to SRAM.
+ */
+static uintptr_t sram_virt_addr;
+
+/**
+ * SGCN buffer offset within SGCN.
+ */
+static uintptr_t sram_buffer_offset;
+
+/**
+ * Initializes the SGCN driver.
+ * Maps the physical memory (SRAM) and registers the interrupt. 
+ */
+void sgcn_init(void)
+{
+	sram_virt_addr = (uintptr_t) as_get_mappable_page(
+		sysinfo_value("sram.area.size"));
+	int result = physmem_map(
+		(void *) sysinfo_value("sram.address.physical"),
+		(void *) sram_virt_addr,
+		sysinfo_value("sram.area.size") / PAGE_SIZE,
+		AS_AREA_READ | AS_AREA_WRITE
+		);
+	if (result != 0) {
+		printf("SGCN: uspace driver could not map physical memory.");
+	}
+	
+	sram_buffer_offset = sysinfo_value("sram.buffer.offset");
+	ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"),
+		0, (void *) 0);
+}
+
+/**
+ * Handler of the "key pressed" event. Reads codes of all the pressed keys from
+ * the buffer. 
+ */
+void sgcn_key_pressed(void)
+{
+	char c;
+	
+	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->in_end;
+	uint32_t size = end - begin;
+	
+	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);
+	
+	while (*in_rdptr_ptr != *in_wrptr_ptr) {
+		c = *buf_ptr;
+		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
+		buf_ptr = (volatile char *)
+			SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+		if (c == '\r') {
+                        c = '\n';
+                }
+		kbd_process_no_fb(&keybuffer, c);
+	}
+}
+
+/** @}
+ */
Index: uspace/srv/kbd/genarch/include/nofb.h
===================================================================
--- uspace/srv/kbd/genarch/include/nofb.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/genarch/include/nofb.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,48 @@
+/*
+ * 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 kbd
+ * @{
+ */ 
+/** @file
+ */
+
+#ifndef KBD_genarch_NOFB_H_
+#define KBD_genarch_NOFB_H_
+
+
+#include <key_buffer.h>
+#include <genarch/scanc.h>
+
+extern int kbd_process_no_fb(keybuffer_t *keybuffer, int scan_code);
+
+#endif
+
+/**
+ * @}
+ */ 
Index: uspace/srv/kbd/genarch/src/nofb.c
===================================================================
--- uspace/srv/kbd/genarch/src/nofb.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/genarch/src/nofb.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2006 Josef Cejka
+ * 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 kbdmips32 mips32
+ * @brief	HelenOS mips32 arch dependent parts of uspace keyboard handler.
+ * @ingroup  kbd
+ * @{
+ */ 
+ 
+/** @file
+ */
+
+#include <genarch/nofb.h>
+#include <stdio.h> // DELETE!!!
+
+#define KEY_F1 0x504f1bL
+#define KEY_F2 0x514f1bL
+#define KEY_F3 0x524f1bL
+#define KEY_F4 0x534f1bL
+#define KEY_F5 0x35315b1bL
+#define KEY_F6 0x37315b1bL
+#define KEY_F7 0x38315b1bL
+#define KEY_F8 0x39315b1bL
+#define KEY_F9 0x30325b1bL
+#define KEY_F10 0x31325b1bL
+#define KEY_F11 0x33325b1bL
+#define KEY_F12 0x34325b1bL
+
+/**
+ * Processes the key pressed - pushes the key code into the key buffer.
+ * Used in MSIM and Serengeti, i.e. non-framebuffer consoles.
+ */
+int kbd_process_no_fb(keybuffer_t *keybuffer, int scan_code)
+{
+	static unsigned long buf = 0;
+	static int count = 0;	
+	
+	if(scan_code == 0x7e) {
+		switch (buf) {
+		case KEY_F5:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 5);
+			buf = count = 0;
+			return 1;
+		case KEY_F6:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 6);
+			buf = count = 0;
+			return 1;
+		case KEY_F7:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 7);
+			buf = count = 0;
+			return 1;
+		case KEY_F8:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 8);
+			buf = count = 0;
+			return 1;
+		case KEY_F9:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 9);
+			buf = count = 0;
+			return 1;
+		case KEY_F10:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 10);
+			buf = count = 0;
+			return 1;
+		case KEY_F11:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 11);
+			buf = count = 0;
+			return 1;
+		case KEY_F12:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 12);
+			buf = count = 0;
+			return 1;
+		default:
+			keybuffer_push(keybuffer, buf & 0xff);
+			keybuffer_push(keybuffer, (buf >> 8) &0xff);
+			keybuffer_push(keybuffer, (buf >> 16) &0xff);
+			keybuffer_push(keybuffer, (buf >> 24) &0xff);
+			keybuffer_push(keybuffer, scan_code);
+			buf = count = 0;
+			return 1;
+		}
+	}
+
+	buf |= ((unsigned long) scan_code)<<(8*(count++));
+	
+	if((buf & 0xff) != (KEY_F1 & 0xff)) {
+		keybuffer_push(keybuffer, buf);
+		buf = count = 0;
+		return 1;
+	}
+
+	if (count <= 1) 
+		return 1;
+
+	if ((buf & 0xffff) != (KEY_F1 & 0xffff) 
+		&& (buf & 0xffff) != (KEY_F5 & 0xffff) ) {
+
+		keybuffer_push(keybuffer, buf & 0xff);
+		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		buf = count = 0;
+		return 1;
+	}
+
+	if (count <= 2) 
+		return 1;
+
+	switch (buf) {
+	case KEY_F1:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 1);
+		buf = count = 0;
+		return 1;
+	case KEY_F2:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 2);
+		buf = count = 0;
+		return 1;
+	case KEY_F3:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 3);
+		buf = count = 0;
+		return 1;
+	case KEY_F4:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 4);
+		buf = count = 0;
+		return 1;
+	}
+
+
+	if((buf & 0xffffff) != (KEY_F5 & 0xffffff)
+		&& (buf & 0xffffff) != (KEY_F9 & 0xffffff)) {
+
+		keybuffer_push(keybuffer, buf & 0xff);
+		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
+		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
+		buf=count=0;
+		return 1;
+	}
+
+	if (count <= 3)
+		return 1;
+	
+	switch (buf) {
+	case KEY_F5:
+	case KEY_F6:
+	case KEY_F7:
+	case KEY_F8:
+	case KEY_F9:
+	case KEY_F10:
+	case KEY_F11:
+	case KEY_F12:
+		return 1;
+	default:
+		keybuffer_push(keybuffer, buf & 0xff);
+		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push(keybuffer, (buf >> 16) &0xff);
+		keybuffer_push(keybuffer, (buf >> 24) &0xff);
+		buf = count = 0;
+		return 1;
+	}
+
+	return 1;
+}
+
+/** @}
+ */
