216 lines
6.1 KiB
ArmAsm
216 lines
6.1 KiB
ArmAsm
/*
|
|
* Copyright (C) 2018-2022 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
* This is entry for AP startup and BSP S3 wakeup
|
|
*
|
|
* When system jump to trampoline_start16, the CPU is in x86 real
|
|
* mode with no stack setup. CS:IP points to trampoline_start16.
|
|
*
|
|
* The CPU will be changed to long mode finally with temperay
|
|
* page table and gdt in this file. Then jump to different C main
|
|
* entry according to whether it's AP startup or BSP S3 resume.
|
|
* The real page table and gdt will be setup in C main entry.
|
|
*/
|
|
|
|
/* NOTE:
|
|
*
|
|
* MISRA C requires that all unsigned constants should have the suffix 'U'
|
|
* (e.g. 0xffU), but the assembler may not accept such C-style constants. For
|
|
* example, binutils 2.26 fails to compile assembly in that case. To work this
|
|
* around, all unsigned constants must be explicitly spells out in assembly
|
|
* with a comment tracking the original expression from which the magic
|
|
* number is calculated. As an example:
|
|
*
|
|
* /* 0x00000668 =
|
|
* * (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) *\/
|
|
* movl $0x00000668, %eax
|
|
*
|
|
* Make sure that these numbers are updated accordingly if the definition of
|
|
* the macros involved are changed.
|
|
*/
|
|
|
|
.extern init_secondary_pcpu
|
|
|
|
.section .trampoline_reset,"ax"
|
|
|
|
.align 4
|
|
.code16
|
|
.global trampoline_start16
|
|
.org 0
|
|
trampoline_start16:
|
|
|
|
/* Disable local interrupts */
|
|
cli
|
|
|
|
/*
|
|
* There are two paths system could come here:
|
|
* - AP startup
|
|
* Silicon will set AP to real mode and setup CS:IP before
|
|
* jmp to trampoline_start16. And the IP is always 0 for sure.
|
|
* - BSP wakeup from S3
|
|
* Some bootloader (like ABL) doesn't guarante IP is set to
|
|
* zero before jump to trampoline_start16 after system resume
|
|
* from S3.
|
|
*
|
|
* To make trampoline code could work with all these cases, a far
|
|
* jump is issued here as fixup. It will update the CS:IP according
|
|
* to where the trampoline code is located.
|
|
*
|
|
* Here, we issue a far jump with "JMP ptr16:16" format (please refer
|
|
* sdm vol2A - JMP instruction description). The jump target is set
|
|
* to trampoline_fixup_target_addr. From trampoline_fixup_target_addr,
|
|
* The CS has same value for both AP startup and BSP wakeup from S3.
|
|
*
|
|
* Because the limitation of real mode (can't access ip register
|
|
* directly. So can't setup the trampoline_fixup_ip and
|
|
* trampoline_fixup_cs), we have to update the trampoline_fixup_ip
|
|
* and trampoline_fixup_cs when we preparing the trampoline code.
|
|
*
|
|
* Refer to preparing_trampoline() for fixup CS:IP setup
|
|
*/
|
|
.byte 0xea /* Opcode of "JMP ptr16:16" */
|
|
.global trampoline_fixup_ip
|
|
trampoline_fixup_ip:
|
|
.word 0 /* "EIP is intruction following JUMP instruction" */
|
|
.global trampoline_fixup_cs
|
|
trampoline_fixup_cs:
|
|
.word 0 /* CS */
|
|
|
|
.global trampoline_fixup_target
|
|
trampoline_fixup_target:
|
|
mov %cs, %ax
|
|
mov %ax, %ds
|
|
|
|
/* Set DE, PAE, MCE and OS support bits in CR4 */
|
|
|
|
/* 0x00000668 =
|
|
* (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) */
|
|
movl $0x00000668, %eax
|
|
mov %eax, %cr4
|
|
|
|
/* Set CR3 to PML4 table address */
|
|
|
|
movl $cpu_boot_page_tables_ptr, %ebx
|
|
mov (%ebx), %eax
|
|
mov %eax, %cr3
|
|
|
|
/* Set LME bit in EFER */
|
|
|
|
/* 0xc0000080 = MSR_IA32_EFER */
|
|
movl $0xc0000080, %ecx
|
|
rdmsr
|
|
/* 0x00000100 = MSR_IA32_EFER_LME_BIT */
|
|
orl $0x00000100, %eax
|
|
wrmsr
|
|
|
|
/* 0xc0000080 = MSR_IA32_EFER */
|
|
movl $0xc0000080, %ecx
|
|
rdmsr
|
|
/* 0x00000800 = MSR_IA32_EFER_NXE_BIT */
|
|
orl $0x00000800, %eax
|
|
wrmsr
|
|
|
|
/* Enable paging, protection, numeric error and co-processor
|
|
monitoring in CR0 to enter long mode */
|
|
|
|
mov %cr0, %ebx
|
|
/* 0x80000023 = (CR0_PG | CR0_PE | CR0_MP | CR0_NE) */
|
|
orl $0x80000023, %ebx
|
|
mov %ebx, %cr0
|
|
|
|
/* Load temportary GDT pointer value */
|
|
lgdt (trampoline_gdt_ptr - trampoline_start16)
|
|
|
|
/* Perform a long jump based to start executing in 64-bit mode */
|
|
|
|
movl $trampoline_start64_fixup, %ebx
|
|
ljmpl *(%ebx)
|
|
|
|
.align 8
|
|
.global trampoline_start64_fixup
|
|
trampoline_start64_fixup:
|
|
.long trampoline_start64
|
|
/* 0x0008 = HOST_GDT_RING0_CODE_SEL */
|
|
.word 0x0008
|
|
|
|
.code64
|
|
trampoline_start64:
|
|
|
|
/* Set up all other data segment registers */
|
|
/* 0x0010 = HOST_GDT_RING0_DATA_SEL */
|
|
movl $0x0010, %eax
|
|
mov %eax, %ss
|
|
mov %eax, %ds
|
|
mov %eax, %es
|
|
mov %eax, %fs
|
|
mov %eax, %gs
|
|
|
|
movq secondary_cpu_stack(%rip), %rsp
|
|
|
|
/* Jump to C entry */
|
|
movq main_entry(%rip), %rax
|
|
jmp *%rax
|
|
|
|
|
|
/* main entry */
|
|
.align 8
|
|
.global main_entry
|
|
main_entry:
|
|
.quad init_secondary_pcpu /* default entry is AP start entry */
|
|
|
|
.global secondary_cpu_stack
|
|
secondary_cpu_stack:
|
|
.quad 0
|
|
|
|
/* GDT table */
|
|
.align 4
|
|
trampoline_gdt:
|
|
.quad 0x0000000000000000
|
|
.quad 0x00af9b000000ffff
|
|
.quad 0x00cf93000000ffff
|
|
trampoline_gdt_end:
|
|
|
|
/* GDT pointer */
|
|
.align 2
|
|
.global trampoline_gdt_ptr
|
|
trampoline_gdt_ptr:
|
|
.short (trampoline_gdt_end - trampoline_gdt) - 1
|
|
.quad trampoline_gdt
|
|
|
|
/* PML4, PDPT, and PD tables initialized to map first 4 GBytes of memory */
|
|
.align 4
|
|
.global cpu_boot_page_tables_ptr
|
|
cpu_boot_page_tables_ptr:
|
|
.long cpu_boot_page_tables_start
|
|
|
|
/*0x1000 = PAGE_SIZE*/
|
|
.align 0x1000
|
|
.global cpu_boot_page_tables_start
|
|
cpu_boot_page_tables_start:
|
|
/* 0x3 = (PAGE_PRESENT | PAGE_RW) */
|
|
.quad trampoline_pdpt_addr + 0x3
|
|
/*0x1000 = PAGE_SIZE*/
|
|
.align 0x1000
|
|
.global trampoline_pdpt_addr
|
|
trampoline_pdpt_addr:
|
|
address = 0
|
|
.rept 4
|
|
/* 0x3 = (PAGE_PRESENT | PAGE_RW) */
|
|
.quad trampoline_pdt_addr + address + 0x3
|
|
/*0x1000 = PAGE_SIZE*/
|
|
address = address + 0x1000
|
|
.endr
|
|
/*0x1000 = PAGE_SIZE*/
|
|
.align 0x1000
|
|
trampoline_pdt_addr:
|
|
address = 0
|
|
.rept 2048
|
|
/* 0x83 = (PAGE_PSE | PAGE_PRESENT | PAGE_RW) */
|
|
.quad address + 0x83
|
|
address = address + 0x200000
|
|
.endr
|
|
|
|
.end
|