Index: boot/arch/sparc64/loader/asm.S
===================================================================
--- boot/arch/sparc64/loader/asm.S	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/arch/sparc64/loader/asm.S	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -101,4 +101,5 @@
 	mov %o1, %o0
 	mov %o2, %o1
+	mov %o3, %o2
 	jmp %l1				! jump to kernel
 	nop
Index: boot/arch/sparc64/loader/asm.h
===================================================================
--- boot/arch/sparc64/loader/asm.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/arch/sparc64/loader/asm.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -36,5 +36,5 @@
 
 extern void halt(void);
-extern void jump_to_kernel(void *entry, void *bootinfo, unsigned int bootinfo_size) __attribute__((noreturn));
+extern void jump_to_kernel(void *entry, int bsp, void *bootinfo, unsigned int bootinfo_size) __attribute__((noreturn));
 
 #endif
Index: boot/arch/sparc64/loader/main.c
===================================================================
--- boot/arch/sparc64/loader/main.c	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/arch/sparc64/loader/main.c	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -37,6 +37,4 @@
 #include <align.h>
 
-#define KERNEL_VIRTUAL_ADDRESS 0x400000
-
 bootinfo_t bootinfo;
 
@@ -58,9 +56,5 @@
 	}
 	
-	if (!ofw_cpu(&bootinfo.cpu))
-		printf("Error: unable to get cpu properties\n");
-
-	printf("\nDevice info\n");
-	printf(" cpu: %dMHz\n", bootinfo.cpu.clock_frequency/1000000);
+	printf("\nSystem info\n");
 	printf(" memory: %dM\n", bootinfo.memmap.total>>20);
 
@@ -97,5 +91,10 @@
 	printf("done.\n");
 
+	printf("\nChecking for secondary processors...");
+	if (!ofw_cpu())
+		printf("Error: unable to get cpu properties\n");
+	printf("done.\n");
+
 	printf("\nBooting the kernel...\n");
-	jump_to_kernel((void *) KERNEL_VIRTUAL_ADDRESS, &bootinfo, sizeof(bootinfo));
+	jump_to_kernel((void *) KERNEL_VIRTUAL_ADDRESS, 1, &bootinfo, sizeof(bootinfo));
 }
Index: boot/arch/sparc64/loader/main.h
===================================================================
--- boot/arch/sparc64/loader/main.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/arch/sparc64/loader/main.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -35,4 +35,6 @@
 #include <types.h>
 
+#define KERNEL_VIRTUAL_ADDRESS 0x400000
+
 #define TASKMAP_MAX_RECORDS 32
 
@@ -48,11 +50,6 @@
 
 typedef struct {
-	uint32_t clock_frequency;
-} cpu_t;
-
-typedef struct {
 	taskmap_t taskmap;
 	memmap_t memmap;
-	cpu_t cpu;
 	ballocs_t ballocs;
 	ofw_tree_node_t *ofw_root;
Index: boot/arch/sparc64/loader/ofwarch.c
===================================================================
--- boot/arch/sparc64/loader/ofwarch.c	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/arch/sparc64/loader/ofwarch.c	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -54,5 +54,10 @@
 }
 
-int ofw_cpu(cpu_t *cpu)
+
+#define ASI_UPA_CONFIG		0x4a
+#define UPA_CONFIG_MID_SHIFT 	17
+#define UPA_CONFIG_MID_MASK	0x1f
+
+int ofw_cpu(void)
 {
 	char type_name[BUF_SIZE];
@@ -62,21 +67,31 @@
 	if (node == 0 || node == -1) {
 		printf("Could not find any child nodes of the root node.\n");
-		return;
+		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;
 	
 	for (; node != 0 && node != -1; node = ofw_get_peer_node(node)) {
 		if (ofw_get_property(node, "device_type", type_name, sizeof(type_name)) > 0) {
 			if (strcmp(type_name, "cpu") == 0) {
-				uint32_t mhz;
+				uint32_t mid;
 				
-				if (ofw_get_property(node, "clock-frequency", &mhz, sizeof(mhz)) <= 0)
+				if (ofw_get_property(node, "upa-portid", &mid, sizeof(mid)) <= 0)
 					continue;
 					
-				cpu->clock_frequency = mhz;
-				return 1;
+				if (current_mid != mid) {
+					/*
+					 * Start secondary processor.
+					 */
+					(void) ofw_call("SUNW,start-cpu", 3, 1, NULL, node, KERNEL_VIRTUAL_ADDRESS, 0);
+				}
 			}
 		}
-	};
+	}
 
-	return 0;
+	return 1;
 }
Index: boot/arch/sparc64/loader/ofwarch.h
===================================================================
--- boot/arch/sparc64/loader/ofwarch.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/arch/sparc64/loader/ofwarch.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -35,7 +35,5 @@
 #define OFW_SIZE_CELLS		2
 
-extern int bpp2align[];
-
-extern int ofw_cpu(cpu_t *cpu);
+extern int ofw_cpu(void);
 
 #endif
Index: boot/genarch/ofw.c
===================================================================
--- boot/genarch/ofw.c	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/genarch/ofw.c	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -84,5 +84,5 @@
  * @return Return value returned by the client interface.
  */
-static 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;
Index: boot/genarch/ofw.h
===================================================================
--- boot/genarch/ofw.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ boot/genarch/ofw.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -91,5 +91,4 @@
 extern uintptr_t ofw_cif;
 
-
 extern phandle ofw_chosen;
 extern ihandle ofw_stdout;
@@ -114,4 +113,5 @@
 
 extern int ofw(ofw_args_t *arg);
+extern unsigned long ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets, ...);
 extern unsigned int ofw_get_address_cells(const phandle device);
 extern unsigned int ofw_get_size_cells(const phandle device);
Index: kernel/arch/sparc64/include/arch.h
===================================================================
--- kernel/arch/sparc64/include/arch.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/include/arch.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -38,8 +38,8 @@
 #define KERN_sparc64_ARCH_H_
 
-#define ASI_AIUP	0x10		/** Access to primary context with user privileges. */
-#define ASI_AIUS	0x11		/** Access to secondary context with user privileges. */
-
+#define ASI_AIUP		0x10	/** Access to primary context with user privileges. */
+#define ASI_AIUS		0x11	/** Access to secondary context with user privileges. */
 #define ASI_NUCLEUS_QUAD_LDD	0x24	/** ASI for 16-byte atomic loads. */
+#define ASI_UPA_CONFIG		0x4a	/** ASI of the UPA_CONFIG register. */
 
 #define NWINDOW		8		/** Number of register window sets. */
Index: kernel/arch/sparc64/include/asm.h
===================================================================
--- kernel/arch/sparc64/include/asm.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/include/asm.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -359,4 +359,13 @@
 }
 
+/** 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/boot/boot.h
===================================================================
--- kernel/arch/sparc64/include/boot/boot.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/include/boot/boot.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -71,8 +71,4 @@
 } memmap_t;
 
-typedef struct {
-	uint32_t clock_frequency;
-} processor_t;
-
 /** Bootinfo structure.
  *
@@ -82,5 +78,4 @@
 	taskmap_t taskmap;
 	memmap_t memmap;
-	processor_t processor;
 	ballocs_t ballocs;
 	ofw_tree_node_t *ofw_root;
Index: kernel/arch/sparc64/include/register.h
===================================================================
--- kernel/arch/sparc64/include/register.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/include/register.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -118,4 +118,21 @@
 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/src/cpu/cpu.c
===================================================================
--- kernel/arch/sparc64/src/cpu/cpu.c	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/src/cpu/cpu.c	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -36,13 +36,40 @@
 #include <cpu.h>
 #include <arch.h>
+#include <print.h>
 #include <arch/register.h>
-#include <print.h>
-#include <arch/boot/boot.h>
+#include <genarch/ofw/ofw_tree.h>
+#include <arch/types.h>
+#include <arch/drivers/tick.h>
 
+/** Perform sparc64 specific initialization of the processor structure for the current processor. */
 void cpu_arch_init(void)
 {
-	CPU->arch.clock_frequency = bootinfo.processor.clock_frequency;
+	ofw_tree_node_t *node;
+	uint32_t mid;
+	uint32_t clock_frequency = 0;
+	upa_config_t upa_config;
+	
+	upa_config.value = upa_config_read();
+	node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu");
+	while (node) {
+		ofw_tree_property_t *prop;
+		
+		prop = ofw_tree_getprop(node, "upa-portid");
+		if (prop && prop->value) {
+			mid = *((uint32_t *) prop->value);
+			if (mid == upa_config.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();
 }
 
+/** Read version information from the current processor. */
 void cpu_identify(void)
 {
@@ -50,4 +77,8 @@
 }
 
+/** Print version information for a processor.
+ *
+ * @param m Processor structure of the CPU for which version information is to be printed.
+ */
 void cpu_print_report(cpu_t *m)
 {
Index: kernel/arch/sparc64/src/drivers/tick.c
===================================================================
--- kernel/arch/sparc64/src/drivers/tick.c	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/src/drivers/tick.c	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -53,5 +53,5 @@
 	interrupt_register(14, "tick_int", tick_interrupt);
 	compare.int_dis = false;
-	compare.tick_cmpr = bootinfo.processor.clock_frequency/HZ;
+	compare.tick_cmpr = CPU->arch.clock_frequency/HZ;
 	tick_compare_write(compare.value);
 	tick_write(0);
Index: kernel/arch/sparc64/src/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sparc64.c	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/src/sparc64.c	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -38,5 +38,4 @@
 #include <arch/trap/trap.h>
 #include <arch/console.h>
-#include <arch/drivers/tick.h>
 #include <proc/thread.h>
 #include <console/console.h>
@@ -73,5 +72,4 @@
 {
 	trap_init();
-	tick_init();
 }
 
Index: kernel/arch/sparc64/src/start.S
===================================================================
--- kernel/arch/sparc64/src/start.S	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/arch/sparc64/src/start.S	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -44,6 +44,7 @@
  * 
  * The registers are expected to be in this state:
- * - %o0 bootinfo structure address
- * - %o1 bootinfo structure size
+ * - %o0 non-zero for the bootstrup processor, zero for application/secondary processors
+ * - %o1 bootinfo structure address
+ * - %o2 bootinfo structure size
  *
  * Moreover, we depend on boot having established the
@@ -56,4 +57,6 @@
 .global kernel_image_start
 kernel_image_start:
+	brz %o0, kernel_image_start		! block secondary processors
+	nop
 
 	/*
@@ -73,6 +76,4 @@
 	 * to the kernel bootinfo structure.
 	 */
-	mov %o1, %o2
-	mov %o0, %o1
 	sethi %hi(bootinfo), %o0
 	call memcpy
Index: kernel/genarch/include/ofw/ofw_tree.h
===================================================================
--- kernel/genarch/include/ofw/ofw_tree.h	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/genarch/include/ofw/ofw_tree.h	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -129,4 +129,7 @@
 extern ofw_tree_node_t *ofw_tree_lookup(const char *path);
 extern ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node, const char *name);
+extern ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name);
+extern ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node, const char *device_type);
+extern ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node, const char *device_type);
 
 extern bool ofw_fhc_apply_ranges(ofw_tree_node_t *node, ofw_fhc_reg_t *reg, uintptr_t *pa);
Index: kernel/genarch/src/ofw/ofw_tree.c
===================================================================
--- kernel/genarch/src/ofw/ofw_tree.c	(revision 6ff1f1e849d8a798e3ed34a6dcdd58b2f25b0055)
+++ kernel/genarch/src/ofw/ofw_tree.c	(revision 45b26dad9e99feac8777a9787b017301df054794)
@@ -98,5 +98,5 @@
  * @return NULL if there is no such child or pointer to the matching child node.
  */
-static ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name)
+ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name)
 {
 	ofw_tree_node_t *cur;
@@ -125,4 +125,51 @@
 }
 
+/** 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)
+{
+	ofw_tree_node_t *cur;
+	ofw_tree_property_t *prop;
+	
+	for (cur = node->child; cur; cur = cur->peer) {
+		prop = ofw_tree_getprop(cur, "device_type");
+		if (!prop || !prop->value)
+			continue;
+		if (strcmp(prop->value, name) == 0)
+			return cur;
+	}
+			
+	return NULL;
+}
+
+/** 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)
+{
+	ofw_tree_node_t *cur;
+	ofw_tree_property_t *prop;
+	
+	for (cur = node->peer; cur; cur = cur->peer) {
+		prop = ofw_tree_getprop(cur, "device_type");
+		if (!prop || !prop->value)
+			continue;
+		if (strcmp(prop->value, name) == 0)
+			return cur;
+	}
+			
+	return NULL;
+}
+
+
 /** Lookup OpenFirmware node by its path.
  *
