; **************************************************************************** ; * ; * @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: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $ ; ; **************************************************************************** ; ; Copyright 2008 - 2012 ADVANCED MICRO DEVICES, INC. All Rights Reserved. ; ; AMD is granting you permission to use this software (the Materials) ; pursuant to the terms and conditions of your Software License Agreement ; with AMD. This header does *NOT* give you permission to use the Materials ; or any rights under AMD's intellectual property. Your use of any portion ; of these Materials shall constitute your acceptance of those terms and ; conditions. If you do not agree to the terms and conditions of the Software ; License Agreement, please do not use any portion of these Materials. ; ; CONFIDENTIALITY: The Materials and all other information, identified as ; confidential and provided to you by AMD shall be kept confidential in ; accordance with the terms and conditions of the Software License Agreement. ; ; LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION ; PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED ; WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF ; MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE, ; OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE. ; IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER ; (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS ; INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE, ; GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER ; RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF ; THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE ; EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, ; THE ABOVE LIMITATION MAY NOT APPLY TO YOU. ; ; AMD does not assume any responsibility for any errors which may appear in ; the Materials or any other related information provided to you by AMD, or ; result from use of the Materials or any related information. ; ; You agree that you will not reverse engineer or decompile the Materials. ; ; NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any ; further information, software, technical information, know-how, or show-how ; available to you. Additionally, AMD retains the right to modify the ; Materials at any time, without notice, and is not obligated to provide such ; modified Materials to you. ; ; U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with ; "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is ; subject to the restrictions as set forth in FAR 52.227-14 and ; DFAR252.227-7013, et seq., or its successor. Use of the Materials by the ; Government constitutes acknowledgement of AMD's proprietary rights in them. ; ; EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any ; direct product thereof will be exported directly or indirectly, into any ; country prohibited by the United States Export Administration Act and the ; regulations thereunder, without the required authorization from the U.S. ; government nor will be used for any purpose prohibited by the same. ;***************************************************************************** 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