blob: e6b95386570af7b2fc4ffdfde8b608b3c4c1dc67 [file] [log] [blame]
Kerry Shehe8689ed2012-01-20 13:57:48 +08001; ****************************************************************************
2; *
3; * @file
4; *
5; * Agesa structures and definitions
6; *
7; * Contains AMD AGESA core interface
8; *
9; * @xrefitem bom "File Content Label" "Release Content"
10; * @e project: AGESA
11; * @e sub-project: Include
12; * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $
13;
14; ****************************************************************************
15;
16; Copyright (C) 2012 Advanced Micro Devices, Inc.
17; All rights reserved.
18;
19; Redistribution and use in source and binary forms, with or without
20; modification, are permitted provided that the following conditions are met:
21; * Redistributions of source code must retain the above copyright
22; notice, this list of conditions and the following disclaimer.
23; * Redistributions in binary form must reproduce the above copyright
24; notice, this list of conditions and the following disclaimer in the
25; documentation and/or other materials provided with the distribution.
26; * Neither the name of Advanced Micro Devices, Inc. nor the names of
27; its contributors may be used to endorse or promote products derived
28; from this software without specific prior written permission.
29;
30; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
31; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33; DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
34; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40;
41;*****************************************************************************
42
43PARAM1 textequ <[bp+8]>
44PARAM2 textequ <[bp+12]>
45PARAM3 textequ <[bp+16]>
46RETAddress textequ <[bp+4]>
47
48AMD_PRIVATE_PARAMS STRUCT
49 Gate16_CS DW ? ; Segment of AMD_BRIDGE_32 and AMD_CALLOUT_16
50 Gate16_SS DW ? ; RM stack segment
51 Router_Seg DW ? ; Segment of oem router
52 Router_Off DW ? ; Offset of oem router
53AMD_PRIVATE_PARAMS ENDS
54
55; OEM may pre-define the GDT and selector offsets. If they do not, use our defaults.
56IFNDEF AGESA_SELECTOR_GDT
57 AGESA_SELECTOR_GDT EQU 00h
58ENDIF
59IFNDEF AGESA_SELECTOR_CODE16
60 AGESA_SELECTOR_CODE16 EQU 08h
61ENDIF
62IFNDEF AGESA_SELECTOR_DATA16
63 AGESA_SELECTOR_DATA16 EQU 10h
64ENDIF
65IFNDEF AGESA_SELECTOR_CODE32
66 AGESA_SELECTOR_CODE32 EQU 18h
67ENDIF
68IFNDEF AGESA_SELECTOR_DATA32
69 AGESA_SELECTOR_DATA32 EQU 20h
70ENDIF
71
72
73AMD_BRIDGE_32_GDT MACRO GDT_Name:REQ
74
75 GDT_Name LABEL BYTE
76 DD 000000000h, 000000000h ; NULL descriptor
77 DD 00000ffffh, 000009b00h ; 16-bit code, fixed up
78 DD 00000ffffh, 000009300h ; 16-bit data, fixed up
79 DD 00000ffffh, 000CF9B00h ; 32-bit protected mode code
80 DD 00000ffffh, 000CF9300h ; 32-bit protected mode data
81 GDT_Length EQU ($-GDT_Name)
82
83ENDM
84
85;+-------------------------------------------------------------------------
86;
87; AMD_BRIDGE_32 - Execute Agesa through Pushhigh interface
88;
89; Processing:
90; The following steps are taken:
91; 1) Enter 32bit Protected Mode (PM32)
92; 2) Run AGESA code
93; 3) Restore Real Mode (RM)
94;
95; Entry:
96; [big real mode] : ds, es set to base 0 limit 4G segment
97; EDX - if not 0, provides a FAR PTR to oem router (Seg | Offset)
98; ESI - configuration block pointer
99;
100; Exit:
101; EAX - return value
102; ESI - configuration block pointer
103; ds, es, fs, gs - Set to 4GB segment limit for Big Real Mode
104;
105; Modified:
106; None
107;
108
109AMD_BRIDGE_32 MACRO GDT_Name
110
111 local copyGDT
112 local flushTo16PM
113 local agesaReturnAddress
114 local leave32bitPM
115 local flush2RM
116
117 push gs
118 push fs
119 push ebx
120 push ecx
121 push edi
122 mov eax, esp
123 push eax
124 movzx esp, sp
125;
126; Do not use any locals here, BP will be changed frequently during RM->PM32->RM
127;
128 pushf
129 cli ; Disable interrupts during AGESA
130 cld ; Need known direction flag during AGESA
131
132;
133; Save the FAR PTR input parameter
134;
135 mov gs, dx ; Offset
136 shr edx, 16
137 mov fs, dx ; Segment
138;
139; Determine where our binary file is and get entry point
140;
141 mov edx, (AMD_CONFIG_PARAMS PTR [esi]).ImageBasePtr
142 add edx, (AMD_IMAGE_HEADER PTR [edx]).EntryPointAddress
143;
144; Figure out the return address we will use after calling AGESA
145; and store it in ebx until we have our stack set up properly
146;
147 mov ebx, cs
148 shl ebx, 4
149 add ebx, OFFSET agesaReturnAddress
150;
151; Save our current RM stack AND entry EBP
152;
153 push ebp
154; push esp
155 push ss
156
157;
158; BEGIN --- STACK MUST BE BALANCED AT THIS POINT --- BEGIN
159;
160; Copy the GDT onto the stack for modification
161;
162 mov cx, GDT_Length
163 sub sp, cx
164 mov bp, sp
165 lea di, GDT_Name
166copyGDT:
167 mov al, cs:[di]
168 mov [bp], al
169 inc di
170 inc bp
171 loop copyGDT
172;
173; Patch 16-bit code and data descriptors on stack. We will
174; fix up CS and SS for PM16 during the callout if applicable.
175;
176 mov bp, sp
177
178 mov eax, cs
179 shl eax, 4
180 mov [bp+AGESA_SELECTOR_CODE16+2], ax
181 shr eax, 16
182 mov [bp+AGESA_SELECTOR_CODE16+4], al
183
184 mov eax, ss
185 shl eax, 4
186 mov [bp+AGESA_SELECTOR_DATA16+2], ax
187 shr eax, 16
188 mov [bp+AGESA_SELECTOR_DATA16+4], al
189;
190; Need to place Length and Address on GDT
191;
192 mov eax, ss
193 shl eax, 4
194 add eax, esp
195 push eax
196 push WORD PTR (GDT_Length-1)
197;
198; Load the GDT
199;
200 mov bp, sp
201 lgdt FWORD PTR [bp]
202;
203; TABLE 1
204;
205; Place PRIVATE DATA on stack DIRECTLY following GDT
206; During this routine, stack data is critical. If
207; order is changed or additional added, bad things
208; will happen!
209;
210; HIGHEST PHYSICAL ADDRESS
211;
212; | ... |
213; ------------------------
214; | old RM SP |
215; | old RM SS |
216; ------------------------ sp + SIZEOF AMD_PRIVATE_PARAMS + (SIZEOF GDT_LENGTH + 6 {size, address})
217; | GDT_DATA32 |
218; | ... |
219; | GDT_NULL |
220; | GDT Addr, Length |
221; ------------------------ sp + SIZEOF AMD_PRIVATE_PARAMS
222; | Priv.Gate16_SS |
223; | Priv.Gate16_CS |
224; ------------------------ sp
225; ------ THEN PUSH -------
226; | Return to 16-bit CS |
227; | Return to 16-bit Off |
228; | ... |
229;
230; LOWEST PHYSICAL ADDRESS
231;
232 mov edi, esp
233 sub edi, SIZEOF AMD_PRIVATE_PARAMS
234 mov ax, cs
235 mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_CS, ax
236 mov ax, ss
237 mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_SS, ax
238 mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Off, gs
239 mov (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Seg, fs
240
241 mov esp, edi
242;
243; Save an address for returning to 16 bit real mode on stack,
244; we'll use it in a far ret after turning off CR0.PE so that
245; we can take our address off and force a far jump. Be sure
246; no unexpected data is on the stack after this!
247;
248 mov ax, cs
249 push cs
250 lea ax, flush2RM
251 push ax
252;
253; Convert ss:esp to "flat"
254;
255
256 mov ax, sp
257 push ax
258 mov eax, ss
259 shl eax, 4
260 add eax, esp
261 mov esp, eax ; Load the zero based ESP
262
263;
264; Set CR0.PE
265;
266 mov eax, CR0 ; Get CPU control word 0
267 or al, 01 ; Enable CPU protected mode
268 mov CR0, eax ; Write back to CPU control word 0
269 jmp flushTo16PM
270
271flushTo16PM:
272;
273; 16-bit protected mode
274;
275 mov ax, AGESA_SELECTOR_DATA32
276 mov ds, ax
277 mov es, ax
278 mov fs, ax
279 mov gs, ax
280 mov ss, ax
281;
282; Push our parameters RIGHT TO LEFT, and then return address
283;
284 push esi ; AGESA configuration block pointer (data)
285 push ebx ; after AGESA return offset (32PM flat) - consumed by dispatcher ret
286 pushd AGESA_SELECTOR_CODE32 ; AGESA entry selector (32PM flat)
287 push edx ; AGESA entry point (32PM flat)
288
289 DB 066h
290 retf ; <><><> Enter AGESA 32-bit code!!! <><><>
291
292agesaReturnAddress:
293;
294; Returns from the Agesa 32-bit code still PM32
295;
296 DB 0EAh
297 DD OFFSET leave32bitPM
298 DW AGESA_SELECTOR_CODE16
299
300leave32bitPM:
301;
302; Now in 16-bit PM
303;
304 add esp, 4 ; +4 to remove our config block pointer
305;
306; Eax reserve AGESA_STATUS return code, save it
307;
308 mov ebx, eax
309;
310; Turn off CR0.PE, restore 64K stack limit
311;
312 pop ax
313 mov sp, ax
314 mov ax, AGESA_SELECTOR_DATA16
315 mov ss, ax
316
317 mov eax, CR0
318 and al, NOT 1 ; Disable protected mode
319 mov CR0, eax ; Write back CR0.PE
320;
321; Jump far to enter RM, we saved this address on the stack
322; already. Hopefully stack is balanced through AGESA
323; nor were any params added by pushing them on the stack and
324; not removing them between BEGIN-END comments.
325;
326 retf
327
328flush2RM:
329;
330; Set segments registers for big real mode before returning
331;
332 xor ax, ax
333 mov ds, ax
334 mov es, ax
335 mov fs, ax
336 mov gs, ax
337;
338; Discard GDT, +6 for GDT pointer/size, privates
339;
340 add esp, GDT_Length + 6 + SIZEOF AMD_PRIVATE_PARAMS
341;
342; Restore real mode stack and entry EBP
343;
344 pop cx
345; mov esp, [esp]
346 mov ss, cx
347 pop ebp
348;
349; Restore AGESA_STATUS return code to eax
350;
351 mov eax, ebx
352;
353; END --- STACK MUST BE BALANCED TO THIS POINT --- END
354;
355
356 popf
357 pop ebx
358 mov esp, ebx
359 pop edi
360 pop ecx
361 pop ebx
362 pop fs
363 pop gs
364 ; EXIT AMD_BRIDGE_32
365ENDM
366;+-------------------------------------------------------------------------
367;
368; AMD_CALLOUT_16 - Execute Callback from Pushhigh interface
369;
370; Processing:
371; The following steps are taken:
372; 1) Enter PM16
373; 2) Setup stack, get private params
374; 3) Enter RM
375; 4) Get 3 params
376; 5) Call oemCallout OR oem router
377; 6) Enter PM32
378; 7) Return to Agesa PH
379;
380; Entry:
381; [32-bit protected mode]
382; [esp+8] Func
383; [esp+12] Data
384; [esp+16] Configuration Block
385; [esp+4] return address to Agesa
386;
387; Exit:
388; [32-bit protected mode]
389;
390; Modified:
391; None
392;
393AMD_CALLOUT_16 MACRO LocalOemCalloutRouter
394;
395; Note that we are still PM32, so MASM may work strangely
396;
397
398 push bp ; Save our original SP to access params
399 mov bp, sp
400 push bx
401 push si
402 push di
403 push cx
404 push dx
405 push di
406
407 DB 066h, 0EAh
408 DW OFFSET PM16Entry
409 DW AGESA_SELECTOR_CODE16
410
411PM16Entry:
412;
413; PM16 CS, but still PM32 SS, as we need to access our private params
414; before we enter RM.
415;
416; Note: we are working below the stack temporarily, and and it will
417; not affect our ability to get entry params
418;
419 xor ecx, ecx
420 xor edx, edx
421;
422; SGDT will give us the original location of the GDT on our CAS stack.
423; We need this value because our private parameters are located just
424; below the GDT.
425;
426 mov edi, esp
427 sub edi, GDT_Length + 6
428 sgdt FWORD PTR [edi] ; [edi] = word size, dword address
429 mov edi, DWORD PTR [edi+2] ; Get the PM32 address only
430 sub edi, SIZEOF AMD_PRIVATE_PARAMS + 6
431;
432; cx = code segment of this code in RM
433; dx = stack segment of CAS in RM
434; fs = code segment of oem router (save for later)
435; gs = offset of oem router (save for later)
436; fs and gs are loaded after switch to real mode because we can't
437; use them as scratch pad registers in protected mode
438;
439 mov cx, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_CS
440 mov dx, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Gate16_SS
441
442 mov eax, edi ; Save edi in eax for after RM switch
443 mov edi, esp ; Save our current ESP for RM
444
445 movzx ebx, dx
446 shl ebx, 4
447 sub esp, ebx
448
449;
450; We had been accessing the stack in PM32, we will now change to PM16 so we
451; will make the stack segment 64KB limit so SP needs to be fixed made PM16
452; compatible.
453;
454 mov bx, AGESA_SELECTOR_DATA16
455 mov ss, bx
456
457;
458; Save the RM segment and RM offset of the jump we will need to make in
459; order to enter RM so that code in this segment is relocatable.
460;
461; BEGIN --- Don't unbalance the stack --- BEGIN
462;
463 push cx
464 pushw OFFSET RMEntry
465
466 mov ebx, CR0
467 and bl, NOT 1
468 mov CR0, ebx ; CR0.PE cleared
469;
470; Far jump to clear segment descriptor cache and enter RM
471;
472 retf
473
474RMEntry:
475;
476; We are in RM, setup RM stack
477;
478 movzx ebx, dx ; Get RM SS in ebx
479 shl ebx, 4 ; Get our stack top on entry in EBP to
480 sub ebp, ebx ; access our entry parameters
481 sub eax, ebx ; save copy of parameters address
482 mov ss, dx ; Set stack segment
483;
484; We are going to figure out the address to use when we return
485; and have to go back into PM32 while we have access to it
486;
487 movzx ebx, cx ; Get original CS in ebx
488 shl ebx, 4
489 add ebx, OFFSET PM32Entry
490;
491; Now we put our data, func, block params into calling convention
492; for our hook
493;
494; ECX = Func
495; EDX = Data
496; ESI = config pointer
497;
498 mov ecx, PARAM1 ; Func
499 mov edx, PARAM2 ; Data
500 mov esi, PARAM3 ; pointer
501
502 push ebx ; Save PM32 mode switch address
503 push edi ; Save PM32 stack pointer
504 pushf
505;
506; Get Router Function Address
507;
508 mov edi, eax
509 mov ax, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Seg
510 mov fs, ax
511 mov ax, (AMD_PRIVATE_PARAMS PTR ss:[edi]).Router_Off
512 mov gs, ax
513
514 mov eax, AGESA_UNSUPPORTED ; Default return value
515;
516; If AMD_BRIDGE_32 EDX == 0 call oemCallout
517; otherwise call FAR PTR EDX
518;
519; Critical:
520; sp+2 - EDI aka PM32 stack address
521; sp+4 - address of PM32Entry in PM32
522;
523 mov bx, fs
524 shl ebx, 16
525 mov bx, gs
526
527 .if (ebx == 0)
528 call LocalOemCalloutRouter
529 .else
530;
531; Make far call to Router function
532;
533 push cs
534 push offset CalloutReturn
535 push ebx
536 retf
537CalloutReturn:
538 .endif
539;
540; Restore PM32 esp from RM stack
541;
542 popf
543 pop edi ; Our PM32 stack pointer
544 pop edx ; Our PM32 mode switch address
545
546 mov ebx, CR0
547 or bl, 1 ; CR0.PE set
548 mov CR0, ebx
549
550 mov ebx, AGESA_SELECTOR_DATA32
551 pushd AGESA_SELECTOR_CODE32 ; PM32 selector
552 push edx ; PM32 entry point
553
554 DB 066h
555 retf ; Far jump to enter PM32
556
557PM32Entry:
558;
559; END --- Don't unbalance the stack --- END
560; We are now PM32, so remember MASM is assembling in 16-bit again
561;
562 mov ss, bx
563 mov ds, bx
564 mov es, bx
565 mov fs, bx
566 mov gs, bx
567
568 mov sp, di
569 pop di
570 pop dx
571 pop cx
572 pop di
573 pop si
574 pop bx
575 pop bp
576 ; EXIT AMD_CALLOUT_16
577ENDM