;*****************************************************************************
; AMD Generic Encapsulated Software Architecture
;
;  Workfile: arch2008.asm     $Revision: 44323 $    $Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
;
; Description: ARCH2008.ASM - AGESA Architecture 2008 Wrapper Template
;
;*****************************************************************************
;
; Copyright (c) 2011, Advanced Micro Devices, Inc.
; All rights reserved.
; 
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;     * Redistributions of source code must retain the above copyright
;       notice, this list of conditions and the following disclaimer.
;     * Redistributions in binary form must reproduce the above copyright
;       notice, this list of conditions and the following disclaimer in the
;       documentation and/or other materials provided with the distribution.
;     * Neither the name of Advanced Micro Devices, Inc. nor the names of 
;       its contributors may be used to endorse or promote products derived 
;       from this software without specific prior written permission.
; 
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
; 
;*****************************************************************************

    .XLIST
    INCLUDE agesa.inc
    INCLUDE acwrapg.inc       ; Necessary support file as part of wrapper, including but not limited to segment start/end macros.
    INCLUDE acwrap.inc        ; IBVs may specify host BIOS-specific include files required when building.
    INCLUDE cpcarmac.inc
    INCLUDE bridge32.inc
    .LIST
    .586p


;----------------------------------------------------------------------------
; Local definitions
;----------------------------------------------------------------------------

sOemCallout STRUCT
    FuncName   DD   ?         ; Call out function name
    FuncPtr    DW   ?         ; Call out function pointer
sOemCallout ENDS

sOemEventHandler STRUCT
    ClassCode  DD   ?         ; AGESA event log sub-class code
    FuncPtr    DW   ?         ; Event handler function pointer
sOemEventHandler ENDS

;; A typical legacy BIOS implementation may require the E000 and F000 segments
;; to be cached.
EXE_CACHE_REGION_BASE_0  EQU  0E0000h
EXE_CACHE_REGION_SIZE_0  EQU  20000h

;; In this sample implementation, the B1 and B2 images are placed next to each
;; other in the BIOS ROM to help with the maximization of cached code.
EXE_CACHE_REGION_BASE_1  EQU  AGESA_B1_ADDRESS
EXE_CACHE_REGION_SIZE_1  EQU  40000h

;; The third region is not needed in our example.
EXE_CACHE_REGION_BASE_2  EQU  0
EXE_CACHE_REGION_SIZE_2  EQU  0


;----------------------------------------------------------------------------
;    PERSISTENT SEGMENT
; This segment is required to be present throughout all BIOS execution.
;----------------------------------------------------------------------------

AMD_PERSISTENT_START


;----------------------------------------------------------------------------
; Instantiate the global descriptor table
;----------------------------------------------------------------------------

AMD_BRIDGE_32_GDT AMD_GDT         ; Instantiate the global descriptor table
                                  ; required by the push-high mechanism.


;----------------------------------------------------------------------------
; Declare the external routines required in the persistent segment
;----------------------------------------------------------------------------

;+-------------------------------------------------------------------------
;
;   AmdDfltRet
;
;   Entry:
;     None
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     Near stub procedure.  Simply perform a retn instruction.
;
EXTERN AmdDfltRet:NEAR


;+-------------------------------------------------------------------------
;
;   AmdDfltRetFar
;
;   Entry:
;     None
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     Far stub procedure.  Simply perform a retf instruction.
;
EXTERN AmdDfltRetFar:FAR


;----------------------------------------------------------------------------
; Declare the optional external routines in the persistent segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   myModuleTypeMismatchHandler (Example)
;
;   Entry:
;     ESI - Pointer to the EVENT_PARAMS structure of the failure.
;     [ESI].DataParam1 - Socket
;     [ESI].DataParam2 - DCT
;     [ESI].DataParam3 - Channel
;     [ESI].DataParam4 - 0x00000000
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This procedure can be used to react to a memory module type
;     mismatch error discovered by the AGESA code.  Actions taken
;     may include, but are not limited to:
;       Logging the event to NV for display later
;       Reset, excluding the mismatch on subsequent reboot
;       Do nothing
;
;   Dependencies:
;     None
;
EXTERN myModuleTypeMismatchHandler(AmdDfltRet):NEAR

;+---------------------------------------------------------------------------
;
;   oemPlatformConfigInit (Optional)
;
;   Entry:
;     EDI - 32-bit flat pointer to the PLATFORM_CONFIGURATION to be
;           passed in to the next AGESA entry point.
;
;           typedef struct {
;             IN PERFORMANCE_PROFILE PlatformProfile;
;             IN CPU_HT_DEEMPHASIS_LEVEL *PlatformDeemphasisList;
;             IN UINT8               CoreLevelingMode;
;             IN PLATFORM_C1E_MODES  C1eMode;
;             IN UINT32              C1ePlatformData;
;             IN BOOLEAN             UserOptionDmi;
;             IN BOOLEAN             UserOptionPState;
;             IN BOOLEAN             UserOptionSrat;
;             IN BOOLEAN             UserOptionSlit;
;             IN BOOLEAN             UserOptionWhea;
;             IN UINT32              PowerCeiling;
;             IN BOOLEAN             PstateIndependent;
;           } PLATFORM_CONFIGURATION;
;
;           typedef struct {
;             IN UINT8 Socket;
;             IN UINT8 Link;
;             IN UINT8 LoFreq;
;             IN UINT8 HighFreq;
;             IN PLATFORM_DEEMPHASIS_LEVEL     ReceiverDeemphasis;
;             IN PLATFORM_DEEMPHASIS_LEVEL     DcvDeemphasis;
;           } CPU_HT_DEEMPHASIS_LEVEL;
;
;           typedef struct {
;             IN PLATFORM_CONTROL_FLOW PlatformControlFlowMode;
;             IN BOOLEAN               UseHtAssist;
;             IN BOOLEAN               Use32ByteRefresh;
;             IN BOOLEAN               UseVariableMctIsocPriority;
;           } PERFORMANCE_PROFILE;
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     Provide a single hook routine to modify the parameters of a
;     PLATFORM_CONFIGURATION structure before any entry point that
;     has such a structure as an input.
;
;   Dependencies:
;     None
;
;   Example:
;     If your platform is running in UMA mode, the following code
;     may be added:
;       mov  (PLATFORM_CONFIGURATION PTR [edi]).PlatformProfile.PlatformControlFlowMode, UmaDr
;
EXTERN oemPlatformConfigInit(AmdDfltRetFar):FAR

;+---------------------------------------------------------------------------
;
;   oemCallout (Optional)
;
;   Entry:
;     ECX - Callout function number
;     EDX - Function-specific UINTN
;     ESI - Pointer to function specific data
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;
;   Modified:
;     None
;
;   Purpose:
;     The default call out router function which resides in the same
;     segment as the push-high bridge code.
;
;   Dependencies:
;     None
;
EXTERN oemCallout(AmdDfltRet):NEAR


;----------------------------------------------------------------------------
; Define the sample wrapper routines for the persistent segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   AmdBridge32
;
;   Entry:
;     EDX - A Real Mode FAR pointer using seg16:Offset16 format that
;           points to a local host environment call-out router. If
;           this pointer is not equal to zero, then this pointer is
;           used as the call-out router instead of the standard
;           OemCallout. This may be useful when the call-out router
;           is not located in the same segment as the AmdBridge32 and
;           AmdCallout16 routines.
;     ESI - A Flat Mode pointer (32-bit address) that points to the
;           configuration block (AMD_CONFIG_PARAMS) for the AGESA
;           software function.
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;
;   Modified:
;     None
;
;   Purpose:
;     Execute an AGESA software function through the Push-High interface.
;
;   Dependencies:
;     This procedure requires a stack. The host environment must use the
;     provided service function to establish the stack environment prior
;     to making the call to this procedure.
;
AmdBridge32 PROC FAR PUBLIC
    AMD_BRIDGE_32 AMD_GDT             ; use the macro for the body
    ret
AmdBridge32 ENDP


;+---------------------------------------------------------------------------
;
;   AmdEnableStack
;
;   Entry:
;     BX - Return address
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;     SS:ESP - Points to the private stack location for this processor core.
;     ECX - Upon success, contains this processor core's stack size in bytes.
;
;   Modified:
;     EAX, ECX, EDX, EDI, ESI, ESP, DS, ES
;
;   Purpose:
;     This procedure is used to establish the stack within the host environment.
;
;   Dependencies:
;     The host environment must use this procedure and not rely on any other
;     sources to create the stack region.
;
AmdEnableStack PROC NEAR PUBLIC
    AMD_ENABLE_STACK
    ;; EAX = AGESA_SUCCESS, The stack space has been allocated for this core.
    ;; EAX = AGESA_WARNING, The stack has already been set up.  SS:ESP is set
    ;;       to stack top, and ECX is the stack size in bytes.
    jmp   bx
AmdEnableStack ENDP


;+---------------------------------------------------------------------------
;
;   AmdDisableStack
;
;   Entry:
;     BX - Return address
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;
;   Modified:
;     EAX, ECX, EDX, ESI, ESP
;
;   Purpose:
;     This procedure is used to remove the pre-memory stack from within the
;     host environment.
;     The exit state for the BSP is described as follows:
;       Memory region 00000-9FFFF MTRRS are set as WB memory.
;       Processor Cache is enabled (CD bit is cleared).
;       MTRRs used for execution cache are kept.
;       Cache content is flushed (invalidated without write-back).
;       Any family-specific clean-up done.
;     The exit state for the APs is described as follows:
;       Memory region 00000-9FFFF MTRRS are set as WB memory.
;       Memory region A0000-DFFFF MTRRS are set as UC IO.
;       Memory region E0000-FFFFF MTRRS are set as UC memory.
;       MTRRs used for execution cache are cleared.
;       Processor Cache is disabled (CD bit is set).
;       Top-of-Memory (TOM) set to the system top of memory as determined
;         by the memory initialization routines.
;       System lock command is enabled.
;       Any family-specific clean-up done.
;
;   Dependencies:
;     The host environment must use this procedure and not rely on any other
;     sources to break down the stack region.
;     If executing in 16-bit code, the host environment must establish the
;     "Big Real" mode of 32-bit addressing of data.
;
AmdDisableStack PROC NEAR PUBLIC
    AMD_DISABLE_STACK
    ;; EAX = AGESA_SUCCESS, The stack space has been disabled for this core.
    jmp   bx
AmdDisableStack ENDP


;+---------------------------------------------------------------------------
;
;   AmdCallout16
;
;   Entry:
;     [esp+8] - Func
;     [esp+12] - Data
;     [esp+16] - Configuration Block
;     [esp+4] - Return address to AGESA
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;
;   Modified:
;     None
;
;   Purpose:
;     Execute callback from the push-high interface.
;
;   Dependencies:
;     None
;
AmdCallout16 PROC FAR PUBLIC ; declare the procedure
    AMD_CALLOUT_16 oemCallout ; use the macro for the body
    ret
AmdCallout16 ENDP


;+---------------------------------------------------------------------------
;
;   AmdProcessAgesaErrors (Optional)
;
;   Entry:
;     AL - Heap status of the AGESA entry point that was just invoked.
;     EBX - AGESA image base address.
;     EDX - Segment / Offset of the appropriate callout router function.
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This procedure is used to handle any errors that may have occurred
;     during an AGESA entry point.
;
;   Dependencies:
;     None
;
AmdProcessAgesaErrors PROC FAR PUBLIC
    LOCAL localCpuInterfaceBlock:EVENT_PARAMS

    pushad
    xor   edi, edi
    mov   di, ss
    shl   edi, 4
    lea   esi, localCpuInterfaceBlock
    add   esi, edi

    ; Fill default config block
    mov   (EVENT_PARAMS PTR [esi]).StdHeader.Func, AMD_READ_EVENT_LOG
    mov   (EVENT_PARAMS PTR [esi]).StdHeader.ImageBasePtr, ebx
    mov   (EVENT_PARAMS PTR [esi]).StdHeader.AltImageBasePtr, 0
    mov   (EVENT_PARAMS PTR [esi]).StdHeader.HeapStatus, al
    mov   edi, SEG AmdCallout16
    shl   edi, 4
    add   edi, OFFSET AmdCallout16
    mov   (EVENT_PARAMS PTR [esi]).StdHeader.CalloutPtr, edi

    ; Flush the event log searching for, and handling all monitored events
    xor   eax, eax
    .while (eax == 0)
        push  edx
        call  AmdBridge32
        pop   edx
        .if (eax == AGESA_SUCCESS)
            mov   eax, (EVENT_PARAMS PTR [esi]).EventInfo
            .if (eax != 0)
                lea   di, cs:AgesaEventTable

loopThruTable:
                cmp   di, OFFSET cs:AgesaEventTableEnd
                jae   unhandledEvent

                cmp   eax, cs:[di].sOemEventHandler.ClassCode
                je    FoundMatch
                add   di, SIZEOF sOemEventHandler
                jmp   loopThruTable

FoundMatch:
                mov   bx, cs:[di].sOemEventHandler.FuncPtr
                call  bx

unhandledEvent:
                xor   eax, eax
            .else
                mov   al, 1
            .endif
        .endif
    .endw
    popad
    ret

AmdProcessAgesaErrors ENDP


;----------------------------------------------------------------------------
; Define the error handler table
;----------------------------------------------------------------------------

AgesaEventTable LABEL BYTE
    ;; Add entries as desired
    ;;---------
    ;; EXAMPLE
    ;;---------
    sOemEventHandler <MEM_ERROR_MODULE_TYPE_MISMATCH_DIMM, OFFSET myModuleTypeMismatchHandler>
AgesaEventTableEnd LABEL BYTE


AMD_PERSISTENT_END




;----------------------------------------------------------------------------
;    RECOVERY SEGMENT
; This segment resides in the classic 'boot-block,' and is used
; for recovery.
;----------------------------------------------------------------------------

AMD_RECOVERY_START


;----------------------------------------------------------------------------
; Declare the external routines required in the recovery segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   myReadSPDRecovery (Required for proper recovery mode operation)
;
;   Entry:
;     ESI - Pointer to an AGESA_READ_SPD_PARAMS structure.
;
;     typedef struct {
;       IN OUT AMD_CONFIG_PARAMS StdHeader;
;       IN       UINT8 SocketId;
;       IN       UINT8 MemChannelId;
;       IN       UINT8 DimmId;
;       IN OUT   UINT8 *Buffer;
;       IN OUT   MEM_DATA_STRUCT *MemData;
;     } AGESA_READ_SPD_PARAMS;
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS Indicates the SPD block for the indicated
;                         DIMM was read successfully.
;           AGESA_BOUNDS_CHK The specified DIMM is not present.
;           AGESA_UNSUPPORTED This is a required function, so this
;                             value being returned causes a critical
;                             error response value from the AGESA
;                             software function and no memory initialized.
;           AGESA_ERROR The DIMM SPD read process has generated
;                       communication errors.
;
;   Modified:
;     None
;
;   Purpose:
;     This call out reads a block of memory SPD data and places it
;     into the provided buffer.
;
;   Dependencies:
;     None
;
EXTERN myReadSPDRecovery:NEAR


;----------------------------------------------------------------------------
; Define the sample wrapper routines for the recovery segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   AmdInitResetWrapper
;
;   Entry:
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     A minimal initialization of the processor core is performed. This
;     procedure must be called by all processor cores. The code path
;     separates the BSP from the APs and performs a separate and appropriate
;     list of tasks for each class of core.
;     For the BSP, the following actions are performed:
;       Internal heap sub-system initialization
;       Primary non-coherent HyperTransportT link initialization
;       Return to the host environment to test for Recovery Mode.
;     The AP processor cores do not participate in the recovery process.
;     However, they execute this routine after being released to execute
;     by the BSP during the main boot process. Their actions include the
;     following:
;       Internal heap sub-system initialization
;       Proceed to a wait loop waiting for commands from the BSP
;
;     For the cache regions, up to three regions of execution cache can be
;     allocated following the following rules:
;     1. Once a region is allocated, it cannot be de-allocated. However, it
;        can be expanded.
;     2. At most, two of the three regions can be located above 1 MByte. A
;        region failing this rule is ignored.
;     3. All region addresses must be at or above the 0x000D0000 linear
;        address. A region failing this rule is ignored.
;     4. The address is aligned on a 32-KByte boundary. Starting addresses
;        is rounded down to the nearest 32-Kbyte boundary.
;     5. The execution cache size must be a multiple of 32 KByte. Size is
;        rounded up to the next multiple of 32 KByte.
;     6. A region must not span either the 1-MByte boundary or the 4-GByte
;        boundary. Allocated size is truncated to not span the boundary.
;     7. The granted cached execution regions, address, and size are calculated
;        based on the available cache resources of the processor core.
;        Allocations are made up to the limit of cache available on the
;        installed processor.
;     Warning: Enabling instruction cache outside of this interface can cause
;              data corruption.
;
;   Dependencies:
;     This procedure is expected to be executed soon after a system reset
;     for the main boot path or resume path of execution.
;
;     This procedure requires a stack.
;
;     Because the heap system is not yet operational at the point of the
;     interface call, the host environment must allocate the storage for
;     the AMD_RESET_PARAMS structure before making the first call to
;     AmdCreateStruct.  This is the ByHost method of allocation.
;
AmdInitResetWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS
    local localResetParams:AMD_RESET_PARAMS

    pushad

    ; Prepare for the call to initialize the input parameters for AmdInitReset
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B1_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    ; Use the 'ByHost' allocation method because the heap has not been initialized as of yet.
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_RESET
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, ByHost
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, sizeof AMD_RESET_PARAMS
    lea   edx, localResetParams
    add   edx, eax
    push  edx
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr, edx
    mov   dx, SEG AmdCalloutRouterRecovery
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterRecovery
    push  edx
    call  AmdBridge32
    pop   edx
    pop   esi

    ; The structure has been initialized.  Now modify the default settings as desired.

    ; Allocate the execution cache to maximize the amount of code in ROM that is cached.
    ; Placing the B1 and B2 images near one another is a good way to ensure the AGESA code
    ; is cached.
    mov   (AMD_RESET_PARAMS ptr [esi]).CacheRegion.ExeCacheStartAddr, EXE_CACHE_REGION_BASE_0
    mov   (AMD_RESET_PARAMS ptr [esi]).CacheRegion.ExeCacheSize, EXE_CACHE_REGION_SIZE_0
    mov   (AMD_RESET_PARAMS ptr [esi + sizeof EXECUTION_CACHE_REGION]).CacheRegion.ExeCacheStartAddr, EXE_CACHE_REGION_BASE_1
    mov   (AMD_RESET_PARAMS ptr [esi + sizeof EXECUTION_CACHE_REGION]).CacheRegion.ExeCacheSize, EXE_CACHE_REGION_SIZE_1
    mov   (AMD_RESET_PARAMS ptr [esi + (2 * sizeof EXECUTION_CACHE_REGION)]).CacheRegion.ExeCacheStartAddr, EXE_CACHE_REGION_BASE_2
    mov   (AMD_RESET_PARAMS ptr [esi + (2 * sizeof EXECUTION_CACHE_REGION)]).CacheRegion.ExeCacheSize, EXE_CACHE_REGION_SIZE_2

    ; Call in to the AmdInitReset entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS Early initialization completed successfully.
    ;;  AGESA_WARNING One or more of the execution cache allocation
    ;;                rules were violated, but an adjustment was made
    ;;                and space was allocated.
    ;;  AGESA_ERROR One or more of the execution cache allocation rules
    ;;              were violated, which resulted in a requested cache
    ;;              region to not be allocated.
    ;;              The storage space allocated for the AMD_RESET_PARAMS
    ;;              structure is insufficient.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_RESET_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B1_ADDRESS
        call  AmdProcessAgesaErrors
    .endif


    ;; Here are what the MTRRs should look like based off of the CacheRegions specified above:

    ;; Fixed-Range MTRRs
    ;; Name                 Address         Value
    ;; ----------------     --------        ----------------
    ;; MTRRfix4k_E0000      0000026C        0505050505050505
    ;; MTRRfix4k_E8000      0000026D        0505050505050505
    ;; MTRRfix4k_F0000      0000026E        0505050505050505
    ;; MTRRfix4k_F8000      0000026F        0505050505050505
    ;; MTRRdefType          000002FF        0000000000000C00
    ;;
    ;; Variable-Range MTRRs and IO Range
    ;;       MTRRphysBase(n)             MTRRphysMask(n)
    ;;       -----------------           -----------------
    ;; n=0   0000000000000000            0000000000000000
    ;; n=1   0000000000000000            0000000000000000
    ;; n=2   0000000000000000            0000000000000000
    ;; n=3   0000000000000000            0000000000000000
    ;; n=4   0000000000000000            0000000000000000
    ;; n=5   Heap Base (Varies by core)  0000FFFFFFFF0800
    ;; n=6   AGESA_B1_ADDRESS | 6        0000FFFFFFFC0800
    ;; n=7   0000000000000000            0000000000000000


    ;; Because the allocation method is 'ByHost,' the call to AMD_RELEASE_STRUCT is
    ;; not necessary.  Stack space reclamation is left up to the host BIOS.

    popad
    ret


AmdInitResetWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdInitRecoveryWrapper
;
;   Entry:
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     Perform a minimum initialization of the processor and memory to
;     support a recovery mode flash ROM update.
;     For the BSP, the following actions are performed:
;       Configuration of CPU core for recovery process
;       Minimal initialization of some memory
;     The AP processor cores do not participate in the recovery process.
;     No actions or tasks are performed by the AP cores for this time point.
;
;   Dependencies:
;     This procedure requires a stack. The host environment must use one of
;     the provided service functions to establish the stack environment prior
;     to making the call to this procedure.
;
AmdInitRecoveryWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdInitRecovery
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B1_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_RECOVERY
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PreMemHeap
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterRecovery
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterRecovery
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.


    ; Call in to the AmdInitRecovery entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS The function has completed successfully.
    ;;  AGESA_WARNING One or more of the allocation rules were violated,
    ;;                but an adjustment was made and space was allocated.
    ;;  AGESA_ERROR One or more of the allocation rules were violated,
    ;;              which resulted in a requested cache region to not be
    ;;              allocated.
    ;;  AGESA_FATAL No memory was found in the system.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_RECOVERY_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B1_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    ; Allow AGESA to free the space used by AmdInitRecovery
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32

    popad
    ret
AmdInitRecoveryWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdCalloutRouterRecovery
;
;   Entry:
;     ECX - Callout function number
;     EDX - Function-specific UINTN
;     ESI - Pointer to function specific data
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;
;   Modified:
;     None
;
;   Purpose:
;     The call out router function for AmdInitReset and
;     AmdInitRecovery.
;
;   Dependencies:
;     None
;
AmdCalloutRouterRecovery PROC FAR PUBLIC USES ECX EBX ESI BX DI DS ES
    xor   ax, ax
    mov   ds, ax
    mov   es, ax
    lea   di, cs:CalloutRouterTableRecovery
    mov   eax, AGESA_UNSUPPORTED

loopThruTable:
    cmp   di, OFFSET cs:CalloutRouterTableRecoveryEnd
    jae   amdCpuCalloutExit ; exit with AGESA_UNSUPPORTED
    cmp   ecx, cs:[di].sOemCallout.FuncName
    je    FoundMatch
    add   di, SIZEOF sOemCallout
    jmp   loopThruTable

FoundMatch:
    mov   bx, cs:[di].sOemCallout.FuncPtr
    call  bx

amdCpuCalloutExit:
    ret
AmdCalloutRouterRecovery ENDP


;----------------------------------------------------------------------------
; Define the callout dispatch table for the recovery segment
;----------------------------------------------------------------------------

CalloutRouterTableRecovery LABEL BYTE
    ;; Standard B1 implementations only need the SPD reader call out function to be implemented.
    sOemCallout <AGESA_READ_SPD, OFFSET myReadSPDRecovery>
CalloutRouterTableRecoveryEnd LABEL BYTE


AMD_RECOVERY_END



;----------------------------------------------------------------------------
;    PRE-MEMORY SEGMENT
; This segment must be uncompressed in the ROM image.
;----------------------------------------------------------------------------

AMD_PREMEM_START


;----------------------------------------------------------------------------
; Declare the external routines required in the recovery segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   myReadSPDPremem (Required)
;
;   Entry:
;     ESI - Pointer to an AGESA_READ_SPD_PARAMS structure
;
;     typedef struct {
;       IN OUT AMD_CONFIG_PARAMS StdHeader;
;       IN       UINT8 SocketId;
;       IN       UINT8 MemChannelId;
;       IN       UINT8 DimmId;
;       IN OUT   UINT8 *Buffer;
;       IN OUT   MEM_DATA_STRUCT *MemData;
;     } AGESA_READ_SPD_PARAMS;
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS Indicates the SPD block for the indicated
;                         DIMM was read successfully.
;           AGESA_BOUNDS_CHK The specified DIMM is not present.
;           AGESA_UNSUPPORTED This is a required function, so this
;                             value being returned causes a critical
;                             error response value from the AGESA
;                             software function and no memory initialized.
;           AGESA_ERROR The DIMM SPD read process has generated
;                       communication errors.
;
;   Modified:
;     None
;
;   Purpose:
;     This call out reads a block of memory SPD data and places it
;     into the provided buffer.
;
;   Dependencies:
;     None
;
EXTERN myReadSPDPremem:NEAR

;+-------------------------------------------------------------------------
;
;   AmdDfltRetPremem
;
;   Entry:
;     None
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     Near stub procedure in the prememory segment.  Simply perform a
;     retn instruction.
;
EXTERN AmdDfltRetPremem:NEAR

;+---------------------------------------------------------------------------
;
;   myDoReset (Required)
;
;   Entry:
;     EDX - Reset type
;           1 - Warm reset whenever
;           2 - Cold reset whenever
;           3 - Warm reset immediately
;           4 - Cold reset immediately
;     ESI - Pointer to an AMD_CONFIG_PARAMS structure.
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS The function has completed successfully.
;           AGESA_UNSUPPORTED This is a required function, so this
;                             value being returned causes a critical
;                             error response value from the AGESA
;                             software function.
;
;   Modified:
;     None
;
;   Purpose:
;     This host environment function must initiate the specified type
;     of system reset.
;
;     Implementation of this function by the host environment is
;     REQUIRED. Some host environments may record this as a request
;     allowing other elements in the system to perform some additional
;     tasks before the actual reset is issued.
;
;   Dependencies:
;     The AMD processor contains 3 bits (BiosRstDet[2:0]) in a PCI
;     register (F0x6C Link Initialization Control Register) that
;     indicate the reset status. These bits are reserved for use by
;     the AGESA software and should not be modified by the host
;     environment.
;
EXTERN myDoReset:NEAR


;+---------------------------------------------------------------------------
;
;   myGetNonVolatileS3Context (Required for proper S3 operation)
;
;   Entry:
;     None
;
;   Exit:
;     EBX - Pointer to the non-volatile S3 context block
;     ECX - Size in bytes of the non-volatile S3 context block
;
;   Modified:
;     None
;
;   Purpose:
;     The host environment must return the pointer to the data
;     saved during the mySaveNonVolatileS3Context routine.
;
;   Dependencies:
;     None
;
EXTERN myGetNonVolatileS3Context:NEAR


;----------------------------------------------------------------------------
; Declare the optional external routines in the prememory segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   myAgesaHookBeforeExitSelfRefresh (Optional)
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - 44h
;     ESI - Pointer to a data structure containing the memory information
;
;   Exit:
;     After returning control to AGESA, AGESA will display: - AGESA_TESTPOINT - 45h
;     EAX - Contains the AGESA_STATUS return code
;           AGESA_SUCCESS The function has completed successfully
;           AGESA_UNSUPPORTED This function is not implemented by the host environment
;           AGESA_WARNING A non-critical issue has occued in the host environment
;
;   Modified:
;     None
;
;   Purpose:
;     General purpose hook called before the exiting self refresh
;     This procedure is called once per channel
;
;     Implementation of this function is optional for the host environment
;     This call-out is an opportunity for the host environment to make dynamic
;     modifications to the memory timing settings specific to the board or host
;     environment before exiting self refresh on S3 resume
;
;   Dependencies:
;     This procedure is called before the exit self refresh bit is set in the resume
;     sequence. The host environment must initiate the OS restart process. This procedure
;     requires a stack. The host environment must establish the stack environment prior
;     to making the call to this procedure
;
EXTERN myAgesaHookBeforeExitSelfRefresh(AmdDfltRetPremem):NEAR


;+---------------------------------------------------------------------------
;
;   myHookBeforeDramInit (Optional)
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - 40h
;     ESI - Pointer to a data structure containing the memory information
;
;   Exit:
;     After returning control to AGESA, AGESA will display - AGESA_TESTPOINT - 41h
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS The function has completed successfully.
;           AGESA_UNSUPPORTED This function is not implemented by the host environment
;
;   Modified:
;     None
;
;   Purpose:
;     General-purpose hook called before the DRAM_Init bit is set. Called
;     once per MCT
;
;     Implementation of this function is optional for the host environment
;     This call-out is an opportunity for the host environment to make
;     dynamic modifications to the memory timing settings specific to the
;     board or host environment
;
;   Dependencies:
;     None
;
EXTERN myHookBeforeDramInit(AmdDfltRetPremem):NEAR


;+---------------------------------------------------------------------------
;
;   myHookBeforeDQSTraining (Optional)
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - 42h
;     ESI - Pointer to a data structure containing the memory information.
;
;   Exit:
;     After returning control to AGESA, AGESA will display - AGESA_TESTPOINT - 43h
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS The function has completed successfully.
;           AGESA_UNSUPPORTED This function is not implemented by the
;                             host environment.
;
;   Modified:
;     None
;
;   Purpose:
;     General-purpose hook called just before the memory training processes
;     begin. Called once per MCT.
;
;     Implementation of this function is optional for the host environment.
;     This call-out is an opportunity for the host environment to make
;     dynamic modifications to the memory timing settings specific to the
;     board or host environment.
;
;     The host environment may also use this call-out for some board-
;     specific features that should be activated at this time point,
;     such as:
;       Low voltage DIMMs-the host environment should set the recommended
;       voltages found in the memory data structure for each memory
;       channel. This needs to occur before training begins.
;
;   Dependencies:
;     None
;
EXTERN myHookBeforeDQSTraining(AmdDfltRetPremem):NEAR


;----------------------------------------------------------------------------
; Define the sample wrapper routines for the prememory segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   AmdInitEarlyWrapper
;
;   Entry:
;     On Entry to "AmdInitEarly" AGESA will display AGESA_TESTPOINT - C4h
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Exit from "AmdInitEarly" AGESA will display AGESA_TESTPOINT - C5h
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     A full initialization of the processor is performed. Action details
;     differ for the BSP and AP processor cores.
;     For the BSP, the following actions are performed:
;       Full HyperTransportT link initialization, coherent and non-coherent
;       Processor register loading
;       Microcode patch load
;       Errata workaround processing
;       Launch all processor cores
;       Configure the processor power management capabilities
;       Request a warm reset if needed
;     For the AP, the following actions are performed:
;       Processor register loading
;       Microcode patch load
;       Errata workaround processing
;       Configure the processor power management capabilities
;
;   Dependencies:
;     This procedure is expected to be called before main memory initialization
;     and before the system warm reset. Prior to this, the basic configuration
;     done by the AmdInitReset routine must be completed.
;
;     This procedure requires a stack. The host environment must use one of the
;     provided service functions to establish the stack environment prior to
;     making the call to this procedure.
;
;     The processes performed at this time point require communication between
;     processor cores.
;
;     The host environment must recognize that all processor cores are running
;     in parallel and avoid activities that might interfere with the core-to-core
;     communication, such as modifying the MTRR settings or writing to the APIC
;     registers.
;
AmdInitEarlyWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdInitEarly
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_EARLY
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PreMemHeap
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPremem
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPremem
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, (SIZEOF AMD_CONFIG_PARAMS + (3 * (SIZEOF EXECUTION_CACHE_REGION)))
    call  oemPlatformConfigInit

    ; Call in to the AmdInitEarly entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS The function has completed successfully.
    ;;  AGESA_ALERT An HyperTransportT link CRC error was observed.
    ;;  AGESA_WARNING One of more of the allocation rules were violated,
    ;;                but an adjustment was made and space was allocated.
    ;;                Or a HyperTransport device does not have the expected
    ;;                capabilities, or unusable redundant HyperTransport
    ;;                links were found.
    ;;  AGESA_ERROR One or more of the allocation rules were violated, which
    ;;              resulted in a requested cache region to not be allocated.
    ;;              Or, a HyperTransport device failed to initialize.
    ;;  AGESA_CRITICAL An illegal or unsupported mixture of processor types was
    ;;                 found, or the processors installed were found to have an
    ;;                 insufficient MP capability rating for this platform.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_EARLY_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    ; Allow AGESA to free the space used by AmdInitEarly
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32


    popad
    ret
AmdInitEarlyWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdInitPostWrapper
;
;   Entry:
;     On Entry to "AmdInitPost" AGESA will display AGESA_TESTPOINT - C6h
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Exit from "AmdInitPost" AGESA will display AGESA_TESTPOINT - C7h
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     The main system memory is located, initialized, and brought on-line.
;     The processor(s) are prepared for full operation and control by the
;     host environment. Action details differ for the BSP and AP processor
;     cores.
;     For the BSP, the following actions are performed:
;       Full memory initialization and configuration. BSP is the master for
;       this process and may delegate some tasks to APs.
;       AP collection of data for use later.
;       Transfer the HOBs including the artifact data out of the pre-memory
;       cache storage into a temporary holding buffer in the main memory.
;       Check the BIST status of the BSP
;       Shut down the APs.
;       Prepare for the host environment to begin main boot activity.
;       Disable the pre-memory stack.
;     For the APs, the following actions are performed:
;       Report core identity information.
;       Execute indicated memory initialization processes as directed.
;       Check the BIST status of the AP
;       Disable the pre-memory stack.
;       Prepare to halt, giving control to host environment.
;     The entire range of system memory is enabled for Write-Back cache.
;     The fixed MTRRs and the variable MTRRs[7:6] are not changed in order
;     to leave in place any flash ROM region currently set for Write-Protect
;     execution cache.
;
;   Dependencies:
;     This procedure is called after the host environment has determined that
;     a normal boot to operating system should be performed after any system
;     warm reset is completed and after the configuration done by AmdInitEarly
;     has completed.
;
;     This procedure requires a stack. The host environment must use one of the
;     provided service functions to establish the stack environment prior to
;     making the call to this procedure.
;
;     The processes performed at this time point require communication between
;     processor cores.  The host environment must recognize that all processor
;     cores are running in parallel and avoid activities that might interfere
;     with the core-to-core communication, such as modifying the MTRR settings
;     or writing to the APIC registers.
;
AmdInitPostWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdInitPost
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_POST
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PreMemHeap
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPremem
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPremem
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, SIZEOF AMD_CONFIG_PARAMS
    call  oemPlatformConfigInit

    ; Call in to the AmdInitPost entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS The function has completed successfully.
    ;;  AGESA_ALERT   A BIST error was found on one of the cores.
    ;;  AGESA_WARNING HT Assist feature is running sub-optimally.
    ;;  AGESA_FATAL   Memory initialization failed.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_POST_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    ; Allow AGESA to free the space used by AmdInitPost
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32


    popad
    ret
AmdInitPostWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdInitResumeWrapper
;
;   Entry:
;     On Entry to "AmdInitResume" AGESA will display AGESA_TESTPOINT - D0h
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Exit from "AmdInitResume" AGESA will display AGESA_TESTPOINT - D1h
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This procedure initializes or re-initializes the silicon components
;     for the resume boot path.  For the processor, main memory is brought
;     out of self-refresh mode. This procedure will use the context data
;     in the NvStorage area of the input structure to re-start the main
;     memory.  The host environment must fill the AMD_S3_PARAMS NvStorage
;     and VolatileStorage pointers and related size elements to describe
;     the location of the context data. Note that for this procedure, the
;     two data areas do not need to be contained in one buffer zone, they
;     can be anywhere in the accessible memory address space. If the host
;     environment uses a non-volatile storage device accessed on the system
;     address bus such as flashROM, then the context data does not need to
;     be moved prior to this call. If the host environment uses a non-
;     volatile storage device not located on the system address bus (e.g.
;     CMOS or SSEPROM) then the host environment must transfer the context
;     data to a buffer in main memory prior to calling this procedure.
;
;   Dependencies:
;     The host environment must have determined that the system should take
;     the resume path prior to calling this procedure. The configuration
;     done by AmdInitEarly and any necessary warm reset must be complete.
;     After this procedure, execution proceeds to general system restoration.
;
;     This procedure requires a stack. The host environment must use one of
;     the provided service functions to establish the stack environment prior
;     to making the call to this procedure.
;
AmdInitResumeWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdInitResume
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_RESUME
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PreMemHeap
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPremem
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPremem
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, (SIZEOF AMD_CONFIG_PARAMS + SIZEOF AMD_S3_PARAMS)
    call  oemPlatformConfigInit

    call  myGetNonVolatileS3Context
    mov   (AMD_RESUME_PARAMS ptr [esi]).S3DataBlock.NvStorage, ebx
    mov   (AMD_RESUME_PARAMS ptr [esi]).S3DataBlock.NvStorageSize, ecx

    ; Call in to the AmdInitResume entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS Re-initialization has been completed successfully.
    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_RESUME_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif


    ; Allow AGESA to free the space used by AmdInitResume
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32


    popad
    ret
AmdInitResumeWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdCalloutRouterPremem
;
;   Entry:
;     ECX - Callout function number
;     EDX - Function-specific UINTN
;     ESI - Pointer to function specific data
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;
;   Modified:
;     None
;
;   Purpose:
;     The call out router function for AmdInitEarly,
;     AmdInitPost, and AmdInitResume.
;
;   Dependencies:
;     None
;
AmdCalloutRouterPremem PROC FAR PUBLIC USES ECX EBX ESI BX DI DS ES
    xor   ax, ax
    mov   ds, ax
    mov   es, ax
    lea   di, cs:CalloutRouterTablePremem
    mov   eax, AGESA_UNSUPPORTED

loopThruTable:
    cmp   di, OFFSET cs:CalloutRouterTablePrememEnd
    jae   amdCpuCalloutExit ; exit with AGESA_UNSUPPORTED
    cmp   ecx, cs:[di].sOemCallout.FuncName
    je    FoundMatch
    add   di, SIZEOF sOemCallout
    jmp   loopThruTable

FoundMatch:
    mov   bx, cs:[di].sOemCallout.FuncPtr
    call  bx

amdCpuCalloutExit:
    ret
AmdCalloutRouterPremem ENDP


;----------------------------------------------------------------------------
; Define the callout dispatch table for the prememory segment
;----------------------------------------------------------------------------

CalloutRouterTablePremem LABEL BYTE
    ;; Add entries as desired.
    sOemCallout <AGESA_READ_SPD, OFFSET myReadSPDPremem>
    sOemCallout <AGESA_HOOKBEFORE_DRAM_INIT, OFFSET myHookBeforeDramInit>
    sOemCallout <AGESA_HOOKBEFORE_DQS_TRAINING, OFFSET myHookBeforeDQSTraining>
    sOemCallout <AGESA_HOOKBEFORE_EXIT_SELF_REF, OFFSET myAgesaHookBeforeExitSelfRefresh>
    sOemCallout <AGESA_DO_RESET, OFFSET myDoReset>
CalloutRouterTablePrememEnd LABEL BYTE



AMD_PREMEM_END


;----------------------------------------------------------------------------
;    POST SEGMENT
; This segment may be decompressed and run from system RAM.
;----------------------------------------------------------------------------

AMD_POST_START


;----------------------------------------------------------------------------
; Declare the external routines required in the POST segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   myAllocateBuffer (Required)
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - E2h
;     ESI - Pointer to an AGESA_BUFFER_PARAMS structure.
;
;           typedef struct {
;             IN OUT   AMD_CONFIG_PARAMS StdHeader;
;             IN       UINT32 BufferLength;
;             IN       UINT32 BufferHandle;
;                OUT   VOID *BufferPointer;
;           } AGESA_BUFFER_PARAMS;
;
;   Exit:
;     After this hook, AGESA will display - AGESA_TESTPOINT - E3h
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS The requested size of memory has been
;                         successfully allocated.
;           AGESA_UNSUPPORTED This is a required function, so this
;                             value being returned causes a critical
;                             error response value from the AGESA
;                             software function.
;           AGESA_ERROR Less than the requested amount of memory
;                       was allocated.
;
;   Modified:
;     EAX
;
;   Purpose:
;     This function is used after main memory has been initialized
;     and the host environment has taken control of memory allocation.
;     This function must allocate a buffer of the requested size or
;     larger. This function is required to be implemented by the host
;     environment.
;
;   Dependencies:
;     The following call-outs must work together in the host system.
;     Parameters of the same name have the same function and must be
;     treated the same in each function:
;       AgesaAllocateBuffer
;       AgesaDeallocateBuffer
;       AgesaLocateBuffer
;       AgesaRunFcnOnAp
;     The host environment may need to reserve a location in the buffer
;     to store any host environment specific value(s). The returned
;     pointer must not include this reserved space. The host environment
;     on the AgesaDeallocateBuffer call needs to account for the reserved
;     space.  This reserved space may be an identifier or the "handle"
;     used to identify the specific memory block.
;
EXTERN myAllocateBuffer:NEAR

;+---------------------------------------------------------------------------
;
;   myDeallocateBuffer (Required)
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - E4h
;     ESI - Pointer to an AGESA_BUFFER_PARAMS structure.
;
;           typedef struct {
;             IN OUT   AMD_CONFIG_PARAMS StdHeader;
;             IN       UINT32 BufferLength;
;             IN       UINT32 BufferHandle;
;                OUT   VOID *BufferPointer;
;           } AGESA_BUFFER_PARAMS;
;
;   Exit:
;     After this hook, AGESA will display - AGESA_TESTPOINT - E5h
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS The function has completed successfully.
;           AGESA_BOUNDS_CHK The BufferHandle is invalid. The AGESA
;                            software continues with its function.
;           AGESA_UNSUPPORTED This is a required function, so this
;                             value being returned causes a critical
;                             error response value from the AGESA
;                             software function.
;
;   Modified:
;     EAX
;
;   Purpose:
;     This function is used after main memory has been initialized
;     and the host environment has taken control of memory allocation.
;     This function releases a valid working buffer. This function is
;     required for the host environment to implement.
;
;   Dependencies:
;     The following call-outs must work together in the host system.
;     Parameters of the same name have the same function and must be
;     treated the same in each function:
;       AgesaAllocateBuffer
;       AgesaDeallocateBuffer
;       AgesaLocateBuffer
;       AgesaRunFcnOnAp
;
EXTERN myDeallocateBuffer:NEAR

;+---------------------------------------------------------------------------
;
;   myLocateBuffer (Required)
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - E6h
;     ESI - Pointer to an AGESA_BUFFER_PARAMS structure.
;
;           typedef struct {
;             IN OUT   AMD_CONFIG_PARAMS StdHeader;
;             IN       UINT32 BufferLength;
;             IN       UINT32 BufferHandle;
;                OUT   VOID *BufferPointer;
;           } AGESA_BUFFER_PARAMS;
;
;   Exit:
;     After this hook, AGESA will display - AGESA_TESTPOINT - E7h
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS The function has completed successfully.
;           AGESA_BOUNDS_CHK The presented handle is invalid or the
;                            buffer could not be located.
;
;   Modified:
;     EAX
;
;   Purpose:
;     This function is used after main memory has been initialized
;     and the host environment has taken control of memory allocation.
;     This function must locate the buffer related to the indicated
;     handle and return the address of the buffer and its length.
;     This function is required to be implemented in the host
;     environment.
;
;   Dependencies:
;     The following call-outs must work together in the host system.
;     Parameters of the same name have the same function and must be
;     treated the same in each function:
;       AgesaAllocateBuffer
;       AgesaDeallocateBuffer
;       AgesaLocateBuffer
;       AgesaRunFcnOnAp
;
EXTERN myLocateBuffer:NEAR


;+---------------------------------------------------------------------------
;
;   myRunFuncOnAp (Required)
;
;   Entry:
;     EDX - Local APIC ID of the target core.
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     The host environment must route execution to the target AP and
;     have that AP call the AmdLateRunApTaskWrapper routine defined
;     above.
;
;   Dependencies:
;     None
;
EXTERN myRunFuncOnAp:NEAR

;+---------------------------------------------------------------------------
;
;   mySaveNonVolatileS3Context (Required for proper S3 operation)
;
;   Entry:
;     EBX - Pointer to the non-volatile S3 context block
;     ECX - Size in bytes of the non-volatile S3 context block
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     The host environment must save the non-volatile data to an area
;     that will not lose context while in the ACPI S3 sleep state, but
;     cannot be placed in system RAM.  This data will need to be
;     available during the call to AmdInitResume.
;
;   Dependencies:
;     None
;
EXTERN mySaveNonVolatileS3Context:NEAR

;+---------------------------------------------------------------------------
;
;   mySaveVolatileS3Context (Required for proper S3 operation)
;
;   Entry:
;     EBX - Pointer to the volatile S3 context block
;     ECX - Size in bytes of the volatile S3 context block
;
;   Exit:
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     The host environment must save the volatile data to an area
;     that will not lose context while in the ACPI S3 sleep state.
;     This data will need to be available during the call to
;     AmdS3LateRestore.
;
;   Dependencies:
;     None
;
EXTERN mySaveVolatileS3Context:NEAR

;+---------------------------------------------------------------------------
;
;   myGetVolatileS3Context (Required for proper S3 operation)
;
;   Entry:
;     None
;
;   Exit:
;     EBX - Pointer to the volatile S3 context block
;     ECX - Size in bytes of the volatile S3 context block
;
;   Modified:
;     None
;
;   Purpose:
;     The host environment must return the pointer to the data
;     saved during the mySaveVolatileS3Context routine.
;
;   Dependencies:
;     None
;
EXTERN myGetVolatileS3Context:NEAR


;----------------------------------------------------------------------------
; Define the sample wrapper routines for the POST segment
;----------------------------------------------------------------------------

;+---------------------------------------------------------------------------
;
;   AmdInitEnvWrapper
;
;   Entry:
;     On Entry to "AmdInitEnv" AGESA will display AGESA_TESTPOINT - C8h
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Exit from "AmdInitEnv" AGESA will display AGESA_TESTPOINT - C9h
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This procedure uses the AgesaAllocateBuffer call-out to acquire
;     permanent buffer space for the UEFI Hand-Off Blocks (HOBs). This
;     is also known as, or includes, artifact data being used by the
;     AGESA software. Upon entry to this procedure, the data is being
;     held in a temporary memory location and it must be moved to a
;     location controlled and protected by the host environment.
;
;     These actions are performed by the BSP. The APs are not assigned
;     any tasks at this time point.
;
;   Dependencies:
;     This procedure must be called after full memory is initialized and
;     the host environment has taken control of main memory allocation.
;     This procedure should be called before the PCI enumeration takes
;     place and as soon as possible after the host environment memory
;     allocation sub-system has started.
;
;     This procedure requires a stack. The host environment must use one
;     of the provided service functions to establish the stack environment
;     prior to making the call to this procedure.
;
AmdInitEnvWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdInitEnv
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_ENV
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PostMemDram
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPost
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPost
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, SIZEOF AMD_CONFIG_PARAMS
    call  oemPlatformConfigInit

    ; Call in to the AmdInitEnv entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS The function has completed successfully.
    ;;  AGESA_ERROR The artifact data could not be found or the host
    ;;  environment failed to allocate sufficient buffer space.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_ENV_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    ; Allow AGESA to free the space used by AmdInitEnv
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32


    popad
    ret
AmdInitEnvWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdInitMidWrapper
;
;   Entry:
;     On Entry to "AmdInitMid" AGESA will display AGESA_TESTPOINT - CAh
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Exit from "AmdInitMid" AGESA will display AGESA_TESTPOINT - CBh
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This procedure call performs special configuration requirements for
;     the graphics display hardware.
;
;     These actions are performed by the BSP. The APs are not assigned any
;     tasks at this time point.
;
;   Dependencies:
;     This procedure must be called after PCI enumeration has allocated
;     resources, but before the video BIOS call is performed.
;
;     This procedure requires a stack. The host environment must use one
;     of the provided service functions to establish the stack environment
;     prior to making the call to this procedure.
;
AmdInitMidWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdInitMid
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_MID
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PostMemDram
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPost
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPost
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, SIZEOF AMD_CONFIG_PARAMS
    call  oemPlatformConfigInit

    ; Call in to the AmdInitMid entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS The function has completed successfully.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_MID_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    ; Allow AGESA to free the space used by AmdInitMid
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32


    popad
    ret

AmdInitMidWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdInitLateWrapper
;
;   Entry:
;     On Entry to "AmdInitLate" AGESA will display AGESA_TESTPOINT - CCh
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Exit from "AmdInitLate" AGESA will display AGESA_TESTPOINT - CDh
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     The main purpose of this function is to generate informational
;     data tables used by the operating system. The individual tables
;     can be selected for generation through the user selection entries
;     on the input parameters.
;
;     This routine uses the Call-Out AgesaAllocateBuffer to allocate a
;     buffer of the proper size to contain the data.
;
;     The code path separates the BSP from the APs and perform a separate
;     and appropriate list of tasks for each class of core.
;     For the BSP, the following actions are performed:
;       Allocate buffer space for the tables.
;       Generate the table contents.
;       Make sure that the CPU is in a known good power state before
;       proceeding to boot the OS.
;     For the APs, the following actions are performed:
;       Final register settings preparing for entry to OS.
;       Establish the final PState for entry to OS.
;
;   Dependencies:
;     This routine is expected to be executed late in the boot sequence
;     after main memory has been initialized, after PCI enumeration has
;     completed, after the host environment ACPI sub-system has started,
;     after the host environment has taken control of the APs, but just
;     before the start of OS boot.
;
;     The host environment must provide the required call-outs listed in
;     the "Required Call-Out Procedures" section of the AGESA interface
;     specification to provide the buffer space in main memory and execute
;     code on the APs. The host environment must register the created ACPI
;     table in the main ACPI pointer tables. This may require moving the
;     generated tables to another location in memory.
;
;     This procedure requires a stack. The host environment must establish
;     the stack environment prior to making the call to this procedure.
;     Some functions depend upon the preservation of the heap data across
;     the shift from pre-memory environment to a post-memory environment.
;     If that data was not preserved, then those functions cannot complete
;     and an error is returned.
;
AmdInitLateWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdInitLate
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_INIT_LATE
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PostMemDram
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPost
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPost
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, SIZEOF AMD_CONFIG_PARAMS
    call  oemPlatformConfigInit

    ; Call in to the AmdInitLate entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS The function has completed successfully.
    ;;  AGESA_ALERT
    ;;  AGESA_ERROR The system could not allocate the needed amount of
    ;;  buffer space; or could not locate the artifact data block in
    ;;  memory. Likely cause: the host environment may not have preserved
    ;;  the data properly.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_LATE_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    push  es
    mov   ax, SEG AmdAcpiSratPointer
    mov   es, ax

    mov   ebx, (AMD_LATE_PARAMS ptr [esi]).AcpiSrat
    mov   es:AmdAcpiSratPointer, ebx
    mov   eax, DWORD PTR [ebx + 4]
    mov   es:AmdAcpiSratSize, eax

    mov   ebx, (AMD_LATE_PARAMS ptr [esi]).AcpiSlit
    mov   es:AmdAcpiSlitPointer, ebx
    mov   eax, DWORD PTR [ebx + 4]
    mov   es:AmdAcpiSlitSize, eax

    mov   ebx, (AMD_LATE_PARAMS ptr [esi]).AcpiPState
    mov   es:AmdAcpiSsdtPointer, ebx
    mov   eax, DWORD PTR [ebx + 4]
    mov   es:AmdAcpiSsdtSize, eax

    xor   eax, eax

    mov   ebx, (AMD_LATE_PARAMS ptr [esi]).AcpiWheaMce
    mov   es:AmdAcpiWheaMcePointer, ebx
    mov   ax, WORD PTR [ebx]
    mov   es:AmdAcpiWheaMceSize, eax

    mov   ebx, (AMD_LATE_PARAMS ptr [esi]).AcpiWheaMce
    mov   es:AmdAcpiWheaCmcPointer, ebx
    mov   ax, WORD PTR [ebx]
    mov   es:AmdAcpiWheaCmcSize, eax

    mov   eax, (AMD_LATE_PARAMS ptr [esi]).DmiTable
    mov   es:AmdDmiInfoPointer, eax
    pop   es


    ; Allow AGESA to free the space used by AmdInitLate
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32

    popad
    ret

AmdInitLateWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdS3SaveWrapper
;
;   Entry:
;     On Entry to "AmdS3Save" AGESA will display AGESA_TESTPOINT - CEh
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Entry to "AmdS3Save" AGESA will display AGESA_TESTPOINT - CFh
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This procedure saves critical registers and/or configuration
;     information for preservation across a system suspend mode. All
;     actions needed to prepare the processor for suspend mode is
;     performed, however this procedure does NOT initiate the suspend
;     process. The host environment is expected to perform that duty.
;
;     These actions are performed by the BSP. The APs are not assigned
;     any tasks at this time point.
;
;     The initializer routine will NULL out the save area pointers and
;     sizes. This procedure will determine the size of storage needed
;     for all the processor context, and make a call out to the environment
;     for allocation of one buffer to store all of the data. Upon exit, the
;     pointers and sizes within the AMD_S3_PARAMS structure will be updated
;     with the appropriate addresses within the buffer that was allocated.
;     The host environment is expected to then transfer the data pointed to
;     by NvStorage to a non-volatile storage area, and the data pointed to
;     by VolatileStorage to either a non-volatile storage area or system
;     RAM that retains its content across suspend.
;
;   Dependencies:
;     The host environment must initiate the suspend process.
;
;     This procedure requires a stack. The host environment must establish
;     the stack environment prior to making the call to this procedure.
;
AmdS3SaveWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdS3Save
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_S3_SAVE
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PostMemDram
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPost
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPost
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, (SIZEOF AMD_CONFIG_PARAMS + SIZEOF AMD_S3_PARAMS)
    call  oemPlatformConfigInit

    ; Call in to the AmdS3Save entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS All suspend duties have been completed successfully.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_S3SAVE_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    mov   ecx, (AMD_S3SAVE_PARAMS ptr [esi]).S3DataBlock.NvStorageSize
    .if (ecx != 0)
        mov   ebx, (AMD_S3SAVE_PARAMS ptr [esi]).S3DataBlock.NvStorage
        call  mySaveNonVolatileS3Context
    .endif

    mov   ecx, (AMD_S3SAVE_PARAMS ptr [esi]).S3DataBlock.VolatileStorageSize
    .if (ecx != 0)
        mov   ebx, (AMD_S3SAVE_PARAMS ptr [esi]).S3DataBlock.VolatileStorage
        call  mySaveVolatileS3Context
    .endif

    ; Allow AGESA to free the space used by AmdS3Save
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32

    popad
    ret

AmdS3SaveWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdS3LateRestoreWrapper
;
;   Entry:
;     On Entry to "AmdS3LateRestore" AGESA will display AGESA_TESTPOINT - D2h
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     On Exit from "AmdS3LateRestore" AGESA will display AGESA_TESTPOINT - D3h
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This procedure restores the processor state, reloads critical
;     silicon component registers, and performs any re-initialization
;     required by the silicon. This procedure will use the context data
;     in the VolatileStorage area of the input structure to restore the
;     processor registers.
;
;     The host environment must fill the AMD_S3_PARAMS NvStorage and
;     VolatileStorage pointers and related size elements to describe
;     the location of the context data. Note that for this procedure,
;     the two data areas do not need to be contained in one buffer zone,
;     they can be anywhere in the accessible memory address space. If
;     the host environment uses a non-volatile storage device accessed
;     on the system address bus such as flashROM, then the context data
;     does not need to be moved prior to this call. If the host
;     environment uses a non-volatile storage device not located on the
;     system address bus (e.g. CMOS or SSEPROM) then the host environment
;     must transfer the context data to a buffer in main memory prior to
;     calling this procedure.
;
;     These actions are performed by the BSP. The APs are not assigned
;     any tasks at this time point.
;
;   Dependencies:
;     This procedure is called late in the resume sequence, after the
;     PCI control space is restored and just before resuming operating
;     system execution.
;
;     The host environment must initiate the OS restart process.
;
;     This procedure requires a stack. The host environment must establish
;     the stack environment prior to making the call to this procedure.
;
AmdS3LateRestoreWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdS3LateRestore
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_S3LATE_RESTORE
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PostMemDram
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPost
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPost
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    mov   edi, esi
    add   edi, (SIZEOF AMD_CONFIG_PARAMS + SIZEOF AMD_S3_PARAMS)
    call  oemPlatformConfigInit

    call  myGetVolatileS3Context
    mov   (AMD_S3LATE_PARAMS ptr [esi]).S3DataBlock.VolatileStorage, ebx
    mov   (AMD_S3LATE_PARAMS ptr [esi]).S3DataBlock.VolatileStorageSize, ecx

    ; Call in to the AmdS3LateRestore entry point
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    ;;  AGESA_SUCCESS All resume processes have been completed successfully.

    .if (eax != AGESA_SUCCESS)
        mov   al, (AMD_S3LATE_PARAMS ptr [esi]).StdHeader.HeapStatus
        mov   ebx, AGESA_B2_ADDRESS
        call  AmdProcessAgesaErrors
    .endif

    ; Allow AGESA to free the space used by AmdS3LateRestore
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32

    popad
    ret
AmdS3LateRestoreWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdLateRunApTaskWrapper
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - D4h
;     DS - 0000 with 4 gigabyte access
;     ES - 0000 with 4 gigabyte access
;
;   Exit:
;     After this hook, AGESA will display - AGESA_TESTPOINT - D5h
;     None
;
;   Modified:
;     None
;
;   Purpose:
;     This entry point is tightly connected with the "AgesaRunFcnOnAp"
;     call out.  The AGESA software will call the call-out "AgesaRunFcnOnAp";
;     the host environment will then call this entry point to have the AP
;     execute the requested function. This is needed late in the Post and
;     Resume branches for running an AP task since the AGESA software has
;     relinquished control of the APs to the host environment.
;
;   Dependencies:
;     The host environment must implement the"AgesaRunFcnOnAp" call-out
;     and route execution to the target AP.
;
AmdLateRunApTaskWrapper PROC NEAR PUBLIC
    local localCfgBlock:AMD_INTERFACE_PARAMS

    pushad

    ; Prepare for the call to create and initialize the input parameters for AmdLateRunApTask
    xor   eax, eax
    mov   ax, ss
    shl   eax, 4
    lea   esi, localCfgBlock
    add   esi, eax
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.ImageBasePtr, AGESA_B2_ADDRESS
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_CREATE_STRUCT
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.AltImageBasePtr, 0
    mov   edx, SEG AmdCallout16
    shl   edx, 4
    add   edx, OFFSET AmdCallout16
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.CalloutPtr, edx

    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AgesaFunctionName, AMD_LATE_RUN_AP_TASK
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).AllocationMethod, PostMemDram
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).NewStructSize, 0
    push  esi
    mov   dx, SEG AmdCalloutRouterPost
    shl   edx, 16
    mov   dx, OFFSET AmdCalloutRouterPost
    push  edx
    call  AmdBridge32
    pop   edx

    mov   esi, (AMD_INTERFACE_PARAMS ptr [esi]).NewStructPtr

    ; The structure has been initialized.  Now modify the default settings as desired.

    push  es
    mov   ax, SEG AmdRunCodeOnApDataPointer
    mov   es, ax
    mov   eax, es:AmdRunCodeOnApDataPointer
    mov   (AP_EXE_PARAMS PTR [esi]).RelatedDataBlock, eax
    mov   eax, es:AmdRunCodeOnApDataSize
    mov   (AP_EXE_PARAMS PTR [esi]).RelatedBlockLength, eax
    mov   eax, es:AmdRunCodeOnApFunction
    mov   (AP_EXE_PARAMS PTR [esi]).FunctionNumber, eax
    pop   es

    ; Call in to the AmdLateRunApTask dispatcher
    push  edx
    call  AmdBridge32
    pop   edx

    ;;  EAX = AGESA_STATUS
    push  es
    mov   bx, SEG AmdRunCodeOnApStatus
    mov   es, bx
    mov   es:AmdRunCodeOnApStatus, eax
    pop   es

    ; Allow AGESA to free the space used by AmdLateRunApTask
    pop   esi
    mov   (AMD_INTERFACE_PARAMS ptr [esi]).StdHeader.Func, AMD_RELEASE_STRUCT
    call  AmdBridge32

    popad
    ret

AmdLateRunApTaskWrapper ENDP


;+---------------------------------------------------------------------------
;
;   AmdRunFuncOnAp (Required)
;
;   Entry:
;     Prior to this hook, AGESA will display - AGESA_TESTPOINT - E8h
;     EDX - Local APIC ID of the target core.
;     ESI - Pointer to an AP_EXE_PARAMS structure.
;
;           typedef struct {
;             IN OUT   AMD_CONFIG_PARAMS StdHeader;
;             IN       UINT32 FunctionNumber;
;             IN       VOID *RelatedDataBlock;
;             IN       UINT32 RelatedDataBlockLength;
;           } AP_EXE_PARAMS;
;
;   Exit:
;     After this hook, AGESA will display - AGESA_TESTPOINT - E9h
;     EAX - Contains the AGESA_STATUS return code.
;           AGESA_SUCCESS The function has completed successfully.
;           AGESA_UNSUPPORTED This is a required function, so this value
;                             being returned causes a critical error
;                             response value from the AGESAT software
;                             function and no memory initialized.
;           AGESA_WARNING The AP did not respond.
;
;   Modified:
;     EAX
;
;   Purpose:
;     This function is used after main memory has been initialized
;     and the host environment has taken control of AP task dispatching.
;     This function must cause the indicated function code to be executed
;     upon the specified Application Processor. This procedure must be
;     executed in 32-bit mode. This function is required to be implemented
;     in the host environment.
;
;   Dependencies:
;     The host environment must route execution to the target AP and
;     have that AP call the"AmdLateRunApTask" entry point.
;
AmdRunFuncOnAp PROC NEAR PUBLIC

    push  es
    mov   ax, SEG AmdRunCodeOnApDataPointer
    mov   es, ax
    mov   eax, (AP_EXE_PARAMS PTR [esi]).RelatedDataBlock
    mov   es:AmdRunCodeOnApDataPointer, eax
    mov   eax, (AP_EXE_PARAMS PTR [esi]).RelatedBlockLength
    mov   es:AmdRunCodeOnApDataSize, eax
    mov   eax, (AP_EXE_PARAMS PTR [esi]).FunctionNumber
    mov   es:AmdRunCodeOnApFunction, eax
    mov   eax, AGESA_UNSUPPORTED
    mov   es:AmdRunCodeOnApStatus, eax
    pop   es

    call  myRunFuncOnAp

    push  es
    mov   ax, SEG AmdRunCodeOnApStatus
    mov   es, ax
    mov   eax, es:AmdRunCodeOnApStatus
    pop   es
    ret
AmdRunFuncOnAp ENDP



;+---------------------------------------------------------------------------
;
;   AmdCalloutRouterPost
;
;   Entry:
;     ECX - Callout function number
;     EDX - Function-specific UINTN
;     ESI - Pointer to function specific data
;
;   Exit:
;     EAX - Contains the AGESA_STATUS return code.
;
;   Modified:
;     None
;
;   Purpose:
;     The call out router function for AmdInitEnv,
;     AmdInitMid, AmdInitLate, AmdS3Save, and
;     AmdS3LateRestore.
;
;   Dependencies:
;     None
;
AmdCalloutRouterPost PROC FAR PUBLIC USES ECX EBX ESI BX DI DS ES
    xor   ax, ax
    mov   ds, ax
    mov   es, ax
    lea   di, cs:CalloutRouterTablePost
    mov   eax, AGESA_UNSUPPORTED

loopThruTable:
    cmp   di, OFFSET cs:CalloutRouterTablePostEnd
    jae   amdCpuCalloutExit ; exit with AGESA_UNSUPPORTED
    cmp   ecx, cs:[di].sOemCallout.FuncName
    je    FoundMatch
    add   di, SIZEOF sOemCallout
    jmp   loopThruTable

FoundMatch:
    mov   bx, cs:[di].sOemCallout.FuncPtr
    call  bx

amdCpuCalloutExit:
    ret
AmdCalloutRouterPost ENDP


;----------------------------------------------------------------------------
; Define the callout dispatch table for the POST segment
;----------------------------------------------------------------------------

CalloutRouterTablePost LABEL BYTE
    ;; Add entries as desired.
    sOemCallout <AGESA_ALLOCATE_BUFFER, OFFSET myAllocateBuffer>
    sOemCallout <AGESA_DEALLOCATE_BUFFER, OFFSET myDeallocateBuffer>
    sOemCallout <AGESA_LOCATE_BUFFER, OFFSET myLocateBuffer>
    sOemCallout <AGESA_RUNFUNC_ONAP, OFFSET AmdRunFuncOnAp>
CalloutRouterTablePostEnd LABEL BYTE

AMD_POST_END


;----------------------------------------------------------------------------
;    CPU DATA SEGMENT
; This segment must be writable, and present at the time that
; AmdInitLate is run.
;----------------------------------------------------------------------------

CPU_DATASEG_START

  ;; Data used to store pointers for later use by the host environment.
  PUBLIC AmdAcpiSratPointer
  PUBLIC AmdAcpiSratSize
  PUBLIC AmdAcpiSlitPointer
  PUBLIC AmdAcpiSlitSize
  PUBLIC AmdAcpiSsdtPointer
  PUBLIC AmdAcpiSsdtSize
  PUBLIC AmdAcpiWheaMcePointer
  PUBLIC AmdAcpiWheaMceSize
  PUBLIC AmdAcpiWheaCmcPointer
  PUBLIC AmdAcpiWheaCmcSize
  PUBLIC AmdDmiInfoPointer
  AmdAcpiSratPointer     DWORD ?
  AmdAcpiSratSize        DWORD ?
  AmdAcpiSlitPointer     DWORD ?
  AmdAcpiSlitSize        DWORD ?
  AmdAcpiSsdtPointer     DWORD ?
  AmdAcpiSsdtSize        DWORD ?
  AmdAcpiWheaMcePointer  DWORD ?
  AmdAcpiWheaMceSize     DWORD ?
  AmdAcpiWheaCmcPointer  DWORD ?
  AmdAcpiWheaCmcSize     DWORD ?
  AmdDmiInfoPointer      DWORD ?

  ;; Data used for communication between the AP and the BSP.
  PUBLIC AmdRunCodeOnApDataPointer
  PUBLIC AmdRunCodeOnApDataSize
  PUBLIC AmdRunCodeOnApFunction
  PUBLIC AmdRunCodeOnApStatus
  AmdRunCodeOnApDataPointer  DWORD ?
  AmdRunCodeOnApDataSize     DWORD ?
  AmdRunCodeOnApFunction     DWORD ?
  AmdRunCodeOnApStatus       DWORD ?

CPU_DATASEG_END


END
