mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 08:21:36 +01:00 
			
		
		
		
	The Intel SIPI (start-up inter-processor interrupt) vector is the entry point for each secondary CPU (also called an AP - applications processor). The assembler and C code are linked, so add comments to indicate this. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
		
			
				
	
	
		
			218 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2015 Google, Inc
 | |
|  *
 | |
|  * SPDX-License-Identifier:	GPL-2.0
 | |
|  *
 | |
|  * 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
 |