mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-03 21:17:23 +01:00 
			
		
		
		
	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);
 | 
						|
}
 |