1/* 2 * Copyright (c) 2015 Google, Inc 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 * 6 * Taken from coreboot file of the same name 7 */ 8 9/* 10 * The SIPI vector is responsible for initializing the APs in the sytem. It 11 * loads microcode, sets up MSRs, and enables caching before calling into 12 * C code 13 */ 14 15#include <asm/global_data.h> 16#include <asm/msr-index.h> 17#include <asm/processor.h> 18#include <asm/processor-flags.h> 19#include <asm/sipi.h> 20 21#define CODE_SEG (X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE) 22#define DATA_SEG (X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE) 23 24/* 25 * First we have the 16-bit section. Every AP process starts here. 26 * The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow 27 * U-Boot's 32-bit code to become visible, then jump to ap_start. 28 * 29 * Note that this code is copied to RAM below 1MB in mp_init.c, and runs from 30 * there, but the 32-bit code (ap_start and onwards) is part of U-Boot and 31 * is therefore relocated to the top of RAM with other U-Boot code. This 32 * means that for the 16-bit code we must write relocatable code, but for the 33 * rest, we can do what we like. 34 */ 35.text 36.code16 37.globl ap_start16 38ap_start16: 39 cli 40 xorl %eax, %eax 41 movl %eax, %cr3 /* Invalidate TLB */ 42 43 /* setup the data segment */ 44 movw %cs, %ax 45 movw %ax, %ds 46 47 /* Use an address relative to the data segment for the GDT */ 48 movl $gdtaddr, %ebx 49 subl $ap_start16, %ebx 50 51 data32 lgdt (%ebx) 52 53 movl %cr0, %eax 54 andl $(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \ 55 X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax 56 orl $(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax 57 movl %eax, %cr0 58 59 movl $ap_start_jmp, %eax 60 subl $ap_start16, %eax 61 movw %ax, %bp 62 63 /* Jump to ap_start within U-Boot */ 64data32 cs ljmp *(%bp) 65 66 .align 4 67.globl sipi_params_16bit 68sipi_params_16bit: 69 /* 48-bit far pointer */ 70ap_start_jmp: 71 .long 0 /* offset set to ap_start by U-Boot */ 72 .word CODE_SEG /* segment */ 73 74 .word 0 /* padding */ 75gdtaddr: 76 .word 0 /* limit */ 77 .long 0 /* table */ 78 .word 0 /* unused */ 79 80.globl ap_start16_code_end 81ap_start16_code_end: 82 83/* 84 * Set up the special 'fs' segment for global_data. Then jump to ap_continue 85 * to set up the AP. 86 */ 87.globl ap_start 88ap_start: 89 .code32 90 movw $DATA_SEG, %ax 91 movw %ax, %ds 92 movw %ax, %es 93 movw %ax, %ss 94 movw %ax, %gs 95 96 movw $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax 97 movw %ax, %fs 98 99 /* Load the Interrupt descriptor table */ 100 mov idt_ptr, %ebx 101 lidt (%ebx) 102 103 /* Obtain cpu number */ 104 movl ap_count, %eax 1051: 106 movl %eax, %ecx 107 inc %ecx 108 lock cmpxchg %ecx, ap_count 109 jnz 1b 110 111 /* Setup stacks for each CPU */ 112 movl stack_size, %eax 113 mul %ecx 114 movl stack_top, %edx 115 subl %eax, %edx 116 mov %edx, %esp 117 /* Save cpu number */ 118 mov %ecx, %esi 119 120 /* Determine if one should check microcode versions */ 121 mov microcode_ptr, %edi 122 test %edi, %edi 123 jz microcode_done /* Bypass if no microde exists */ 124 125 /* Get the Microcode version */ 126 mov $1, %eax 127 cpuid 128 mov $MSR_IA32_UCODE_REV, %ecx 129 rdmsr 130 /* If something already loaded skip loading again */ 131 test %edx, %edx 132 jnz microcode_done 133 134 /* Determine if parallel microcode loading is allowed */ 135 cmp $0xffffffff, microcode_lock 136 je load_microcode 137 138 /* Protect microcode loading */ 139lock_microcode: 140 lock bts $0, microcode_lock 141 jc lock_microcode 142 143load_microcode: 144 /* Load new microcode */ 145 mov $MSR_IA32_UCODE_WRITE, %ecx 146 xor %edx, %edx 147 mov %edi, %eax 148 /* 149 * The microcode pointer is passed in pointing to the header. Adjust 150 * pointer to reflect the payload (header size is 48 bytes) 151 */ 152 add $UCODE_HEADER_LEN, %eax 153 pusha 154 wrmsr 155 popa 156 157 /* Unconditionally unlock microcode loading */ 158 cmp $0xffffffff, microcode_lock 159 je microcode_done 160 161 xor %eax, %eax 162 mov %eax, microcode_lock 163 164microcode_done: 165 /* 166 * Load MSRs. Each entry in the table consists of: 167 * 0: index, 168 * 4: value[31:0] 169 * 8: value[63:32] 170 * See struct saved_msr in mp_init.c. 171 */ 172 mov msr_table_ptr, %edi 173 mov msr_count, %ebx 174 test %ebx, %ebx 175 jz 1f 176load_msr: 177 mov (%edi), %ecx 178 mov 4(%edi), %eax 179 mov 8(%edi), %edx 180 wrmsr 181 add $12, %edi 182 dec %ebx 183 jnz load_msr 184 1851: 186 /* Enable caching */ 187 mov %cr0, %eax 188 andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax 189 mov %eax, %cr0 190 191 /* c_handler(cpu_num) */ 192 movl %esi, %eax /* cpu_num */ 193 mov c_handler, %esi 194 call *%esi 195 196 /* This matches struct sipi_param */ 197 .align 4 198.globl sipi_params 199sipi_params: 200idt_ptr: 201 .long 0 202stack_top: 203 .long 0 204stack_size: 205 .long 0 206microcode_lock: 207 .long 0 208microcode_ptr: 209 .long 0 210msr_table_ptr: 211 .long 0 212msr_count: 213 .long 0 214c_handler: 215 .long 0 216ap_count: 217 .long 0 218