2 Call into 16-bit BIOS code, Use AsmThunk16 function of BaseLib.
4 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "LegacyBiosInterface.h"
19 THUNK_CONTEXT mThunkContext
;
22 Thunk to 16-bit real mode and execute a software interrupt with a vector
23 of BiosInt. Regs will contain the 16-bit register context on entry and
26 @param This Protocol instance pointer.
27 @param BiosInt Processor interrupt vector to invoke
28 @param Regs Register contexted passed into (and returned) from thunk to
31 @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
33 @retval TRUE There was a BIOS erro in the target code.
39 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
41 IN EFI_IA32_REGISTER_SET
*Regs
44 Regs
->X
.Flags
.Reserved1
= 1;
45 Regs
->X
.Flags
.Reserved2
= 0;
46 Regs
->X
.Flags
.Reserved3
= 0;
47 Regs
->X
.Flags
.Reserved4
= 0;
48 Regs
->X
.Flags
.IOPL
= 3;
54 return InternalLegacyBiosFarCall (
56 (UINT16
) (((UINT32
*)NULL
)[BiosInt
] >> 16),
57 (UINT16
) ((UINT32
*)NULL
)[BiosInt
],
60 sizeof (Regs
->X
.Flags
)
65 Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
66 16-bit register context on entry and exit. Arguments can be passed on
69 @param This Protocol instance pointer.
70 @param Segment Segemnt of 16-bit mode call
71 @param Offset Offset of 16-bit mdoe call
72 @param Regs Register contexted passed into (and returned) from
74 @param Stack Caller allocated stack used to pass arguments
75 @param StackSize Size of Stack in bytes
77 @retval FALSE Thunk completed, and there were no BIOS errors in
78 the target code. See Regs for status.
79 @retval TRUE There was a BIOS erro in the target code.
85 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
88 IN EFI_IA32_REGISTER_SET
*Regs
,
93 Regs
->X
.Flags
.Reserved1
= 1;
94 Regs
->X
.Flags
.Reserved2
= 0;
95 Regs
->X
.Flags
.Reserved3
= 0;
96 Regs
->X
.Flags
.Reserved4
= 0;
97 Regs
->X
.Flags
.IOPL
= 3;
100 Regs
->X
.Flags
.TF
= 0;
101 Regs
->X
.Flags
.CF
= 0;
103 return InternalLegacyBiosFarCall (This
, Segment
, Offset
, Regs
, Stack
, StackSize
);
107 Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
108 16-bit register context on entry and exit. Arguments can be passed on
111 @param This Protocol instance pointer.
112 @param Segment Segemnt of 16-bit mode call
113 @param Offset Offset of 16-bit mdoe call
114 @param Regs Register contexted passed into (and returned) from thunk to
116 @param Stack Caller allocated stack used to pass arguments
117 @param StackSize Size of Stack in bytes
119 @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
121 @retval TRUE There was a BIOS erro in the target code.
126 InternalLegacyBiosFarCall (
127 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
130 IN EFI_IA32_REGISTER_SET
*Regs
,
136 LEGACY_BIOS_INSTANCE
*Private
;
139 IA32_REGISTER_SET ThunkRegSet
;
140 BOOLEAN InterruptState
;
142 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
144 ZeroMem (&ThunkRegSet
, sizeof (ThunkRegSet
));
145 ThunkRegSet
.X
.DI
= Regs
->X
.DI
;
146 ThunkRegSet
.X
.SI
= Regs
->X
.SI
;
147 ThunkRegSet
.X
.BP
= Regs
->X
.BP
;
148 ThunkRegSet
.X
.BX
= Regs
->X
.BX
;
149 ThunkRegSet
.X
.DX
= Regs
->X
.DX
;
151 // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
152 // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
154 ThunkRegSet
.E
.ECX
= Regs
->E
.ECX
;
155 ThunkRegSet
.X
.AX
= Regs
->X
.AX
;
156 ThunkRegSet
.E
.DS
= Regs
->X
.DS
;
157 ThunkRegSet
.E
.ES
= Regs
->X
.ES
;
159 CopyMem (&(ThunkRegSet
.E
.EFLAGS
.UintN
), &(Regs
->X
.Flags
), sizeof (Regs
->X
.Flags
));
162 // Clear the error flag; thunk code may set it. Stack16 should be the high address
163 // Make Statk16 address the low 16 bit must be not zero.
165 Stack16
= (UINT16
*)((UINT8
*) mThunkContext
.RealModeBuffer
+ mThunkContext
.RealModeBufferSize
- sizeof (UINT16
));
168 // Save and disable interrutp of debug timer
170 InterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
173 // The call to Legacy16 is a critical section to EFI
175 OriginalTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
177 if (Stack
!= NULL
&& StackSize
!= 0) {
179 // Copy Stack to low memory stack
181 Stack16
-= StackSize
/ sizeof (UINT16
);
182 CopyMem (Stack16
, Stack
, StackSize
);
185 ThunkRegSet
.E
.SS
= (UINT16
) (((UINTN
) Stack16
>> 16) << 12);
186 ThunkRegSet
.E
.ESP
= (UINT16
) (UINTN
) Stack16
;
187 ThunkRegSet
.E
.CS
= Segment
;
188 ThunkRegSet
.E
.Eip
= Offset
;
190 mThunkContext
.RealModeState
= &ThunkRegSet
;
193 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
195 Status
= Private
->Legacy8259
->SetMode (Private
->Legacy8259
, Efi8259LegacyMode
, NULL
, NULL
);
196 ASSERT_EFI_ERROR (Status
);
198 AsmThunk16 (&mThunkContext
);
201 // OPROM may allocate EBDA range by itself and change EBDA base and EBDA size.
202 // Get the current EBDA base address, and compared with pre-allocate minimum
203 // EBDA base address, if the current EBDA base address is smaller, it indicates
204 // PcdEbdaReservedMemorySize should be adjusted to larger for more OPROMs.
208 UINTN EbdaBaseAddress
;
209 UINTN ReservedEbdaBaseAddress
;
211 EbdaBaseAddress
= (*(UINT16
*) (UINTN
) 0x40E) << 4;
212 ReservedEbdaBaseAddress
= CONVENTIONAL_MEMORY_TOP
- PcdGet32 (PcdEbdaReservedMemorySize
);
213 ASSERT (ReservedEbdaBaseAddress
<= EbdaBaseAddress
);
217 if (Stack
!= NULL
&& StackSize
!= 0) {
219 // Copy low memory stack to Stack
221 CopyMem (Stack
, Stack16
, StackSize
);
225 // Restore protected mode interrupt state
227 Status
= Private
->Legacy8259
->SetMode (Private
->Legacy8259
, Efi8259ProtectedMode
, NULL
, NULL
);
228 ASSERT_EFI_ERROR (Status
);
230 mThunkContext
.RealModeState
= NULL
;
233 // End critical section
235 gBS
->RestoreTPL (OriginalTpl
);
238 // Restore interrutp of debug timer
240 SaveAndSetDebugTimerInterrupt (InterruptState
);
242 Regs
->E
.EDI
= ThunkRegSet
.E
.EDI
;
243 Regs
->E
.ESI
= ThunkRegSet
.E
.ESI
;
244 Regs
->E
.EBP
= ThunkRegSet
.E
.EBP
;
245 Regs
->E
.EBX
= ThunkRegSet
.E
.EBX
;
246 Regs
->E
.EDX
= ThunkRegSet
.E
.EDX
;
247 Regs
->E
.ECX
= ThunkRegSet
.E
.ECX
;
248 Regs
->E
.EAX
= ThunkRegSet
.E
.EAX
;
249 Regs
->X
.SS
= ThunkRegSet
.E
.SS
;
250 Regs
->X
.CS
= ThunkRegSet
.E
.CS
;
251 Regs
->X
.DS
= ThunkRegSet
.E
.DS
;
252 Regs
->X
.ES
= ThunkRegSet
.E
.ES
;
254 CopyMem (&(Regs
->X
.Flags
), &(ThunkRegSet
.E
.EFLAGS
.UintN
), sizeof (Regs
->X
.Flags
));
256 return (BOOLEAN
) (Regs
->X
.Flags
.CF
== 1);
260 Allocate memory < 1 MB and copy the thunker code into low memory. Se up
263 @param Private Private context for Legacy BIOS
265 @retval EFI_SUCCESS Should only pass.
269 LegacyBiosInitializeThunk (
270 IN LEGACY_BIOS_INSTANCE
*Private
273 EFI_PHYSICAL_ADDRESS MemoryAddress
;
275 MemoryAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Private
->IntThunk
;
277 mThunkContext
.RealModeBuffer
= (VOID
*) (UINTN
) (MemoryAddress
+ ((sizeof (LOW_MEMORY_THUNK
) / EFI_PAGE_SIZE
) + 1) * EFI_PAGE_SIZE
);
278 mThunkContext
.RealModeBufferSize
= EFI_PAGE_SIZE
;
279 mThunkContext
.ThunkAttributes
= THUNK_ATTRIBUTE_BIG_REAL_MODE
| THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
;
281 AsmPrepareThunk16 (&mThunkContext
);