; **************************************************************************** ; * ; * @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 02:16:51 -0700 (Wed, 22 Dec 2010) $ ; ; **************************************************************************** ; ; Copyright (C) 2012 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