1bcecde140a561c64e297225904afebebd62336cejljusten/** @file
2bcecde140a561c64e297225904afebebd62336cejljusten  Call into 16-bit BIOS code
3bcecde140a561c64e297225904afebebd62336cejljusten
4bcecde140a561c64e297225904afebebd62336cejljusten  BugBug: Thunker does A20 gate. Can we get rid of this code or
5bcecde140a561c64e297225904afebebd62336cejljusten          put it into Legacy16 code.
6bcecde140a561c64e297225904afebebd62336cejljusten
71a45b15eae48d9bf498daf5b0c0771659d75faa2Jeff FanCopyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
8bcecde140a561c64e297225904afebebd62336cejljusten
9bcecde140a561c64e297225904afebebd62336cejljustenThis program and the accompanying materials
10bcecde140a561c64e297225904afebebd62336cejljustenare licensed and made available under the terms and conditions
11bcecde140a561c64e297225904afebebd62336cejljustenof the BSD License which accompanies this distribution.  The
12bcecde140a561c64e297225904afebebd62336cejljustenfull text of the license may be found at
13bcecde140a561c64e297225904afebebd62336cejljustenhttp://opensource.org/licenses/bsd-license.php
14bcecde140a561c64e297225904afebebd62336cejljusten
15bcecde140a561c64e297225904afebebd62336cejljustenTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16bcecde140a561c64e297225904afebebd62336cejljustenWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17bcecde140a561c64e297225904afebebd62336cejljusten
18bcecde140a561c64e297225904afebebd62336cejljusten**/
19bcecde140a561c64e297225904afebebd62336cejljusten
20bcecde140a561c64e297225904afebebd62336cejljusten#include "LegacyBiosInterface.h"
21bcecde140a561c64e297225904afebebd62336cejljusten#include "IpfThunk.h"
22bcecde140a561c64e297225904afebebd62336cejljusten
23bcecde140a561c64e297225904afebebd62336cejljusten/**
24bcecde140a561c64e297225904afebebd62336cejljusten  Gets the current flat GDT and IDT descriptors and  store them in
25bcecde140a561c64e297225904afebebd62336cejljusten  Private->IntThunk.  These values are used by the Thunk code.
26bcecde140a561c64e297225904afebebd62336cejljusten  This method must be called before every thunk in order to assure
27bcecde140a561c64e297225904afebebd62336cejljusten  that the correct GDT and IDT are restored after the thunk.
28bcecde140a561c64e297225904afebebd62336cejljusten
29bcecde140a561c64e297225904afebebd62336cejljusten  @param  Private            Private context for Legacy BIOS
30bcecde140a561c64e297225904afebebd62336cejljusten
31bcecde140a561c64e297225904afebebd62336cejljusten  @retval EFI_SUCCESS        Should only pass.
32bcecde140a561c64e297225904afebebd62336cejljusten
33bcecde140a561c64e297225904afebebd62336cejljusten**/
34bcecde140a561c64e297225904afebebd62336cejljustenEFI_STATUS
35bcecde140a561c64e297225904afebebd62336cejljustenLegacyBiosGetFlatDescs (
36bcecde140a561c64e297225904afebebd62336cejljusten  IN  LEGACY_BIOS_INSTANCE    *Private
37bcecde140a561c64e297225904afebebd62336cejljusten  )
38bcecde140a561c64e297225904afebebd62336cejljusten{
39bcecde140a561c64e297225904afebebd62336cejljusten  return EFI_SUCCESS;
40bcecde140a561c64e297225904afebebd62336cejljusten}
41bcecde140a561c64e297225904afebebd62336cejljusten
42bcecde140a561c64e297225904afebebd62336cejljusten
43bcecde140a561c64e297225904afebebd62336cejljusten/**
44bcecde140a561c64e297225904afebebd62336cejljusten  BIOS interrupt call function.
45bcecde140a561c64e297225904afebebd62336cejljusten
46bcecde140a561c64e297225904afebebd62336cejljusten  @param  BiosInt            Int number of BIOS call
47bcecde140a561c64e297225904afebebd62336cejljusten  @param  Segment            Segment number
48bcecde140a561c64e297225904afebebd62336cejljusten  @param  Offset             Offset in segment
49bcecde140a561c64e297225904afebebd62336cejljusten  @param  Regs               IA32 Register set.
50bcecde140a561c64e297225904afebebd62336cejljusten  @param  Stack              Base address of stack
51bcecde140a561c64e297225904afebebd62336cejljusten  @param  StackSize          Size of stack
52bcecde140a561c64e297225904afebebd62336cejljusten
53bcecde140a561c64e297225904afebebd62336cejljusten  @retval EFI_SUCCESS        BIOS interrupt call succeeds.
54bcecde140a561c64e297225904afebebd62336cejljusten
55bcecde140a561c64e297225904afebebd62336cejljusten**/
56bcecde140a561c64e297225904afebebd62336cejljustenEFI_STATUS
57bcecde140a561c64e297225904afebebd62336cejljustenBiosIntCall (
58bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINT16                            BiosInt,
59bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINT16                            Segment,
60bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINT16                            Offset,
61bcecde140a561c64e297225904afebebd62336cejljusten  IN  EFI_IA32_REGISTER_SET             *Regs,
62bcecde140a561c64e297225904afebebd62336cejljusten  IN  VOID                              *Stack,
63bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINTN                             StackSize
64bcecde140a561c64e297225904afebebd62336cejljusten  )
65bcecde140a561c64e297225904afebebd62336cejljusten{
66bcecde140a561c64e297225904afebebd62336cejljusten  IPF_DWORD_REGS  DwordRegs;
67bcecde140a561c64e297225904afebebd62336cejljusten  UINT64          IntTypeVariable;
68bcecde140a561c64e297225904afebebd62336cejljusten
69bcecde140a561c64e297225904afebebd62336cejljusten  IntTypeVariable = 0x8000000000000000;
701a45b15eae48d9bf498daf5b0c0771659d75faa2Jeff Fan  IntTypeVariable |= (UINT64)BiosInt;
71bcecde140a561c64e297225904afebebd62336cejljusten
72bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Cs    = Segment;
73bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Eip   = Offset;
74bcecde140a561c64e297225904afebebd62336cejljusten
75bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Ds    = Regs->X.DS;
76bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Es    = Regs->X.ES;
77bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Fs    = Regs->X.ES;
78bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Gs    = Regs->X.ES;
79bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Ss    = 0xFFFF;
80bcecde140a561c64e297225904afebebd62336cejljusten
81bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Eax   = Regs->X.AX;
82bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Ebx   = Regs->X.BX;
83bcecde140a561c64e297225904afebebd62336cejljusten  //
84bcecde140a561c64e297225904afebebd62336cejljusten  // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
85bcecde140a561c64e297225904afebebd62336cejljusten  // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
86bcecde140a561c64e297225904afebebd62336cejljusten  //
87bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Ecx   = Regs->E.ECX;
88bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Edx   = Regs->X.DX;
89bcecde140a561c64e297225904afebebd62336cejljusten
90bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Ebp   = Regs->X.BP;
91bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Eflag = *((UINT16 *) &Regs->X.Flags);
92bcecde140a561c64e297225904afebebd62336cejljusten
93bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Edi   = Regs->X.DI;
94bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Esi   = Regs->X.SI;
95bcecde140a561c64e297225904afebebd62336cejljusten  DwordRegs.Esp   = 0xFFFFFFFF;
96bcecde140a561c64e297225904afebebd62336cejljusten
97bcecde140a561c64e297225904afebebd62336cejljusten  EfiIaEntryPoint (IntTypeVariable, &DwordRegs, ((UINTN) Stack + StackSize), StackSize);
98bcecde140a561c64e297225904afebebd62336cejljusten
99bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.CS  = DwordRegs.Cs;
100bcecde140a561c64e297225904afebebd62336cejljusten
101bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.DS  = (UINT16) DwordRegs.Ds;
102bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.SS  = (UINT16) DwordRegs.Ss;
103bcecde140a561c64e297225904afebebd62336cejljusten
104bcecde140a561c64e297225904afebebd62336cejljusten  Regs->E.EAX  = DwordRegs.Eax;
105bcecde140a561c64e297225904afebebd62336cejljusten  Regs->E.EBX  = DwordRegs.Ebx;
106bcecde140a561c64e297225904afebebd62336cejljusten  Regs->E.ECX  = DwordRegs.Ecx;
107bcecde140a561c64e297225904afebebd62336cejljusten  Regs->E.EDX  = DwordRegs.Edx;
108bcecde140a561c64e297225904afebebd62336cejljusten
109bcecde140a561c64e297225904afebebd62336cejljusten  Regs->E.EBP  = DwordRegs.Ebp;
110bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (&Regs->X.Flags, &DwordRegs.Eflag, sizeof (EFI_FLAGS_REG));
111bcecde140a561c64e297225904afebebd62336cejljusten
112bcecde140a561c64e297225904afebebd62336cejljusten  Regs->E.EDI  = DwordRegs.Edi;
113bcecde140a561c64e297225904afebebd62336cejljusten  Regs->E.ESI  = DwordRegs.Esi;
114bcecde140a561c64e297225904afebebd62336cejljusten
115bcecde140a561c64e297225904afebebd62336cejljusten  return EFI_SUCCESS;
116bcecde140a561c64e297225904afebebd62336cejljusten}
117bcecde140a561c64e297225904afebebd62336cejljusten
118bcecde140a561c64e297225904afebebd62336cejljusten
119bcecde140a561c64e297225904afebebd62336cejljusten/**
120bcecde140a561c64e297225904afebebd62336cejljusten  Template of real mode code.
121bcecde140a561c64e297225904afebebd62336cejljusten
122bcecde140a561c64e297225904afebebd62336cejljusten  @param  CodeStart          Start address of code.
123bcecde140a561c64e297225904afebebd62336cejljusten  @param  CodeEnd            End address of code
124bcecde140a561c64e297225904afebebd62336cejljusten  @param  ReverseThunkStart  Start of reverse thunk.
125bcecde140a561c64e297225904afebebd62336cejljusten  @param  IntThunk           Low memory thunk.
126bcecde140a561c64e297225904afebebd62336cejljusten
127bcecde140a561c64e297225904afebebd62336cejljusten**/
128bcecde140a561c64e297225904afebebd62336cejljustenVOID
129bcecde140a561c64e297225904afebebd62336cejljustenRealModeTemplate (
130bcecde140a561c64e297225904afebebd62336cejljusten  OUT UINTN          *CodeStart,
131bcecde140a561c64e297225904afebebd62336cejljusten  OUT UINTN          *CodeEnd,
132bcecde140a561c64e297225904afebebd62336cejljusten  OUT UINTN          *ReverseThunkStart,
133bcecde140a561c64e297225904afebebd62336cejljusten  LOW_MEMORY_THUNK   *IntThunk
134bcecde140a561c64e297225904afebebd62336cejljusten  )
135bcecde140a561c64e297225904afebebd62336cejljusten{
136bcecde140a561c64e297225904afebebd62336cejljusten  SAL_RETURN_REGS SalStatus;
137bcecde140a561c64e297225904afebebd62336cejljusten
138bcecde140a561c64e297225904afebebd62336cejljusten  SalStatus           = EsalGetReverseThunkAddress ();
139bcecde140a561c64e297225904afebebd62336cejljusten
140bcecde140a561c64e297225904afebebd62336cejljusten  *CodeStart          = SalStatus.r9;
141bcecde140a561c64e297225904afebebd62336cejljusten  *CodeEnd            = SalStatus.r10;
142bcecde140a561c64e297225904afebebd62336cejljusten  *ReverseThunkStart  = SalStatus.r11;
143bcecde140a561c64e297225904afebebd62336cejljusten
144bcecde140a561c64e297225904afebebd62336cejljusten}
145bcecde140a561c64e297225904afebebd62336cejljusten
146bcecde140a561c64e297225904afebebd62336cejljusten
147bcecde140a561c64e297225904afebebd62336cejljusten/**
148bcecde140a561c64e297225904afebebd62336cejljusten  Allocate memory < 1 MB and copy the thunker code into low memory. Se up
149bcecde140a561c64e297225904afebebd62336cejljusten  all the descriptors.
150bcecde140a561c64e297225904afebebd62336cejljusten
151bcecde140a561c64e297225904afebebd62336cejljusten  @param  Private            Private context for Legacy BIOS
152bcecde140a561c64e297225904afebebd62336cejljusten
153bcecde140a561c64e297225904afebebd62336cejljusten  @retval EFI_SUCCESS        Should only pass.
154bcecde140a561c64e297225904afebebd62336cejljusten
155bcecde140a561c64e297225904afebebd62336cejljusten**/
156bcecde140a561c64e297225904afebebd62336cejljustenEFI_STATUS
157bcecde140a561c64e297225904afebebd62336cejljustenLegacyBiosInitializeThunk (
158bcecde140a561c64e297225904afebebd62336cejljusten  IN  LEGACY_BIOS_INSTANCE    *Private
159bcecde140a561c64e297225904afebebd62336cejljusten  )
160bcecde140a561c64e297225904afebebd62336cejljusten{
161bcecde140a561c64e297225904afebebd62336cejljusten  GDT32               *CodeGdt;
162bcecde140a561c64e297225904afebebd62336cejljusten  GDT32               *DataGdt;
163bcecde140a561c64e297225904afebebd62336cejljusten  UINTN             CodeStart;
164bcecde140a561c64e297225904afebebd62336cejljusten  UINTN             CodeEnd;
165bcecde140a561c64e297225904afebebd62336cejljusten  UINTN             ReverseThunkStart;
166bcecde140a561c64e297225904afebebd62336cejljusten  UINT32            Base;
167bcecde140a561c64e297225904afebebd62336cejljusten  LOW_MEMORY_THUNK  *IntThunk;
168bcecde140a561c64e297225904afebebd62336cejljusten  UINTN             TempData;
169bcecde140a561c64e297225904afebebd62336cejljusten
170bcecde140a561c64e297225904afebebd62336cejljusten  ASSERT (Private);
171bcecde140a561c64e297225904afebebd62336cejljusten
172bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk = Private->IntThunk;
173bcecde140a561c64e297225904afebebd62336cejljusten
174bcecde140a561c64e297225904afebebd62336cejljusten  //
175bcecde140a561c64e297225904afebebd62336cejljusten  // Clear the reserved descriptor
176bcecde140a561c64e297225904afebebd62336cejljusten  //
177bcecde140a561c64e297225904afebebd62336cejljusten  ZeroMem (&(IntThunk->RealModeGdt[0]), sizeof (GDT32));
178bcecde140a561c64e297225904afebebd62336cejljusten
179bcecde140a561c64e297225904afebebd62336cejljusten  //
180bcecde140a561c64e297225904afebebd62336cejljusten  // Setup a descriptor for real-mode code
181bcecde140a561c64e297225904afebebd62336cejljusten  //
182bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt = &(IntThunk->RealModeGdt[1]);
183bcecde140a561c64e297225904afebebd62336cejljusten
184bcecde140a561c64e297225904afebebd62336cejljusten  //
185bcecde140a561c64e297225904afebebd62336cejljusten  // Fill in the descriptor with our real-mode segment value
186bcecde140a561c64e297225904afebebd62336cejljusten  //
187bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->Type = 0xA;
188bcecde140a561c64e297225904afebebd62336cejljusten  //
189bcecde140a561c64e297225904afebebd62336cejljusten  // code/read
190bcecde140a561c64e297225904afebebd62336cejljusten  //
191bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->System       = 1;
192bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->Dpl          = 0;
193bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->Present      = 1;
194bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->Software     = 0;
195bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->Reserved     = 0;
196bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->DefaultSize  = 0;
197bcecde140a561c64e297225904afebebd62336cejljusten  //
198bcecde140a561c64e297225904afebebd62336cejljusten  // 16 bit operands
199bcecde140a561c64e297225904afebebd62336cejljusten  //
200bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->Granularity  = 0;
201bcecde140a561c64e297225904afebebd62336cejljusten
202bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->LimitHi      = 0;
203bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->LimitLo      = 0xffff;
204bcecde140a561c64e297225904afebebd62336cejljusten
205bcecde140a561c64e297225904afebebd62336cejljusten  Base                  = (*((UINT32 *) &IntThunk->Code));
206bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->BaseHi       = (Base >> 24) & 0xFF;
207bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->BaseMid      = (Base >> 16) & 0xFF;
208bcecde140a561c64e297225904afebebd62336cejljusten  CodeGdt->BaseLo       = Base & 0xFFFF;
209bcecde140a561c64e297225904afebebd62336cejljusten
210bcecde140a561c64e297225904afebebd62336cejljusten  //
211bcecde140a561c64e297225904afebebd62336cejljusten  // Setup a descriptor for read-mode data
212bcecde140a561c64e297225904afebebd62336cejljusten  //
213bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt = &(IntThunk->RealModeGdt[2]);
214bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (DataGdt, CodeGdt, sizeof (GDT32));
215bcecde140a561c64e297225904afebebd62336cejljusten
216bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt->Type = 0x2;
217bcecde140a561c64e297225904afebebd62336cejljusten  //
218bcecde140a561c64e297225904afebebd62336cejljusten  // read/write data
219bcecde140a561c64e297225904afebebd62336cejljusten  //
220bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt->BaseHi = 0x0;
221bcecde140a561c64e297225904afebebd62336cejljusten  //
222bcecde140a561c64e297225904afebebd62336cejljusten  // Base = 0
223bcecde140a561c64e297225904afebebd62336cejljusten  //
224bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt->BaseMid = 0x0;
225bcecde140a561c64e297225904afebebd62336cejljusten  //
226bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt->BaseLo = 0x0;
227bcecde140a561c64e297225904afebebd62336cejljusten  //
228bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt->LimitHi = 0x0F;
229bcecde140a561c64e297225904afebebd62336cejljusten  //
230bcecde140a561c64e297225904afebebd62336cejljusten  // Limit = 4Gb
231bcecde140a561c64e297225904afebebd62336cejljusten  //
232bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt->LimitLo = 0xFFFF;
233bcecde140a561c64e297225904afebebd62336cejljusten  //
234bcecde140a561c64e297225904afebebd62336cejljusten  DataGdt->Granularity = 0x1;
235bcecde140a561c64e297225904afebebd62336cejljusten  //
236bcecde140a561c64e297225904afebebd62336cejljusten  //
237bcecde140a561c64e297225904afebebd62336cejljusten  // Compute selector value
238bcecde140a561c64e297225904afebebd62336cejljusten  //
239bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->RealModeGdtDesc.Limit = (UINT16) (sizeof (IntThunk->RealModeGdt) - 1);
240bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (&IntThunk->RealModeGdtDesc.Base, (UINT32 *) &IntThunk->RealModeGdt, sizeof (UINT32));
241bcecde140a561c64e297225904afebebd62336cejljusten  //
242bcecde140a561c64e297225904afebebd62336cejljusten  //  IntThunk->RealModeGdtDesc.Base = *((UINT32*) &IntThunk->RealModeGdt);
243bcecde140a561c64e297225904afebebd62336cejljusten  //
244bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->RealModeIdtDesc.Limit = 0xFFFF;
245bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->RealModeIdtDesc.Base  = 0;
246bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->LowCodeSelector       = (UINT32) ((UINTN) CodeGdt - IntThunk->RealModeGdtDesc.Base);
247bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->LowDataSelector       = (UINT32) ((UINTN) DataGdt - IntThunk->RealModeGdtDesc.Base);
248bcecde140a561c64e297225904afebebd62336cejljusten
249bcecde140a561c64e297225904afebebd62336cejljusten  //
250bcecde140a561c64e297225904afebebd62336cejljusten  // Initialize low real-mode code thunk
251bcecde140a561c64e297225904afebebd62336cejljusten  //
252bcecde140a561c64e297225904afebebd62336cejljusten  RealModeTemplate (&CodeStart, &CodeEnd, &ReverseThunkStart, IntThunk);
253bcecde140a561c64e297225904afebebd62336cejljusten
254bcecde140a561c64e297225904afebebd62336cejljusten  TempData                        = (UINTN) &(IntThunk->Code);
255bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->LowReverseThunkStart  = ((UINT32) TempData + (UINT32) (ReverseThunkStart - CodeStart));
256bcecde140a561c64e297225904afebebd62336cejljusten
257bcecde140a561c64e297225904afebebd62336cejljusten  EsalSetSalDataArea (TempData, (UINTN) IntThunk);
258bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (IntThunk->Code, (VOID *) CodeStart, CodeEnd - CodeStart);
259bcecde140a561c64e297225904afebebd62336cejljusten
260bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->EfiToLegacy16InitTable.ReverseThunkCallSegment = EFI_SEGMENT (*((UINT32 *) &IntThunk->LowReverseThunkStart));
261bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->EfiToLegacy16InitTable.ReverseThunkCallOffset = EFI_OFFSET (*((UINT32 *) &IntThunk->LowReverseThunkStart));
262bcecde140a561c64e297225904afebebd62336cejljusten
263bcecde140a561c64e297225904afebebd62336cejljusten  return EFI_SUCCESS;
264bcecde140a561c64e297225904afebebd62336cejljusten}
265bcecde140a561c64e297225904afebebd62336cejljusten
266bcecde140a561c64e297225904afebebd62336cejljusten
267bcecde140a561c64e297225904afebebd62336cejljusten/**
268bcecde140a561c64e297225904afebebd62336cejljusten  Thunk to 16-bit real mode and execute a software interrupt with a vector
269bcecde140a561c64e297225904afebebd62336cejljusten  of BiosInt. Regs will contain the 16-bit register context on entry and
270bcecde140a561c64e297225904afebebd62336cejljusten  exit.
271bcecde140a561c64e297225904afebebd62336cejljusten
272bcecde140a561c64e297225904afebebd62336cejljusten  @param  This               Protocol instance pointer.
273bcecde140a561c64e297225904afebebd62336cejljusten  @param  BiosInt            Processor interrupt vector to invoke
274bcecde140a561c64e297225904afebebd62336cejljusten  @param  Regs               Register contexted passed into (and returned) from
275bcecde140a561c64e297225904afebebd62336cejljusten                             thunk to  16-bit mode
276bcecde140a561c64e297225904afebebd62336cejljusten
277bcecde140a561c64e297225904afebebd62336cejljusten  @retval FALSE              Thunk completed, and there were no BIOS errors in the
278bcecde140a561c64e297225904afebebd62336cejljusten                             target code. See Regs for status.
279bcecde140a561c64e297225904afebebd62336cejljusten  @retval TRUE               There was a BIOS erro in the target code.
280bcecde140a561c64e297225904afebebd62336cejljusten
281bcecde140a561c64e297225904afebebd62336cejljusten**/
282bcecde140a561c64e297225904afebebd62336cejljustenBOOLEAN
283bcecde140a561c64e297225904afebebd62336cejljustenEFIAPI
284bcecde140a561c64e297225904afebebd62336cejljustenLegacyBiosInt86 (
285bcecde140a561c64e297225904afebebd62336cejljusten  IN EFI_LEGACY_BIOS_PROTOCOL           *This,
286bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINT8                             BiosInt,
287bcecde140a561c64e297225904afebebd62336cejljusten  IN  EFI_IA32_REGISTER_SET             *Regs
288bcecde140a561c64e297225904afebebd62336cejljusten  )
289bcecde140a561c64e297225904afebebd62336cejljusten{
290bcecde140a561c64e297225904afebebd62336cejljusten  EFI_STATUS            Status;
291bcecde140a561c64e297225904afebebd62336cejljusten  LEGACY_BIOS_INSTANCE  *Private;
292bcecde140a561c64e297225904afebebd62336cejljusten  LOW_MEMORY_THUNK      *IntThunk;
293bcecde140a561c64e297225904afebebd62336cejljusten  UINT16                *Stack16;
294bcecde140a561c64e297225904afebebd62336cejljusten  EFI_TPL               OriginalTpl;
295bcecde140a561c64e297225904afebebd62336cejljusten  UINTN                 IaSegment;
296bcecde140a561c64e297225904afebebd62336cejljusten  UINTN                 IaOffset;
297bcecde140a561c64e297225904afebebd62336cejljusten  UINTN                 *Address;
298bcecde140a561c64e297225904afebebd62336cejljusten  UINTN                 TempData;
299bcecde140a561c64e297225904afebebd62336cejljusten
300bcecde140a561c64e297225904afebebd62336cejljusten  Private   = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
301bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk  = Private->IntThunk;
302bcecde140a561c64e297225904afebebd62336cejljusten
303bcecde140a561c64e297225904afebebd62336cejljusten  //
304bcecde140a561c64e297225904afebebd62336cejljusten  // Get the current flat GDT, IDT, and SS and store them in Private->IntThunk.
305bcecde140a561c64e297225904afebebd62336cejljusten  //
306bcecde140a561c64e297225904afebebd62336cejljusten  Status = LegacyBiosGetFlatDescs (Private);
307bcecde140a561c64e297225904afebebd62336cejljusten  ASSERT_EFI_ERROR (Status);
308bcecde140a561c64e297225904afebebd62336cejljusten
309bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved1 = 1;
310bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved2 = 0;
311bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved3 = 0;
312bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved4 = 0;
313bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.IOPL      = 3;
314bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.NT        = 0;
315bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.IF        = 1;
316bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.TF        = 0;
317bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.CF        = 0;
318bcecde140a561c64e297225904afebebd62336cejljusten  //
319bcecde140a561c64e297225904afebebd62336cejljusten  // Clear the error flag; thunk code may set it.
320bcecde140a561c64e297225904afebebd62336cejljusten  //
321bcecde140a561c64e297225904afebebd62336cejljusten  Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
322bcecde140a561c64e297225904afebebd62336cejljusten
323bcecde140a561c64e297225904afebebd62336cejljusten  //
324bcecde140a561c64e297225904afebebd62336cejljusten  // Copy regs to low memory stack
325bcecde140a561c64e297225904afebebd62336cejljusten  //
326bcecde140a561c64e297225904afebebd62336cejljusten  Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
327bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
328bcecde140a561c64e297225904afebebd62336cejljusten
329bcecde140a561c64e297225904afebebd62336cejljusten  //
330bcecde140a561c64e297225904afebebd62336cejljusten  // Provide low stack esp
331bcecde140a561c64e297225904afebebd62336cejljusten  //
332bcecde140a561c64e297225904afebebd62336cejljusten  TempData            = ((UINTN) Stack16) - ((UINTN) IntThunk);
333bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->LowStack  = *((UINT32 *) &TempData);
334bcecde140a561c64e297225904afebebd62336cejljusten
335bcecde140a561c64e297225904afebebd62336cejljusten  //
336bcecde140a561c64e297225904afebebd62336cejljusten  // Stack for reverse thunk flat mode.
337bcecde140a561c64e297225904afebebd62336cejljusten  //    It must point to top of stack (end of stack space).
338bcecde140a561c64e297225904afebebd62336cejljusten  //
339bcecde140a561c64e297225904afebebd62336cejljusten  TempData                = ((UINTN) IntThunk->RevThunkStack) + LOW_STACK_SIZE;
340bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->RevFlatStack  = *((UINT32 *) &TempData);
341bcecde140a561c64e297225904afebebd62336cejljusten
342bcecde140a561c64e297225904afebebd62336cejljusten  //
343bcecde140a561c64e297225904afebebd62336cejljusten  // The call to Legacy16 is a critical section to EFI
344bcecde140a561c64e297225904afebebd62336cejljusten  //
345bcecde140a561c64e297225904afebebd62336cejljusten  OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
346bcecde140a561c64e297225904afebebd62336cejljusten
347bcecde140a561c64e297225904afebebd62336cejljusten  //
348bcecde140a561c64e297225904afebebd62336cejljusten  // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
349bcecde140a561c64e297225904afebebd62336cejljusten  //
350bcecde140a561c64e297225904afebebd62336cejljusten  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
351bcecde140a561c64e297225904afebebd62336cejljusten  ASSERT_EFI_ERROR (Status);
352bcecde140a561c64e297225904afebebd62336cejljusten
353bcecde140a561c64e297225904afebebd62336cejljusten  //
354bcecde140a561c64e297225904afebebd62336cejljusten  // Call the real mode thunk code
355bcecde140a561c64e297225904afebebd62336cejljusten  //
356bcecde140a561c64e297225904afebebd62336cejljusten  TempData  = BiosInt * 4;
357bcecde140a561c64e297225904afebebd62336cejljusten  Address   = (UINTN *) TempData;
358bcecde140a561c64e297225904afebebd62336cejljusten  IaOffset  = 0xFFFF & (*Address);
359bcecde140a561c64e297225904afebebd62336cejljusten  IaSegment = 0xFFFF & ((*Address) >> 16);
360bcecde140a561c64e297225904afebebd62336cejljusten
361bcecde140a561c64e297225904afebebd62336cejljusten  Status = BiosIntCall (
362bcecde140a561c64e297225904afebebd62336cejljusten            BiosInt,
363bcecde140a561c64e297225904afebebd62336cejljusten            (UINT16) IaSegment,
364bcecde140a561c64e297225904afebebd62336cejljusten            (UINT16) IaOffset,
365bcecde140a561c64e297225904afebebd62336cejljusten            (EFI_IA32_REGISTER_SET *) Stack16,
366bcecde140a561c64e297225904afebebd62336cejljusten            IntThunk,
367bcecde140a561c64e297225904afebebd62336cejljusten            IntThunk->LowStack
368bcecde140a561c64e297225904afebebd62336cejljusten            );
369bcecde140a561c64e297225904afebebd62336cejljusten
370bcecde140a561c64e297225904afebebd62336cejljusten  //
371bcecde140a561c64e297225904afebebd62336cejljusten  // Check for errors with the thunk
372bcecde140a561c64e297225904afebebd62336cejljusten  //
373bcecde140a561c64e297225904afebebd62336cejljusten  switch (Status) {
374bcecde140a561c64e297225904afebebd62336cejljusten  case THUNK_OK:
375bcecde140a561c64e297225904afebebd62336cejljusten    break;
376bcecde140a561c64e297225904afebebd62336cejljusten
377bcecde140a561c64e297225904afebebd62336cejljusten  case THUNK_ERR_A20_UNSUP:
378bcecde140a561c64e297225904afebebd62336cejljusten  case THUNK_ERR_A20_FAILED:
379bcecde140a561c64e297225904afebebd62336cejljusten  default:
380bcecde140a561c64e297225904afebebd62336cejljusten    //
381bcecde140a561c64e297225904afebebd62336cejljusten    // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
382bcecde140a561c64e297225904afebebd62336cejljusten    //
383bcecde140a561c64e297225904afebebd62336cejljusten    Regs->X.Flags.CF = 1;
384bcecde140a561c64e297225904afebebd62336cejljusten    break;
385bcecde140a561c64e297225904afebebd62336cejljusten  }
386bcecde140a561c64e297225904afebebd62336cejljusten
387bcecde140a561c64e297225904afebebd62336cejljusten  Status  = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
388bcecde140a561c64e297225904afebebd62336cejljusten  ASSERT_EFI_ERROR (Status);
389bcecde140a561c64e297225904afebebd62336cejljusten
390bcecde140a561c64e297225904afebebd62336cejljusten  //
391bcecde140a561c64e297225904afebebd62336cejljusten  // End critical section
392bcecde140a561c64e297225904afebebd62336cejljusten  //
393bcecde140a561c64e297225904afebebd62336cejljusten  gBS->RestoreTPL (OriginalTpl);
394bcecde140a561c64e297225904afebebd62336cejljusten
395bcecde140a561c64e297225904afebebd62336cejljusten  //
396bcecde140a561c64e297225904afebebd62336cejljusten  // Return the resulting registers
397bcecde140a561c64e297225904afebebd62336cejljusten  //
398bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
399bcecde140a561c64e297225904afebebd62336cejljusten
400bcecde140a561c64e297225904afebebd62336cejljusten  return (BOOLEAN) (Regs->X.Flags.CF != 0);
401bcecde140a561c64e297225904afebebd62336cejljusten}
402bcecde140a561c64e297225904afebebd62336cejljusten
403bcecde140a561c64e297225904afebebd62336cejljusten
404bcecde140a561c64e297225904afebebd62336cejljusten/**
405bcecde140a561c64e297225904afebebd62336cejljusten  Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
406bcecde140a561c64e297225904afebebd62336cejljusten  16-bit register context on entry and exit. Arguments can be passed on
407bcecde140a561c64e297225904afebebd62336cejljusten  the Stack argument
408bcecde140a561c64e297225904afebebd62336cejljusten
409bcecde140a561c64e297225904afebebd62336cejljusten  @param  This               Protocol instance pointer.
410bcecde140a561c64e297225904afebebd62336cejljusten  @param  Segment            Segemnt of 16-bit mode call
411bcecde140a561c64e297225904afebebd62336cejljusten  @param  Offset             Offset of 16-bit mdoe call
412bcecde140a561c64e297225904afebebd62336cejljusten  @param  Regs               Register contexted passed into (and returned) from
413bcecde140a561c64e297225904afebebd62336cejljusten                             thunk to  16-bit mode
414bcecde140a561c64e297225904afebebd62336cejljusten  @param  Stack              Caller allocated stack used to pass arguments
415bcecde140a561c64e297225904afebebd62336cejljusten  @param  StackSize          Size of Stack in bytes
416bcecde140a561c64e297225904afebebd62336cejljusten
417bcecde140a561c64e297225904afebebd62336cejljusten  @retval FALSE              Thunk completed, and there were no BIOS errors in the
418bcecde140a561c64e297225904afebebd62336cejljusten                             target code. See Regs for status.
419bcecde140a561c64e297225904afebebd62336cejljusten  @retval TRUE               There was a BIOS erro in the target code.
420bcecde140a561c64e297225904afebebd62336cejljusten
421bcecde140a561c64e297225904afebebd62336cejljusten**/
422bcecde140a561c64e297225904afebebd62336cejljustenBOOLEAN
423bcecde140a561c64e297225904afebebd62336cejljustenEFIAPI
424bcecde140a561c64e297225904afebebd62336cejljustenLegacyBiosFarCall86 (
425bcecde140a561c64e297225904afebebd62336cejljusten  IN EFI_LEGACY_BIOS_PROTOCOL           *This,
426bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINT16                            Segment,
427bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINT16                            Offset,
428bcecde140a561c64e297225904afebebd62336cejljusten  IN  EFI_IA32_REGISTER_SET             *Regs,
429bcecde140a561c64e297225904afebebd62336cejljusten  IN  VOID                              *Stack,
430bcecde140a561c64e297225904afebebd62336cejljusten  IN  UINTN                             StackSize
431bcecde140a561c64e297225904afebebd62336cejljusten  )
432bcecde140a561c64e297225904afebebd62336cejljusten{
433bcecde140a561c64e297225904afebebd62336cejljusten  EFI_STATUS            Status;
434bcecde140a561c64e297225904afebebd62336cejljusten  LEGACY_BIOS_INSTANCE  *Private;
435bcecde140a561c64e297225904afebebd62336cejljusten  LOW_MEMORY_THUNK      *IntThunk;
436bcecde140a561c64e297225904afebebd62336cejljusten  UINT16                *Stack16;
437bcecde140a561c64e297225904afebebd62336cejljusten  EFI_TPL               OriginalTpl;
438bcecde140a561c64e297225904afebebd62336cejljusten  UINTN                 IaSegment;
439bcecde140a561c64e297225904afebebd62336cejljusten  UINTN                 IaOffset;
440bcecde140a561c64e297225904afebebd62336cejljusten  UINTN                 TempData;
441bcecde140a561c64e297225904afebebd62336cejljusten
442bcecde140a561c64e297225904afebebd62336cejljusten  Private   = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
443bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk  = Private->IntThunk;
444bcecde140a561c64e297225904afebebd62336cejljusten  IaSegment = Segment;
445bcecde140a561c64e297225904afebebd62336cejljusten  IaOffset  = Offset;
446bcecde140a561c64e297225904afebebd62336cejljusten
447bcecde140a561c64e297225904afebebd62336cejljusten  //
448bcecde140a561c64e297225904afebebd62336cejljusten  // Get the current flat GDT and IDT and store them in Private->IntThunk.
449bcecde140a561c64e297225904afebebd62336cejljusten  //
450bcecde140a561c64e297225904afebebd62336cejljusten  Status = LegacyBiosGetFlatDescs (Private);
451bcecde140a561c64e297225904afebebd62336cejljusten  ASSERT_EFI_ERROR (Status);
452bcecde140a561c64e297225904afebebd62336cejljusten
453bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved1 = 1;
454bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved2 = 0;
455bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved3 = 0;
456bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.Reserved4 = 0;
457bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.IOPL      = 3;
458bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.NT        = 0;
459bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.IF        = 1;
460bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.TF        = 0;
461bcecde140a561c64e297225904afebebd62336cejljusten  Regs->X.Flags.CF        = 0;
462bcecde140a561c64e297225904afebebd62336cejljusten  //
463bcecde140a561c64e297225904afebebd62336cejljusten  // Clear the error flag; thunk code may set it.
464bcecde140a561c64e297225904afebebd62336cejljusten  //
465bcecde140a561c64e297225904afebebd62336cejljusten  Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
466bcecde140a561c64e297225904afebebd62336cejljusten  if (Stack != NULL && StackSize != 0) {
467bcecde140a561c64e297225904afebebd62336cejljusten    //
468bcecde140a561c64e297225904afebebd62336cejljusten    // Copy Stack to low memory stack
469bcecde140a561c64e297225904afebebd62336cejljusten    //
470bcecde140a561c64e297225904afebebd62336cejljusten    Stack16 -= StackSize / sizeof (UINT16);
471bcecde140a561c64e297225904afebebd62336cejljusten    CopyMem (Stack16, Stack, StackSize);
472bcecde140a561c64e297225904afebebd62336cejljusten  }
473bcecde140a561c64e297225904afebebd62336cejljusten  //
474bcecde140a561c64e297225904afebebd62336cejljusten  // Copy regs to low memory stack
475bcecde140a561c64e297225904afebebd62336cejljusten  //
476bcecde140a561c64e297225904afebebd62336cejljusten  Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
477bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
478bcecde140a561c64e297225904afebebd62336cejljusten
479bcecde140a561c64e297225904afebebd62336cejljusten  //
480bcecde140a561c64e297225904afebebd62336cejljusten  // Provide low stack esp
481bcecde140a561c64e297225904afebebd62336cejljusten  //
482bcecde140a561c64e297225904afebebd62336cejljusten  TempData            = ((UINTN) Stack16) - ((UINTN) IntThunk);
483bcecde140a561c64e297225904afebebd62336cejljusten  IntThunk->LowStack  = *((UINT32 *) &TempData);
484bcecde140a561c64e297225904afebebd62336cejljusten
485bcecde140a561c64e297225904afebebd62336cejljusten  //
486bcecde140a561c64e297225904afebebd62336cejljusten  // The call to Legacy16 is a critical section to EFI
487bcecde140a561c64e297225904afebebd62336cejljusten  //
488bcecde140a561c64e297225904afebebd62336cejljusten  OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
489bcecde140a561c64e297225904afebebd62336cejljusten
490bcecde140a561c64e297225904afebebd62336cejljusten  //
491bcecde140a561c64e297225904afebebd62336cejljusten  // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
492bcecde140a561c64e297225904afebebd62336cejljusten  //
493bcecde140a561c64e297225904afebebd62336cejljusten  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
494bcecde140a561c64e297225904afebebd62336cejljusten  ASSERT_EFI_ERROR (Status);
495bcecde140a561c64e297225904afebebd62336cejljusten
496bcecde140a561c64e297225904afebebd62336cejljusten  //
497bcecde140a561c64e297225904afebebd62336cejljusten  // Call the real mode thunk code
498bcecde140a561c64e297225904afebebd62336cejljusten  //
499bcecde140a561c64e297225904afebebd62336cejljusten  Status = BiosIntCall (
500bcecde140a561c64e297225904afebebd62336cejljusten            0x100,
501bcecde140a561c64e297225904afebebd62336cejljusten            (UINT16) IaSegment,
502bcecde140a561c64e297225904afebebd62336cejljusten            (UINT16) IaOffset,
503bcecde140a561c64e297225904afebebd62336cejljusten            (EFI_IA32_REGISTER_SET *) Stack16,
504bcecde140a561c64e297225904afebebd62336cejljusten            IntThunk,
505bcecde140a561c64e297225904afebebd62336cejljusten            IntThunk->LowStack
506bcecde140a561c64e297225904afebebd62336cejljusten            );
507bcecde140a561c64e297225904afebebd62336cejljusten
508bcecde140a561c64e297225904afebebd62336cejljusten  //
509bcecde140a561c64e297225904afebebd62336cejljusten  // Check for errors with the thunk
510bcecde140a561c64e297225904afebebd62336cejljusten  //
511bcecde140a561c64e297225904afebebd62336cejljusten  switch (Status) {
512bcecde140a561c64e297225904afebebd62336cejljusten  case THUNK_OK:
513bcecde140a561c64e297225904afebebd62336cejljusten    break;
514bcecde140a561c64e297225904afebebd62336cejljusten
515bcecde140a561c64e297225904afebebd62336cejljusten  case THUNK_ERR_A20_UNSUP:
516bcecde140a561c64e297225904afebebd62336cejljusten  case THUNK_ERR_A20_FAILED:
517bcecde140a561c64e297225904afebebd62336cejljusten  default:
518bcecde140a561c64e297225904afebebd62336cejljusten    //
519bcecde140a561c64e297225904afebebd62336cejljusten    // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
520bcecde140a561c64e297225904afebebd62336cejljusten    //
521bcecde140a561c64e297225904afebebd62336cejljusten    Regs->X.Flags.CF = 1;
522bcecde140a561c64e297225904afebebd62336cejljusten    break;
523bcecde140a561c64e297225904afebebd62336cejljusten  }
524bcecde140a561c64e297225904afebebd62336cejljusten  //
525bcecde140a561c64e297225904afebebd62336cejljusten  // Restore protected mode interrupt state
526bcecde140a561c64e297225904afebebd62336cejljusten  //
527bcecde140a561c64e297225904afebebd62336cejljusten  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
528bcecde140a561c64e297225904afebebd62336cejljusten  ASSERT_EFI_ERROR (Status);
529bcecde140a561c64e297225904afebebd62336cejljusten
530bcecde140a561c64e297225904afebebd62336cejljusten  //
531bcecde140a561c64e297225904afebebd62336cejljusten  // End critical section
532bcecde140a561c64e297225904afebebd62336cejljusten  //
533bcecde140a561c64e297225904afebebd62336cejljusten  gBS->RestoreTPL (OriginalTpl);
534bcecde140a561c64e297225904afebebd62336cejljusten
535bcecde140a561c64e297225904afebebd62336cejljusten  //
536bcecde140a561c64e297225904afebebd62336cejljusten  // Return the resulting registers
537bcecde140a561c64e297225904afebebd62336cejljusten  //
538bcecde140a561c64e297225904afebebd62336cejljusten  CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
539bcecde140a561c64e297225904afebebd62336cejljusten  Stack16 += sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
540bcecde140a561c64e297225904afebebd62336cejljusten
541bcecde140a561c64e297225904afebebd62336cejljusten  if (Stack != NULL && StackSize != 0) {
542bcecde140a561c64e297225904afebebd62336cejljusten    //
543bcecde140a561c64e297225904afebebd62336cejljusten    // Copy low memory stack to Stack
544bcecde140a561c64e297225904afebebd62336cejljusten    //
545bcecde140a561c64e297225904afebebd62336cejljusten    CopyMem (Stack, Stack16, StackSize);
546bcecde140a561c64e297225904afebebd62336cejljusten    Stack16 += StackSize / sizeof (UINT16);
547bcecde140a561c64e297225904afebebd62336cejljusten  }
548bcecde140a561c64e297225904afebebd62336cejljusten
549bcecde140a561c64e297225904afebebd62336cejljusten  return (BOOLEAN) (Regs->X.Flags.CF != 0);
550bcecde140a561c64e297225904afebebd62336cejljusten}
551