summaryrefslogtreecommitdiff
path: root/Core/EM/CSM/thunk/x86/x86thunk.asm
blob: 9a5a7819e189ea590ae4877ae93f09812968d9ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
;**********************************************************************
;**********************************************************************
;**                                                                  **
;**        (C)Copyright 1985-2012, American Megatrends, Inc.         **
;**                                                                  **
;**                       All Rights Reserved.                       **
;**                                                                  **
;**           5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093      **
;**                                                                  **
;**                       Phone: (770)-246-8600                      **
;**                                                                  **
;**********************************************************************
;**********************************************************************

;**********************************************************************
; $Header: /Alaska/SOURCE/Modules/CSM/Generic/Thunk/x86/x86thunk.asm 37    10/07/13 9:01a Olegi $
;
; $Revision: 37 $
;
; $Date: 10/07/13 9:01a $
;**********************************************************************
; Revision History
; ----------------
; $Log: /Alaska/SOURCE/Modules/CSM/Generic/Thunk/x86/x86thunk.asm $
; 
; 37    10/07/13 9:01a Olegi
; EIP135289
; Legacy2Efi changes - CR4 save/restore
; 
; 36    12/14/12 6:19p Olegi
; [TAG]  		EIP109554
; [Category]  	Improvement
; [Description]  	Aptio4: Update CSM thunk to use private GDT instead of
; GDT on entry point
; [Files]  		x86thunk.asm
; 
; 35    7/23/12 12:59p Olegi
; [TAG]  		EIP95386
; [Category]  	Improvement
; [Description]  	CR3 register save/restore
; 
; 34    6/13/12 12:49p Olegi
; [TAG]  		EIP92524
; [Category]  	Improvement
; [Description]  	IDT location is limited to 4GB in CSM thunk
; 
; 33    12/05/11 5:53p Olegi
; [TAG]  		EIP77045
; [Category]  	Improvement
; [Description]  	Changed the values to be loaded to the segment
; registers from static number (8) to a dynamic number that represents a
; valid descriptor.
; [Files]  		x86thunk.asm
; 
; 32    12/01/10 9:37a Olegi
; FarCall86 is modified to return data in stack when expected.
; 
; 31    11/15/10 6:21p Olegi
; [TAG]  		EIP48242
; [Category]  	Bug Fix
; [Severity]  	Critical
; [Symptom]  	thunk problems for IA32 projects
; [RootCause]  	wrong paths in thunk code for IA32 projects
; [Solution]  	fixed the thunk code
; [Files]  		x86thunk.asm
; 
; 30    9/15/10 1:40p Olegi
; Reverse thunk stack usage modified: stack for the PM operations will be
; allocated externally.
; 
; 29    9/13/10 5:26p Vyacheslava
; Added variable PmStackPtr to use a new stack space. 
; 
; 28    9/08/10 6:16p Vyacheslava
; Bugfix in reverse thunk: there was wrong assumption about stack
; re-assignment. When caller (OptionROM) reassignes stack, reverse thunk
; was failing.
; 
; 27    7/26/10 2:23p Vyacheslava
; 
; 26    7/25/10 2:44p Olegi
; 
; 25    7/25/10 1:07p Olegi
; Bugfixes in the reverse thunk implementation.
; 
; 24    7/24/10 12:38p Olegi
; 
; 23    7/23/10 4:09p Olegi
; Initial reverse thunk implementation.
; 
; 22    7/19/10 4:44p Olegi
; 
; 21    1/12/10 11:47a Olegi
; Copyright message updated.
; 
; 20    11/12/08 5:02p Olegi
; 
; 19    5/11/07 11:12a Markw
; Save ss and set it to a flat descriptor in 64-bit mode.
; 
; 18    4/27/07 5:14p Olegi
; CSM.CHM file preparation.
; 
; 17    9/15/06 12:02p Markw
; Disable PAE when thunking because windows expects PAE in CR4 to be
; disabled after calling INT19h to boot.
; 
; 16    8/24/06 3:11p Felixp
; Preliminary x64 support (work in progress)
; 
; 15    5/25/06 2:23p Olegi
; 
; 14    3/03/06 11:09a Markw
; Removed some duplicate code.
; 
; 13    10/14/05 10:16a Markw
; Removed previous changes.
; 
; 11    8/02/05 4:24p Markw
; Removed some db66 from sgdt and sidt. It was instructing the CPU to do
; a 24-bit load. However, the CPU was loading 32-bit that was needed, so
; it worked even though the spec described the operation differently.
; 
; 10    5/12/05 12:57p Markw
; Fixed lidt in portected mode. It was only loading 24 of 32 bits.
; 
; 9     4/18/05 10:54a Markw
; Remove pushing/popping ebx (entry point).
; make segments equal segement instead of fixup.
; 
; 8     3/04/05 1:48p Mandal
; 
;**********************************************************************
;<AMI_FHDR_START>
;
; Name:	x86Thunk.asm
;
; Description: x86 CPU thunk functions
;
;<AMI_FHDR_END>
;**********************************************************************

.586P
.model small

;STACK_SIZE equ 8192
STACK_TOP equ (4096 * 3)

FAR_CALL_PTR_16 struct
	ptr_offset	dw ?
	seg_offset	dw ? 
FAR_CALL_PTR_16 ends

REGISTERS struct
	reg_eax dd ?
	reg_ebx	dd ?
	reg_ecx	dd ?
	reg_edx	dd ?
	reg_esi	dd ?
	reg_edi	dd ?
	reg_eflags dd ?
	reg_es	dw ?
	reg_cs	dw ?
	reg_ss	dw ?
	reg_ds	dw ?
	reg_fs	dw ?
	reg_gs	dw ?
	reg_ebp	dd ?
REGISTERS ends

STACK_PARAM struct
	StackPtr        dd ?
	StackSize	dd ?
STACK_PARAM ends

THUNK_DATA struct
	FarCallPtr16 FAR_CALL_PTR_16 <>
	Regs		 REGISTERS <>
	StackParm 	 STACK_PARAM<>
	isFarCall	 db 0
	BiosInt		 db 0
THUNK_DATA ends


ASSUME ds:THUNK_SEG

THUNK_SEG SEGMENT USE32 'CODE'

THUNK proc
	jmp over_data
; The following data must be here. Don't move. These are used by the Thunk C driver.
	dw	LOWWORD offset Fixups
	dw	LOWWORD offset ReverseThunk
	ThunkData THUNK_DATA <>
over_data:
	cli
;--------------------------------------------------------------------------------
; The following code switches from protected mode (from x64 if EFIx64 is defined,
; otherwise from 32-bit protected mode) to 16-bit real mode.
;--------------------------------------------------------------------------------
; Calculate entry point and load EBX/RBX with it.

	push	ebx

	call	@f
@@:
	pop	ebx
	sub	ebx, @b     ; RBX/EBX - physical address of CSM16 entry point

	mov	DWORD PTR [RtReturnResult+ebx], eax

	sidt	fword ptr [IdtSave+ebx]	;Save IDT
	sgdt	fword ptr [GdtSave+ebx]	;Save GDT
	lgdt	fword ptr [GdtDescriptor+ebx]

	mov	eax, cr3		;;Save CR3, CR4
	mov	[CR3Save+ebx], eax
	mov	eax, cr4
	mov	[CR4Save+ebx], eax

	;Save segement registers.
	mov	ax, ds
	push	eax			;64-bit doesn't support push ds, es, ss
	mov	ax, es
	push	eax
	mov	ax, ss
	push	eax
	push	fs
	push	gs
	mov	ax, cs	  ;This must be last for cs restore.
	push	eax

	mov	eax,  DATA_SEL		;make sure segments are approriate for 32-bit mode.
	mov	ds, ax      ; Load SS with the known descriptor value
	mov	es, ax
	mov	ss, ax
	mov	fs, ax
	mov	gs, ax


ifdef EFIx64
;---Jump from long mode to compatiblity mode---
	;jmp	far ptr [ComModeAdr]
	db	0ffh,2dh
	dd	ComModeAdr - $ - 4

ComMode:
;---Go to protected mode---
	mov	eax, cr0
	btr	eax, 31
	mov	cr0, eax		;Now in protected mode.
	jmp	$+2

	mov ecx, 0c0000080h
	rdmsr
	btr	eax, 8
	wrmsr
	
	mov	eax, cr4
	btr	eax, 5
	mov	cr4, eax	;Turn off PAE bit. Windows expects when calling INT19h.
endif

	cmp	BYTE PTR [IsReverseThunk+ebx], 1
	je	no_stack_to_copy

	pushad
	pushfd

;--Save Data--
	mov	[StackSave+ebx], esp	;Save 32 bit stack address of this module.

	;---Copy Stack parameters of LegacyBiosFarCall---
	mov	ecx, [ThunkData.StackParm.StackSize+ebx]
	or	ecx, ecx
	jz	no_stack_to_copy

	mov	esi, [ThunkData.StackParm.StackPtr+ebx]
	mov	edi, ebx
	add	edi, STACK_TOP
	sub	edi, ecx
	rep	movsb
no_stack_to_copy:
;--Switch to real mode--	
	lidt	fword ptr [LegacyLdtDescriptor+ebx]

	mov	ax, DATA_SEL_16
	mov	ds, ax
	mov	es, ax
	mov	ss, ax
	mov	fs, ax
	mov	gs, ax

	;jmp	CODE_SEL_16:next
	db	0eah
	dd	offset next
	dw	CODE_SEL_16
next:
	mov	eax, cr0
	and	al, 0feh
	mov	cr0, eax

	;--ITP doesn't display disassebly correctly until jump to real mode.

	;jmp	CS_SEGMENT:RealModeAddr
	db 0eah
	dw LOWWORD offset RealMode
RealModeFixUp:
	dw 0
RealMode:
	db 8ch, 0c8h	;mov	ax, cs
	db 8eh, 0d8h	;mov    ds, ax
	db 8eh, 0c0h	;mov    es, ax
	db 8eh, 0d0h	;mov    ss, ax
	db 8eh, 0e0h	;mov    fs, ax
	db 8eh, 0e8h	;mov    gs, ax

;	sti
;---------------Real mode operations-----------
	db 2eh, 80h, 3eh
	dw LOWWORD offset IsReverseThunk
	db 1	;cmp	cs:IsReverseThunk, 1

	jnz	@f

	db 2eh, 0c6h, 6
	dw LOWWORD offset IsReverseThunk
	db 0	;mov	cs:IsReverseThunk, 0

	; Restore the registers from RtRegs
	push	cs
	pop	ss
	
	db 0bch		; mov	sp, LOWWORD OFFSET RtRegs
	dw LOWWORD OFFSET RtRegs

	pop	gs
	pop	fs
	pop	es
	pop	ds
	db 66h, 61h	; popad

	; Restore stack pointer and its contents

	db 2eh, 8eh, 16h	;mov cs:RtStackSave+4, ss
	dw LOWWORD offset RtStackSave+4

	db 66h, 2eh, 8bh, 26h	;mov sp, cs:RtStackSave
	dw LOWWORD offset RtStackSave

	; Restore flags
	db 66h, 2eh, 0ffh, 36h	; push DWORD PTR cs:RtSavedFlags
	dw LOWWORD OFFSET RtSavedFlags
	db 66h, 9dh		; popfd

	db 83h, 0c4h, 4		; add sp, 4: prepare stack for a push

	db 66h, 2eh, 0ffh, 36h	; push dword ptr cs:RtRetAddressSave
	dw LOWWORD offset RtRetAddressSave

	db 66h, 2eh, 0a1h		;mov eax, RtReturnResult
	dw LOWWORD offset RtReturnResult

	db 0cbh	;retf		; reverse thunk call returns control

@@:
	db 66h
	mov	esp, STACK_TOP	;This is the top stack for real mode.

	db 2bh, 26h	;sub sp, word ptr ThunkData.StackParm.StackSize
	dw LOWWORD offset ThunkData.StackParm.StackSize

	;---copy registers for FarCall and BIOS INT---

	db 66h, 8bh, 1eh			;mov ebx, ThunkData.regs.reg_ebx
	dw LOWWORD offset ThunkData.regs.reg_ebx
	db 66h, 8bh, 0eh			;mov ecx, ThunkData.regs.reg_ecx
	dw LOWWORD offset ThunkData.regs.reg_ecx
	db 66h, 8bh, 16h			;mov edx, ThunkData.regs.reg_edx
	dw LOWWORD offset ThunkData.regs.reg_edx
	db 66h, 8bh, 36h			;mov esi, ThunkData.regs.reg_esi
	dw LOWWORD offset ThunkData.regs.reg_esi
	db 66h, 8bh, 3eh			;mov edi, ThunkData.regs.reg_edi
	dw LOWWORD offset ThunkData.regs.reg_edi
	db 66h, 8bh, 2eh			;mov ebp, ThunkData.regs.reg_ebp
	dw LOWWORD offset ThunkData.regs.reg_ebp

	db 0a1h					;mov ax, ThunkData.regs.reg_es
	dw LOWWORD offset ThunkData.regs.reg_es

	db 08eh, 0c0h				;mov	es, ax

	db 66h, 0a1h				;mov eax, ThunkData.regs.reg_eax
	dw LOWWORD offset ThunkData.regs.reg_eax

	;Change ds last, since above operations depend on ds.
	db 0ffh, 36h				;push ThunkData.regs.reg_ds
	dw LOWWORD offset ThunkData.regs.reg_ds
	pop	ds

    ;Don't load the flags! They aren't needed, and if they aren't
    ;initialized properly, the system hangs.

	;--Call real mode function or interrupt--
	sti

	db 2eh, 80h, 3eh	;cmp cs:ThunkData.isFarCall, 0
	dw LOWWORD offset ThunkData.isFarCall
	db 0

	jnz	FarCall

	db 66h
	pushad

	db 2eh, 0a0h		;mov	al, cs:ThunkData.BiosInt
	dw LOWWORD offset ThunkData.BiosInt

	db 2eh, 0a2h		;mov	cs:intxx, al	;Sets the intermediate value for intxx below.
	dw LOWWORD offset intxx	

	db 66h
	mov	eax, 1
	cpuid		;serializing instruction because of runtime code modification.

	db 66h
	popad

	db 0cdh						;Execute int x
intxx label byte
	db 0

	jmp	@f
FarCall:
	;call dword ptr cs:[ThunkData.FarCallPtr16]
	db 02eh, 0ffh, 1eh				;Execute far call
	dw LOWWORD offset ThunkData.FarCallPtr16
@@:

	cli
	;--Copy registers back for FarCall and BIOS INT---

	db 66h, 2eh, 0a3h		;mov cs:ThunkData.regs.reg_eax, eax
	dw LOWWORD offset ThunkData.regs.reg_eax

	push	ds

	db 2eh, 08fh, 6			;pop cs:ThunkData.regs.reg_ds
	dw LOWWORD offset ThunkData.regs.reg_ds

	db 8ch, 0c8h	;mov	ax, cs
	db 8eh, 0d8h	;mov    ds, ax

	db 66h, 89h, 1eh		;mov ThunkData.regs.reg_ebx, ebx
	dw LOWWORD offset ThunkData.regs.reg_ebx

	db 66h, 89h, 0eh		;mov  ThunkData.regs.reg_ecx, ecx
	dw LOWWORD offset ThunkData.regs.reg_ecx

	db 66h, 89h, 16h		;mov ThunkData.regs.reg_edx, edx
	dw LOWWORD offset ThunkData.regs.reg_edx

	db 66h, 89h, 36h		;mov ThunkData.regs.reg_esi, esi
	dw LOWWORD offset ThunkData.regs.reg_esi

	db 66h, 89h, 3eh		;mov ThunkData.regs.reg_edi, edi
	dw LOWWORD offset ThunkData.regs.reg_edi

	db 66h, 89h, 2eh		;mov ThunkData.regs.reg_ebp, ebp
	dw LOWWORD offset ThunkData.regs.reg_ebp

	db 08ch ,0c0h			;mov ax, es

	db 0a3h				;mov ThunkData.regs.reg_es, ax
	dw LOWWORD offset ThunkData.regs.reg_es

	db 09ch				;pushf
	db 08fh, 6			;pop	ThunkData.regs.reg_eflags
	dw LOWWORD offset ThunkData.regs.reg_eflags

;--------------End Real Mode operations---------
RealToPm:
	db 66h
	xor	ebx, ebx
	db 8ch, 0cbh	;mov    bx, cs
	db 66h
	shl	ebx, 4	;ebx = entry point

	;--Switch to protected mode--
;	cli

	;Reload GDT in case it was changed.
	;lgdt	fword ptr cs:[GdtDescriptor]
	db 66h,02eh,0fh,1,16h
	dw LOWWORD offset GdtDescriptor

	mov	eax, cr0
	or	al, 1		;Set PE bit
	mov	cr0, eax	;Turn on Protected Mode

	;jmp CODE_SEL:P32MODE
	db 66h, 0eah
P32ModeFixUp:
	dd offset P32Mode
	dw CODE_SEL

P32Mode::
	mov	ax, DATA_SEL 
	mov	ds, ax
	mov	es, ax
	mov	ss, ax
	mov	fs, ax
	mov	gs, ax
	cmp	BYTE PTR [IsReverseThunk + ebx], 1
	je	CreateReverseThunkESP
	mov	esp, [StackSave + ebx]	;Get original stack back.
	;---Copy Stack parameters of LegacyBiosFarCall---;
	mov	ecx, [ThunkData.StackParm.StackSize+ebx]
	or	ecx, ecx
	jz	@F
	mov 	edi, [ThunkData.StackParm.StackPtr+ebx]
	mov	esi, ebx
	add	esi, STACK_TOP
	sub	esi, ecx
	rep movsb
@@:
	popfd
	popad
	jmp	DonePreparingESP

CreateReverseThunkESP:			; EBX = ThunkStart code segment << 4
	mov	[ThunkStart + ebx], ebx
	mov	esp, [PmStackPtr + ebx]

ifdef EFIx64
	sub	esp, 20h		; allocate 20h bytes in stack (x64 calling convention)
endif
	mov	[esp], ebx
ifdef EFIx64
	mov	DWORD PTR [esp+4], 0
endif
	sub	esp, 4
	mov	[esp], esi		; Function pointer (DWORD)
ifdef EFIx64
	mov	DWORD PTR [esp], 0
	sub	esp, 4
	mov	[esp], esi		; Function pointer (QWORD)
endif

DonePreparingESP:
	xor	eax, eax		; short/quick way to set EAX = 0
	lldt	ax			; (source operand == 0) => LDTR is invalid

ifdef EFIx64
	mov	eax, cr4
	bts	eax, 5
	mov	cr4, eax		;Enable PAE

	mov	ecx, 0c0000080h
	rdmsr
	bts	eax, 8
	wrmsr

	mov	eax, cr0
	bts	eax, 31
	mov	cr0, eax		;Now in compatibility mode.
	jmp	$+2

	pushd CODE_SEL_64
	call	@f	;push rip/eip
@@:
	add	dword ptr [esp], @f - $
	retf
@@:

    ;--In long mode.
endif

	lgdt	fword ptr [GdtSave + ebx]  ;Restore GDT
	lidt	fword ptr [IdtSave+ebx]	;Restore IDT

    ;restore original cs
    ;rsp/esp = cs
	call	@f	;push rip/eip	
@@:
	add	dword ptr [esp], @f - $
ifdef EFIx64
	db 48h
endif
	retf	;pop cs and eip.
@@:

	pop	gs
	pop	fs
	pop	eax
	mov	ss, ax
	pop	eax
	mov	es, ax
	pop	eax
	mov	ds, ax

ifdef EFIx64
	;TODO: Double check Reverse Thunk code.
	cmp	BYTE PTR [IsReverseThunk+ebx], 1
	jne	@f
; Reverse thunk - copy parameters to RCX, RDX, R8, R9
	db 48h, 8bh, 4ch, 24h, 28h	; mov	rcx, [rsp + 28h]
	db 48h, 8bh, 54h, 24h, 30h	; mov	rdx, [rsp + 30h]
	db 67h, 4ch, 8bh, 44h, 24h, 38h ; mov	r8d, [rsp + 38h]
	db 67h, 4ch, 8bh, 4ch, 24h, 40h ; mov	r9d, [rsp + 40h]

	jmp	RealToPm_Exit
@@:
endif

	mov	eax, cs:[CR3Save + ebx]
	mov	cr3, eax
	mov	eax, cs:[CR4Save + ebx]
	mov	cr4, eax
	pop	ebx
RealToPm_Exit:
	ret

;-----------------------------------------------------------
ReverseThunk:
	; Save flags
	db 66h, 9ch		; pushfd
	db 66h, 2eh, 8fh, 6	; pop DWORD PTR cs:RtSavedFlags
	dw LOWWORD OFFSET RtSavedFlags

	cli

	db 66h, 2eh, 89h, 26h	;mov cs:RtStackSave, esp
	dw LOWWORD offset RtStackSave

	db 2eh, 8ch, 16h	;mov cs:RtStackSave+4, ss
	dw LOWWORD offset RtStackSave+4

	; Get the PM stack pointer from the stack
	db	89h, 0e5h		; mov	bp, sp
	db	66h, 8bh, 46h, 4	; mov	eax, [bp+4]
	db	66h, 2eh, 0a3h		; mov cs:PmStackPtr, eax
	dw	LOWWORD offset PmStackPtr

        ; Get return address and store it in cs:RtRetAddressSave
	db	66h, 8bh, 46h, 0	; mov	eax, [bp+0]
	db	66h, 2eh, 0a3h		; mov cs:RtRetAddressSave, eax
	dw	LOWWORD offset RtRetAddressSave

	; Save the registers in RtRegs
	push	cs
	pop	ss
	
	db 0bch		; mov	sp, LOWWORD OFFSET RtRegs+28h
	dw LOWWORD OFFSET RtRegs+28h

	db 66h, 60h	; pushad
	push	ds
	push	es
	push	fs
	push	gs

	; Restore SS:ESP
	db 66h, 2eh, 8bh, 26h	;mov esp, cs:RtStackSave
	dw LOWWORD offset RtStackSave

	db 2eh, 8eh, 16h	;mov ss, cs:RtStackSave+4
	dw LOWWORD offset RtStackSave+4

	db 2eh, 0c6h, 06h	;mov cs:[IsReverseThunk], 1
	dw LOWWORD offset IsReverseThunk
	db 1

	db 0e9h
	dw RealToPm - ($+2)	;jmp NEAR RealToPm
	
;-----------------------------------------------------------
	reg_gs	dw ?
	reg_fs	dw ?
	reg_es	dw ?
	reg_ds	dw ?
	reg_eflags dd ?

Fixups:
ifdef EFIx64
    ;In 64 bit mode, but compiled under 32-bit mode.
	push	ebx		;(push rbx) cpuid changes ebx
	mov	edx, ecx
	shr	edx, 4		;Get segment

;--Fixups---
	;add 	ComModeFixup, ecx
	db 01, 0dh
	dd ComModeFixup - $ - 4
	;add 	P32ModeFixUp, ecx
	db 01, 0dh
	dd P32ModeFixUp - $ - 4
	;add 	GdtDescriptorFixUp, ecx
	db 01, 0dh
	dd GdtDescriptorFixUp - $ - 4
;	add	CODE_SEL_BASE_FIXUP, ecx ;must use add because upper 8 bit shouldn't change. Only 20 bit number.
	db 01, 0dh
	dd CODE_SEL_BASE_FIXUP - $ - 4
;	mov	word ptr RealModeFixUp, dx
	db 66h, 89h, 15h
	dd RealModeFixUp - $ - 4
	mov	eax, 1
	cpuid			;serialization for fixups
	pop	ebx		;pop rbx
else
	push	ebp
	mov	ebp, esp

	push	ebx
	push	edx

	mov	ebx, [ebp+8]	;Get base address of this module
	mov	edx, ebx
	shr	edx, 4		;Get segment

;--Fixups---
	add	[P32ModeFixUp+ebx], ebx
	add	[GdtDescriptorFixUp+ebx], ebx
	add	[CODE_SEL_BASE_FIXUP+ebx], ebx		;must use add because upper 8 bit shouldn't change. Only 20 bit number.
	mov	word ptr [RealModeFixUp+ebx], dx

	mov	eax, 1
	cpuid						;serialization for fixups
	mov	ebx, [ebp + 8]				;restore ebx

	pop	edx
	pop	ebx
	pop	ebp
endif
	ret

align 16
GDT_BASE:
NULL_SEL	equ	$-GDT_BASE	 ;NULL Selector 0
	dq 0
DATA_SEL 		equ	$-GDT_BASE
	dq 00cf93000000ffffh
CODE_SEL			equ	$-GDT_BASE
    dq 00cf9b000000ffffh
CODE_SEL_64	equ	$-GDT_BASE
	dq 00af9b000000ffffh
DATA_SEL_16	equ	$-GDT_BASE
	dq 008f93000000ffffh

CODE_SEL_16	equ	$-GDT_BASE
	dw 0ffffh
CODE_SEL_BASE_FIXUP:			;Only 20 bits max
	dw 0
	db 0
	
	db 09ah
	db 0
	db 0

GDT_SIZE	equ $-GDT_BASE		;Size of Descriptor Table
GdtDescriptor:
	dw GDT_SIZE - 1			; GDT limit
GdtDescriptorFixUp:
	dq OFFSET GDT_BASE		; GDT base

ifdef EFIx64
align 8
ComModeFixup equ $
ComModeAdr equ $
	dd  offset ComMode
	dw CODE_SEL
endif

	public StackSave
StackSave label dword
	dd 0
align 8
	public CR3Save
CR3Save label dword
	dq	0
align 8
	public CR4Save
CR4Save label dword
	dq	0
align 8
	public GdtSave
GdtSave	label fword
	dw 0
	dq 0

align 8
	public IdtSave
IdtSave label fword	
	dw 0
	dq 0
align 8
	public LegacyLdtDescriptor
LegacyLdtDescriptor label fword
	dw 3ffh
	dq 0

;------Reverse thunk data------------
IsReverseThunk		db 0
RtReturnResult		dd 0
RtSavedFlags		dd 0
RtStackSave		db 6 dup (0)    ; DW for SS, DD for ESP
PmStackPtr		dd 0
RtRetAddressSave	dd 0
ThunkStart 		dd 0
RtRegs	 		REGISTERS <>

THUNK	endp
THUNK_SEG ENDS
end

;**********************************************************************
;**********************************************************************
;**                                                                  **
;**        (C)Copyright 1985-2012, American Megatrends, Inc.         **
;**                                                                  **
;**                       All Rights Reserved.                       **
;**                                                                  **
;**           5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093      **
;**                                                                  **
;**                       Phone: (770)-246-8600                      **
;**                                                                  **
;**********************************************************************
;**********************************************************************