rem: sleep(200);
add: spin(200);
context: smp_boot_all_cpus(void){	uint32 trampoline_code;	uint32 trampoline_stack;	uint32 i;	// XXX assume low 1 meg is identity mapped by the 1st stage bootloader	// and nothing important is in 0x9e000 & 0x9f000	// allocate a stack and a code area for the smp trampoline	// (these have to be < 1M physical)	trampoline_code = 0x9f000; 	// 640kB - 4096 == 0x9f000	trampoline_stack = 0x9e000; // 640kB - 8192 == 0x9e000	map_page(0x9f000, 0x9f000);	map_page(0x9e000, 0x9e000);	// copy the trampoline code over	memcpy((char *)trampoline_code, &smp_trampoline,		(uint32)&smp_trampoline_end - (uint32)&smp_trampoline);	// boot the cpus	for (i = 1; i < gKernelArgs.num_cpus; i++) {		uint32 *final_stack;		uint32 *final_stack_ptr;		uint32 *tramp_stack_ptr;		uint32 config;		uint32 num_startups;		uint32 j;		// create a final stack the trampoline code will put the ap processor on		gKernelArgs.cpu_kstack[i].start = gKernelArgs.virtual_allocated_range[0].start + gKernelArgs.virtual_allocated_range[0].size;		gKernelArgs.cpu_kstack[i].size = STACK_SIZE * B_PAGE_SIZE;		for (j = 0; j < gKernelArgs.cpu_kstack[i].size / B_PAGE_SIZE; j++) {			// map the pages in			map_page(gKernelArgs.physical_allocated_range[0].start + gKernelArgs.physical_allocated_range[0].size,				gKernelArgs.virtual_allocated_range[0].start + gKernelArgs.virtual_allocated_range[0].size);			gKernelArgs.physical_allocated_range[0].size += B_PAGE_SIZE;			gKernelArgs.virtual_allocated_range[0].size += B_PAGE_SIZE;		}		// set this stack up		final_stack = (uint32 *)gKernelArgs.cpu_kstack[i].start;		memset(final_stack, 0, STACK_SIZE * B_PAGE_SIZE);		final_stack_ptr = (final_stack + (STACK_SIZE * B_PAGE_SIZE) / sizeof(uint32)) - 1;		*final_stack_ptr = (uint32)&smp_cpu_ready;		final_stack_ptr--;		// set the trampoline stack up		tramp_stack_ptr = (uint32 *)(trampoline_stack + B_PAGE_SIZE - 4);		// final location of the stack		*tramp_stack_ptr = ((uint32)final_stack) + STACK_SIZE * B_PAGE_SIZE - sizeof(uint32);		tramp_stack_ptr--;		// page dir		*tramp_stack_ptr = gKernelArgs.arch_args.phys_pgdir;		tramp_stack_ptr--;		// put a gdt descriptor at the bottom of the stack		*((uint16 *)trampoline_stack) = 0x18 - 1; // LIMIT		*((uint32 *)(trampoline_stack + 2)) = trampoline_stack + 8;		// put the gdt at the bottom		memcpy(&((uint32 *)trampoline_stack)[2], (void *)gKernelArgs.arch_args.vir_gdt, 6*4);		/* clear apic errors */		if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {			apic_write(APIC_ESR, 0);			apic_read(APIC_ESR);		}		/* send (aka assert) INIT IPI */		config = (apic_read(APIC_ICR2) & 0x00ffffff) | (gKernelArgs.arch_args.cpu_apic_id[i] << 24);		apic_write(APIC_ICR2, config); /* set target pe */		config = (apic_read(APIC_ICR1) & 0xfff00000) | 0x0000c500;		apic_write(APIC_ICR1, config);		// wait for pending to end		while ((apic_read(APIC_ICR1) & 0x00001000) == 0x00001000)			;		/* deassert INIT */		config = (apic_read(APIC_ICR2) & 0x00ffffff) | (gKernelArgs.arch_args.cpu_apic_id[i] << 24);		apic_write(APIC_ICR2, config);		config = (apic_read(APIC_ICR1) & 0xfff00000) | 0x00008500;		apic_write(APIC_ICR1, config);		// wait for pending to end		while ((apic_read(APIC_ICR1) & 0x00001000) == 0x00001000)			;		/* wait 10ms */		sleep(10000);		/* is this a local apic or an 82489dx ? */		num_startups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) ? 2 : 0;		for (j = 0; j < num_startups; j++) {			/* it's a local apic, so send STARTUP IPIs */			apic_write(APIC_ESR, 0);			/* set target pe */			config = (apic_read(APIC_ICR2) & 0xf0ffffff) | (gKernelArgs.arch_args.cpu_apic_id[i] << 24);			apic_write(APIC_ICR2, config);			/* send the IPI */			config = (apic_read(APIC_ICR1) & 0xfff0f800) | APIC_DM_STARTUP |				(0x9f000 >> 12);			apic_write(APIC_ICR1, config);			/* wait */			sleep(200);			while ((apic_read(APIC_ICR1)& 0x00001000) == 0x00001000)				;		}	}	return 0;}