+ post_code(0x22)
+
+ /* Enable local apic. */
+ movl $LAPIC_BASE_MSR, %ecx
+ rdmsr
+ andl $(~CPU_PHYSMASK_HI), %edx
+ andl $(~LAPIC_BASE_MSR_ADDR_MASK), %eax
+ orl $(LAPIC_DEFAULT_BASE | LAPIC_BASE_MSR_ENABLE), %eax
+ wrmsr
+ andl $LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR, %eax
+ jz ap_init
+
+bsp_init:
+
+ post_code(0x23)
+
+ /* Send INIT IPI to all excluding ourself. */
+ movl LAPIC(ICR), %edi
+ movl $(LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | LAPIC_DM_INIT), %eax
+1: movl %eax, (%edi)
+ movl $0x30, %ecx
+2: pause
+ dec %ecx
+ jnz 2b
+ movl (%edi), %ecx
+ andl $LAPIC_ICR_BUSY, %ecx
+ jnz 1b
+
+ post_code(0x24)
+
+ /* For a hyper-threading processor, cache must not be disabled
+ * on an AP on the same physical package with the BSP.
+ */
+ movl $01, %eax
+ cpuid
+ btl $28, %edx
+ jnc sipi_complete
+ bswapl %ebx
+ cmpb $01, %bh
+ jbe sipi_complete
+
+hyper_threading_cpu:
+
+ /* delay 10 ms */
+ movl $10000, %ecx
+1: inb $0x80, %al
+ dec %ecx
+ jnz 1b
+
+ post_code(0x25)
+
+ /* Send Start IPI to all excluding ourself. */
+ movl LAPIC(ICR), %edi
+ movl $(LAPIC_DEST_ALLBUT | LAPIC_DM_STARTUP | START_IPI_VECTOR), %eax
+1: movl %eax, (%edi)
+ movl $0x30, %ecx
+2: pause
+ dec %ecx
+ jnz 2b
+ movl (%edi), %ecx
+ andl $LAPIC_ICR_BUSY, %ecx
+ jnz 1b
+
+ /* delay 250 us */
+ movl $250, %ecx
+1: inb $0x80, %al
+ dec %ecx
+ jnz 1b
+
+ post_code(0x26)
+
+ /* Wait for sibling CPU to start. */
+1: movl $(MTRRphysBase_MSR(0)), %ecx
+ rdmsr
+ andl %eax, %eax
+ jnz sipi_complete
+
+ movl $0x30, %ecx
+2: pause
+ dec %ecx
+ jnz 2b
+ jmp 1b
+
+
+ap_init:
+ post_code(0x27)
+
+ /* Do not disable cache (so BSP can enable it). */
+ movl %cr0, %eax
+ andl $(~((1 << 30) | (1 << 29))), %eax
+ movl %eax, %cr0
+
+ post_code(0x28)
+
+ /* MTRR registers are shared between HT siblings. */
+ movl $(MTRRphysBase_MSR(0)), %ecx
+ movl $(1<<12), %eax
+ xorl %edx, %edx
+ wrmsr
+
+ post_code(0x29)
+
+ap_halt:
+ cli
+1: hlt
+ jnz 1b
+
+
+
+sipi_complete:
+
+ post_code(0x2a)
+