mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 05:28:13 +00:00 
			
		
		
		
	 1a45b15eae
			
		
	
	
		1a45b15eae
		
	
	
	
	
		
			
			Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Eric Dong <Eric.Dong@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15778 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			551 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			551 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Call into 16-bit BIOS code
 | |
| 
 | |
|   BugBug: Thunker does A20 gate. Can we get rid of this code or
 | |
|           put it into Legacy16 code.
 | |
| 
 | |
| Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions
 | |
| of the BSD License which accompanies this distribution.  The
 | |
| full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "LegacyBiosInterface.h"
 | |
| #include "IpfThunk.h"
 | |
| 
 | |
| /**
 | |
|   Gets the current flat GDT and IDT descriptors and  store them in
 | |
|   Private->IntThunk.  These values are used by the Thunk code.
 | |
|   This method must be called before every thunk in order to assure
 | |
|   that the correct GDT and IDT are restored after the thunk.
 | |
| 
 | |
|   @param  Private            Private context for Legacy BIOS
 | |
| 
 | |
|   @retval EFI_SUCCESS        Should only pass.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LegacyBiosGetFlatDescs (
 | |
|   IN  LEGACY_BIOS_INSTANCE    *Private
 | |
|   )
 | |
| {
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   BIOS interrupt call function.
 | |
| 
 | |
|   @param  BiosInt            Int number of BIOS call
 | |
|   @param  Segment            Segment number
 | |
|   @param  Offset             Offset in segment
 | |
|   @param  Regs               IA32 Register set.
 | |
|   @param  Stack              Base address of stack
 | |
|   @param  StackSize          Size of stack
 | |
| 
 | |
|   @retval EFI_SUCCESS        BIOS interrupt call succeeds.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| BiosIntCall (
 | |
|   IN  UINT16                            BiosInt,
 | |
|   IN  UINT16                            Segment,
 | |
|   IN  UINT16                            Offset,
 | |
|   IN  EFI_IA32_REGISTER_SET             *Regs,
 | |
|   IN  VOID                              *Stack,
 | |
|   IN  UINTN                             StackSize
 | |
|   )
 | |
| {
 | |
|   IPF_DWORD_REGS  DwordRegs;
 | |
|   UINT64          IntTypeVariable;
 | |
| 
 | |
|   IntTypeVariable = 0x8000000000000000;
 | |
|   IntTypeVariable |= (UINT64)BiosInt;
 | |
| 
 | |
|   DwordRegs.Cs    = Segment;
 | |
|   DwordRegs.Eip   = Offset;
 | |
| 
 | |
|   DwordRegs.Ds    = Regs->X.DS;
 | |
|   DwordRegs.Es    = Regs->X.ES;
 | |
|   DwordRegs.Fs    = Regs->X.ES;
 | |
|   DwordRegs.Gs    = Regs->X.ES;
 | |
|   DwordRegs.Ss    = 0xFFFF;
 | |
| 
 | |
|   DwordRegs.Eax   = Regs->X.AX;
 | |
|   DwordRegs.Ebx   = Regs->X.BX;
 | |
|   //
 | |
|   // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
 | |
|   // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
 | |
|   //
 | |
|   DwordRegs.Ecx   = Regs->E.ECX;
 | |
|   DwordRegs.Edx   = Regs->X.DX;
 | |
| 
 | |
|   DwordRegs.Ebp   = Regs->X.BP;
 | |
|   DwordRegs.Eflag = *((UINT16 *) &Regs->X.Flags);
 | |
| 
 | |
|   DwordRegs.Edi   = Regs->X.DI;
 | |
|   DwordRegs.Esi   = Regs->X.SI;
 | |
|   DwordRegs.Esp   = 0xFFFFFFFF;
 | |
| 
 | |
|   EfiIaEntryPoint (IntTypeVariable, &DwordRegs, ((UINTN) Stack + StackSize), StackSize);
 | |
| 
 | |
|   Regs->X.CS  = DwordRegs.Cs;
 | |
| 
 | |
|   Regs->X.DS  = (UINT16) DwordRegs.Ds;
 | |
|   Regs->X.SS  = (UINT16) DwordRegs.Ss;
 | |
| 
 | |
|   Regs->E.EAX  = DwordRegs.Eax;
 | |
|   Regs->E.EBX  = DwordRegs.Ebx;
 | |
|   Regs->E.ECX  = DwordRegs.Ecx;
 | |
|   Regs->E.EDX  = DwordRegs.Edx;
 | |
| 
 | |
|   Regs->E.EBP  = DwordRegs.Ebp;
 | |
|   CopyMem (&Regs->X.Flags, &DwordRegs.Eflag, sizeof (EFI_FLAGS_REG));
 | |
| 
 | |
|   Regs->E.EDI  = DwordRegs.Edi;
 | |
|   Regs->E.ESI  = DwordRegs.Esi;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Template of real mode code.
 | |
| 
 | |
|   @param  CodeStart          Start address of code.
 | |
|   @param  CodeEnd            End address of code
 | |
|   @param  ReverseThunkStart  Start of reverse thunk.
 | |
|   @param  IntThunk           Low memory thunk.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| RealModeTemplate (
 | |
|   OUT UINTN          *CodeStart,
 | |
|   OUT UINTN          *CodeEnd,
 | |
|   OUT UINTN          *ReverseThunkStart,
 | |
|   LOW_MEMORY_THUNK   *IntThunk
 | |
|   )
 | |
| {
 | |
|   SAL_RETURN_REGS SalStatus;
 | |
| 
 | |
|   SalStatus           = EsalGetReverseThunkAddress ();
 | |
| 
 | |
|   *CodeStart          = SalStatus.r9;
 | |
|   *CodeEnd            = SalStatus.r10;
 | |
|   *ReverseThunkStart  = SalStatus.r11;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Allocate memory < 1 MB and copy the thunker code into low memory. Se up
 | |
|   all the descriptors.
 | |
| 
 | |
|   @param  Private            Private context for Legacy BIOS
 | |
| 
 | |
|   @retval EFI_SUCCESS        Should only pass.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LegacyBiosInitializeThunk (
 | |
|   IN  LEGACY_BIOS_INSTANCE    *Private
 | |
|   )
 | |
| {
 | |
|   GDT32               *CodeGdt;
 | |
|   GDT32               *DataGdt;
 | |
|   UINTN             CodeStart;
 | |
|   UINTN             CodeEnd;
 | |
|   UINTN             ReverseThunkStart;
 | |
|   UINT32            Base;
 | |
|   LOW_MEMORY_THUNK  *IntThunk;
 | |
|   UINTN             TempData;
 | |
| 
 | |
|   ASSERT (Private);
 | |
| 
 | |
|   IntThunk = Private->IntThunk;
 | |
| 
 | |
|   //
 | |
|   // Clear the reserved descriptor
 | |
|   //
 | |
|   ZeroMem (&(IntThunk->RealModeGdt[0]), sizeof (GDT32));
 | |
| 
 | |
|   //
 | |
|   // Setup a descriptor for real-mode code
 | |
|   //
 | |
|   CodeGdt = &(IntThunk->RealModeGdt[1]);
 | |
| 
 | |
|   //
 | |
|   // Fill in the descriptor with our real-mode segment value
 | |
|   //
 | |
|   CodeGdt->Type = 0xA;
 | |
|   //
 | |
|   // code/read
 | |
|   //
 | |
|   CodeGdt->System       = 1;
 | |
|   CodeGdt->Dpl          = 0;
 | |
|   CodeGdt->Present      = 1;
 | |
|   CodeGdt->Software     = 0;
 | |
|   CodeGdt->Reserved     = 0;
 | |
|   CodeGdt->DefaultSize  = 0;
 | |
|   //
 | |
|   // 16 bit operands
 | |
|   //
 | |
|   CodeGdt->Granularity  = 0;
 | |
| 
 | |
|   CodeGdt->LimitHi      = 0;
 | |
|   CodeGdt->LimitLo      = 0xffff;
 | |
| 
 | |
|   Base                  = (*((UINT32 *) &IntThunk->Code));
 | |
|   CodeGdt->BaseHi       = (Base >> 24) & 0xFF;
 | |
|   CodeGdt->BaseMid      = (Base >> 16) & 0xFF;
 | |
|   CodeGdt->BaseLo       = Base & 0xFFFF;
 | |
| 
 | |
|   //
 | |
|   // Setup a descriptor for read-mode data
 | |
|   //
 | |
|   DataGdt = &(IntThunk->RealModeGdt[2]);
 | |
|   CopyMem (DataGdt, CodeGdt, sizeof (GDT32));
 | |
| 
 | |
|   DataGdt->Type = 0x2;
 | |
|   //
 | |
|   // read/write data
 | |
|   //
 | |
|   DataGdt->BaseHi = 0x0;
 | |
|   //
 | |
|   // Base = 0
 | |
|   //
 | |
|   DataGdt->BaseMid = 0x0;
 | |
|   //
 | |
|   DataGdt->BaseLo = 0x0;
 | |
|   //
 | |
|   DataGdt->LimitHi = 0x0F;
 | |
|   //
 | |
|   // Limit = 4Gb
 | |
|   //
 | |
|   DataGdt->LimitLo = 0xFFFF;
 | |
|   //
 | |
|   DataGdt->Granularity = 0x1;
 | |
|   //
 | |
|   //
 | |
|   // Compute selector value
 | |
|   //
 | |
|   IntThunk->RealModeGdtDesc.Limit = (UINT16) (sizeof (IntThunk->RealModeGdt) - 1);
 | |
|   CopyMem (&IntThunk->RealModeGdtDesc.Base, (UINT32 *) &IntThunk->RealModeGdt, sizeof (UINT32));
 | |
|   //
 | |
|   //  IntThunk->RealModeGdtDesc.Base = *((UINT32*) &IntThunk->RealModeGdt);
 | |
|   //
 | |
|   IntThunk->RealModeIdtDesc.Limit = 0xFFFF;
 | |
|   IntThunk->RealModeIdtDesc.Base  = 0;
 | |
|   IntThunk->LowCodeSelector       = (UINT32) ((UINTN) CodeGdt - IntThunk->RealModeGdtDesc.Base);
 | |
|   IntThunk->LowDataSelector       = (UINT32) ((UINTN) DataGdt - IntThunk->RealModeGdtDesc.Base);
 | |
| 
 | |
|   //
 | |
|   // Initialize low real-mode code thunk
 | |
|   //
 | |
|   RealModeTemplate (&CodeStart, &CodeEnd, &ReverseThunkStart, IntThunk);
 | |
| 
 | |
|   TempData                        = (UINTN) &(IntThunk->Code);
 | |
|   IntThunk->LowReverseThunkStart  = ((UINT32) TempData + (UINT32) (ReverseThunkStart - CodeStart));
 | |
| 
 | |
|   EsalSetSalDataArea (TempData, (UINTN) IntThunk);
 | |
|   CopyMem (IntThunk->Code, (VOID *) CodeStart, CodeEnd - CodeStart);
 | |
| 
 | |
|   IntThunk->EfiToLegacy16InitTable.ReverseThunkCallSegment = EFI_SEGMENT (*((UINT32 *) &IntThunk->LowReverseThunkStart));
 | |
|   IntThunk->EfiToLegacy16InitTable.ReverseThunkCallOffset = EFI_OFFSET (*((UINT32 *) &IntThunk->LowReverseThunkStart));
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Thunk to 16-bit real mode and execute a software interrupt with a vector
 | |
|   of BiosInt. Regs will contain the 16-bit register context on entry and
 | |
|   exit.
 | |
| 
 | |
|   @param  This               Protocol instance pointer.
 | |
|   @param  BiosInt            Processor interrupt vector to invoke
 | |
|   @param  Regs               Register contexted passed into (and returned) from
 | |
|                              thunk to  16-bit mode
 | |
| 
 | |
|   @retval FALSE              Thunk completed, and there were no BIOS errors in the
 | |
|                              target code. See Regs for status.
 | |
|   @retval TRUE               There was a BIOS erro in the target code.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| LegacyBiosInt86 (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
 | |
|   IN  UINT8                             BiosInt,
 | |
|   IN  EFI_IA32_REGISTER_SET             *Regs
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   LEGACY_BIOS_INSTANCE  *Private;
 | |
|   LOW_MEMORY_THUNK      *IntThunk;
 | |
|   UINT16                *Stack16;
 | |
|   EFI_TPL               OriginalTpl;
 | |
|   UINTN                 IaSegment;
 | |
|   UINTN                 IaOffset;
 | |
|   UINTN                 *Address;
 | |
|   UINTN                 TempData;
 | |
| 
 | |
|   Private   = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
 | |
|   IntThunk  = Private->IntThunk;
 | |
| 
 | |
|   //
 | |
|   // Get the current flat GDT, IDT, and SS and store them in Private->IntThunk.
 | |
|   //
 | |
|   Status = LegacyBiosGetFlatDescs (Private);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Regs->X.Flags.Reserved1 = 1;
 | |
|   Regs->X.Flags.Reserved2 = 0;
 | |
|   Regs->X.Flags.Reserved3 = 0;
 | |
|   Regs->X.Flags.Reserved4 = 0;
 | |
|   Regs->X.Flags.IOPL      = 3;
 | |
|   Regs->X.Flags.NT        = 0;
 | |
|   Regs->X.Flags.IF        = 1;
 | |
|   Regs->X.Flags.TF        = 0;
 | |
|   Regs->X.Flags.CF        = 0;
 | |
|   //
 | |
|   // Clear the error flag; thunk code may set it.
 | |
|   //
 | |
|   Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
 | |
| 
 | |
|   //
 | |
|   // Copy regs to low memory stack
 | |
|   //
 | |
|   Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
 | |
|   CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   //
 | |
|   // Provide low stack esp
 | |
|   //
 | |
|   TempData            = ((UINTN) Stack16) - ((UINTN) IntThunk);
 | |
|   IntThunk->LowStack  = *((UINT32 *) &TempData);
 | |
| 
 | |
|   //
 | |
|   // Stack for reverse thunk flat mode.
 | |
|   //    It must point to top of stack (end of stack space).
 | |
|   //
 | |
|   TempData                = ((UINTN) IntThunk->RevThunkStack) + LOW_STACK_SIZE;
 | |
|   IntThunk->RevFlatStack  = *((UINT32 *) &TempData);
 | |
| 
 | |
|   //
 | |
|   // The call to Legacy16 is a critical section to EFI
 | |
|   //
 | |
|   OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 | |
| 
 | |
|   //
 | |
|   // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
 | |
|   //
 | |
|   Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Call the real mode thunk code
 | |
|   //
 | |
|   TempData  = BiosInt * 4;
 | |
|   Address   = (UINTN *) TempData;
 | |
|   IaOffset  = 0xFFFF & (*Address);
 | |
|   IaSegment = 0xFFFF & ((*Address) >> 16);
 | |
| 
 | |
|   Status = BiosIntCall (
 | |
|             BiosInt,
 | |
|             (UINT16) IaSegment,
 | |
|             (UINT16) IaOffset,
 | |
|             (EFI_IA32_REGISTER_SET *) Stack16,
 | |
|             IntThunk,
 | |
|             IntThunk->LowStack
 | |
|             );
 | |
| 
 | |
|   //
 | |
|   // Check for errors with the thunk
 | |
|   //
 | |
|   switch (Status) {
 | |
|   case THUNK_OK:
 | |
|     break;
 | |
| 
 | |
|   case THUNK_ERR_A20_UNSUP:
 | |
|   case THUNK_ERR_A20_FAILED:
 | |
|   default:
 | |
|     //
 | |
|     // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
 | |
|     //
 | |
|     Regs->X.Flags.CF = 1;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   Status  = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // End critical section
 | |
|   //
 | |
|   gBS->RestoreTPL (OriginalTpl);
 | |
| 
 | |
|   //
 | |
|   // Return the resulting registers
 | |
|   //
 | |
|   CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   return (BOOLEAN) (Regs->X.Flags.CF != 0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
 | |
|   16-bit register context on entry and exit. Arguments can be passed on
 | |
|   the Stack argument
 | |
| 
 | |
|   @param  This               Protocol instance pointer.
 | |
|   @param  Segment            Segemnt of 16-bit mode call
 | |
|   @param  Offset             Offset of 16-bit mdoe call
 | |
|   @param  Regs               Register contexted passed into (and returned) from
 | |
|                              thunk to  16-bit mode
 | |
|   @param  Stack              Caller allocated stack used to pass arguments
 | |
|   @param  StackSize          Size of Stack in bytes
 | |
| 
 | |
|   @retval FALSE              Thunk completed, and there were no BIOS errors in the
 | |
|                              target code. See Regs for status.
 | |
|   @retval TRUE               There was a BIOS erro in the target code.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| LegacyBiosFarCall86 (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
 | |
|   IN  UINT16                            Segment,
 | |
|   IN  UINT16                            Offset,
 | |
|   IN  EFI_IA32_REGISTER_SET             *Regs,
 | |
|   IN  VOID                              *Stack,
 | |
|   IN  UINTN                             StackSize
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   LEGACY_BIOS_INSTANCE  *Private;
 | |
|   LOW_MEMORY_THUNK      *IntThunk;
 | |
|   UINT16                *Stack16;
 | |
|   EFI_TPL               OriginalTpl;
 | |
|   UINTN                 IaSegment;
 | |
|   UINTN                 IaOffset;
 | |
|   UINTN                 TempData;
 | |
| 
 | |
|   Private   = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
 | |
|   IntThunk  = Private->IntThunk;
 | |
|   IaSegment = Segment;
 | |
|   IaOffset  = Offset;
 | |
| 
 | |
|   //
 | |
|   // Get the current flat GDT and IDT and store them in Private->IntThunk.
 | |
|   //
 | |
|   Status = LegacyBiosGetFlatDescs (Private);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Regs->X.Flags.Reserved1 = 1;
 | |
|   Regs->X.Flags.Reserved2 = 0;
 | |
|   Regs->X.Flags.Reserved3 = 0;
 | |
|   Regs->X.Flags.Reserved4 = 0;
 | |
|   Regs->X.Flags.IOPL      = 3;
 | |
|   Regs->X.Flags.NT        = 0;
 | |
|   Regs->X.Flags.IF        = 1;
 | |
|   Regs->X.Flags.TF        = 0;
 | |
|   Regs->X.Flags.CF        = 0;
 | |
|   //
 | |
|   // Clear the error flag; thunk code may set it.
 | |
|   //
 | |
|   Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
 | |
|   if (Stack != NULL && StackSize != 0) {
 | |
|     //
 | |
|     // Copy Stack to low memory stack
 | |
|     //
 | |
|     Stack16 -= StackSize / sizeof (UINT16);
 | |
|     CopyMem (Stack16, Stack, StackSize);
 | |
|   }
 | |
|   //
 | |
|   // Copy regs to low memory stack
 | |
|   //
 | |
|   Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
 | |
|   CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   //
 | |
|   // Provide low stack esp
 | |
|   //
 | |
|   TempData            = ((UINTN) Stack16) - ((UINTN) IntThunk);
 | |
|   IntThunk->LowStack  = *((UINT32 *) &TempData);
 | |
| 
 | |
|   //
 | |
|   // The call to Legacy16 is a critical section to EFI
 | |
|   //
 | |
|   OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 | |
| 
 | |
|   //
 | |
|   // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
 | |
|   //
 | |
|   Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Call the real mode thunk code
 | |
|   //
 | |
|   Status = BiosIntCall (
 | |
|             0x100,
 | |
|             (UINT16) IaSegment,
 | |
|             (UINT16) IaOffset,
 | |
|             (EFI_IA32_REGISTER_SET *) Stack16,
 | |
|             IntThunk,
 | |
|             IntThunk->LowStack
 | |
|             );
 | |
| 
 | |
|   //
 | |
|   // Check for errors with the thunk
 | |
|   //
 | |
|   switch (Status) {
 | |
|   case THUNK_OK:
 | |
|     break;
 | |
| 
 | |
|   case THUNK_ERR_A20_UNSUP:
 | |
|   case THUNK_ERR_A20_FAILED:
 | |
|   default:
 | |
|     //
 | |
|     // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
 | |
|     //
 | |
|     Regs->X.Flags.CF = 1;
 | |
|     break;
 | |
|   }
 | |
|   //
 | |
|   // Restore protected mode interrupt state
 | |
|   //
 | |
|   Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // End critical section
 | |
|   //
 | |
|   gBS->RestoreTPL (OriginalTpl);
 | |
| 
 | |
|   //
 | |
|   // Return the resulting registers
 | |
|   //
 | |
|   CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
 | |
|   Stack16 += sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
 | |
| 
 | |
|   if (Stack != NULL && StackSize != 0) {
 | |
|     //
 | |
|     // Copy low memory stack to Stack
 | |
|     //
 | |
|     CopyMem (Stack, Stack16, StackSize);
 | |
|     Stack16 += StackSize / sizeof (UINT16);
 | |
|   }
 | |
| 
 | |
|   return (BOOLEAN) (Regs->X.Flags.CF != 0);
 | |
| }
 |