;------------------------------------------------------------------------------ ;
; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution.  The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
;   MpFuncs.nasm
;
; Abstract:
;
;   This is the assembly code for Multi-processor S3 support
;
;-------------------------------------------------------------------------------

extern ASM_PFX(InitializeFloatingPointUnits)

%define VacantFlag 0x0
%define NotVacantFlag 0xff

%define LockLocation RendezvousFunnelProcEnd - RendezvousFunnelProcStart
%define StackStartAddressLocation LockLocation + 0x8
%define StackSizeLocation LockLocation + 0x10
%define CProcedureLocation LockLocation + 0x18
%define GdtrLocation LockLocation + 0x20
%define IdtrLocation LockLocation + 0x2A
%define BufferStartLocation LockLocation + 0x34
%define Cr3OffsetLocation LockLocation + 0x38

;-------------------------------------------------------------------------------------
;RendezvousFunnelProc  procedure follows. All APs execute their procedure. This
;procedure serializes all the AP processors through an Init sequence. It must be
;noted that APs arrive here very raw...ie: real mode, no stack.
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
;IS IN MACHINE CODE.
;-------------------------------------------------------------------------------------
;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);

;text      SEGMENT
DEFAULT REL
SECTION .text

BITS 16
global ASM_PFX(RendezvousFunnelProc)
ASM_PFX(RendezvousFunnelProc):
RendezvousFunnelProcStart:

; At this point CS = 0x(vv00) and ip= 0x0.

        mov        ax,  cs
        mov        ds,  ax
        mov        es,  ax
        mov        ss,  ax
        xor        ax,  ax
        mov        fs,  ax
        mov        gs,  ax

flat32Start:

        mov        si, BufferStartLocation
        mov        edx,dword [si]          ; EDX is keeping the start address of wakeup buffer

        mov        si, Cr3OffsetLocation
        mov        ecx,dword [si]          ; ECX is keeping the value of CR3

        mov        si, GdtrLocation
o32     lgdt       [cs:si]

        mov        si, IdtrLocation
o32     lidt       [cs:si]

        xor        ax,  ax
        mov        ds,  ax

        mov        eax, cr0                    ; Get control register 0
        or         eax, 0x000000001            ; Set PE bit (bit #0)
        mov        cr0, eax

FLAT32_JUMP:

a32     jmp   dword 0x20:0x0

BITS 32
PMODE_ENTRY:                         ; protected mode entry point

        mov        ax,  0x18
o16     mov        ds,  ax
o16     mov        es,  ax
o16     mov        fs,  ax
o16     mov        gs,  ax
o16     mov        ss,  ax                     ; Flat mode setup.

        mov        eax, cr4
        bts        eax, 5
        mov        cr4, eax

        mov        cr3, ecx

        mov        esi, edx                    ; Save wakeup buffer address

        mov        ecx, 0xc0000080             ; EFER MSR number.
        rdmsr                                  ; Read EFER.
        bts        eax, 8                      ; Set LME=1.
        wrmsr                                  ; Write EFER.

        mov        eax, cr0                    ; Read CR0.
        bts        eax, 31                     ; Set PG=1.
        mov        cr0, eax                    ; Write CR0.

LONG_JUMP:

a16     jmp   dword 0x38:0x0

BITS 64
LongModeStart:

        mov         ax,  0x30
o16     mov         ds,  ax
o16     mov         es,  ax
o16     mov         ss,  ax

        mov  edi, esi
        add  edi, LockLocation
        mov  al,  NotVacantFlag
TestLock:
        xchg byte [edi], al
        cmp  al, NotVacantFlag
        jz   TestLock

ProgramStack:

        mov  edi, esi
        add  edi, StackSizeLocation
        mov  rax, qword [edi]
        mov  edi, esi
        add  edi, StackStartAddressLocation
        add  rax, qword [edi]
        mov  rsp, rax
        mov  qword [edi], rax

Releaselock:

        mov  al,  VacantFlag
        mov  edi, esi
        add  edi, LockLocation
        xchg byte [edi], al

        ;
        ; Call assembly function to initialize FPU.
        ;
        mov         rax, ASM_PFX(InitializeFloatingPointUnits)
        sub         rsp, 0x20
        call        rax
        add         rsp, 0x20

        ;
        ; Call C Function
        ;
        mov         edi, esi
        add         edi, CProcedureLocation
        mov         rax, qword [edi]

        test        rax, rax
        jz          GoToSleep

        sub         rsp, 0x20
        call        rax
        add         rsp, 0x20

GoToSleep:
        cli
        hlt
        jmp         $-2

RendezvousFunnelProcEnd:

;-------------------------------------------------------------------------------------
;  AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
; comments here for definition of address map
global ASM_PFX(AsmGetAddressMap)
ASM_PFX(AsmGetAddressMap):
        mov         rax, RendezvousFunnelProcStart
        mov         qword [rcx], rax
        mov         qword [rcx+0x8], PMODE_ENTRY - RendezvousFunnelProcStart
        mov         qword [rcx+0x10], FLAT32_JUMP - RendezvousFunnelProcStart
        mov         qword [rcx+0x18], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
        mov         qword [rcx+0x20], LongModeStart - RendezvousFunnelProcStart
        mov         qword [rcx+0x28], LONG_JUMP - RendezvousFunnelProcStart
        ret