blob: ca02c3dcc616253bdb754ac3c5a40c565fec42fd [file] [log] [blame]
; ****************************************************************************
; *
; * @file
; *
; * Agesa structures and definitions
; *
; * Contains AMD AGESA core interface
; *
; * @xrefitem bom "File Content Label" "Release Content"
; * @e project: AGESA
; * @e sub-project: Include
; * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 17:16:51 +0800 (Wed, 22 Dec 2010) $
;
; ****************************************************************************
;
; 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.
;*****************************************************************************
PARAM1 textequ <[bp+8]>
PARAM2 textequ <[bp+12]>
PARAM3 textequ <[bp+16]>
RETAddress textequ <[bp+4]>
AMD_PRIVATE_PARAMS STRUCT
Gate16_CS DW ? ; Segment of AMD_BRIDGE_32 and AMD_CALLOUT_16
Gate16_SS DW ? ; RM stack segment
Router_Seg DW ? ; Segment of oem router
Router_Off DW ? ; Offset of oem router
AMD_PRIVATE_PARAMS ENDS
; OEM may pre-define the GDT and selector offsets. If they do not, use our defaults.
IFNDEF AGESA_SELECTOR_GDT
AGESA_SELECTOR_GDT EQU 00h
ENDIF
IFNDEF AGESA_SELECTOR_CODE16
AGESA_SELECTOR_CODE16 EQU 08h
ENDIF
IFNDEF AGESA_SELECTOR_DATA16
AGESA_SELECTOR_DATA16 EQU 10h
ENDIF
IFNDEF AGESA_SELECTOR_CODE32
AGESA_SELECTOR_CODE32 EQU 18h
ENDIF
IFNDEF AGESA_SELECTOR_DATA32
AGESA_SELECTOR_DATA32 EQU 20h
ENDIF
AMD_BRIDGE_32_GDT MACRO GDT_Name:REQ
GDT_Name LABEL BYTE
DD 000000000h, 000000000h ; NULL descriptor
DD 00000ffffh, 000009b00h ; 16-bit code, fixed up
DD 00000ffffh, 000009300h ; 16-bit data, fixed up
DD 00000ffffh, 000CF9B00h ; 32-bit protected mode code
DD 00000ffffh, 000CF9300h ; 32-bit protected mode data
GDT_Length EQU ($-GDT_Name)
ENDM
;+-------------------------------------------------------------------------
;
; AMD_BRIDGE_32 - Execute Agesa through Pushhigh interface
;
; Processing:
; The following steps are taken:
; 1) Enter 32bit Protected Mode (PM32)
; 2) Run AGESA code
; 3) Restore Real Mode (RM)
;
; Entry:
; [big real mode] : ds, es set to base 0 limit 4G segment
; EDX - if not 0, provides a FAR PTR to oem router (Seg | Offset)
; ESI - configuration block pointer
;
; Exit:
; EAX - return value
; ESI - configuration block pointer
; ds, es, fs, gs - Set to 4GB segment limit for Big Real Mode
;
; Modified:
; None
;
AMD_BRIDGE_32 MACRO GDT_Name
local copyGDT
local flushTo16PM
local agesaReturnAddress
local leave32bitPM
local flush2RM
push gs
push fs
push ebx
push ecx
push edi
mov eax, esp
push eax
movzx esp, sp
;
; Do not use any locals here, BP will be changed frequently during RM->PM32->RM
;
pushf
cli ; Disable interrupts during AGESA
cld ; Need known direction flag during AGESA
;
; Save the FAR PTR input parameter
;
mov gs, dx ; Offset
shr edx, 16
mov fs, dx ; Segment
;
; Determine where our binary file is and get entry point
;
mov edx, (AMD_CONFIG_PARAMS PTR [esi]).ImageBasePtr
add edx, (AMD_IMAGE_HEADER PTR [edx]).EntryPointAddress
;
; Figure out the return address we will use after calling AGESA
; and store it in ebx until we have our stack set up properly
;
mov ebx, cs
shl ebx, 4
add ebx, OFFSET agesaReturnAddress
;
; Save our current RM stack AND entry EBP
;
push ebp
; push esp
push ss
;
; BEGIN --- STACK MUST BE BALANCED AT THIS POINT --- BEGIN
;
; Copy the GDT onto the stack for modification
;
mov cx, GDT_Length
sub sp, cx
mov bp, sp
lea di, GDT_Name
copyGDT:
mov al, cs:[di]
mov [bp], al
inc di
inc bp
loop copyGDT
;
; Patch 16-bit code and data descriptors on stack. We will
; fix up CS and SS for PM16 during the callout if applicable.
;
mov bp, sp
mov eax, cs
shl eax, 4
mov [bp+AGESA_SELECTOR_CODE16+2], ax
shr eax, 16
mov [bp+AGESA_SELECTOR_CODE16+4], al
mov eax, ss
shl eax, 4
mov [bp+AGESA_SELECTOR_DATA16+2], ax
shr eax, 16
mov [bp+AGESA_SELECTOR_DATA16+4], al
;
; Need to place Length and Address on GDT
;
mov eax, ss
shl eax, 4
add eax, esp
push eax
push WORD PTR (GDT_Length-1)
;
; Load the GDT
;
mov bp, sp
lgdt FWORD PTR [bp]
;
; TABLE 1
;
; Place PRIVATE DATA on stack DIRECTLY following GDT
; During this routine, stack data is critical. If
; order is changed or additional added, bad things
; will happen!
;
; HIGHEST PHYSICAL ADDRESS
;
; | ... |
; ------------------------
; | old RM SP |
; | old RM SS |
; ------------------------ sp + SIZEOF AMD_PRIVATE_PARAMS + (SIZEOF GDT_LENGTH + 6 {size, address})
; | GDT_DATA32 |
; | ... |
; | GDT_NULL |
; | GDT Addr, Length |
; ------------------------ sp + SIZEOF AMD_PRIVATE_PARAMS
; | Priv.Gate16_SS |
; | Priv.Gate16_CS |
; ------------------------ sp
; ------ THEN PUSH -------
; | Return to 16-bit CS |
; | Return to 16-bit Off |
; | ... |
;
; LOWEST PHYSICAL ADDRESS
;
mov edi, esp
sub edi, SIZEOF AMD_PRIVATE_PARAMS
mov ax, cs
mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_CS, ax
mov ax, ss
mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_SS, ax
mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Off, gs
mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Seg, fs
mov esp, edi
;
; Save an address for returning to 16 bit real mode on stack,
; we'll use it in a far ret after turning off CR0.PE so that
; we can take our address off and force a far jump. Be sure
; no unexpected data is on the stack after this!
;
mov ax, cs
push cs
lea ax, flush2RM
push ax
;
; Convert ss:esp to "flat"
;
mov ax, sp
push ax
mov eax, ss
shl eax, 4
add eax, esp
mov esp, eax ; Load the zero based ESP
;
; Set CR0.PE
;
mov eax, CR0 ; Get CPU control word 0
or al, 01 ; Enable CPU protected mode
mov CR0, eax ; Write back to CPU control word 0
jmp flushTo16PM
flushTo16PM:
;
; 16-bit protected mode
;
mov ax, AGESA_SELECTOR_DATA32
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
;
; Push our parameters RIGHT TO LEFT, and then return address
;
push esi ; AGESA configuration block pointer (data)
push ebx ; after AGESA return offset (32PM flat) - consumed by dispatcher ret
pushd AGESA_SELECTOR_CODE32 ; AGESA entry selector (32PM flat)
push edx ; AGESA entry point (32PM flat)
DB 066h
retf ; <><><> Enter AGESA 32-bit code!!! <><><>
agesaReturnAddress:
;
; Returns from the Agesa 32-bit code still PM32
;
DB 0EAh
DD OFFSET leave32bitPM
DW AGESA_SELECTOR_CODE16
leave32bitPM:
;
; Now in 16-bit PM
;
add esp, 4 ; +4 to remove our config block pointer
;
; Eax reserve AGESA_STATUS return code, save it
;
mov ebx, eax
;
; Turn off CR0.PE, restore 64K stack limit
;
pop ax
mov sp, ax
mov ax, AGESA_SELECTOR_DATA16
mov ss, ax
mov eax, CR0
and al, NOT 1 ; Disable protected mode
mov CR0, eax ; Write back CR0.PE
;
; Jump far to enter RM, we saved this address on the stack
; already. Hopefully stack is balanced through AGESA
; nor were any params added by pushing them on the stack and
; not removing them between BEGIN-END comments.
;
retf
flush2RM:
;
; Set segments registers for big real mode before returning
;
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;
; Discard GDT, +6 for GDT pointer/size, privates
;
add esp, GDT_Length + 6 + SIZEOF AMD_PRIVATE_PARAMS
;
; Restore real mode stack and entry EBP
;
pop cx
; mov esp, [esp]
mov ss, cx
pop ebp
;
; Restore AGESA_STATUS return code to eax
;
mov eax, ebx
;
; END --- STACK MUST BE BALANCED TO THIS POINT --- END
;
popf
pop ebx
mov esp, ebx
pop edi
pop ecx
pop ebx
pop fs
pop gs
; EXIT AMD_BRIDGE_32
ENDM
;+-------------------------------------------------------------------------
;
; AMD_CALLOUT_16 - Execute Callback from Pushhigh interface
;
; Processing:
; The following steps are taken:
; 1) Enter PM16
; 2) Setup stack, get private params
; 3) Enter RM
; 4) Get 3 params
; 5) Call oemCallout OR oem router
; 6) Enter PM32
; 7) Return to Agesa PH
;
; Entry:
; [32-bit protected mode]
; [esp+8] Func
; [esp+12] Data
; [esp+16] Configuration Block
; [esp+4] return address to Agesa
;
; Exit:
; [32-bit protected mode]
;
; Modified:
; None
;
AMD_CALLOUT_16 MACRO LocalOemCalloutRouter
;
; Note that we are still PM32, so MASM may work strangely
;
push bp ; Save our original SP to access params
mov bp, sp
push bx
push si
push di
push cx
push dx
push di
DB 066h, 0EAh
DW OFFSET PM16Entry
DW AGESA_SELECTOR_CODE16
PM16Entry:
;
; PM16 CS, but still PM32 SS, as we need to access our private params
; before we enter RM.
;
; Note: we are working below the stack temporarily, and and it will
; not affect our ability to get entry params
;
xor ecx, ecx
xor edx, edx
;
; SGDT will give us the original location of the GDT on our CAS stack.
; We need this value because our private parameters are located just
; below the GDT.
;
mov edi, esp
sub edi, GDT_Length + 6
sgdt FWORD PTR [edi] ; [edi] = word size, dword address
mov edi, DWORD PTR [edi+2] ; Get the PM32 address only
sub edi, SIZEOF AMD_PRIVATE_PARAMS + 6
;
; cx = code segment of this code in RM
; dx = stack segment of CAS in RM
; fs = code segment of oem router (save for later)
; gs = offset of oem router (save for later)
; fs and gs are loaded after switch to real mode because we can't
; use them as scratch pad registers in protected mode
;
mov cx, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_CS
mov dx, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_SS
mov eax, edi ; Save edi in eax for after RM switch
mov edi, esp ; Save our current ESP for RM
movzx ebx, dx
shl ebx, 4
sub esp, ebx
;
; We had been accessing the stack in PM32, we will now change to PM16 so we
; will make the stack segment 64KB limit so SP needs to be fixed made PM16
; compatible.
;
mov bx, AGESA_SELECTOR_DATA16
mov ss, bx
;
; Save the RM segment and RM offset of the jump we will need to make in
; order to enter RM so that code in this segment is relocatable.
;
; BEGIN --- Don't unbalance the stack --- BEGIN
;
push cx
pushw OFFSET RMEntry
mov ebx, CR0
and bl, NOT 1
mov CR0, ebx ; CR0.PE cleared
;
; Far jump to clear segment descriptor cache and enter RM
;
retf
RMEntry:
;
; We are in RM, setup RM stack
;
movzx ebx, dx ; Get RM SS in ebx
shl ebx, 4 ; Get our stack top on entry in EBP to
sub ebp, ebx ; access our entry parameters
sub eax, ebx ; save copy of parameters address
mov ss, dx ; Set stack segment
;
; We are going to figure out the address to use when we return
; and have to go back into PM32 while we have access to it
;
movzx ebx, cx ; Get original CS in ebx
shl ebx, 4
add ebx, OFFSET PM32Entry
;
; Now we put our data, func, block params into calling convention
; for our hook
;
; ECX = Func
; EDX = Data
; ESI = config pointer
;
mov ecx, PARAM1 ; Func
mov edx, PARAM2 ; Data
mov esi, PARAM3 ; pointer
push ebx ; Save PM32 mode switch address
push edi ; Save PM32 stack pointer
pushf
;
; Get Router Function Address
;
mov edi, eax
mov ax, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Seg
mov fs, ax
mov ax, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Off
mov gs, ax
mov eax, AGESA_UNSUPPORTED ; Default return value
;
; If AMD_BRIDGE_32 EDX == 0 call oemCallout
; otherwise call FAR PTR EDX
;
; Critical:
; sp+2 - EDI aka PM32 stack address
; sp+4 - address of PM32Entry in PM32
;
mov bx, fs
shl ebx, 16
mov bx, gs
.if (ebx == 0)
call LocalOemCalloutRouter
.else
;
; Make far call to Router function
;
push cs
push offset CalloutReturn
push ebx
retf
CalloutReturn:
.endif
;
; Restore PM32 esp from RM stack
;
popf
pop edi ; Our PM32 stack pointer
pop edx ; Our PM32 mode switch address
mov ebx, CR0
or bl, 1 ; CR0.PE set
mov CR0, ebx
mov ebx, AGESA_SELECTOR_DATA32
pushd AGESA_SELECTOR_CODE32 ; PM32 selector
push edx ; PM32 entry point
DB 066h
retf ; Far jump to enter PM32
PM32Entry:
;
; END --- Don't unbalance the stack --- END
; We are now PM32, so remember MASM is assembling in 16-bit again
;
mov ss, bx
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
mov sp, di
pop di
pop dx
pop cx
pop di
pop si
pop bx
pop bp
; EXIT AMD_CALLOUT_16
ENDM