Index: uspace/srv/fb/Makefile
===================================================================
--- uspace/srv/fb/Makefile	(revision 323a5aaf36674c20719d102e0508c32ef466bfa3)
+++ uspace/srv/fb/Makefile	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 323a5aaf36674c20719d102e0508c32ef466bfa3)
+++ uspace/srv/fb/main.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 323a5aaf36674c20719d102e0508c32ef466bfa3)
+++ uspace/srv/fb/msim.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
+++ uspace/srv/fb/serial_console.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
+++ uspace/srv/fb/serial_console.h	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
+++ uspace/srv/fb/sgcn.c	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
+++ uspace/srv/fb/sgcn.h	(revision 2b1f8608eb11a5a5a4ef29c4d03641eff9b079ac)
@@ -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
+
+/** 
+ * @}
+ */
