| /* SPDX-License-Identifier: GPL-2.0 */ | 
 | /* | 
 |  * Copyright (c) 2015 Google, Inc | 
 |  * | 
 |  * Taken from coreboot file of the same name | 
 |  */ | 
 |  | 
 | /* | 
 |  * The SIPI vector is responsible for initializing the APs in the sytem. It | 
 |  * loads microcode, sets up MSRs, and enables caching before calling into | 
 |  * C code | 
 |  */ | 
 |  | 
 | #include <asm/global_data.h> | 
 | #include <asm/msr-index.h> | 
 | #include <asm/processor.h> | 
 | #include <asm/processor-flags.h> | 
 | #include <asm/sipi.h> | 
 |  | 
 | #define CODE_SEG	(X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE) | 
 | #define DATA_SEG	(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE) | 
 |  | 
 | /* | 
 |  * First we have the 16-bit section. Every AP process starts here. | 
 |  * The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow | 
 |  * U-Boot's 32-bit code to become visible, then jump to ap_start. | 
 |  * | 
 |  * Note that this code is copied to RAM below 1MB in mp_init.c, and runs from | 
 |  * there, but the 32-bit code (ap_start and onwards) is part of U-Boot and | 
 |  * is therefore relocated to the top of RAM with other U-Boot code. This | 
 |  * means that for the 16-bit code we must write relocatable code, but for the | 
 |  * rest, we can do what we like. | 
 |  */ | 
 | .text | 
 | .code16 | 
 | .globl ap_start16 | 
 | ap_start16: | 
 | 	cli | 
 | 	xorl	%eax, %eax | 
 | 	movl	%eax, %cr3		/* Invalidate TLB */ | 
 |  | 
 | 	/* setup the data segment */ | 
 | 	movw	%cs, %ax | 
 | 	movw	%ax, %ds | 
 |  | 
 | 	/* Use an address relative to the data segment for the GDT */ | 
 | 	movl	$gdtaddr, %ebx | 
 | 	subl	$ap_start16, %ebx | 
 |  | 
 | 	data32 lgdt (%ebx) | 
 |  | 
 | 	movl	%cr0, %eax | 
 | 	andl	$(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \ | 
 | 		    X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax | 
 | 	orl	$(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax | 
 | 	movl	%eax, %cr0 | 
 |  | 
 | 	movl	$ap_start_jmp, %eax | 
 | 	subl	$ap_start16, %eax | 
 | 	movw	%ax, %bp | 
 |  | 
 | 	/* Jump to ap_start within U-Boot */ | 
 | data32 cs	ljmp	*(%bp) | 
 |  | 
 | 	.align	4 | 
 | .globl sipi_params_16bit | 
 | sipi_params_16bit: | 
 | 	/* 48-bit far pointer */ | 
 | ap_start_jmp: | 
 | 	.long	0		/* offset set to ap_start by U-Boot */ | 
 | 	.word	CODE_SEG	/* segment */ | 
 |  | 
 | 	.word	0		/* padding */ | 
 | gdtaddr: | 
 | 	.word	0 /* limit */ | 
 | 	.long	0 /* table */ | 
 | 	.word	0 /* unused */ | 
 |  | 
 | .globl ap_start16_code_end | 
 | ap_start16_code_end: | 
 |  | 
 | /* | 
 |  * Set up the special 'fs' segment for global_data. Then jump to ap_continue | 
 |  * to set up the AP. | 
 |  */ | 
 | .globl ap_start | 
 | ap_start: | 
 | 	.code32 | 
 | 	movw	$DATA_SEG, %ax | 
 | 	movw	%ax, %ds | 
 | 	movw	%ax, %es | 
 | 	movw	%ax, %ss | 
 | 	movw	%ax, %gs | 
 |  | 
 | 	movw	$(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax | 
 | 	movw	%ax, %fs | 
 |  | 
 | 	/* Load the Interrupt descriptor table */ | 
 | 	mov	idt_ptr, %ebx | 
 | 	lidt	(%ebx) | 
 |  | 
 | 	/* Obtain cpu number */ | 
 | 	movl	ap_count, %eax | 
 | 1: | 
 | 	movl	%eax, %ecx | 
 | 	inc	%ecx | 
 | 	lock cmpxchg %ecx, ap_count | 
 | 	jnz	1b | 
 |  | 
 | 	/* Setup stacks for each CPU */ | 
 | 	movl	stack_size, %eax | 
 | 	mul	%ecx | 
 | 	movl	stack_top, %edx | 
 | 	subl	%eax, %edx | 
 | 	mov	%edx, %esp | 
 | 	/* Save cpu number */ | 
 | 	mov	%ecx, %esi | 
 |  | 
 | 	/* Determine if one should check microcode versions */ | 
 | 	mov	microcode_ptr, %edi | 
 | 	test	%edi, %edi | 
 | 	jz	microcode_done /* Bypass if no microde exists */ | 
 |  | 
 | 	/* Get the Microcode version */ | 
 | 	mov	$1, %eax | 
 | 	cpuid | 
 | 	mov	$MSR_IA32_UCODE_REV, %ecx | 
 | 	rdmsr | 
 | 	/* If something already loaded skip loading again */ | 
 | 	test	%edx, %edx | 
 | 	jnz	microcode_done | 
 |  | 
 | 	/* Determine if parallel microcode loading is allowed */ | 
 | 	cmp	$0xffffffff, microcode_lock | 
 | 	je	load_microcode | 
 |  | 
 | 	/* Protect microcode loading */ | 
 | lock_microcode: | 
 | 	lock bts $0, microcode_lock | 
 | 	jc	lock_microcode | 
 |  | 
 | load_microcode: | 
 | 	/* Load new microcode */ | 
 | 	mov	$MSR_IA32_UCODE_WRITE, %ecx | 
 | 	xor	%edx, %edx | 
 | 	mov	%edi, %eax | 
 | 	/* | 
 | 	 * The microcode pointer is passed in pointing to the header. Adjust | 
 | 	 * pointer to reflect the payload (header size is 48 bytes) | 
 | 	 */ | 
 | 	add	$UCODE_HEADER_LEN, %eax | 
 | 	pusha | 
 | 	wrmsr | 
 | 	popa | 
 |  | 
 | 	/* Unconditionally unlock microcode loading */ | 
 | 	cmp	$0xffffffff, microcode_lock | 
 | 	je	microcode_done | 
 |  | 
 | 	xor	%eax, %eax | 
 | 	mov	%eax, microcode_lock | 
 |  | 
 | microcode_done: | 
 | 	/* | 
 | 	 * Load MSRs. Each entry in the table consists of: | 
 | 	 * 0: index, | 
 | 	 * 4: value[31:0] | 
 | 	 * 8: value[63:32] | 
 | 	 * See struct saved_msr in mp_init.c. | 
 | 	 */ | 
 | 	mov	msr_table_ptr, %edi | 
 | 	mov	msr_count, %ebx | 
 | 	test	%ebx, %ebx | 
 | 	jz	1f | 
 | load_msr: | 
 | 	mov	(%edi), %ecx | 
 | 	mov	4(%edi), %eax | 
 | 	mov	8(%edi), %edx | 
 | 	wrmsr | 
 | 	add	$12, %edi | 
 | 	dec	%ebx | 
 | 	jnz	load_msr | 
 |  | 
 | 1: | 
 | 	/* Enable caching */ | 
 | 	mov	%cr0, %eax | 
 | 	andl	$(~(X86_CR0_CD | X86_CR0_NW)), %eax | 
 | 	mov	%eax, %cr0 | 
 |  | 
 | 	/* c_handler(cpu_num) */ | 
 | 	movl	%esi, %eax	/* cpu_num */ | 
 | 	mov	c_handler, %esi | 
 | 	call	*%esi | 
 |  | 
 | 	/* This matches struct sipi_param */ | 
 | 	.align	4 | 
 | .globl	sipi_params | 
 | sipi_params: | 
 | idt_ptr: | 
 | 	.long 0 | 
 | stack_top: | 
 | 	.long 0 | 
 | stack_size: | 
 | 	.long 0 | 
 | microcode_lock: | 
 | 	.long 0 | 
 | microcode_ptr: | 
 | 	.long 0 | 
 | msr_table_ptr: | 
 | 	.long 0 | 
 | msr_count: | 
 | 	.long 0 | 
 | c_handler: | 
 | 	.long 0 | 
 | ap_count: | 
 | 	.long 0 |