/** @file

Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef _LEGACY_BIOS_INTERFACE_
#define _LEGACY_BIOS_INTERFACE_


#include <FrameworkDxe.h>
#include <IndustryStandard/Pci.h>
#include <IndustryStandard/SmBios.h>
#include <IndustryStandard/Acpi10.h>

#include <Guid/SmBios.h>
#include <Guid/Acpi.h>
#include <Guid/DxeServices.h>
#include <Guid/LegacyBios.h>
#include <Guid/StatusCodeDataTypeId.h>
#include <Guid/ImageAuthentication.h>

#include <Protocol/BlockIo.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/PciIo.h>
#include <Protocol/Cpu.h>
#include <Protocol/Timer.h>
#include <Protocol/IsaIo.h>
#include <Protocol/LegacyRegion2.h>
#include <Protocol/SimpleTextIn.h>
#include <Protocol/LegacyInterrupt.h>
#include <Protocol/LegacyBios.h>
#include <Protocol/DiskInfo.h>
#include <Protocol/GenericMemoryTest.h>
#include <Protocol/LegacyBiosPlatform.h>
#include <Protocol/DevicePath.h>
#include <Protocol/Legacy8259.h>
#include <Protocol/PciRootBridgeIo.h>
#include <Protocol/SerialIo.h>
#include <Protocol/SuperIo.h>
#include <Protocol/IoMmu.h>

#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/ReportStatusCodeLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/HobLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include <Library/DevicePathLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/DebugAgentLib.h>

//
// BUGBUG: This entry maybe changed to PCD in future and wait for
//         redesign of BDS library
//
#define MAX_BBS_ENTRIES 0x100

//
// Thunk Status Codes
//   (These apply only to errors with the thunk and not to the code that was
//   thunked to.)
//
#define THUNK_OK              0x00
#define THUNK_ERR_A20_UNSUP   0x01
#define THUNK_ERR_A20_FAILED  0x02

//
// Vector base definitions
//
//
// 8259 Hardware definitions
//
#define LEGACY_MODE_BASE_VECTOR_MASTER     0x08
#define LEGACY_MODE_BASE_VECTOR_SLAVE      0x70

//
// The original PC used INT8-F for master PIC. Since these mapped over
// processor exceptions TIANO moved the master PIC to INT68-6F.
//
// The vector base for slave PIC is set as 0x70 for PC-AT compatibility.
//
#define PROTECTED_MODE_BASE_VECTOR_MASTER  0x68
#define PROTECTED_MODE_BASE_VECTOR_SLAVE   0x70

//
// When we call CSM16 functions, some CSM16 use es:[offset + 0xabcd] to get data passed from CSM32,
// offset + 0xabcd could overflow which exceeds 0xFFFF which is invalid in real mode.
// So this will keep offset as small as possible to avoid offset overflow in real mode.
//
#define NORMALIZE_EFI_SEGMENT(_Adr)      (UINT16) (((UINTN) (_Adr)) >> 4)
#define NORMALIZE_EFI_OFFSET(_Adr)       (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xf)

//
// Trace defines
//
//
#define LEGACY_BDA_TRACE    0x000
#define LEGACY_BIOS_TRACE   0x040
#define LEGACY_BOOT_TRACE   0x080
#define LEGACY_CMOS_TRACE   0x0C0
#define LEGACY_IDE_TRACE    0x100
#define LEGACY_MP_TRACE     0x140
#define LEGACY_PCI_TRACE    0x180
#define LEGACY_SIO_TRACE    0x1C0

#define LEGACY_PCI_TRACE_000 LEGACY_PCI_TRACE + 0x00
#define LEGACY_PCI_TRACE_001 LEGACY_PCI_TRACE + 0x01
#define LEGACY_PCI_TRACE_002 LEGACY_PCI_TRACE + 0x02
#define LEGACY_PCI_TRACE_003 LEGACY_PCI_TRACE + 0x03
#define LEGACY_PCI_TRACE_004 LEGACY_PCI_TRACE + 0x04
#define LEGACY_PCI_TRACE_005 LEGACY_PCI_TRACE + 0x05
#define LEGACY_PCI_TRACE_006 LEGACY_PCI_TRACE + 0x06
#define LEGACY_PCI_TRACE_007 LEGACY_PCI_TRACE + 0x07
#define LEGACY_PCI_TRACE_008 LEGACY_PCI_TRACE + 0x08
#define LEGACY_PCI_TRACE_009 LEGACY_PCI_TRACE + 0x09
#define LEGACY_PCI_TRACE_00A LEGACY_PCI_TRACE + 0x0A
#define LEGACY_PCI_TRACE_00B LEGACY_PCI_TRACE + 0x0B
#define LEGACY_PCI_TRACE_00C LEGACY_PCI_TRACE + 0x0C
#define LEGACY_PCI_TRACE_00D LEGACY_PCI_TRACE + 0x0D
#define LEGACY_PCI_TRACE_00E LEGACY_PCI_TRACE + 0x0E
#define LEGACY_PCI_TRACE_00F LEGACY_PCI_TRACE + 0x0F

#define BDA_VIDEO_MODE      0x49

#define IDE_PI_REGISTER_PNE     BIT0
#define IDE_PI_REGISTER_SNE     BIT2

typedef struct {
  UINTN   PciSegment;
  UINTN   PciBus;
  UINTN   PciDevice;
  UINTN   PciFunction;
  UINT32  ShadowAddress;
  UINT32  ShadowedSize;
  UINT8   DiskStart;
  UINT8   DiskEnd;
} ROM_INSTANCE_ENTRY;

//
// Values for RealModeGdt
//
#if defined (MDE_CPU_IA32)

#define NUM_REAL_GDT_ENTRIES  3
#define CONVENTIONAL_MEMORY_TOP 0xA0000   // 640 KB
#define INITIAL_VALUE_BELOW_1K  0x0

#elif defined (MDE_CPU_X64)

#define NUM_REAL_GDT_ENTRIES  8
#define CONVENTIONAL_MEMORY_TOP 0xA0000   // 640 KB
#define INITIAL_VALUE_BELOW_1K  0x0

#endif

#pragma pack(1)

//
// Define what a processor GDT looks like
//
typedef struct {
  UINT32  LimitLo : 16;
  UINT32  BaseLo : 16;
  UINT32  BaseMid : 8;
  UINT32  Type : 4;
  UINT32  System : 1;
  UINT32  Dpl : 2;
  UINT32  Present : 1;
  UINT32  LimitHi : 4;
  UINT32  Software : 1;
  UINT32  Reserved : 1;
  UINT32  DefaultSize : 1;
  UINT32  Granularity : 1;
  UINT32  BaseHi : 8;
} GDT32;

typedef struct {
  UINT16  LimitLow;
  UINT16  BaseLow;
  UINT8   BaseMid;
  UINT8   Attribute;
  UINT8   LimitHi;
  UINT8   BaseHi;
} GDT64;

//
// Define what a processor descriptor looks like
// This data structure must be kept in sync with ASM STRUCT in Thunk.inc
//
typedef struct {
  UINT16  Limit;
  UINT64  Base;
} DESCRIPTOR64;

typedef struct {
  UINT16  Limit;
  UINT32  Base;
} DESCRIPTOR32;

//
// Low stub lay out
//
#define LOW_STACK_SIZE      (8 * 1024)  // 8k?
#define EFI_MAX_E820_ENTRY  100
#define FIRST_INSTANCE      1
#define NOT_FIRST_INSTANCE  0

#if defined (MDE_CPU_IA32)
typedef struct {
  //
  // Space for the code
  //  The address of Code is also the beginning of the relocated Thunk code
  //
  CHAR8                             Code[4096]; // ?
  //
  // The address of the Reverse Thunk code
  //  Note that this member CONTAINS the address of the relocated reverse thunk
  //  code unlike the member variable 'Code', which IS the address of the Thunk
  //  code.
  //
  UINT32                            LowReverseThunkStart;

  //
  // Data for the code (cs releative)
  //
  DESCRIPTOR32                      GdtDesc;          // Protected mode GDT
  DESCRIPTOR32                      IdtDesc;          // Protected mode IDT
  UINT32                            FlatSs;
  UINT32                            FlatEsp;

  UINT32                            LowCodeSelector;  // Low code selector in GDT
  UINT32                            LowDataSelector;  // Low data selector in GDT
  UINT32                            LowStack;
  DESCRIPTOR32                      RealModeIdtDesc;

  //
  // real-mode GDT (temporary GDT with two real mode segment descriptors)
  //
  GDT32                             RealModeGdt[NUM_REAL_GDT_ENTRIES];
  DESCRIPTOR32                      RealModeGdtDesc;

  //
  // Members specifically for the reverse thunk
  //  The RevReal* members are used to store the current state of real mode
  //  before performing the reverse thunk.  The RevFlat* members must be set
  //  before calling the reverse thunk assembly code.
  //
  UINT16                            RevRealDs;
  UINT16                            RevRealSs;
  UINT32                            RevRealEsp;
  DESCRIPTOR32                      RevRealIdtDesc;
  UINT16                            RevFlatDataSelector;  // Flat data selector in GDT
  UINT32                            RevFlatStack;

  //
  // A low memory stack
  //
  CHAR8                             Stack[LOW_STACK_SIZE];

  //
  // Stack for flat mode after reverse thunk
  // @bug    - This may no longer be necessary if the reverse thunk interface
  //           is changed to have the flat stack in a different location.
  //
  CHAR8                             RevThunkStack[LOW_STACK_SIZE];

  //
  // Legacy16 Init memory map info
  //
  EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;

  EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;

  CHAR8                             InterruptRedirectionCode[32];
  EFI_LEGACY_INSTALL_PCI_HANDLER    PciHandler;
  EFI_DISPATCH_OPROM_TABLE          DispatchOpromTable;
  BBS_TABLE                         BbsTable[MAX_BBS_ENTRIES];
} LOW_MEMORY_THUNK;

#elif defined (MDE_CPU_X64)

typedef struct {
  //
  // Space for the code
  //  The address of Code is also the beginning of the relocated Thunk code
  //
  CHAR8                             Code[4096]; // ?

  //
  // Data for the code (cs releative)
  //
  DESCRIPTOR64                      X64GdtDesc;          // Protected mode GDT
  DESCRIPTOR64                      X64IdtDesc;          // Protected mode IDT
  UINTN                             X64Ss;
  UINTN                             X64Esp;

  UINTN                             RealStack;
  DESCRIPTOR32                      RealModeIdtDesc;
  DESCRIPTOR32                      RealModeGdtDesc;

  //
  // real-mode GDT (temporary GDT with two real mode segment descriptors)
  //
  GDT64                             RealModeGdt[NUM_REAL_GDT_ENTRIES];
  UINT64                            PageMapLevel4;

  //
  // A low memory stack
  //
  CHAR8                             Stack[LOW_STACK_SIZE];

  //
  // Legacy16 Init memory map info
  //
  EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;

  EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;

  CHAR8                             InterruptRedirectionCode[32];
  EFI_LEGACY_INSTALL_PCI_HANDLER    PciHandler;
  EFI_DISPATCH_OPROM_TABLE          DispatchOpromTable;
  BBS_TABLE                         BbsTable[MAX_BBS_ENTRIES];
} LOW_MEMORY_THUNK;

#endif

//
// PnP Expansion Header
//
typedef struct {
  UINT32  PnpSignature;
  UINT8   Revision;
  UINT8   Length;
  UINT16  NextHeader;
  UINT8   Reserved1;
  UINT8   Checksum;
  UINT32  DeviceId;
  UINT16  MfgPointer;
  UINT16  ProductNamePointer;
  UINT8   Class;
  UINT8   SubClass;
  UINT8   Interface;
  UINT8   DeviceIndicators;
  UINT16  Bcv;
  UINT16  DisconnectVector;
  UINT16  Bev;
  UINT16  Reserved2;
  UINT16  StaticResourceVector;
} LEGACY_PNP_EXPANSION_HEADER;

typedef struct {
  UINT8   PciSegment;
  UINT8   PciBus;
  UINT8   PciDevice;
  UINT8   PciFunction;
  UINT16  Vid;
  UINT16  Did;
  UINT16  SysSid;
  UINT16  SVid;
  UINT8   Class;
  UINT8   SubClass;
  UINT8   Interface;
  UINT8   Reserved;
  UINTN   RomStart;
  UINTN   ManufacturerString;
  UINTN   ProductNameString;
} LEGACY_ROM_AND_BBS_TABLE;

//
// Structure how EFI has mapped a devices HDD drive numbers.
// Boot to EFI aware OS or shell requires this mapping when
// 16-bit CSM assigns drive numbers.
// This mapping is ignored booting to a legacy OS.
//
typedef struct {
  UINT8 PciSegment;
  UINT8 PciBus;
  UINT8 PciDevice;
  UINT8 PciFunction;
  UINT8 StartDriveNumber;
  UINT8 EndDriveNumber;
} LEGACY_EFI_HDD_TABLE;

//
// This data is passed to Leacy16Boot
//
typedef enum {
  EfiAcpiAddressRangeMemory   = 1,
  EfiAcpiAddressRangeReserved = 2,
  EfiAcpiAddressRangeACPI     = 3,
  EfiAcpiAddressRangeNVS      = 4,
  EfiAddressRangePersistentMemory = 7
} EFI_ACPI_MEMORY_TYPE;

typedef struct {
  UINT64                BaseAddr;
  UINT64                Length;
  EFI_ACPI_MEMORY_TYPE  Type;
} EFI_E820_ENTRY64;

typedef struct {
  UINT32                BassAddrLow;
  UINT32                BaseAddrHigh;
  UINT32                LengthLow;
  UINT32                LengthHigh;
  EFI_ACPI_MEMORY_TYPE  Type;
} EFI_E820_ENTRY;

#pragma pack()

extern BBS_TABLE           *mBbsTable;

extern EFI_GENERIC_MEMORY_TEST_PROTOCOL *gGenMemoryTest;

extern BOOLEAN mEndOfDxe;

#define PORT_70 0x70
#define PORT_71 0x71

#define CMOS_0A     0x0a  ///< Status register A
#define CMOS_0D     0x0d  ///< Status register D
#define CMOS_0E     0x0e  ///< Diagnostic Status
#define CMOS_0F     0x0f  ///< Shutdown status
#define CMOS_10     0x10  ///< Floppy type
#define CMOS_12     0x12  ///< IDE type
#define CMOS_14     0x14  ///< Same as BDA 40:10
#define CMOS_15     0x15  ///< Low byte of base memory in 1k increments
#define CMOS_16     0x16  ///< High byte of base memory in 1k increments
#define CMOS_17     0x17  ///< Low byte of 1MB+ memory in 1k increments - max 15 MB
#define CMOS_18     0x18  ///< High byte of 1MB+ memory in 1k increments - max 15 MB
#define CMOS_19     0x19  ///< C: extended drive type
#define CMOS_1A     0x1a  ///< D: extended drive type
#define CMOS_2E     0x2e  ///< Most significient byte of standard checksum
#define CMOS_2F     0x2f  ///< Least significient byte of standard checksum
#define CMOS_30     0x30  ///< CMOS 0x17
#define CMOS_31     0x31  ///< CMOS 0x18
#define CMOS_32     0x32  ///< Century byte

//
// 8254 Timer registers
//
#define TIMER0_COUNT_PORT                         0x40
#define TIMER1_COUNT_PORT                         0x41
#define TIMER2_COUNT_PORT                         0x42
#define TIMER_CONTROL_PORT                        0x43

//
// Timer 0, Read/Write LSB then MSB, Square wave output, binary count use.
//
#define TIMER0_CONTROL_WORD         0x36

#define LEGACY_BIOS_INSTANCE_SIGNATURE  SIGNATURE_32 ('L', 'B', 'I', 'T')
typedef struct {
  UINTN                             Signature;

  EFI_HANDLE                        Handle;
  EFI_LEGACY_BIOS_PROTOCOL          LegacyBios;

  EFI_HANDLE                        ImageHandle;

  //
  // CPU Architectural Protocol
  //
  EFI_CPU_ARCH_PROTOCOL             *Cpu;

  //
  // Timer Architectural Protocol
  //
  EFI_TIMER_ARCH_PROTOCOL           *Timer;
  BOOLEAN                           TimerUses8254;

  //
  // Protocol to Lock and Unlock 0xc0000 - 0xfffff
  //
  EFI_LEGACY_REGION2_PROTOCOL       *LegacyRegion;

  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;

  //
  // Interrupt control for thunk and PCI IRQ
  //
  EFI_LEGACY_8259_PROTOCOL          *Legacy8259;

  //
  // PCI Interrupt PIRQ control
  //
  EFI_LEGACY_INTERRUPT_PROTOCOL     *LegacyInterrupt;

  //
  // Generic Memory Test
  //
  EFI_GENERIC_MEMORY_TEST_PROTOCOL  *GenericMemoryTest;

  //
  // TRUE if PCI Interupt Line registers have been programmed.
  //
  BOOLEAN                           PciInterruptLine;

  //
  // Code space below 1MB needed by thunker to transition to real mode.
  // Contains stack and real mode code fragments
  //
  LOW_MEMORY_THUNK                  *IntThunk;

  //
  // Starting shadow address of the Legacy BIOS
  //
  UINT32                            BiosStart;
  UINT32                            LegacyBiosImageSize;

  //
  // Start of variables used by CsmItp.mac ITP macro file and/os LegacyBios
  //
  UINT8                             Dump[4];

  //
  // $EFI Legacy16 code entry info in memory < 1 MB;
  //
  EFI_COMPATIBILITY16_TABLE         *Legacy16Table;
  VOID                              *Legacy16InitPtr;
  VOID                              *Legacy16BootPtr;
  VOID                              *InternalIrqRoutingTable;
  UINT32                            NumberIrqRoutingEntries;
  VOID                              *BbsTablePtr;
  VOID                              *HddTablePtr;
  UINT32                            NumberHddControllers;

  //
  // Cached copy of Legacy16 entry point
  //
  UINT16                            Legacy16CallSegment;
  UINT16                            Legacy16CallOffset;

  //
  // Returned from $EFI and passed in to OPROMS
  //
  UINT16                            PnPInstallationCheckSegment;
  UINT16                            PnPInstallationCheckOffset;

  //
  // E820 table
  //
  EFI_E820_ENTRY                    E820Table[EFI_MAX_E820_ENTRY];
  UINT32                            NumberE820Entries;

  //
  // True if legacy VGA INT 10h handler installed
  //
  BOOLEAN                           VgaInstalled;

  //
  // Number of IDE drives
  //
  UINT8                             IdeDriveCount;

  //
  // Current Free Option ROM space. An option ROM must NOT go past
  // BiosStart.
  //
  UINT32                            OptionRom;

  //
  // Save Legacy16 unexpected interrupt vector. Reprogram INT 68-6F from
  // EFI values to legacy value just before boot.
  //
  UINT32                            BiosUnexpectedInt;
  UINT32                            ThunkSavedInt[8];
  UINT16                            ThunkSeg;
  LEGACY_EFI_HDD_TABLE              *LegacyEfiHddTable;
  UINT16                            LegacyEfiHddTableIndex;
  UINT8                             DiskEnd;
  UINT8                             Disk4075;
  UINT16                            TraceIndex;
  UINT16                            Trace[0x200];

  //
  // Indicate that whether GenericLegacyBoot is entered or not
  //
  BOOLEAN                           LegacyBootEntered;

  //
  // CSM16 PCI Interface Version
  //
  UINT16                            Csm16PciInterfaceVersion;

} LEGACY_BIOS_INSTANCE;


#pragma pack(1)

/*
  40:00-01 Com1
  40:02-03 Com2
  40:04-05 Com3
  40:06-07 Com4
  40:08-09 Lpt1
  40:0A-0B Lpt2
  40:0C-0D Lpt3
  40:0E-0E Ebda segment
  40:10-11 MachineConfig
  40:12    Bda12 - skip
  40:13-14 MemSize below 1MB
  40:15-16 Bda15_16 - skip
  40:17    Keyboard Shift status
  40:18-19 Bda18_19 - skip
  40:1A-1B Key buffer head
  40:1C-1D Key buffer tail
  40:1E-3D Bda1E_3D- key buffer -skip
  40:3E-3F FloppyData 3E = Calibration status 3F = Motor status
  40:40    FloppyTimeout
  40:41-74 Bda41_74 - skip
  40:75    Number of HDD drives
  40:76-77 Bda76_77 - skip
  40:78-79 78 = Lpt1 timeout, 79 = Lpt2 timeout
  40:7A-7B 7A = Lpt3 timeout, 7B = Lpt4 timeout
  40:7C-7D 7C = Com1 timeout, 7D = Com2 timeout
  40:7E-7F 7E = Com3 timeout, 7F = Com4 timeout
  40:80-81 Pointer to start of key buffer
  40:82-83 Pointer to end of key buffer
  40:84-87 Bda84_87 - skip
  40:88    HDD Data Xmit rate
  40:89-8f skip
  40:90    Floppy data rate
  40:91-95 skip
  40:96    Keyboard Status
  40:97    LED Status
  40:98-101 skip
*/
typedef struct {
  UINT16  Com1;
  UINT16  Com2;
  UINT16  Com3;
  UINT16  Com4;
  UINT16  Lpt1;
  UINT16  Lpt2;
  UINT16  Lpt3;
  UINT16  Ebda;
  UINT16  MachineConfig;
  UINT8   Bda12;
  UINT16  MemSize;
  UINT8   Bda15_16[0x02];
  UINT8   ShiftStatus;
  UINT8   Bda18_19[0x02];
  UINT16  KeyHead;
  UINT16  KeyTail;
  UINT16  Bda1E_3D[0x10];
  UINT16  FloppyData;
  UINT8   FloppyTimeout;
  UINT8   Bda41_74[0x34];
  UINT8   NumberOfDrives;
  UINT8   Bda76_77[0x02];
  UINT16  Lpt1_2Timeout;
  UINT16  Lpt3_4Timeout;
  UINT16  Com1_2Timeout;
  UINT16  Com3_4Timeout;
  UINT16  KeyStart;
  UINT16  KeyEnd;
  UINT8   Bda84_87[0x4];
  UINT8   DataXmit;
  UINT8   Bda89_8F[0x07];
  UINT8   FloppyXRate;
  UINT8   Bda91_95[0x05];
  UINT8   KeyboardStatus;
  UINT8   LedStatus;
} BDA_STRUC;
#pragma pack()

#define LEGACY_BIOS_INSTANCE_FROM_THIS(this)  CR (this, LEGACY_BIOS_INSTANCE, LegacyBios, LEGACY_BIOS_INSTANCE_SIGNATURE)

/**
  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
  );


/**
  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
  );


/**
  Test to see if a legacy PCI ROM exists for this device. Optionally return
  the Legacy ROM instance for this PCI device.

  @param  This                   Protocol instance pointer.
  @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
                                 be loaded
  @param  RomImage               Return the legacy PCI ROM for this device
  @param  RomSize                Size of ROM Image
  @param  Flags                  Indicates if ROM found and if PC-AT.

  @retval EFI_SUCCESS            Legacy Option ROM available for this device
  @retval EFI_UNSUPPORTED        Legacy Option ROM not supported.

**/
EFI_STATUS
EFIAPI
LegacyBiosCheckPciRom (
  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,
  IN  EFI_HANDLE                        PciHandle,
  OUT VOID                              **RomImage, OPTIONAL
  OUT UINTN                             *RomSize, OPTIONAL
  OUT UINTN                             *Flags
  );


/**
  Assign drive number to legacy HDD drives prior to booting an EFI
  aware OS so the OS can access drives without an EFI driver.
  Note: BBS compliant drives ARE NOT available until this call by
  either shell or EFI.

  @param  This                   Protocol instance pointer.
  @param  BbsCount               Number of BBS_TABLE structures
  @param  BbsTable               List BBS entries

  @retval EFI_SUCCESS            Drive numbers assigned

**/
EFI_STATUS
EFIAPI
LegacyBiosPrepareToBootEfi (
  IN EFI_LEGACY_BIOS_PROTOCOL         *This,
  OUT UINT16                          *BbsCount,
  OUT BBS_TABLE                       **BbsTable
  );


/**
  To boot from an unconventional device like parties and/or execute
  HDD diagnostics.

  @param  This                   Protocol instance pointer.
  @param  Attributes             How to interpret the other input parameters
  @param  BbsEntry               The 0-based index into the BbsTable for the parent
                                  device.
  @param  BeerData               Pointer to the 128 bytes of ram BEER data.
  @param  ServiceAreaData        Pointer to the 64 bytes of raw Service Area data.
                                 The caller must provide a pointer to the specific
                                 Service Area and not the start all Service Areas.
 EFI_INVALID_PARAMETER if error. Does NOT return if no error.

**/
EFI_STATUS
EFIAPI
LegacyBiosBootUnconventionalDevice (
  IN EFI_LEGACY_BIOS_PROTOCOL         *This,
  IN UDC_ATTRIBUTES                   Attributes,
  IN UINTN                            BbsEntry,
  IN VOID                             *BeerData,
  IN VOID                             *ServiceAreaData
  );


/**
  Load a legacy PC-AT OPROM on the PciHandle device. Return information
  about how many disks were added by the OPROM and the shadow address and
  size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:

  @param  This                   Protocol instance pointer.
  @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
                                 be loaded. This value is NULL if RomImage is
                                 non-NULL. This is the normal case.
  @param  RomImage               A PCI PC-AT ROM image. This argument is non-NULL
                                 if there is no hardware associated with the ROM
                                 and thus no PciHandle, otherwise is must be NULL.
                                 Example is PXE base code.
  @param  Flags                  Indicates if ROM found and if PC-AT.
  @param  DiskStart              Disk number of first device hooked by the ROM. If
                                 DiskStart is the same as DiskEnd no disked were
                                 hooked.
  @param  DiskEnd                Disk number of the last device hooked by the ROM.
  @param  RomShadowAddress       Shadow address of PC-AT ROM
  @param  RomShadowedSize        Size of RomShadowAddress in bytes

  @retval EFI_SUCCESS            Legacy ROM loaded for this device
  @retval EFI_INVALID_PARAMETER  PciHandle not found
  @retval EFI_UNSUPPORTED        There is no PCI ROM in the ROM BAR or no onboard
                                 ROM

**/
EFI_STATUS
EFIAPI
LegacyBiosInstallPciRom (
  IN  EFI_LEGACY_BIOS_PROTOCOL          * This,
  IN  EFI_HANDLE                        PciHandle,
  IN  VOID                              **RomImage,
  OUT UINTN                             *Flags,
  OUT UINT8                             *DiskStart, OPTIONAL
  OUT UINT8                             *DiskEnd, OPTIONAL
  OUT VOID                              **RomShadowAddress, OPTIONAL
  OUT UINT32                            *RomShadowedSize OPTIONAL
  );


/**
  Fill in the standard BDA for Keyboard LEDs

  @param  This                   Protocol instance pointer.
  @param  Leds                   Current LED status

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
EFIAPI
LegacyBiosUpdateKeyboardLedStatus (
  IN EFI_LEGACY_BIOS_PROTOCOL           *This,
  IN UINT8                              Leds
  );


/**
  Get all BBS info

  @param  This                   Protocol instance pointer.
  @param  HddCount               Number of HDD_INFO structures
  @param  HddInfo                Onboard IDE controller information
  @param  BbsCount               Number of BBS_TABLE structures
  @param  BbsTable               List BBS entries

  @retval EFI_SUCCESS            Tables returned
  @retval EFI_NOT_FOUND          resource not found
  @retval EFI_DEVICE_ERROR       can not get BBS table

**/
EFI_STATUS
EFIAPI
LegacyBiosGetBbsInfo (
  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,
  OUT UINT16                            *HddCount,
  OUT HDD_INFO                          **HddInfo,
  OUT UINT16                            *BbsCount,
  OUT BBS_TABLE                         **BbsTable
  );


/**
  Shadow all legacy16 OPROMs that haven't been shadowed.
  Warning: Use this with caution. This routine disconnects all EFI
  drivers. If used externally then caller must re-connect EFI
  drivers.

  @param  This                   Protocol instance pointer.

  @retval EFI_SUCCESS            OPROMs shadowed

**/
EFI_STATUS
EFIAPI
LegacyBiosShadowAllLegacyOproms (
  IN EFI_LEGACY_BIOS_PROTOCOL   *This
  );


/**
  Attempt to legacy boot the BootOption. If the EFI contexted has been
  compromised this function will not return.

  @param  This                   Protocol instance pointer.
  @param  BbsDevicePath          EFI Device Path from BootXXXX variable.
  @param  LoadOptionsSize        Size of LoadOption in size.
  @param  LoadOptions            LoadOption from BootXXXX variable

  @retval EFI_SUCCESS            Removable media not present

**/
EFI_STATUS
EFIAPI
LegacyBiosLegacyBoot (
  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,
  IN  BBS_BBS_DEVICE_PATH               *BbsDevicePath,
  IN  UINT32                            LoadOptionsSize,
  IN  VOID                              *LoadOptions
  );


/**
  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
  );


/**
  Fill in the standard BDA and EBDA stuff before Legacy16 load

  @param  Private                Legacy BIOS Instance data

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
LegacyBiosInitBda (
  IN  LEGACY_BIOS_INSTANCE    *Private
  );


/**
  Collect IDE Inquiry data from the IDE disks

  @param  Private                Legacy BIOS Instance data
  @param  HddInfo                Hdd Information
  @param  Flag                   Reconnect IdeController or not

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
LegacyBiosBuildIdeData (
  IN  LEGACY_BIOS_INSTANCE      *Private,
  IN  HDD_INFO                  **HddInfo,
  IN  UINT16                    Flag
  );


/**
  Enable ide controller.  This gets disabled when LegacyBoot.c is about
  to run the Option ROMs.

  @param  Private                Legacy BIOS Instance data


**/
VOID
EnableIdeController (
  IN LEGACY_BIOS_INSTANCE       *Private
  );


/**
  If the IDE channel is in compatibility (legacy) mode, remove all
  PCI I/O BAR addresses from the controller.

  @param  IdeController          The handle of target IDE controller


**/
VOID
InitLegacyIdeController (
  IN EFI_HANDLE                 IdeController
  );


/**
  Program the interrupt routing register in all the PCI devices. On a PC AT system
  this register contains the 8259 IRQ vector that matches it's PCI interrupt.

  @param  Private                Legacy  BIOS Instance data

  @retval EFI_SUCCESS            Succeed.
  @retval EFI_ALREADY_STARTED    All PCI devices have been processed.

**/
EFI_STATUS
PciProgramAllInterruptLineRegisters (
  IN  LEGACY_BIOS_INSTANCE      *Private
  );


/**
  Collect EFI Info about legacy devices.

  @param  Private                Legacy BIOS Instance data

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
LegacyBiosBuildSioData (
  IN  LEGACY_BIOS_INSTANCE      *Private
  );


/**
  Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
  to chose the order. Skip any devices that have already have legacy
  BIOS run.

  @param  Private                Protocol instance pointer.

  @retval EFI_SUCCESS            Succeed.
  @retval EFI_UNSUPPORTED        Cannot get VGA device handle.

**/
EFI_STATUS
PciShadowRoms (
  IN  LEGACY_BIOS_INSTANCE      *Private
  );


/**
  Fill in the standard BDA and EBDA stuff prior to legacy Boot

  @param  Private                Legacy BIOS Instance data

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
LegacyBiosCompleteBdaBeforeBoot (
  IN  LEGACY_BIOS_INSTANCE    *Private
  );


/**
  Fill in the standard CMOS stuff before Legacy16 load

  @param  Private                Legacy BIOS Instance data

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
LegacyBiosInitCmos (
  IN  LEGACY_BIOS_INSTANCE    *Private
  );


/**
  Fill in the standard CMOS stuff prior to legacy Boot

  @param  Private                Legacy BIOS Instance data

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
LegacyBiosCompleteStandardCmosBeforeBoot (
  IN  LEGACY_BIOS_INSTANCE    *Private
  );


/**
  Contains the code that is copied into low memory (below 640K).
  This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
  This template must be copied into low memory, and the IDT entries
  0x68-0x6F must be point to the low memory copy of this code.  Each
  entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
  computed.

**/
VOID
InterruptRedirectionTemplate (
  VOID
  );


/**
  Build the E820 table.

  @param  Private                Legacy BIOS Instance data
  @param  Size                   Size of E820 Table

  @retval EFI_SUCCESS            It should always work.

**/
EFI_STATUS
LegacyBiosBuildE820 (
  IN  LEGACY_BIOS_INSTANCE    *Private,
  OUT UINTN                   *Size
  );

/**
  This function is to put all AP in halt state.

  @param  Private                Legacy BIOS Instance data

**/
VOID
ShutdownAPs (
  IN LEGACY_BIOS_INSTANCE              *Private
  );

/**
  Worker function for LegacyBiosGetFlatDescs, retrieving content of
  specific registers.

  @param  IntThunk  Pointer to IntThunk of Legacy BIOS context.

**/
VOID
GetRegisters (
  LOW_MEMORY_THUNK    *IntThunk
  );

/**
  Routine for calling real thunk code.

  @param  RealCode    The address of thunk code.
  @param  BiosInt     The Bios interrupt vector number.
  @param  CallAddress The address of 16-bit mode call.

  @return  Status returned by real thunk code

**/
UINTN
CallRealThunkCode (
  UINT8               *RealCode,
  UINT8               BiosInt,
  UINT32              CallAddress
  );

/**
  Routine for generating soft interrupt.

  @param Vector  The interrupt vector number.

**/
VOID
GenerateSoftInit (
  UINT8               Vector
  );

/**
  Allocate memory for legacy usage.

  @param  AllocateType               The type of allocation to perform.
  @param  MemoryType                 The type of memory to allocate.
  @param  StartPageAddress           Start address of range
  @param  Pages                      Number of pages to allocate
  @param  Result                     Result of allocation

  @retval EFI_SUCCESS                Legacy16 code loaded
  @retval Other                      No protocol installed, unload driver.

**/
EFI_STATUS
AllocateLegacyMemory (
  IN  EFI_ALLOCATE_TYPE         AllocateType,
  IN  EFI_MEMORY_TYPE           MemoryType,
  IN  EFI_PHYSICAL_ADDRESS      StartPageAddress,
  IN  UINTN                     Pages,
  OUT EFI_PHYSICAL_ADDRESS      *Result
  );

/**
  Get a region from the LegacyBios for Tiano usage. Can only be invoked once.

  @param  This                       Protocol instance pointer.
  @param  LegacyMemorySize           Size of required region
  @param  Region                     Region to use. 00 = Either 0xE0000 or 0xF0000
                                     block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
                                     block
  @param  Alignment                  Address alignment. Bit mapped. First non-zero
                                     bit from right is alignment.
  @param  LegacyMemoryAddress        Region Assigned

  @retval EFI_SUCCESS                Region assigned
  @retval EFI_ACCESS_DENIED          Procedure previously invoked
  @retval Other                      Region not assigned

**/
EFI_STATUS
EFIAPI
LegacyBiosGetLegacyRegion (
  IN    EFI_LEGACY_BIOS_PROTOCOL *This,
  IN    UINTN                    LegacyMemorySize,
  IN    UINTN                    Region,
  IN    UINTN                    Alignment,
  OUT   VOID                     **LegacyMemoryAddress
  );

/**
  Get a region from the LegacyBios for Tiano usage. Can only be invoked once.

  @param  This                       Protocol instance pointer.
  @param  LegacyMemorySize           Size of data to copy
  @param  LegacyMemoryAddress        Legacy Region destination address Note: must
                                     be in region assigned by
                                     LegacyBiosGetLegacyRegion
  @param  LegacyMemorySourceAddress  Source of data

  @retval EFI_SUCCESS                Region assigned
  @retval EFI_ACCESS_DENIED          Destination outside assigned region

**/
EFI_STATUS
EFIAPI
LegacyBiosCopyLegacyRegion (
  IN EFI_LEGACY_BIOS_PROTOCOL *This,
  IN    UINTN                 LegacyMemorySize,
  IN    VOID                  *LegacyMemoryAddress,
  IN    VOID                  *LegacyMemorySourceAddress
  );

/**
  Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
  the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
  been shadowed.

  @param  Private                    Legacy BIOS context data

  @retval EFI_SUCCESS                Legacy16 code loaded
  @retval Other                      No protocol installed, unload driver.

**/
EFI_STATUS
ShadowAndStartLegacy16 (
  IN  LEGACY_BIOS_INSTANCE  *Private
  );

/**
  Checks the state of the floppy and if media is inserted.

  This routine checks the state of the floppy and if media is inserted.
  There are 3 cases:
  No floppy present         - Set BBS entry to ignore
  Floppy present & no media - Set BBS entry to lowest priority. We cannot
  set it to ignore since 16-bit CSM will
  indicate no floppy and thus drive A: is
  unusable. CSM-16 will not try floppy since
  lowest priority and thus not incur boot
  time penality.
  Floppy present & media    - Set BBS entry to some priority.

  @return  State of floppy media

**/
UINT8
HasMediaInFloppy (
  VOID
  );

/**
  Identify drive data must be updated to actual parameters before boot.
  This requires updating the checksum, if it exists.

  @param  IdentifyDriveData       ATA Identify Data
  @param  Checksum                checksum of the ATA Identify Data

  @retval EFI_SUCCESS             checksum calculated
  @retval EFI_SECURITY_VIOLATION  IdentifyData invalid

**/
EFI_STATUS
CalculateIdentifyDriveChecksum (
  IN  UINT8     *IdentifyDriveData,
  OUT UINT8     *Checksum
  );

/**
  Identify drive data must be updated to actual parameters before boot.

  @param  IdentifyDriveData       ATA Identify Data

**/
VOID
UpdateIdentifyDriveData (
  IN  UINT8     *IdentifyDriveData
  );

/**
  Complete build of BBS TABLE.

  @param  Private                 Legacy BIOS Instance data
  @param  BbsTable                BBS Table passed to 16-bit code

  @retval EFI_SUCCESS             Removable media not present

**/
EFI_STATUS
LegacyBiosBuildBbs (
  IN  LEGACY_BIOS_INSTANCE      *Private,
  IN  BBS_TABLE                 *BbsTable
  );

/**
  Read CMOS register through index/data port.

  @param[in]  Index   The index of the CMOS register to read.

  @return  The data value from the CMOS register specified by Index.

**/
UINT8
LegacyReadStandardCmos (
  IN UINT8  Index
  );

/**
  Write CMOS register through index/data port.

  @param[in]  Index  The index of the CMOS register to write.
  @param[in]  Value  The value of CMOS register to write.

  @return  The value written to the CMOS register specified by Index.

**/
UINT8
LegacyWriteStandardCmos (
  IN UINT8  Index,
  IN UINT8  Value
  );

/**
  Calculate the new standard CMOS checksum and write it.

  @param  Private      Legacy BIOS Instance data

  @retval EFI_SUCCESS  Calculate 16-bit checksum successfully

**/
EFI_STATUS
LegacyCalculateWriteStandardCmosChecksum (
  VOID
  );

/**
  Test to see if a legacy PCI ROM exists for this device. Optionally return
  the Legacy ROM instance for this PCI device.

  @param[in]  This                   Protocol instance pointer.
  @param[in]  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will be loaded
  @param[out] RomImage               Return the legacy PCI ROM for this device
  @param[out] RomSize                Size of ROM Image
  @param[out] RuntimeImageLength     Runtime size of ROM Image
  @param[out] Flags                  Indicates if ROM found and if PC-AT.
  @param[out] OpromRevision          Revision of the PCI Rom
  @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header

  @return EFI_SUCCESS            Legacy Option ROM available for this device
  @return EFI_ALREADY_STARTED    This device is already managed by its Oprom
  @return EFI_UNSUPPORTED        Legacy Option ROM not supported.

**/
EFI_STATUS
LegacyBiosCheckPciRomEx (
  IN EFI_LEGACY_BIOS_PROTOCOL           *This,
  IN  EFI_HANDLE                        PciHandle,
  OUT VOID                              **RomImage, OPTIONAL
  OUT UINTN                             *RomSize, OPTIONAL
  OUT UINTN                             *RuntimeImageLength, OPTIONAL
  OUT UINTN                             *Flags, OPTIONAL
  OUT UINT8                             *OpromRevision, OPTIONAL
  OUT VOID                              **ConfigUtilityCodeHeader OPTIONAL
  );

/**
  Relocate this image under 4G memory for IPF.

  @param  ImageHandle  Handle of driver image.
  @param  SystemTable  Pointer to system table.

  @retval EFI_SUCCESS  Image successfully relocated.
  @retval EFI_ABORTED  Failed to relocate image.

**/
EFI_STATUS
RelocateImageUnder4GIfNeeded (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  );

/**
  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
InternalLegacyBiosFarCall (
  IN  EFI_LEGACY_BIOS_PROTOCOL        *This,
  IN  UINT16                          Segment,
  IN  UINT16                          Offset,
  IN  EFI_IA32_REGISTER_SET           *Regs,
  IN  VOID                            *Stack,
  IN  UINTN                           StackSize
  );

/**
  Load a legacy PC-AT OpROM for VGA controller.

  @param  Private                Driver private data.

  @retval EFI_SUCCESS            Legacy ROM successfully installed for this device.
  @retval EFI_DEVICE_ERROR       No VGA device handle found, or native EFI video
                                 driver cannot be successfully disconnected, or VGA
                                 thunk driver cannot be successfully connected.

**/
EFI_STATUS
LegacyBiosInstallVgaRom (
  IN  LEGACY_BIOS_INSTANCE            *Private
  );

#endif
