| #include <smp.h> | 
 | #include <arch/arch.h> | 
 | #include <arch/smp.h> | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 | #include <error.h> | 
 | #include <assert.h> | 
 | #include <atomic.h> | 
 | #include <pmap.h> | 
 |  | 
 | volatile uint32_t num_cores_booted = 0; | 
 |  | 
 | void | 
 | smp_boot(void) | 
 | { | 
 | 	smp_percpu_init(); | 
 | 	num_cores_booted = 1; | 
 | 	while(num_cores_booted < num_cores); | 
 | 	printd("%d cores reporting!\n", num_cores); | 
 | } | 
 |  | 
 | void | 
 | smp_init(void) | 
 | { | 
 | 	smp_percpu_init(); | 
 |  | 
 | 	__sync_fetch_and_add(&num_cores_booted, 1); | 
 | 	printd("Good morning, Vietnam! (core id = %d)\n",core_id()); | 
 |  | 
 | 	smp_idle(); | 
 | } | 
 |  | 
 | handler_wrapper_t* | 
 | smp_make_wrapper() | 
 | { | 
 | 	static handler_wrapper_t | 
 | 	wrapper_pool[MAX_NUM_CORES*8] = {{{0},SPINLOCK_INITIALIZER}}; | 
 |  | 
 | 	size_t i; | 
 | 	for(i = 0; i < sizeof(wrapper_pool)/sizeof(wrapper_pool[0]); i++) | 
 | 		if(spin_trylock(&wrapper_pool[i].lock) == 0) | 
 | 			return &wrapper_pool[i]; | 
 | 	return NULL; | 
 | } | 
 |  | 
 | void smp_call_wrapper(uint32_t src, isr_t handler, handler_wrapper_t *wrapper, | 
 |                       void *data) | 
 | { | 
 | 	if(wrapper) | 
 | 		wrapper->wait_list[core_id()] = 0; | 
 | 	handler(0, data); | 
 | } | 
 |  | 
 | int smp_call_function_self(isr_t handler, void* data, | 
 |                            handler_wrapper_t** wait_wrapper) | 
 | { | 
 | 	return smp_call_function_single(core_id(), handler, data, wait_wrapper); | 
 | } | 
 |  | 
 | int smp_call_function_all(isr_t handler, void* data, | 
 |                           handler_wrapper_t** wait_wrapper) | 
 | { | 
 | 	int8_t state = 0; | 
 | 	int i, me; | 
 | 	handler_wrapper_t* wrapper = 0; | 
 | 	if(wait_wrapper) | 
 | 	{ | 
 | 		wrapper = *wait_wrapper = smp_make_wrapper(); | 
 | 		if(!wrapper) | 
 | 			return -ENOMEM; | 
 |  | 
 | 		for(i = 0; i < num_cores; i++) | 
 | 			wrapper->wait_list[i] = 1; | 
 | 	} | 
 |  | 
 | 	enable_irqsave(&state); | 
 |  | 
 | 	// send to others | 
 | 	for(i = 0, me = core_id(); i < num_cores; i++) | 
 | 	{ | 
 | 		if(i == me) | 
 | 			continue; | 
 |  | 
 | 		send_kernel_message(i, (amr_t)smp_call_wrapper, (long)handler, | 
 | 		                    (long)wrapper, (long)data, KMSG_IMMEDIATE); | 
 | 	} | 
 |  | 
 | 	// send to me | 
 | 	send_kernel_message(me, (amr_t)smp_call_wrapper, (long)handler, | 
 | 	                    (long)wrapper, (long)data, KMSG_IMMEDIATE); | 
 |  | 
 | 	cpu_relax(); // wait to get the interrupt | 
 |  | 
 | 	disable_irqsave(&state); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int smp_call_function_single(uint32_t dest, isr_t handler, void* data, | 
 |                              handler_wrapper_t** wait_wrapper) | 
 | { | 
 | 	int8_t state = 0; | 
 | 	handler_wrapper_t* wrapper = 0; | 
 | 	if(wait_wrapper) | 
 | 	{ | 
 | 		wrapper = *wait_wrapper = smp_make_wrapper(); | 
 | 		if(!wrapper) | 
 | 			return -ENOMEM; | 
 | 		wrapper->wait_list[dest] = 1; | 
 | 	} | 
 |  | 
 | 	enable_irqsave(&state); | 
 |  | 
 | 	send_kernel_message(dest, (amr_t)smp_call_wrapper, (long)handler, | 
 | 	                    (long)wrapper, (long)data, KMSG_IMMEDIATE); | 
 |  | 
 | 	cpu_relax(); // wait to get the interrupt, if it's to this core | 
 |  | 
 | 	disable_irqsave(&state); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int smp_call_wait(handler_wrapper_t* wrapper) | 
 | { | 
 | 	int i; | 
 | 	for(i = 0; i < num_cores; i++) | 
 | 		while(wrapper->wait_list[i]); | 
 |  | 
 | 	spin_unlock(&wrapper->lock); | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* Perform any initialization needed by per_cpu_info.  Right now, this just | 
 |  * inits the amsg list.  Make sure every core calls this at some point in the | 
 |  * smp_boot process. */ | 
 | void __arch_pcpu_init(uint32_t coreid) | 
 | { | 
 | 	// Switch to the real L1 page table, rather than the boot page table which | 
 | 	// has the [0,KERNSIZE-1] identity mapping. | 
 | 	extern pte_t l1pt[NPTENTRIES]; | 
 | 	lcr3(PADDR(l1pt)); | 
 |  | 
 | 	register uintptr_t sp asm ("sp"); | 
 | 	set_stack_top(ROUNDUP(sp, PGSIZE)); | 
 | } |