Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:10

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsX8664AMD64
0007  *
0008  * @brief Contains the trampoline code that will be executed by every
0009  * Application Processor when first started.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2024 Matheus Pecoraro
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #include <gdt.h>
0038 #include <smp.h>
0039 #include <rtems/asm.h>
0040 #include <rtems/score/percpu.h>
0041 
0042 .set PM_GDT_CODE_OFFSET, 0x08       # Offset of code segment descriptor into GDT
0043 .set PM_GDT_DATA_OFFSET, 0x10       # Offset of data segment descriptor into GDT
0044 .set CR0_PE,             1          # Protected mode flag on CR0 register
0045 .set CR0_PG,             0x80000000 # Paging flag on CR0 register
0046 .set CR0_EM_BITMASK,     (~0x4)     # Bitmask for disabling x87 FPU Emulation bit
0047 .set CR0_MP,             0x2        # Monitor co-processor flag
0048 .set CR4_PAE,            0x20       # Physical Address Extension flag on CR4 register
0049 .set CR4_OSFXSR,         0x200      # OS support for FXSAVE and FXRSTOR flag
0050 .set CR4_OSXMMEXCPT,     0x400      # OS support for unmasked SIMD FP exceptions flag
0051 .set CR4_SSEFLAGS,       (CR4_OSFXSR | CR4_OSXMMEXCPT)
0052 .set EFER_MSR,           0xC0000080 # EFER MSR number
0053 .set EFER_MSR_LME,       0x100      # Long Mode Enable flag on the EFER MSR
0054 
0055 BEGIN_CODE
0056 
0057 .code16
0058 PUBLIC(_Trampoline_start)
0059 SYM(_Trampoline_start):
0060   cli
0061   cld
0062   jmp .real_mode
0063 
0064 .real_mode:
0065   lgdt (gdt_desc - _Trampoline_start) + TRAMPOLINE_ADDR
0066 
0067   # Enter protected mode
0068   movl %cr0, %eax
0069   orl $CR0_PE, %eax
0070   movl %eax, %cr0
0071 
0072   # Jump to protected mode
0073   ljmpl $PM_GDT_CODE_OFFSET, $((.protected_mode - _Trampoline_start) + TRAMPOLINE_ADDR)
0074 
0075 .code32
0076 .protected_mode:
0077   # Load data segment registers
0078   movw $PM_GDT_DATA_OFFSET, %ax
0079   movw %ax, %ds
0080   movw %ax, %es
0081   movw %ax, %ss
0082 
0083   # Move PML4 table address to cr3
0084   movl $amd64_pml4, %eax
0085   movl %eax, %cr3
0086 
0087   # Flip PAE bit in cr4
0088   movl %cr4, %eax
0089   orl $CR4_PAE, %eax
0090   movl %eax, %cr4
0091 
0092   # Set LME on the EFER MSR
0093   movl $EFER_MSR, %ecx
0094   rdmsr
0095   orl $EFER_MSR_LME, %eax
0096   wrmsr
0097 
0098   # Enable paging
0099   movl %cr0, %eax
0100   orl $CR0_PG, %eax
0101   movl %eax, %cr0
0102 
0103   # Update GDT for long mode
0104   lgdt amd64_gdt_descriptor
0105 
0106   # Jump to long mode
0107   ljmp $GDT_CODE_SEG_OFFSET, $((.long_mode - _Trampoline_start) + TRAMPOLINE_ADDR)
0108 
0109 .code64
0110 .long_mode:
0111   # Load data segment registers
0112   movw $GDT_DATA_SEG_OFFSET, %ax
0113   movw %ax, %ds
0114   movw %ax, %es
0115   movw %ax, %ss
0116   movw %ax, %fs
0117 
0118   # Acquire the processor's stack
0119   GET_SELF_CPU_CONTROL_RAX
0120   movq PER_CPU_INTERRUPT_STACK_HIGH(rax), rsp
0121 
0122   # Enable SSE
0123   movq %cr0, rax
0124   andq $CR0_EM_BITMASK, rax
0125   orq $CR0_MP, rax
0126   movq rax, %cr0
0127   movq %cr4, rax
0128   orq $CR4_SSEFLAGS, rax
0129   movq rax, %cr4
0130 
0131   # Exit trampoline code
0132     movabsq $smp_init_ap, rax
0133     call *rax
0134 
0135 /* Temporary GDT used to get to long mode */
0136 gdt:
0137   /* NULL segment */
0138   .quad 0
0139   /* Code segment */
0140   .word 0xFFFF, 0
0141   .byte 0, 0x9F, 0xCF, 0
0142   /* Data segment */
0143   .word 0xFFFF, 0
0144   .byte 0, 0x92, 0xCF, 0
0145 gdt_desc:
0146     .word (gdt_desc - gdt) - 1
0147     .long (gdt - _Trampoline_start) + TRAMPOLINE_ADDR
0148 
0149 trampoline_end:
0150 PUBLIC(_Trampoline_size)
0151 SYM(_Trampoline_size):
0152 .quad (trampoline_end - _Trampoline_start)