Index: kernel/arch/sparc64/Makefile.inc
===================================================================
--- kernel/arch/sparc64/Makefile.inc	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/Makefile.inc	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -71,4 +71,8 @@
 CONFIG_OFW_TREE = y
 
+ifeq ($(CONFIG_SMP),y)
+	DEFS += -DCONFIG_SMP
+endif
+
 ARCH_SOURCES = \
 	arch/$(ARCH)/src/cpu/cpu.c \
@@ -99,4 +103,10 @@
 	arch/$(ARCH)/src/drivers/scr.c
 
+ifeq ($(CONFIG_SMP),y)
+ARCH_SOURCES += \
+	arch/$(ARCH)/src/smp/ipi.c \
+	arch/$(ARCH)/src/smp/smp.c
+endif
+
 ifeq ($(CONFIG_TSB),y)
 ARCH_SOURCES += \
Index: kernel/arch/sparc64/include/atomic.h
===================================================================
--- kernel/arch/sparc64/include/atomic.h	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/include/atomic.h	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -97,6 +97,7 @@
 {
 	uint64_t v = 1;
+	volatile uintptr_t x = (uint64_t) &val->count;
 
-	__asm__ volatile ("casx %0, %2, %1\n" : "+m" (*val), "+r" (v) : "r" (0));
+	__asm__ volatile ("casx %0, %2, %1\n" : "+m" (*((uint64_t *) x)), "+r" (v) : "r" (0));
 
 	return v;
@@ -107,4 +108,6 @@
 	uint64_t tmp1 = 1;
 	uint64_t tmp2;
+
+	volatile uintptr_t x = (uint64_t) &val->count;
 
 	__asm__ volatile (
@@ -120,5 +123,5 @@
 		"nop\n"
 	"2:\n"
-		: "+m" (*val), "+r" (tmp1), "+r" (tmp2) : "r" (0)
+		: "+m" (*((uint64_t *) x)), "+r" (tmp1), "+r" (tmp2) : "r" (0)
 	);
 	
Index: kernel/arch/sparc64/include/cpu.h
===================================================================
--- kernel/arch/sparc64/include/cpu.h	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/include/cpu.h	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -36,4 +36,5 @@
 #define KERN_sparc64_CPU_H_
 
+#include <arch/types.h>
 #include <arch/register.h>
 
@@ -52,6 +53,7 @@
 
 struct cpu_arch {
+	uint32_t mid;			/**< Processor ID as read from UPA_CONFIG. */
 	ver_reg_t ver;
-	uint32_t clock_frequency;
+	uint32_t clock_frequency;	/**< Processor frequency in MHz. */
 };
 	
Index: kernel/arch/sparc64/include/interrupt.h
===================================================================
--- kernel/arch/sparc64/include/interrupt.h	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/include/interrupt.h	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -41,8 +41,10 @@
 #include <arch/regdef.h>
 
-#define IRQ_COUNT	1	/* TODO */
+#define IRQ_COUNT	1			/* TODO */
 
 #define IVT_ITEMS 	15
 #define IVT_FIRST	1
+
+#define VECTOR_TLB_SHOOTDOWN_IPI	0	/* TODO */
 
 struct istate {
Index: kernel/arch/sparc64/include/regdef.h
===================================================================
--- kernel/arch/sparc64/include/regdef.h	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/include/regdef.h	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -56,4 +56,7 @@
 #define WSTATE_OTHER(n)		((n)<<3)
 
+#define UPA_CONFIG_MID_SHIFT    17
+#define UPA_CONFIG_MID_MASK     0x1f
+
 #endif
 
Index: kernel/arch/sparc64/src/cpu/cpu.c
===================================================================
--- kernel/arch/sparc64/src/cpu/cpu.c	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/src/cpu/cpu.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -51,4 +51,6 @@
 	
 	upa_config.value = upa_config_read();
+	CPU->arch.mid = upa_config.mid;
+	
 	node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
 	while (node) {
@@ -58,5 +60,5 @@
 		if (prop && prop->value) {
 			mid = *((uint32_t *) prop->value);
-			if (mid == upa_config.mid) {
+			if (mid == CPU->arch.mid) {
 				prop = ofw_tree_getprop(node, "clock-frequency");
 				if (prop && prop->value)
@@ -79,4 +81,6 @@
 /** Print version information for a processor.
  *
+ * This function is called by the bootstrap processor.
+ *
  * @param m Processor structure of the CPU for which version information is to be printed.
  */
@@ -85,15 +89,15 @@
 	char *manuf, *impl;
 
-	switch (CPU->arch.ver.manuf) {
-	    case MANUF_FUJITSU:
+	switch (m->arch.ver.manuf) {
+	case MANUF_FUJITSU:
 		manuf = "Fujitsu";
 		break;
-	    case MANUF_ULTRASPARC:
+	case MANUF_ULTRASPARC:
 		manuf = "UltraSPARC";
 		break;
-	    case MANUF_SUN:
+	case MANUF_SUN:
 	    	manuf = "Sun";
 		break;
-	    default:
+	default:
 		manuf = "Unknown";
 		break;
@@ -101,26 +105,26 @@
 	
 	switch (CPU->arch.ver.impl) {
-	    case IMPL_ULTRASPARCI:
+	case IMPL_ULTRASPARCI:
 		impl = "UltraSPARC I";
 		break;
-	    case IMPL_ULTRASPARCII:
+	case IMPL_ULTRASPARCII:
 		impl = "UltraSPARC II";
 		break;
-	    case IMPL_ULTRASPARCII_I:
+	case IMPL_ULTRASPARCII_I:
 		impl = "UltraSPARC IIi";
 		break;
-	    case IMPL_ULTRASPARCII_E:
+	case IMPL_ULTRASPARCII_E:
 		impl = "UltraSPARC IIe";
 		break;
-	    case IMPL_ULTRASPARCIII:
+	case IMPL_ULTRASPARCIII:
 		impl = "UltraSPARC III";
 		break;
-	    case IMPL_ULTRASPARCIV_PLUS:
+	case IMPL_ULTRASPARCIV_PLUS:
 		impl = "UltraSPARC IV+";
 		break;
-	    case IMPL_SPARC64V:
+	case IMPL_SPARC64V:
 		impl = "SPARC 64V";
 		break;
-	    default:
+	default:
 		impl = "Unknown";
 		break;
@@ -128,5 +132,5 @@
 
 	printf("cpu%d: manuf=%s, impl=%s, mask=%d (%dMHz)\n",
-		CPU->id, manuf, impl, CPU->arch.ver.mask, CPU->arch.clock_frequency/1000000);
+		m->id, manuf, impl, m->arch.ver.mask, m->arch.clock_frequency/1000000);
 }
 
Index: kernel/arch/sparc64/src/mm/as.c
===================================================================
--- kernel/arch/sparc64/src/mm/as.c	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/src/mm/as.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -38,4 +38,5 @@
 #include <genarch/mm/asid_fifo.h>
 #include <debug.h>
+#include <config.h>
 
 #ifdef CONFIG_TSB
@@ -52,6 +53,8 @@
 void as_arch_init(void)
 {
-	as_operations = &as_ht_operations;
-	asid_fifo_init();
+	if (config.cpu_active == 1) {
+		as_operations = &as_ht_operations;
+		asid_fifo_init();
+	}
 }
 
Index: kernel/arch/sparc64/src/mm/frame.c
===================================================================
--- kernel/arch/sparc64/src/mm/frame.c	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/src/mm/frame.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -54,19 +54,21 @@
 	pfn_t confdata;
 
-	for (i = 0; i < bootinfo.memmap.count; i++) {
-		uintptr_t start = bootinfo.memmap.zones[i].start;
-		size_t size = bootinfo.memmap.zones[i].size;
+	if (config.cpu_active == 1) {
+		for (i = 0; i < bootinfo.memmap.count; i++) {
+			uintptr_t start = bootinfo.memmap.zones[i].start;
+			size_t size = bootinfo.memmap.zones[i].size;
 
-		/*
-		 * The memmap is created by HelenOS boot loader.
-		 * It already contains no holes.
-		 */
+			/*
+			 * The memmap is created by HelenOS boot loader.
+			 * It already contains no holes.
+			 */
 	
-		confdata = ADDR2PFN(start);
-		if (confdata == 0)
-			confdata = 2;
-		zone_create(ADDR2PFN(start), SIZE2FRAMES(ALIGN_DOWN(size, FRAME_SIZE)),	confdata, 0);
+			confdata = ADDR2PFN(start);
+			if (confdata == 0)
+				confdata = 2;
+			zone_create(ADDR2PFN(start), SIZE2FRAMES(ALIGN_DOWN(size, FRAME_SIZE)),	confdata, 0);
 		
-		last_frame = max(last_frame, start + ALIGN_UP(size, FRAME_SIZE));
+			last_frame = max(last_frame, start + ALIGN_UP(size, FRAME_SIZE));
+		}
 	}
 
Index: kernel/arch/sparc64/src/mm/page.c
===================================================================
--- kernel/arch/sparc64/src/mm/page.c	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/src/mm/page.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -41,8 +41,43 @@
 #include <debug.h>
 #include <align.h>
+#include <config.h>
 
+#ifdef CONFIG_SMP
+/** Entries locked in DTLB of BSP.
+ *
+ * Application processors need to have the same locked entries
+ * in their DTLBs as the bootstrap processor.
+ */
+static struct {
+	uintptr_t virt_page;
+	uintptr_t phys_page;
+	int pagesize_code;
+} bsp_locked_dtlb_entry[DTLB_ENTRY_COUNT];
+
+/** Number of entries in bsp_locked_dtlb_entry array. */
+static count_t bsp_locked_dtlb_entries = 0;
+#endif /* CONFIG_SMP */
+
+/** Perform sparc64 specific initialization of paging. */
 void page_arch_init(void)
 {
-	page_mapping_operations = &ht_mapping_operations;
+	if (config.cpu_active == 1) {
+		page_mapping_operations = &ht_mapping_operations;
+	} else {
+
+#ifdef CONFIG_SMP
+		int i;
+
+		/*
+		 * Copy locked DTLB entries from the BSP.
+		 */		
+		for (i = 0; i < bsp_locked_dtlb_entries; i++) {
+			dtlb_insert_mapping(bsp_locked_dtlb_entry[i].virt_page,
+				bsp_locked_dtlb_entry[i].phys_page, bsp_locked_dtlb_entry[i].pagesize_code,
+				true, false);
+		}
+#endif	
+
+	}
 }
 
@@ -68,6 +103,8 @@
 	int i;
 
+	ASSERT(config.cpu_active == 1);
+
 	struct {
-		int pagesize;
+		int pagesize_code;
 		size_t increment;
 		count_t count;
@@ -102,8 +139,22 @@
 	last_frame = ALIGN_UP(virtaddr + size, 1<<(order + FRAME_WIDTH));
 	
-	for (i = 0; i < sizemap[order].count; i++)
+	for (i = 0; i < sizemap[order].count; i++) {
+		/*
+		 * First, insert the mapping into DTLB.
+		 */
 		dtlb_insert_mapping(virtaddr + i*sizemap[order].increment,
 				    physaddr + i*sizemap[order].increment,
-				    sizemap[order].pagesize, true, false);
+				    sizemap[order].pagesize_code, true, false);
+	
+#ifdef CONFIG_SMP	
+		/*
+		 * Second, save the information about the mapping for APs.
+		 */
+		bsp_locked_dtlb_entry[bsp_locked_dtlb_entries].virt_page = virtaddr + i*sizemap[order].increment;
+		bsp_locked_dtlb_entry[bsp_locked_dtlb_entries].phys_page = physaddr + i*sizemap[order].increment;
+		bsp_locked_dtlb_entry[bsp_locked_dtlb_entries].pagesize_code = sizemap[order].pagesize_code;
+		bsp_locked_dtlb_entries++;
+#endif
+	}
 	
 	return virtaddr;
Index: kernel/arch/sparc64/src/smp/ipi.c
===================================================================
--- kernel/arch/sparc64/src/smp/ipi.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
+++ kernel/arch/sparc64/src/smp/ipi.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 Jakub Jermar
+ * 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
+ */
+
+#include <smp/ipi.h>
+
+void ipi_broadcast_arch(int ipi)
+{
+	/* TODO */
+}
+
+/** @}
+ */
Index: kernel/arch/sparc64/src/smp/smp.c
===================================================================
--- kernel/arch/sparc64/src/smp/smp.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
+++ kernel/arch/sparc64/src/smp/smp.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2006 Jakub Jermar
+ * 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
+ */
+
+#include <smp/smp.h>
+#include <genarch/ofw/ofw_tree.h>
+#include <cpu.h>
+#include <arch/cpu.h>
+#include <arch.h>
+#include <config.h>
+#include <macros.h>
+#include <arch/types.h>
+#include <synch/synch.h>
+#include <synch/waitq.h>
+#include <typedefs.h>
+#include <print.h>
+
+/**
+ * This global variable is used to pick-up application processors
+ * from their active loop in start.S. When a processor looping in
+ * start.S sees that this variable contains its MID, it can
+ * proceed with its initialization.
+ *
+ * This variable is modified only by the bootstrap processor.
+ * Other processors access it read-only.
+ */
+volatile uint64_t waking_up_mid = (uint64_t) -1;
+
+/** Determine number of processors. */
+void smp_init(void)
+{
+	ofw_tree_node_t *node;
+	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");
+	}
+	
+	config.cpu_count = max(1, cnt);
+}
+
+/** Wake application processors up. */
+void kmp(void *arg)
+{
+	ofw_tree_node_t *node;
+	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;
+		}
+
+		/*
+		 * 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 = %d) timed out\n",
+				__FUNCTION__, mid);
+	}
+}
+
+/** @}
+ */
Index: kernel/arch/sparc64/src/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sparc64.c	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/src/sparc64.c	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -71,10 +71,12 @@
 void arch_pre_mm_init(void)
 {
-	trap_init();
+	if (config.cpu_active == 1)
+		trap_init();
 }
 
 void arch_post_mm_init(void)
 {
-	standalone_sparc64_console_init();
+	if (config.cpu_active == 1)
+		standalone_sparc64_console_init();
 }
 
@@ -91,11 +93,13 @@
 	thread_t *t;
 
-	/*
-         * Create thread that polls keyboard.
-         */
-	t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll");
-	if (!t)
-		panic("cannot create kkbdpoll\n");
-	thread_ready(t);
+	if (config.cpu_active == 1) {
+		/*
+	         * Create thread that polls keyboard.
+	         */
+		t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll");
+		if (!t)
+			panic("cannot create kkbdpoll\n");
+		thread_ready(t);
+	}
 }
 
Index: kernel/arch/sparc64/src/start.S
===================================================================
--- kernel/arch/sparc64/src/start.S	(revision 86b31ba91000ae628d5c9947116b77aab8dcd45f)
+++ kernel/arch/sparc64/src/start.S	(revision a9ac978f3aba8259d5f8270ee59a08a41d15d94c)
@@ -27,4 +27,5 @@
 #
 
+#include <arch/arch.h>
 #include <arch/regdef.h>
 #include <arch/boot/boot.h>
@@ -33,4 +34,8 @@
 #include <arch/mm/tlb.h>
 #include <arch/mm/tte.h>
+
+#ifdef CONFIG_SMP
+#include <arch/context_offset.h>
+#endif
 
 .register %g2, #scratch
@@ -227,5 +232,6 @@
 	wrpr %g0, 0, %tl
 
-	brz %l7, 2f				! skip if you are not the bootstrap CPU
+	brz %l7, 1f				! skip if you are not the bootstrap CPU
+	nop
 
 	call arch_pre_main
@@ -237,5 +243,47 @@
 	/* Not reached. */
 
+0:
+	ba 0b
+	nop
+
+
+	/*
+	 * 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
+
+	/*
+	 * Active loop for APs until the BSP picks them up.
+	 * A processor cannot leave the loop until the
+	 * global variable 'waking_up_mid' equals its
+	 * MID.
+	 */
+	set waking_up_mid, %g2
 2:
-	b 2b
-	nop
+	ldx [%g2], %g3
+	cmp %g3, %g1
+	bne 2b
+	nop
+
+#ifdef CONFIG_SMP
+	/*
+	 * Configure stack for the AP.
+	 * The AP is expected to use the stack saved
+	 * in the ctx global variable.
+	 */
+	set ctx, %g1
+	add %g1, OFFSET_SP, %g1
+	ldx [%g1], %o6
+
+	call main_ap
+	nop
+#endif
+
+	/* Not reached. */
+	
+0:
+	ba 0b
+	nop
