]> git.proxmox.com Git - mirror_edk2.git/commitdiff
IntelFrameworkModulePkg: Add Compatibility Support Module (CSM) drivers
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 27 Jun 2011 23:32:56 +0000 (23:32 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 27 Jun 2011 23:32:56 +0000 (23:32 +0000)
Added these drivers:
* LegacyBiosDxe
* BlockIoDxe
* KeyboardDxe
* Snp16Dxe
* VideoDxe

Signed-off-by: jljusten
Reviewed-by: mdkinney
Reviewed-by: geekboy15a
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11905 6f19259b-4bc3-4df7-8a09-765794883524

46 files changed:
IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S [new file with mode: 0644]
IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm [new file with mode: 0644]
IntelFrameworkModulePkg/Include/Guid/LegacyBios.h [new file with mode: 0644]
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc

diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
new file mode 100644 (file)
index 0000000..309cf1a
--- /dev/null
@@ -0,0 +1,782 @@
+/** @file\r
+  EFI glue for BIOS INT 13h block devices.\r
+\r
+  This file is coded to EDD 3.0 as defined by T13 D1386 Revision 4\r
+  Availible on http://www.t13.org/#Project drafts\r
+  Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r4.pdf\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosBlkIo.h"\r
+\r
+//\r
+// Global data declaration\r
+//\r
+//\r
+// EFI Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding = {\r
+  BiosBlockIoDriverBindingSupported,\r
+  BiosBlockIoDriverBindingStart,\r
+  BiosBlockIoDriverBindingStop,\r
+  0x3,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb\r
+//\r
+EFI_LOCK                    mGlobalDataLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION);\r
+\r
+//\r
+// Number of active instances of this protocol.  This is used to allocate/free\r
+// the shared buffer.  You must acquire the semaphore to modify.\r
+//\r
+UINTN                       mActiveInstances = 0;\r
+\r
+//\r
+// Pointer to the beginning of the buffer used for real mode thunk\r
+// You must acquire the semaphore to modify.\r
+//\r
+EFI_PHYSICAL_ADDRESS        mBufferUnder1Mb = 0;\r
+\r
+//\r
+// Address packet is a buffer under 1 MB for all version EDD calls\r
+//\r
+EDD_DEVICE_ADDRESS_PACKET   *mEddBufferUnder1Mb;\r
+\r
+//\r
+// This is a buffer for INT 13h func 48 information\r
+//\r
+BIOS_LEGACY_DRIVE           *mLegacyDriverUnder1Mb;\r
+\r
+//\r
+// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB\r
+//  0xFE00 bytes is the max transfer size supported.\r
+//\r
+VOID                        *mEdd11Buffer;\r
+\r
+EFI_GUID                    mUnknownDevGuid = UNKNOWN_DEVICE_GUID;\r
+\r
+/**\r
+  Driver entry point.\r
+\r
+  @param  ImageHandle  Handle of driver image.\r
+  @param  SystemTable  Pointer to system table.\r
+\r
+  @retval EFI_SUCCESS  Entrypoint successfully executed.\r
+  @retval Others       Fail to execute entrypoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoDriverEntryPoint (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Install protocols\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gBiosBlockIoDriverBinding,\r
+             ImageHandle,\r
+             &gBiosBlockIoComponentName,\r
+             &gBiosBlockIoComponentName2\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver\r
+  //\r
+  return gBS->InstallMultipleProtocolInterfaces (\r
+                &ImageHandle,\r
+                &gEfiLegacyBiosGuid,\r
+                NULL,\r
+                NULL\r
+                );\r
+}\r
+\r
+/**\r
+  Check whether the driver supports this device.\r
+\r
+  @param  This                   The Udriver binding protocol.\r
+  @param  Controller             The controller handle to check.\r
+  @param  RemainingDevicePath    The remaining device path.\r
+\r
+  @retval EFI_SUCCESS            The driver supports this controller.\r
+  @retval other                  This device isn't supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  PCI_TYPE00                Pci;\r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &DevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiDevicePathProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );      \r
+  \r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // See if this is a PCI VGA Controller by looking at the Command register and\r
+  // Class Code Register\r
+  //\r
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+  if (Pci.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE ||\r
+      (Pci.Hdr.ClassCode[2] == PCI_BASE_CLASS_INTELLIGENT && Pci.Hdr.ClassCode[1] == PCI_SUB_CLASS_INTELLIGENT)\r
+      ) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Done:\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiPciIoProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Starts the device with this driver.\r
+\r
+  @param  This                   The driver binding instance.\r
+  @param  Controller             Handle of device to bind driver to.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCESS            The controller is controlled by the driver.\r
+  @retval Other                  This controller cannot be started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  UINT8                     DiskStart;\r
+  UINT8                     DiskEnd;\r
+  BIOS_BLOCK_IO_DEV         *BiosBlockIoPrivate;\r
+  EFI_DEVICE_PATH_PROTOCOL  *PciDevPath;\r
+  UINTN                     Index;\r
+  UINTN                     Flags;\r
+  UINTN                     TmpAddress;\r
+  BOOLEAN                   DeviceEnable;\r
+\r
+  //\r
+  // Initialize variables\r
+  //\r
+  PciIo      = NULL;\r
+  PciDevPath = NULL;\r
+  \r
+  DeviceEnable = FALSE; \r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+  //\r
+  // Open the IO Abstraction(s) needed\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &PciDevPath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+  //\r
+  // Enable the device and make sure VGA cycles are being forwarded to this VGA device\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationEnable,\r
+                    EFI_PCI_DEVICE_ENABLE,\r
+                    NULL\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+  \r
+  DeviceEnable = TRUE;\r
+  \r
+  //\r
+  // Check to see if there is a legacy option ROM image associated with this PCI device\r
+  //\r
+  Status = LegacyBios->CheckPciRom (\r
+                        LegacyBios,\r
+                        Controller,\r
+                        NULL,\r
+                        NULL,\r
+                        &Flags\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+  //\r
+  // Post the legacy option ROM if it is available.\r
+  //\r
+  Status = LegacyBios->InstallPciRom (\r
+                        LegacyBios,\r
+                        Controller,\r
+                        NULL,\r
+                        &Flags,\r
+                        &DiskStart,\r
+                        &DiskEnd,\r
+                        NULL,\r
+                        NULL\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+  //\r
+  // All instances share a buffer under 1MB to put real mode thunk code in\r
+  // If it has not been allocated, then we allocate it.\r
+  //\r
+  if (mBufferUnder1Mb == 0) {\r
+    //\r
+    // Should only be here if there are no active instances\r
+    //\r
+    ASSERT (mActiveInstances == 0);\r
+\r
+    //\r
+    // Acquire the lock\r
+    //\r
+    EfiAcquireLock (&mGlobalDataLock);\r
+\r
+    //\r
+    // Allocate below 1MB\r
+    //\r
+    mBufferUnder1Mb = 0x00000000000FFFFF;\r
+    Status          = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, BLOCK_IO_BUFFER_PAGE_SIZE, &mBufferUnder1Mb);\r
+\r
+    //\r
+    // Release the lock\r
+    //\r
+    EfiReleaseLock (&mGlobalDataLock);\r
+\r
+    //\r
+    // Check memory allocation success\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // In checked builds we want to assert if the allocate failed.\r
+      //\r
+      ASSERT_EFI_ERROR (Status);\r
+      Status          = EFI_OUT_OF_RESOURCES;\r
+      mBufferUnder1Mb = 0;\r
+      goto Error;\r
+    }\r
+\r
+    TmpAddress = (UINTN) mBufferUnder1Mb;\r
+    //\r
+    // Adjusting the value to be on proper boundary\r
+    //\r
+    mEdd11Buffer = (VOID *) ALIGN_VARIABLE (TmpAddress);\r
+\r
+    TmpAddress   = (UINTN) mEdd11Buffer + MAX_EDD11_XFER;\r
+    //\r
+    // Adjusting the value to be on proper boundary\r
+    //\r
+    mLegacyDriverUnder1Mb = (BIOS_LEGACY_DRIVE *) ALIGN_VARIABLE (TmpAddress);\r
+\r
+    TmpAddress = (UINTN) mLegacyDriverUnder1Mb + sizeof (BIOS_LEGACY_DRIVE);\r
+    //\r
+    // Adjusting the value to be on proper boundary\r
+    //\r
+    mEddBufferUnder1Mb = (EDD_DEVICE_ADDRESS_PACKET *) ALIGN_VARIABLE (TmpAddress);\r
+  }\r
+  //\r
+  // Allocate the private device structure for each disk\r
+  //\r
+  for (Index = DiskStart; Index < DiskEnd; Index++) {\r
+\r
+    Status = gBS->AllocatePool (\r
+                    EfiBootServicesData,\r
+                    sizeof (BIOS_BLOCK_IO_DEV),\r
+                    (VOID **) &BiosBlockIoPrivate\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+    //\r
+    // Zero the private device structure\r
+    //\r
+    ZeroMem (BiosBlockIoPrivate, sizeof (BIOS_BLOCK_IO_DEV));\r
+\r
+    //\r
+    // Initialize the private device structure\r
+    //\r
+    BiosBlockIoPrivate->Signature                 = BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE;\r
+    BiosBlockIoPrivate->ControllerHandle          = Controller;\r
+    BiosBlockIoPrivate->LegacyBios                = LegacyBios;\r
+    BiosBlockIoPrivate->PciIo                     = PciIo;\r
+\r
+    BiosBlockIoPrivate->Bios.Floppy               = FALSE;\r
+    BiosBlockIoPrivate->Bios.Number               = (UINT8) Index;\r
+    BiosBlockIoPrivate->Bios.Letter               = (UINT8) (Index - 0x80 + 'C');\r
+    BiosBlockIoPrivate->BlockMedia.RemovableMedia = FALSE;\r
+\r
+    if (BiosInitBlockIo (BiosBlockIoPrivate)) {\r
+      SetBiosInitBlockIoDevicePath (PciDevPath, &BiosBlockIoPrivate->Bios, &BiosBlockIoPrivate->DevicePath);\r
+\r
+      //\r
+      // Install the Block Io Protocol onto a new child handle\r
+      //\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &BiosBlockIoPrivate->Handle,\r
+                      &gEfiBlockIoProtocolGuid,\r
+                      &BiosBlockIoPrivate->BlockIo,\r
+                      &gEfiDevicePathProtocolGuid,\r
+                      BiosBlockIoPrivate->DevicePath,\r
+                      NULL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->FreePool (BiosBlockIoPrivate);\r
+      }\r
+      //\r
+      // Open For Child Device\r
+      //\r
+      Status = gBS->OpenProtocol (\r
+                      Controller,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      (VOID **) &BiosBlockIoPrivate->PciIo,\r
+                      This->DriverBindingHandle,\r
+                      BiosBlockIoPrivate->Handle,\r
+                      EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                      );\r
+\r
+    } else {\r
+      gBS->FreePool (BiosBlockIoPrivate);\r
+    }\r
+  }\r
+\r
+Error:\r
+  if (EFI_ERROR (Status)) {\r
+    if (PciIo != NULL) {\r
+      if (DeviceEnable) {\r
+        PciIo->Attributes (\r
+                PciIo,\r
+                EfiPciIoAttributeOperationDisable,\r
+                EFI_PCI_DEVICE_ENABLE,\r
+                NULL\r
+                );\r
+      }\r
+      gBS->CloseProtocol (\r
+            Controller,\r
+            &gEfiPciIoProtocolGuid,\r
+            This->DriverBindingHandle,\r
+            Controller\r
+            );\r
+      if (PciDevPath != NULL) {\r
+        gBS->CloseProtocol (\r
+              Controller,\r
+              &gEfiDevicePathProtocolGuid,\r
+              This->DriverBindingHandle,\r
+              Controller\r
+              );\r
+      }\r
+      if (mBufferUnder1Mb != 0 && mActiveInstances == 0) {\r
+        gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);\r
+\r
+        //\r
+        // Clear the buffer back to 0\r
+        //\r
+        EfiAcquireLock (&mGlobalDataLock);\r
+        mBufferUnder1Mb = 0;\r
+        EfiReleaseLock (&mGlobalDataLock);\r
+      }\r
+    }\r
+  } else {\r
+    //\r
+    // Successfully installed, so increment the number of active instances\r
+    //\r
+    EfiAcquireLock (&mGlobalDataLock);\r
+    mActiveInstances++;\r
+    EfiReleaseLock (&mGlobalDataLock);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop the device handled by this driver.\r
+\r
+  @param  This                   The driver binding protocol.\r
+  @param  Controller             The controller to release.\r
+  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.\r
+  @param  ChildHandleBuffer      The array of child handle.\r
+\r
+  @retval EFI_SUCCESS            The device was stopped.\r
+  @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.\r
+  @retval Others                 Fail to uninstall protocols attached on the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  BOOLEAN               AllChildrenStopped;\r
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+  BIOS_BLOCK_IO_DEV     *BiosBlockIoPrivate;\r
+  UINTN                 Index;\r
+\r
+  //\r
+  // Decrement the number of active instances\r
+  //\r
+  if (mActiveInstances != 0) {\r
+    //\r
+    // Add a check since the stop function will be called 2 times for each handle\r
+    //\r
+    EfiAcquireLock (&mGlobalDataLock);\r
+    mActiveInstances--;\r
+    EfiReleaseLock (&mGlobalDataLock);\r
+  }\r
+\r
+  if ((mActiveInstances == 0) && (mBufferUnder1Mb != 0)) {\r
+    //\r
+    // Free our global buffer\r
+    //\r
+    Status = gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    EfiAcquireLock (&mGlobalDataLock);\r
+    mBufferUnder1Mb = 0;\r
+    EfiReleaseLock (&mGlobalDataLock);\r
+  }\r
+\r
+  AllChildrenStopped = TRUE;\r
+\r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    BiosBlockIoPrivate = BIOS_BLOCK_IO_FROM_THIS (BlockIo);\r
+\r
+    //\r
+    // Release PCI I/O and Block IO Protocols on the clild handle.\r
+    //\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    &BiosBlockIoPrivate->BlockIo,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    BiosBlockIoPrivate->DevicePath,\r
+                    NULL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      AllChildrenStopped = FALSE;\r
+    }\r
+    //\r
+    // Shutdown the hardware\r
+    //\r
+    BiosBlockIoPrivate->PciIo->Attributes (\r
+                                BiosBlockIoPrivate->PciIo,\r
+                                EfiPciIoAttributeOperationDisable,\r
+                                EFI_PCI_DEVICE_ENABLE,\r
+                                NULL\r
+                                );\r
+\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiPciIoProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          ChildHandleBuffer[Index]\r
+          );\r
+\r
+    gBS->FreePool (BiosBlockIoPrivate);\r
+  }\r
+\r
+  if (!AllChildrenStopped) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Controller\r
+                  );\r
+\r
+  Status = gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Controller\r
+                  );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Build device path for device.\r
+\r
+  @param  BaseDevicePath         Base device path.\r
+  @param  Drive                  Legacy drive.\r
+  @param  DevicePath             Device path for output.\r
+\r
+**/\r
+VOID\r
+SetBiosInitBlockIoDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *BaseDevicePath,\r
+  IN  BIOS_LEGACY_DRIVE         *Drive,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePath\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UNKNOWN_DEVICE_VENDOR_DEVICE_PATH VendorNode;\r
+  \r
+  Status = EFI_UNSUPPORTED;\r
+  \r
+  //\r
+  // BugBug: Check for memory leaks!\r
+  //\r
+  if (Drive->EddVersion == EDD_VERSION_30) {\r
+    //\r
+    // EDD 3.0 case.\r
+    //\r
+    Status = BuildEdd30DevicePath (BaseDevicePath, Drive, DevicePath);\r
+  }\r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EDD 1.1 device case or it is unrecognized EDD 3.0 device\r
+    //\r
+    ZeroMem (&VendorNode, sizeof (VendorNode));\r
+    VendorNode.DevicePath.Header.Type     = HARDWARE_DEVICE_PATH;\r
+    VendorNode.DevicePath.Header.SubType  = HW_VENDOR_DP;\r
+    SetDevicePathNodeLength (&VendorNode.DevicePath.Header, sizeof (VendorNode));\r
+    CopyMem (&VendorNode.DevicePath.Guid, &mUnknownDevGuid, sizeof (EFI_GUID));\r
+    VendorNode.LegacyDriveLetter  = Drive->Number;\r
+    *DevicePath                   = AppendDevicePathNode (BaseDevicePath, &VendorNode.DevicePath.Header);\r
+  }\r
+}\r
+\r
+/**\r
+  Build device path for EDD 3.0.\r
+\r
+  @param  BaseDevicePath         Base device path.\r
+  @param  Drive                  Legacy drive.\r
+  @param  DevicePath             Device path for output.\r
+\r
+  @retval EFI_SUCCESS            The device path is built successfully.\r
+  @retval EFI_UNSUPPORTED        It is failed to built device path.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildEdd30DevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *BaseDevicePath,\r
+  IN  BIOS_LEGACY_DRIVE         *Drive,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  **DevicePath\r
+  )\r
+{\r
+  //\r
+  // AVL    UINT64                  Address;\r
+  // AVL    EFI_HANDLE              Handle;\r
+  //\r
+  EFI_DEV_PATH  Node;\r
+  UINT32        Controller;\r
+\r
+  Controller = (UINT32) Drive->Parameters.InterfacePath.Pci.Controller;\r
+\r
+  ZeroMem (&Node, sizeof (Node));\r
+  if ((AsciiStrnCmp ("ATAPI", Drive->Parameters.InterfaceType, 5) == 0) ||\r
+      (AsciiStrnCmp ("ATA", Drive->Parameters.InterfaceType, 3) == 0)\r
+      ) {\r
+    //\r
+    // ATA or ATAPI drive found\r
+    //\r
+    Node.Atapi.Header.Type    = MESSAGING_DEVICE_PATH;\r
+    Node.Atapi.Header.SubType = MSG_ATAPI_DP;\r
+    SetDevicePathNodeLength (&Node.Atapi.Header, sizeof (ATAPI_DEVICE_PATH));\r
+    Node.Atapi.SlaveMaster      = Drive->Parameters.DevicePath.Atapi.Master;\r
+    Node.Atapi.Lun              = Drive->Parameters.DevicePath.Atapi.Lun;\r
+    Node.Atapi.PrimarySecondary = (UINT8) Controller;\r
+  } else {\r
+    //\r
+    // Not an ATA/ATAPI drive\r
+    //\r
+    if (Controller != 0) {\r
+      ZeroMem (&Node, sizeof (Node));\r
+      Node.Controller.Header.Type      = HARDWARE_DEVICE_PATH;\r
+      Node.Controller.Header.SubType   = HW_CONTROLLER_DP;\r
+      SetDevicePathNodeLength (&Node.Controller.Header, sizeof (CONTROLLER_DEVICE_PATH));\r
+      Node.Controller.ControllerNumber = Controller;\r
+      *DevicePath                      = AppendDevicePathNode (*DevicePath, &Node.DevPath);\r
+    }\r
+\r
+    ZeroMem (&Node, sizeof (Node));\r
+\r
+    if (AsciiStrnCmp ("SCSI", Drive->Parameters.InterfaceType, 4) == 0) {\r
+      //\r
+      // SCSI drive\r
+      //\r
+      Node.Scsi.Header.Type     = MESSAGING_DEVICE_PATH;\r
+      Node.Scsi.Header.SubType  = MSG_SCSI_DP;\r
+      SetDevicePathNodeLength (&Node.Scsi.Header, sizeof (SCSI_DEVICE_PATH));\r
+\r
+      //\r
+      // Lun is miss aligned in both EDD and Device Path data structures.\r
+      //  thus we do a byte copy, to prevent alignment traps on IA-64.\r
+      //\r
+      CopyMem (&Node.Scsi.Lun, &Drive->Parameters.DevicePath.Scsi.Lun, sizeof (UINT16));\r
+      Node.Scsi.Pun = Drive->Parameters.DevicePath.Scsi.Pun;\r
+\r
+    } else if (AsciiStrnCmp ("USB", Drive->Parameters.InterfaceType, 3) == 0) {\r
+      //\r
+      // USB drive\r
+      //\r
+      Node.Usb.Header.Type    = MESSAGING_DEVICE_PATH;\r
+      Node.Usb.Header.SubType = MSG_USB_DP;\r
+      SetDevicePathNodeLength (&Node.Usb.Header, sizeof (USB_DEVICE_PATH));\r
+      Node.Usb.ParentPortNumber = (UINT8) Drive->Parameters.DevicePath.Usb.Reserved;\r
+\r
+    } else if (AsciiStrnCmp ("1394", Drive->Parameters.InterfaceType, 4) == 0) {\r
+      //\r
+      // 1394 drive\r
+      //\r
+      Node.F1394.Header.Type    = MESSAGING_DEVICE_PATH;\r
+      Node.F1394.Header.SubType = MSG_1394_DP;\r
+      SetDevicePathNodeLength (&Node.F1394.Header, sizeof (F1394_DEVICE_PATH));\r
+      Node.F1394.Guid = Drive->Parameters.DevicePath.FireWire.Guid;\r
+\r
+    } else if (AsciiStrnCmp ("FIBRE", Drive->Parameters.InterfaceType, 5) == 0) {\r
+      //\r
+      // Fibre drive\r
+      //\r
+      Node.FibreChannel.Header.Type     = MESSAGING_DEVICE_PATH;\r
+      Node.FibreChannel.Header.SubType  = MSG_FIBRECHANNEL_DP;\r
+      SetDevicePathNodeLength (&Node.FibreChannel.Header, sizeof (FIBRECHANNEL_DEVICE_PATH));\r
+      Node.FibreChannel.WWN = Drive->Parameters.DevicePath.FibreChannel.Wwn;\r
+      Node.FibreChannel.Lun = Drive->Parameters.DevicePath.FibreChannel.Lun;\r
+\r
+    } else {\r
+      DEBUG (\r
+        (\r
+        DEBUG_BLKIO, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n",\r
+        Drive->Number,\r
+        Drive->Parameters.InterfaceType\r
+        )\r
+        );      \r
+    }\r
+  }\r
+\r
+  if (Node.DevPath.Type == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  *DevicePath = AppendDevicePathNode (BaseDevicePath, &Node.DevPath);\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h
new file mode 100644 (file)
index 0000000..de3c8d3
--- /dev/null
@@ -0,0 +1,439 @@
+/** @file\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _BIOS_BLOCK_IO_H_\r
+#define _BIOS_BLOCK_IO_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/LegacyBios.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Guid/LegacyBios.h>\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include "Edd.h"\r
+\r
+#define UNKNOWN_DEVICE_GUID \\r
+  { 0xcf31fac5, 0xc24e, 0x11d2,  {0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b}  }\r
+\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH              DevicePath;\r
+  UINT8                           LegacyDriveLetter;\r
+} UNKNOWN_DEVICE_VENDOR_DEVICE_PATH;\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gBiosBlockIoComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL  gBiosBlockIoComponentName2;\r
+\r
+\r
+//\r
+// Define the I2O class code\r
+//\r
+#define PCI_BASE_CLASS_INTELLIGENT  0x0e\r
+#define PCI_SUB_CLASS_INTELLIGENT   0x00\r
+\r
+//\r
+// Number of pages needed for our buffer under 1MB\r
+//\r
+#define BLOCK_IO_BUFFER_PAGE_SIZE (((sizeof (EDD_DEVICE_ADDRESS_PACKET) + sizeof (BIOS_LEGACY_DRIVE) + MAX_EDD11_XFER) / EFI_PAGE_SIZE) + 1 \\r
+        )\r
+\r
+//\r
+// Driver Binding Protocol functions\r
+//\r
+\r
+/**\r
+  Check whether the driver supports this device.\r
+\r
+  @param  This                   The Udriver binding protocol.\r
+  @param  Controller             The controller handle to check.\r
+  @param  RemainingDevicePath    The remaining device path.\r
+\r
+  @retval EFI_SUCCESS            The driver supports this controller.\r
+  @retval other                  This device isn't supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+\r
+/**\r
+  Starts the device with this driver.\r
+\r
+  @param  This                   The driver binding instance.\r
+  @param  Controller             Handle of device to bind driver to.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCESS            The controller is controlled by the driver.\r
+  @retval Other                  This controller cannot be started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stop the device handled by this driver.\r
+\r
+  @param  This                   The driver binding protocol.\r
+  @param  Controller             The controller to release.\r
+  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.\r
+  @param  ChildHandleBuffer      The array of child handle.\r
+\r
+  @retval EFI_SUCCESS            The device was stopped.\r
+  @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.\r
+  @retval Others                 Fail to uninstall protocols attached on the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   Controller,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// Other internal functions\r
+//\r
+\r
+/**\r
+  Build device path for EDD 3.0.\r
+\r
+  @param  BaseDevicePath         Base device path.\r
+  @param  Drive                  Legacy drive.\r
+  @param  DevicePath             Device path for output.\r
+\r
+  @retval EFI_SUCCESS            The device path is built successfully.\r
+  @retval EFI_UNSUPPORTED        It is failed to built device path.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildEdd30DevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *BaseDevicePath,\r
+  IN  BIOS_LEGACY_DRIVE         *Drive,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  **DevicePath\r
+  );\r
+\r
+/**\r
+  Initialize block I/O device instance\r
+\r
+  @param  Dev   Instance of block I/O device instance\r
+\r
+  @retval TRUE  Initialization succeeds.\r
+  @retval FALSE Initialization fails.\r
+\r
+**/\r
+BOOLEAN\r
+BiosInitBlockIo (\r
+  IN  BIOS_BLOCK_IO_DEV     *Dev\r
+  );\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd30BiosReadBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  );\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd30BiosWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN  UINT32                 MediaId,\r
+  IN  EFI_LBA                Lba,\r
+  IN  UINTN                  BufferSize,\r
+  OUT VOID                   *Buffer\r
+  );\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param  This              Indicates a pointer to the calling context.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoFlushBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL  *This\r
+  );\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param  This                 Indicates a pointer to the calling context.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoReset (\r
+  IN  EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN  BOOLEAN                ExtendedVerification\r
+  );\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd11BiosReadBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  );\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd11BiosWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  );\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosReadLegacyDrive (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  );\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosWriteLegacyDrive (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  );\r
+\r
+/**\r
+  Gets parameters of block I/O device.\r
+\r
+  @param  BiosBlockIoDev Instance of block I/O device.\r
+  @param  Drive          Legacy drive.\r
+\r
+  @return  Result of device parameter retrieval.\r
\r
+**/\r
+UINTN\r
+Int13GetDeviceParameters (\r
+  IN BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,\r
+  IN BIOS_LEGACY_DRIVE    *Drive\r
+  );\r
+\r
+/**\r
+  Extension of INT13 call.\r
+\r
+  @param  BiosBlockIoDev Instance of block I/O device.\r
+  @param  Drive          Legacy drive.\r
+\r
+  @return  Result of this extension.\r
\r
+**/\r
+UINTN\r
+Int13Extensions (\r
+  IN BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,\r
+  IN BIOS_LEGACY_DRIVE    *Drive\r
+  );\r
+\r
+/**\r
+  Gets parameters of legacy drive.\r
+\r
+  @param  BiosBlockIoDev Instance of block I/O device.\r
+  @param  Drive          Legacy drive.\r
+\r
+  @return  Result of drive parameter retrieval.\r
\r
+**/\r
+UINTN\r
+GetDriveParameters (\r
+  IN BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,\r
+  IN  BIOS_LEGACY_DRIVE   *Drive\r
+  );\r
+\r
+/**\r
+  Build device path for device.\r
+\r
+  @param  BaseDevicePath         Base device path.\r
+  @param  Drive                  Legacy drive.\r
+  @param  DevicePath             Device path for output.\r
+\r
+**/\r
+VOID\r
+SetBiosInitBlockIoDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *BaseDevicePath,\r
+  IN  BIOS_LEGACY_DRIVE         *Drive,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePath\r
+  );\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c
new file mode 100644 (file)
index 0000000..c53490b
--- /dev/null
@@ -0,0 +1,1485 @@
+/** @file\r
+  Routines that use BIOS to support INT 13 devices.\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosBlkIo.h"\r
+\r
+//\r
+// Module global variables\r
+//\r
+//\r
+// Address packet is a buffer under 1 MB for all version EDD calls\r
+//\r
+extern EDD_DEVICE_ADDRESS_PACKET  *mEddBufferUnder1Mb;\r
+\r
+//\r
+// This is a buffer for INT 13h func 48 information\r
+//\r
+extern BIOS_LEGACY_DRIVE          *mLegacyDriverUnder1Mb;\r
+\r
+//\r
+// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB\r
+//  0xFE00 bytes is the max transfer size supported.\r
+//\r
+extern VOID                       *mEdd11Buffer;\r
+\r
+\r
+/**\r
+  Initialize block I/O device instance\r
+\r
+  @param  Dev   Instance of block I/O device instance\r
+\r
+  @retval TRUE  Initialization succeeds.\r
+  @retval FALSE Initialization fails.\r
+\r
+**/\r
+BOOLEAN\r
+BiosInitBlockIo (\r
+  IN  BIOS_BLOCK_IO_DEV         *Dev\r
+  )\r
+{\r
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+  EFI_BLOCK_IO_MEDIA    *BlockMedia;\r
+  BIOS_LEGACY_DRIVE     *Bios;\r
+\r
+  BlockIo         = &Dev->BlockIo;\r
+  BlockIo->Media  = &Dev->BlockMedia;\r
+  BlockMedia      = BlockIo->Media;\r
+  Bios            = &Dev->Bios;\r
+\r
+  if (Int13GetDeviceParameters (Dev, Bios) != 0) {\r
+    if (Int13Extensions (Dev, Bios) != 0) {\r
+      BlockMedia->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;\r
+      BlockMedia->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;\r
+\r
+      if ((Bios->Parameters.Flags & EDD_DEVICE_REMOVABLE) == EDD_DEVICE_REMOVABLE) {\r
+        BlockMedia->RemovableMedia = TRUE;\r
+      }\r
+\r
+    } else {\r
+      //\r
+      // Legacy Interfaces\r
+      //\r
+      BlockMedia->BlockSize = 512;\r
+      BlockMedia->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;\r
+    }\r
+\r
+    DEBUG ((DEBUG_INIT, "BlockSize = %d  LastBlock = %d\n", BlockMedia->BlockSize, BlockMedia->LastBlock));\r
+\r
+    BlockMedia->LogicalPartition  = FALSE;\r
+    BlockMedia->WriteCaching      = FALSE;\r
+\r
+    //\r
+    // BugBug: Need to set this for removable media devices if they do not\r
+    //  have media present\r
+    //\r
+    BlockMedia->ReadOnly      = FALSE;\r
+    BlockMedia->MediaPresent  = TRUE;\r
+\r
+    BlockIo->Reset            = BiosBlockIoReset;\r
+    BlockIo->FlushBlocks      = BiosBlockIoFlushBlocks;\r
+\r
+    if (!Bios->ExtendedInt13) {\r
+      //\r
+      // Legacy interfaces\r
+      //\r
+      BlockIo->ReadBlocks   = BiosReadLegacyDrive;\r
+      BlockIo->WriteBlocks  = BiosWriteLegacyDrive;\r
+    } else if ((Bios->EddVersion == EDD_VERSION_30) && (Bios->Extensions64Bit)) {\r
+      //\r
+      // EDD 3.0 Required for Device path, but extended reads are not required.\r
+      //\r
+      BlockIo->ReadBlocks   = Edd30BiosReadBlocks;\r
+      BlockIo->WriteBlocks  = Edd30BiosWriteBlocks;\r
+    } else {\r
+      //\r
+      // Assume EDD 1.1 - Read and Write functions.\r
+      //  This could be EDD 3.0 without Extensions64Bit being set.\r
+      // If it's EDD 1.1 this will work, but the device path will not\r
+      //  be correct. This will cause confusion to EFI OS installation.\r
+      //\r
+      BlockIo->ReadBlocks   = Edd11BiosReadBlocks;\r
+      BlockIo->WriteBlocks  = Edd11BiosWriteBlocks;\r
+    }\r
+\r
+    BlockMedia->LogicalPartition  = FALSE;\r
+    BlockMedia->WriteCaching      = FALSE;\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Gets parameters of block I/O device.\r
+\r
+  @param  BiosBlockIoDev Instance of block I/O device.\r
+  @param  Drive          Legacy drive.\r
+\r
+  @return  Result of device parameter retrieval.\r
\r
+**/\r
+UINTN\r
+Int13GetDeviceParameters (\r
+  IN  BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,\r
+  IN  BIOS_LEGACY_DRIVE    *Drive\r
+  )\r
+{\r
+  UINTN                 CarryFlag;\r
+  UINT16                Cylinder;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  Regs.H.AH = 0x08;\r
+  Regs.H.DL = Drive->Number;\r
+  CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+  DEBUG ((DEBUG_INIT, "Int13GetDeviceParameters: INT 13 08 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));\r
+  if (CarryFlag != 0 || Regs.H.AH != 0x00) {\r
+    Drive->ErrorCode = Regs.H.AH;\r
+    return FALSE;\r
+  }\r
+\r
+  if (Drive->Floppy) {\r
+    if (Regs.H.BL == 0x10) {\r
+      Drive->AtapiFloppy = TRUE;\r
+    } else {\r
+      Drive->MaxHead      = Regs.H.DH;\r
+      Drive->MaxSector    = Regs.H.CL;\r
+      Drive->MaxCylinder  = Regs.H.CH;\r
+      if (Drive->MaxSector == 0) {\r
+        //\r
+        // BugBug: You can not trust the Carry flag.\r
+        //\r
+        return FALSE;\r
+      }\r
+    }\r
+  } else {\r
+    Drive->MaxHead  = (UINT8) (Regs.H.DH & 0x3f);\r
+    Cylinder        = (UINT16) (((UINT16) Regs.H.DH & 0xc0) << 4);\r
+    Cylinder        = (UINT16) (Cylinder | ((UINT16) Regs.H.CL & 0xc0) << 2);\r
+    Drive->MaxCylinder  = (UINT16) (Cylinder + Regs.H.CH);\r
+    Drive->MaxSector    = (UINT8) (Regs.H.CL & 0x3f);\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Extension of INT13 call.\r
+\r
+  @param  BiosBlockIoDev Instance of block I/O device.\r
+  @param  Drive          Legacy drive.\r
+\r
+  @return  Result of this extension.\r
\r
+**/\r
+UINTN\r
+Int13Extensions (\r
+  IN  BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,\r
+  IN  BIOS_LEGACY_DRIVE    *Drive\r
+  )\r
+{\r
+  INTN                  CarryFlag;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  Regs.H.AH = 0x41;\r
+  Regs.X.BX = 0x55aa;\r
+  Regs.H.DL = Drive->Number;\r
+  CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+  DEBUG ((DEBUG_INIT, "Int13Extensions: INT 13 41 DL=%02x : CF=%d BX=%04x\n", Drive->Number, CarryFlag, Regs.X.BX));\r
+  if (CarryFlag != 0 || Regs.X.BX != 0xaa55) {\r
+    Drive->ExtendedInt13            = FALSE;\r
+    Drive->DriveLockingAndEjecting  = FALSE;\r
+    Drive->Edd                      = FALSE;\r
+    return FALSE;\r
+  }\r
+\r
+  Drive->EddVersion               = Regs.H.AH;\r
+  Drive->ExtendedInt13            = (BOOLEAN) ((Regs.X.CX & 0x01) == 0x01);\r
+  Drive->DriveLockingAndEjecting  = (BOOLEAN) ((Regs.X.CX & 0x02) == 0x02);\r
+  Drive->Edd                      = (BOOLEAN) ((Regs.X.CX & 0x04) == 0x04);\r
+  Drive->Extensions64Bit          = (BOOLEAN) (Regs.X.CX & 0x08);\r
+\r
+  Drive->ParametersValid          = (UINT8) GetDriveParameters (BiosBlockIoDev, Drive);\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Gets parameters of legacy drive.\r
+\r
+  @param  BiosBlockIoDev Instance of block I/O device.\r
+  @param  Drive          Legacy drive.\r
+\r
+  @return  Result of drive parameter retrieval.\r
\r
+**/\r
+UINTN\r
+GetDriveParameters (\r
+  IN  BIOS_BLOCK_IO_DEV   *BiosBlockIoDev,\r
+  IN  BIOS_LEGACY_DRIVE   *Drive\r
+  )\r
+{\r
+  INTN                  CarryFlag;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+  UINTN                 PointerMath;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  Regs.H.AH = 0x48;\r
+  Regs.H.DL = Drive->Number;\r
+\r
+  //\r
+  // EDD Buffer must be passed in with max buffer size as first entry in the buffer\r
+  //\r
+  mLegacyDriverUnder1Mb->Parameters.StructureSize = (UINT16) sizeof (EDD_DRIVE_PARAMETERS);\r
+  Regs.X.DS = EFI_SEGMENT ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));\r
+  Regs.X.SI = EFI_OFFSET ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));\r
+  CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+  DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));\r
+  if (CarryFlag != 0 || Regs.H.AH != 0x00) {\r
+    Drive->ErrorCode = Regs.H.AH;\r
+    SetMem (&Drive->Parameters, sizeof (Drive->Parameters), 0xaf);\r
+    return FALSE;\r
+  }\r
+  //\r
+  // We only have one buffer < 1MB, so copy into our instance data\r
+  //\r
+  CopyMem (\r
+    &Drive->Parameters,\r
+    &mLegacyDriverUnder1Mb->Parameters,\r
+    sizeof (Drive->Parameters)\r
+    );\r
+\r
+  if (Drive->AtapiFloppy) {\r
+    //\r
+    // Sense Media Type\r
+    //\r
+    Regs.H.AH = 0x20;\r
+    Regs.H.DL = Drive->Number;\r
+    CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+    DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n", Drive->Number, CarryFlag, Regs.H.AL));\r
+    if (CarryFlag != 0) {\r
+      //\r
+      // Media not present or unknown media present\r
+      //\r
+      if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {\r
+        Drive->MaxHead    = (UINT8) (Drive->Parameters.MaxHeads - 1);\r
+        Drive->MaxSector  = (UINT8) Drive->Parameters.SectorsPerTrack;\r
+        ASSERT (Drive->MaxSector != 0);\r
+        Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);\r
+      } else {\r
+        Drive->MaxHead      = 0;\r
+        Drive->MaxSector    = 1;\r
+        Drive->MaxCylinder  = 0;\r
+      }\r
+\r
+    } else {\r
+      //\r
+      // Media Present\r
+      //\r
+      switch (Regs.H.AL) {\r
+      case 0x03:\r
+        //\r
+        // 720 KB\r
+        //\r
+        Drive->MaxHead      = 1;\r
+        Drive->MaxSector    = 9;\r
+        Drive->MaxCylinder  = 79;\r
+        break;\r
+\r
+      case 0x04:\r
+        //\r
+        // 1.44MB\r
+        //\r
+        Drive->MaxHead      = 1;\r
+        Drive->MaxSector    = 18;\r
+        Drive->MaxCylinder  = 79;\r
+        break;\r
+\r
+      case 0x06:\r
+        //\r
+        // 2.88MB\r
+        //\r
+        Drive->MaxHead      = 1;\r
+        Drive->MaxSector    = 36;\r
+        Drive->MaxCylinder  = 79;\r
+        break;\r
+\r
+      case 0x0C:\r
+        //\r
+        // 360 KB\r
+        //\r
+        Drive->MaxHead      = 1;\r
+        Drive->MaxSector    = 9;\r
+        Drive->MaxCylinder  = 39;\r
+        break;\r
+\r
+      case 0x0D:\r
+        //\r
+        // 1.2 MB\r
+        //\r
+        Drive->MaxHead      = 1;\r
+        Drive->MaxSector    = 15;\r
+        Drive->MaxCylinder  = 79;\r
+        break;\r
+\r
+      case 0x0E:\r
+        //\r
+        // Toshiba 3 mode\r
+        //\r
+      case 0x0F:\r
+        //\r
+        // NEC 3 mode\r
+        //\r
+      case 0x10:\r
+        //\r
+        // Default Media\r
+        //\r
+        if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {\r
+          Drive->MaxHead    = (UINT8) (Drive->Parameters.MaxHeads - 1);\r
+          Drive->MaxSector  = (UINT8) Drive->Parameters.SectorsPerTrack;\r
+          ASSERT (Drive->MaxSector != 0);\r
+          Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);\r
+        } else {\r
+          Drive->MaxHead      = 0;\r
+          Drive->MaxSector    = 1;\r
+          Drive->MaxCylinder  = 0;\r
+        }\r
+        break;\r
+\r
+      default:\r
+        //\r
+        // Unknown media type.\r
+        //\r
+        Drive->MaxHead      = 0;\r
+        Drive->MaxSector    = 1;\r
+        Drive->MaxCylinder  = 0;\r
+        break;\r
+      }\r
+    }\r
+\r
+    Drive->Parameters.PhysicalSectors = (Drive->MaxHead + 1) * Drive->MaxSector * (Drive->MaxCylinder + 1);\r
+    Drive->Parameters.BytesPerSector  = 512;\r
+  }\r
+  //\r
+  // This data comes from the BIOS so it may not allways be valid\r
+  //  since the BIOS may reuse this buffer for future accesses\r
+  //\r
+  PointerMath = EFI_SEGMENT (Drive->Parameters.Fdpt) << 4;\r
+  PointerMath += EFI_OFFSET (Drive->Parameters.Fdpt);\r
+  Drive->FdptPointer = (VOID *) PointerMath;\r
+\r
+  return TRUE;\r
+}\r
+//\r
+// Block IO Routines\r
+//\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd30BiosReadBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA        *Media;\r
+  BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;\r
+  EDD_DEVICE_ADDRESS_PACKET *AddressPacket;\r
+  //\r
+  // I exist only for readability\r
+  //\r
+  EFI_IA32_REGISTER_SET     Regs;\r
+  UINT64                    TransferBuffer;\r
+  UINTN                     NumberOfBlocks;\r
+  UINTN                     TransferByteSize;\r
+  UINTN                     BlockSize;\r
+  BIOS_LEGACY_DRIVE         *Bios;\r
+  UINTN                     CarryFlag;\r
+  UINTN                     MaxTransferBlocks;\r
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
+\r
+  Media     = This->Media;\r
+  BlockSize = Media->BlockSize;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);\r
+  AddressPacket     = mEddBufferUnder1Mb;\r
+\r
+  MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;\r
+\r
+  TransferBuffer    = (UINT64)(UINTN) Buffer;\r
+  for (; BufferSize > 0;) {\r
+    NumberOfBlocks  = BufferSize / BlockSize;\r
+    NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;\r
+    //\r
+    // Max transfer MaxTransferBlocks\r
+    //\r
+    AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);\r
+    AddressPacket->Zero               = 0;\r
+    AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;\r
+    AddressPacket->Zero2              = 0;\r
+    AddressPacket->SegOffset          = 0xffffffff;\r
+    AddressPacket->Lba                = (UINT64) Lba;\r
+    AddressPacket->TransferBuffer     = TransferBuffer;\r
+\r
+    Regs.H.AH                         = 0x42;\r
+    Regs.H.DL                         = BiosBlockIoDev->Bios.Number;\r
+    Regs.X.SI                         = EFI_OFFSET (AddressPacket);\r
+    Regs.X.DS                         = EFI_SEGMENT (AddressPacket);\r
+\r
+    CarryFlag                         = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+    DEBUG (\r
+      (\r
+      DEBUG_BLKIO, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,\r
+      CarryFlag, Regs.H.AH\r
+      )\r
+      );\r
+\r
+    Media->MediaPresent = TRUE;\r
+    if (CarryFlag != 0) {\r
+      //\r
+      // Return Error Status\r
+      //\r
+      BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;\r
+      if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {\r
+        Media->MediaId++;\r
+        Bios = &BiosBlockIoDev->Bios;\r
+        if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {\r
+          if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {\r
+            Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;\r
+            Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;\r
+          } else {\r
+            ASSERT (FALSE);\r
+          }\r
+\r
+          Media->ReadOnly = FALSE;\r
+          gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+          gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);\r
+          return EFI_MEDIA_CHANGED;\r
+        }\r
+      }\r
+\r
+      if (Media->RemovableMedia) {\r
+        Media->MediaPresent = FALSE;\r
+      }\r
+\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    TransferByteSize  = NumberOfBlocks * BlockSize;\r
+    BufferSize        = BufferSize - TransferByteSize;\r
+    TransferBuffer += TransferByteSize;\r
+    Lba += NumberOfBlocks;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd30BiosWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA        *Media;\r
+  BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;\r
+  EDD_DEVICE_ADDRESS_PACKET *AddressPacket;\r
+  //\r
+  // I exist only for readability\r
+  //\r
+  EFI_IA32_REGISTER_SET     Regs;\r
+  UINT64                    TransferBuffer;\r
+  UINTN                     NumberOfBlocks;\r
+  UINTN                     TransferByteSize;\r
+  UINTN                     BlockSize;\r
+  BIOS_LEGACY_DRIVE         *Bios;\r
+  UINTN                     CarryFlag;\r
+  UINTN                     MaxTransferBlocks;\r
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
+\r
+  Media     = This->Media;\r
+  BlockSize = Media->BlockSize;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);\r
+  AddressPacket     = mEddBufferUnder1Mb;\r
+\r
+  MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;\r
+\r
+  TransferBuffer    = (UINT64)(UINTN) Buffer;\r
+  for (; BufferSize > 0;) {\r
+    NumberOfBlocks  = BufferSize / BlockSize;\r
+    NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;\r
+    //\r
+    // Max transfer MaxTransferBlocks\r
+    //\r
+    AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);\r
+    AddressPacket->Zero               = 0;\r
+    AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;\r
+    AddressPacket->Zero2              = 0;\r
+    AddressPacket->SegOffset          = 0xffffffff;\r
+    AddressPacket->Lba                = (UINT64) Lba;\r
+    AddressPacket->TransferBuffer     = TransferBuffer;\r
+\r
+    Regs.H.AH                         = 0x43;\r
+    Regs.H.AL                         = 0x00;\r
+    //\r
+    // Write Verify Off\r
+    //\r
+    Regs.H.DL = (UINT8) (BiosBlockIoDev->Bios.Number);\r
+    Regs.X.SI = EFI_OFFSET (AddressPacket);\r
+    Regs.X.DS = EFI_SEGMENT (AddressPacket);\r
+\r
+    CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+    DEBUG (\r
+      (\r
+      DEBUG_BLKIO, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,\r
+      CarryFlag, Regs.H.AH\r
+      )\r
+      );\r
+\r
+    Media->MediaPresent = TRUE;\r
+    if (CarryFlag != 0) {\r
+      //\r
+      // Return Error Status\r
+      //\r
+      BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;\r
+      if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {\r
+        Media->MediaId++;\r
+        Bios = &BiosBlockIoDev->Bios;\r
+        if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {\r
+          if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {\r
+            Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;\r
+            Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;\r
+          } else {\r
+            ASSERT (FALSE);\r
+          }\r
+\r
+          Media->ReadOnly = FALSE;\r
+          gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+          gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);\r
+          return EFI_MEDIA_CHANGED;\r
+        }\r
+      } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {\r
+        Media->ReadOnly = TRUE;\r
+        return EFI_WRITE_PROTECTED;\r
+      }\r
+\r
+      if (Media->RemovableMedia) {\r
+        Media->MediaPresent = FALSE;\r
+      }\r
+\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Media->ReadOnly   = FALSE;\r
+    TransferByteSize  = NumberOfBlocks * BlockSize;\r
+    BufferSize        = BufferSize - TransferByteSize;\r
+    TransferBuffer += TransferByteSize;\r
+    Lba += NumberOfBlocks;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param  This              Indicates a pointer to the calling context.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoFlushBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL  *This\r
+  )\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param  This                 Indicates a pointer to the calling context.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoReset (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  BOOLEAN               ExtendedVerification\r
+  )\r
+{\r
+  BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+  UINTN                 CarryFlag;\r
+\r
+  BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  Regs.H.AH       = 0x00;\r
+  Regs.H.DL       = BiosBlockIoDev->Bios.Number;\r
+  CarryFlag       = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+  DEBUG (\r
+    (\r
+    DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,\r
+    Regs.H.AH\r
+    )\r
+    );\r
+  if (CarryFlag != 0) {\r
+    if (Regs.H.AL == BIOS_RESET_FAILED) {\r
+      Regs.H.AH = 0x00;\r
+      Regs.H.DL = BiosBlockIoDev->Bios.Number;\r
+      CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+      DEBUG (\r
+        (\r
+        DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,\r
+        Regs.H.AH\r
+        )\r
+        );\r
+      if (CarryFlag != 0) {\r
+        BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+//\r
+//\r
+// These functions need to double buffer all data under 1MB!\r
+//\r
+//\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd11BiosReadBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA        *Media;\r
+  BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;\r
+  EDD_DEVICE_ADDRESS_PACKET *AddressPacket;\r
+  //\r
+  // I exist only for readability\r
+  //\r
+  EFI_IA32_REGISTER_SET     Regs;\r
+  UINT64                    TransferBuffer;\r
+  UINTN                     NumberOfBlocks;\r
+  UINTN                     TransferByteSize;\r
+  UINTN                     BlockSize;\r
+  BIOS_LEGACY_DRIVE         *Bios;\r
+  UINTN                     CarryFlag;\r
+  UINTN                     MaxTransferBlocks;\r
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
+\r
+  Media     = This->Media;\r
+  BlockSize = Media->BlockSize;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);\r
+  AddressPacket     = mEddBufferUnder1Mb;\r
+\r
+  MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;\r
+\r
+  TransferBuffer    = (UINT64)(UINTN) mEdd11Buffer;\r
+  for (; BufferSize > 0;) {\r
+    NumberOfBlocks  = BufferSize / BlockSize;\r
+    NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;\r
+    //\r
+    // Max transfer MaxTransferBlocks\r
+    //\r
+    AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);\r
+    AddressPacket->Zero               = 0;\r
+    AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;\r
+    AddressPacket->Zero2              = 0;\r
+    AddressPacket->SegOffset          = EFI_SEGMENT (TransferBuffer) << 16;\r
+    AddressPacket->SegOffset |= EFI_OFFSET (TransferBuffer);\r
+    AddressPacket->Lba  = (UINT64) Lba;\r
+\r
+    Regs.H.AH           = 0x42;\r
+    Regs.H.DL           = BiosBlockIoDev->Bios.Number;\r
+    Regs.X.SI           = EFI_OFFSET (AddressPacket);\r
+    Regs.X.DS           = EFI_SEGMENT (AddressPacket);\r
+\r
+    CarryFlag           = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+    DEBUG (\r
+      (\r
+      DEBUG_BLKIO, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx  Block(s) %0d \n",\r
+      BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks\r
+      )\r
+      );\r
+    Media->MediaPresent = TRUE;\r
+    if (CarryFlag != 0) {\r
+      //\r
+      // Return Error Status\r
+      //\r
+      BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;\r
+      if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {\r
+        Media->MediaId++;\r
+        Bios = &BiosBlockIoDev->Bios;\r
+        if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {\r
+          if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {\r
+            Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;\r
+            Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;\r
+          } else {\r
+            ASSERT (FALSE);\r
+          }\r
+\r
+          Media->ReadOnly = FALSE;\r
+          gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+          gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);\r
+          return EFI_MEDIA_CHANGED;\r
+        }\r
+      }\r
+\r
+      if (Media->RemovableMedia) {\r
+        Media->MediaPresent = FALSE;\r
+      }\r
+\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    TransferByteSize = NumberOfBlocks * BlockSize;\r
+    CopyMem (Buffer, (VOID *) (UINTN) TransferBuffer, TransferByteSize);\r
+    BufferSize  = BufferSize - TransferByteSize;\r
+    Buffer      = (VOID *) ((UINT8 *) Buffer + TransferByteSize);\r
+    Lba += NumberOfBlocks;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Edd11BiosWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA        *Media;\r
+  BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;\r
+  EDD_DEVICE_ADDRESS_PACKET *AddressPacket;\r
+  //\r
+  // I exist only for readability\r
+  //\r
+  EFI_IA32_REGISTER_SET     Regs;\r
+  UINT64                    TransferBuffer;\r
+  UINTN                     NumberOfBlocks;\r
+  UINTN                     TransferByteSize;\r
+  UINTN                     BlockSize;\r
+  BIOS_LEGACY_DRIVE         *Bios;\r
+  UINTN                     CarryFlag;\r
+  UINTN                     MaxTransferBlocks;\r
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
+\r
+  Media     = This->Media;\r
+  BlockSize = Media->BlockSize;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);\r
+  AddressPacket     = mEddBufferUnder1Mb;\r
+\r
+  MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;\r
+\r
+  TransferBuffer    = (UINT64)(UINTN) mEdd11Buffer;\r
+  for (; BufferSize > 0;) {\r
+    NumberOfBlocks  = BufferSize / BlockSize;\r
+    NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;\r
+    //\r
+    // Max transfer MaxTransferBlocks\r
+    //\r
+    AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);\r
+    AddressPacket->Zero               = 0;\r
+    AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;\r
+    AddressPacket->Zero2              = 0;\r
+    AddressPacket->SegOffset          = EFI_SEGMENT (TransferBuffer) << 16;\r
+    AddressPacket->SegOffset |= EFI_OFFSET (TransferBuffer);\r
+    AddressPacket->Lba  = (UINT64) Lba;\r
+\r
+    Regs.H.AH           = 0x43;\r
+    Regs.H.AL           = 0x00;\r
+    //\r
+    // Write Verify disable\r
+    //\r
+    Regs.H.DL         = BiosBlockIoDev->Bios.Number;\r
+    Regs.X.SI         = EFI_OFFSET (AddressPacket);\r
+    Regs.X.DS         = EFI_SEGMENT (AddressPacket);\r
+\r
+    TransferByteSize  = NumberOfBlocks * BlockSize;\r
+    CopyMem ((VOID *) (UINTN) TransferBuffer, Buffer, TransferByteSize);\r
+\r
+    CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+    DEBUG (\r
+      (\r
+      DEBUG_BLKIO, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx  Block(s) %0d \n",\r
+      BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks\r
+      )\r
+      );\r
+    Media->MediaPresent = TRUE;\r
+    if (CarryFlag != 0) {\r
+      //\r
+      // Return Error Status\r
+      //\r
+      BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;\r
+      if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {\r
+        Media->MediaId++;\r
+        Bios = &BiosBlockIoDev->Bios;\r
+        if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {\r
+          if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {\r
+            Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;\r
+            Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;\r
+          } else {\r
+            ASSERT (FALSE);\r
+          }\r
+\r
+          Media->ReadOnly = FALSE;\r
+          gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+          gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);\r
+          return EFI_MEDIA_CHANGED;\r
+        }\r
+      } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {\r
+        Media->ReadOnly = TRUE;\r
+        return EFI_WRITE_PROTECTED;\r
+      }\r
+\r
+      if (Media->RemovableMedia) {\r
+        Media->MediaPresent = FALSE;\r
+      }\r
+\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Media->ReadOnly = FALSE;\r
+    BufferSize      = BufferSize - TransferByteSize;\r
+    Buffer          = (VOID *) ((UINT8 *) Buffer + TransferByteSize);\r
+    Lba += NumberOfBlocks;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosReadLegacyDrive (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA    *Media;\r
+  BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+  UINTN                 UpperCylinder;\r
+  UINTN                 Temp;\r
+  UINTN                 Cylinder;\r
+  UINTN                 Head;\r
+  UINTN                 Sector;\r
+  UINTN                 NumberOfBlocks;\r
+  UINTN                 TransferByteSize;\r
+  UINTN                 ShortLba;\r
+  UINTN                 CheckLba;\r
+  UINTN                 BlockSize;\r
+  BIOS_LEGACY_DRIVE     *Bios;\r
+  UINTN                 CarryFlag;\r
+  UINTN                 Retry;\r
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+\r
+  Media     = This->Media;\r
+  BlockSize = Media->BlockSize;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);\r
+  ShortLba        = (UINTN) Lba;\r
+\r
+  while (BufferSize != 0) {\r
+    //\r
+    // Compute I/O location in Sector, Head, Cylinder format\r
+    //\r
+    Sector    = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;\r
+    Temp      = ShortLba / BiosBlockIoDev->Bios.MaxSector;\r
+    Head      = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);\r
+    Cylinder  = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);\r
+\r
+    //\r
+    // Limit transfer to this Head & Cylinder\r
+    //\r
+    NumberOfBlocks  = BufferSize / BlockSize;\r
+    Temp            = BiosBlockIoDev->Bios.MaxSector - Sector + 1;\r
+    NumberOfBlocks  = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;\r
+\r
+    Retry           = 3;\r
+    do {\r
+      //\r
+      // Perform the IO\r
+      //\r
+      Regs.H.AH     = 2;\r
+      Regs.H.AL     = (UINT8) NumberOfBlocks;\r
+      Regs.H.DL     = BiosBlockIoDev->Bios.Number;\r
+\r
+      UpperCylinder = (Cylinder & 0x0f00) >> 2;\r
+\r
+      CheckLba      = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;\r
+      CheckLba      = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;\r
+\r
+      DEBUG (\r
+        (DEBUG_BLKIO,\r
+        "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",\r
+        ShortLba,\r
+        CheckLba,\r
+        Sector,\r
+        BiosBlockIoDev->Bios.MaxSector,\r
+        Head,\r
+        BiosBlockIoDev->Bios.MaxHead,\r
+        Cylinder,\r
+        UpperCylinder)\r
+        );\r
+      ASSERT (CheckLba == ShortLba);\r
+\r
+      Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));\r
+      Regs.H.DH = (UINT8) (Head & 0x3f);\r
+      Regs.H.CH = (UINT8) (Cylinder & 0xff);\r
+\r
+      Regs.X.BX = EFI_OFFSET (mEdd11Buffer);\r
+      Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);\r
+\r
+      DEBUG (\r
+        (DEBUG_BLKIO,\r
+        "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",\r
+        Regs.H.AL,\r
+        (UINT8) (Head & 0x3f),\r
+        Regs.H.DL,\r
+        (UINT8) (Cylinder & 0xff),\r
+        (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),\r
+        EFI_OFFSET (mEdd11Buffer),\r
+        EFI_SEGMENT (mEdd11Buffer))\r
+        );\r
+\r
+      CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+      DEBUG (\r
+        (\r
+        DEBUG_BLKIO, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,\r
+        CarryFlag, Regs.H.AH\r
+        )\r
+        );\r
+      Retry--;\r
+    } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);\r
+\r
+    Media->MediaPresent = TRUE;\r
+    if (CarryFlag != 0) {\r
+      //\r
+      // Return Error Status\r
+      //\r
+      BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;\r
+      if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {\r
+        Media->MediaId++;\r
+        Bios = &BiosBlockIoDev->Bios;\r
+        if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {\r
+          //\r
+          // If the size of the media changed we need to reset the disk geometry\r
+          //\r
+          if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {\r
+            Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;\r
+            Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;\r
+          } else {\r
+            //\r
+            // Legacy Interfaces\r
+            //\r
+            Media->LastBlock  = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;\r
+            Media->BlockSize  = 512;\r
+          }\r
+\r
+          Media->ReadOnly = FALSE;\r
+          gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+          gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);\r
+          return EFI_MEDIA_CHANGED;\r
+        }\r
+      }\r
+\r
+      if (Media->RemovableMedia) {\r
+        Media->MediaPresent = FALSE;\r
+      }\r
+\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    TransferByteSize = NumberOfBlocks * BlockSize;\r
+    CopyMem (Buffer, mEdd11Buffer, TransferByteSize);\r
+\r
+    ShortLba    = ShortLba + NumberOfBlocks;\r
+    BufferSize  = BufferSize - TransferByteSize;\r
+    Buffer      = (VOID *) ((UINT8 *) Buffer + TransferByteSize);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosWriteLegacyDrive (\r
+  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
+  IN  UINT32                MediaId,\r
+  IN  EFI_LBA               Lba,\r
+  IN  UINTN                 BufferSize,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA    *Media;\r
+  BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+  UINTN                 UpperCylinder;\r
+  UINTN                 Temp;\r
+  UINTN                 Cylinder;\r
+  UINTN                 Head;\r
+  UINTN                 Sector;\r
+  UINTN                 NumberOfBlocks;\r
+  UINTN                 TransferByteSize;\r
+  UINTN                 ShortLba;\r
+  UINTN                 CheckLba;\r
+  UINTN                 BlockSize;\r
+  BIOS_LEGACY_DRIVE     *Bios;\r
+  UINTN                 CarryFlag;\r
+  UINTN                 Retry;\r
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+\r
+  Media     = This->Media;\r
+  BlockSize = Media->BlockSize;\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);\r
+  ShortLba        = (UINTN) Lba;\r
+\r
+  while (BufferSize != 0) {\r
+    //\r
+    // Compute I/O location in Sector, Head, Cylinder format\r
+    //\r
+    Sector    = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;\r
+    Temp      = ShortLba / BiosBlockIoDev->Bios.MaxSector;\r
+    Head      = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);\r
+    Cylinder  = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);\r
+\r
+    //\r
+    // Limit transfer to this Head & Cylinder\r
+    //\r
+    NumberOfBlocks  = BufferSize / BlockSize;\r
+    Temp            = BiosBlockIoDev->Bios.MaxSector - Sector + 1;\r
+    NumberOfBlocks  = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;\r
+\r
+    Retry           = 3;\r
+    do {\r
+      //\r
+      // Perform the IO\r
+      //\r
+      Regs.H.AH     = 3;\r
+      Regs.H.AL     = (UINT8) NumberOfBlocks;\r
+      Regs.H.DL     = BiosBlockIoDev->Bios.Number;\r
+\r
+      UpperCylinder = (Cylinder & 0x0f00) >> 2;\r
+\r
+      CheckLba      = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;\r
+      CheckLba      = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;\r
+\r
+      DEBUG (\r
+        (DEBUG_BLKIO,\r
+        "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",\r
+        ShortLba,\r
+        CheckLba,\r
+        Sector,\r
+        BiosBlockIoDev->Bios.MaxSector,\r
+        Head,\r
+        BiosBlockIoDev->Bios.MaxHead,\r
+        Cylinder,\r
+        UpperCylinder)\r
+        );\r
+      ASSERT (CheckLba == ShortLba);\r
+\r
+      Regs.H.CL         = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));\r
+      Regs.H.DH         = (UINT8) (Head & 0x3f);\r
+      Regs.H.CH         = (UINT8) (Cylinder & 0xff);\r
+\r
+      Regs.X.BX         = EFI_OFFSET (mEdd11Buffer);\r
+      Regs.X.ES         = EFI_SEGMENT (mEdd11Buffer);\r
+\r
+      TransferByteSize  = NumberOfBlocks * BlockSize;\r
+      CopyMem (mEdd11Buffer, Buffer, TransferByteSize);\r
+\r
+      DEBUG (\r
+        (DEBUG_BLKIO,\r
+        "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",\r
+        Regs.H.AL,\r
+        (UINT8) (Head & 0x3f),\r
+        Regs.H.DL,\r
+        (UINT8) (Cylinder & 0xff),\r
+        (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),\r
+        EFI_OFFSET (mEdd11Buffer),\r
+        EFI_SEGMENT (mEdd11Buffer))\r
+        );\r
+\r
+      CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);\r
+      DEBUG (\r
+        (\r
+        DEBUG_BLKIO, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,\r
+        CarryFlag, Regs.H.AH\r
+        )\r
+        );\r
+      Retry--;\r
+    } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);\r
+\r
+    Media->MediaPresent = TRUE;\r
+    if (CarryFlag != 0) {\r
+      //\r
+      // Return Error Status\r
+      //\r
+      BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;\r
+      if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {\r
+        Media->MediaId++;\r
+        Bios = &BiosBlockIoDev->Bios;\r
+        if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {\r
+          if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {\r
+            Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;\r
+            Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;\r
+          } else {\r
+            //\r
+            // Legacy Interfaces\r
+            //\r
+            Media->LastBlock  = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;\r
+            Media->BlockSize  = 512;\r
+          }\r
+          //\r
+          // If the size of the media changed we need to reset the disk geometry\r
+          //\r
+          Media->ReadOnly = FALSE;\r
+          gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+          gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);\r
+          return EFI_MEDIA_CHANGED;\r
+        }\r
+      } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {\r
+        Media->ReadOnly = TRUE;\r
+        return EFI_WRITE_PROTECTED;\r
+      }\r
+\r
+      if (Media->RemovableMedia) {\r
+        Media->MediaPresent = FALSE;\r
+      }\r
+\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Media->ReadOnly = FALSE;\r
+    ShortLba        = ShortLba + NumberOfBlocks;\r
+    BufferSize      = BufferSize - TransferByteSize;\r
+    Buffer          = (VOID *) ((UINT8 *) Buffer + TransferByteSize);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf
new file mode 100644 (file)
index 0000000..3fcaa27
--- /dev/null
@@ -0,0 +1,58 @@
+## @file\r
+#  Component description file for BIOS Block IO module.\r
+#\r
+# Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution.  The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = BlockIoDxe\r
+  FILE_GUID                      = 4495E47E-42A9-4007-8c17-B6664F909D04\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = BiosBlockIoDriverEntryPoint\r
+\r
+[Sources]\r
+  BiosBlkIo.h\r
+  Edd.h\r
+  BiosBlkIo.c\r
+  BiosInt13.c\r
+  ComponentName.c\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+  BaseMemoryLib\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+  DevicePathLib\r
+  MemoryAllocationLib\r
+\r
+\r
+[Protocols]\r
+  gEfiBlockIoProtocolGuid\r
+  gEfiDevicePathProtocolGuid\r
+  gEfiPciIoProtocolGuid\r
+  gEfiLegacyBiosProtocolGuid\r
+\r
+\r
+[Guids]\r
+  gEfiLegacyBiosGuid\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..88bca13
--- /dev/null
@@ -0,0 +1,309 @@
+/** @file\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosBlkIo.h"\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL     gBiosBlockIoComponentName = {\r
+  BiosBlockIoComponentNameGetDriverName,\r
+  BiosBlockIoComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL    gBiosBlockIoComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosBlockIoComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosBlockIoComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosBlockIoDriverNameTable[] = {\r
+  {\r
+    "eng;en",\r
+    L"BIOS[INT13] Block Io Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mBiosBlockIoDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gBiosBlockIoComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosBlockIoComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h
new file mode 100644 (file)
index 0000000..be4d830
--- /dev/null
@@ -0,0 +1,209 @@
+/** @file\r
+  Include file to suport EDD 3.0.\r
+  This file is coded to T13 D1386 Revision 3\r
+  Availible on http://www.t13.org/#Project drafts\r
+  Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r3.pdf\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EDD_H_\r
+#define _EDD_H_\r
+\r
+//\r
+// packing with no compiler padding, so that the fields\r
+// of the following architected structures can be\r
+// properly accessed from C code.\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT8   Bus;\r
+  UINT8   Device;\r
+  UINT8   Function;\r
+  UINT8   Controller;\r
+  UINT32  Reserved;\r
+} EDD_PCI;\r
+\r
+typedef struct {\r
+  UINT16  Base;\r
+  UINT16  Reserved;\r
+  UINT32  Reserved2;\r
+} EDD_LEGACY;\r
+\r
+typedef union {\r
+  EDD_PCI     Pci;\r
+  EDD_LEGACY  Legacy;\r
+} EDD_INTERFACE_PATH;\r
+\r
+typedef struct {\r
+  UINT8 Master;\r
+  UINT8 Reserved[15];\r
+} EDD_ATA;\r
+\r
+typedef struct {\r
+  UINT8 Master;\r
+  UINT8 Lun;\r
+  UINT8 Reserved[14];\r
+} EDD_ATAPI;\r
+\r
+typedef struct {\r
+  UINT16  Pun;\r
+  UINT64  Lun;\r
+  UINT8   Reserved[6];\r
+} EDD_SCSI;\r
+\r
+typedef struct {\r
+  UINT64  SerialNumber;\r
+  UINT64  Reserved;\r
+} EDD_USB;\r
+\r
+typedef struct {\r
+  UINT64  Guid;\r
+  UINT64  Reserved;\r
+} EDD_1394;\r
+\r
+typedef struct {\r
+  UINT64  Wwn;\r
+  UINT64  Lun;\r
+} EDD_FIBRE;\r
+\r
+typedef union {\r
+  EDD_ATA   Ata;\r
+  EDD_ATAPI Atapi;\r
+  EDD_SCSI  Scsi;\r
+  EDD_USB   Usb;\r
+  EDD_1394  FireWire;\r
+  EDD_FIBRE FibreChannel;\r
+} EDD_DEVICE_PATH;\r
+\r
+typedef struct {\r
+  UINT16              StructureSize;\r
+  UINT16              Flags;\r
+  UINT32              MaxCylinders;\r
+  UINT32              MaxHeads;\r
+  UINT32              SectorsPerTrack;\r
+  UINT64              PhysicalSectors;\r
+  UINT16              BytesPerSector;\r
+  UINT32              Fdpt;\r
+  UINT16              Key;\r
+  UINT8               DevicePathLength;\r
+  UINT8               Reserved1;\r
+  UINT16              Reserved2;\r
+  CHAR8               HostBusType[4];\r
+  CHAR8               InterfaceType[8];\r
+  EDD_INTERFACE_PATH  InterfacePath;\r
+  EDD_DEVICE_PATH     DevicePath;\r
+  UINT8               Reserved3;\r
+  UINT8               Checksum;\r
+} EDD_DRIVE_PARAMETERS;\r
+\r
+//\r
+// EDD_DRIVE_PARAMETERS.Flags defines\r
+//\r
+#define EDD_GEOMETRY_VALID          0x02\r
+#define EDD_DEVICE_REMOVABLE        0x04\r
+#define EDD_WRITE_VERIFY_SUPPORTED  0x08\r
+#define EDD_DEVICE_CHANGE           0x10\r
+#define EDD_DEVICE_LOCKABLE         0x20\r
+\r
+//\r
+// BUGBUG: This bit does not follow the spec. It tends to be always set\r
+//  to work properly with Win98.\r
+//\r
+#define EDD_DEVICE_GEOMETRY_MAX 0x40\r
+\r
+typedef struct {\r
+  UINT8   PacketSizeInBytes;  // 0x18\r
+  UINT8   Zero;\r
+  UINT8   NumberOfBlocks;     // Max 0x7f\r
+  UINT8   Zero2;\r
+  UINT32  SegOffset;\r
+  UINT64  Lba;\r
+  UINT64  TransferBuffer;\r
+  UINT32  ExtendedBlockCount; // Max 0xffffffff\r
+  UINT32  Zero3;\r
+} EDD_DEVICE_ADDRESS_PACKET;\r
+\r
+#define EDD_VERSION_30  0x30\r
+\r
+//\r
+// Int 13 BIOS Errors\r
+//\r
+#define BIOS_PASS                   0x00\r
+#define BIOS_WRITE_PROTECTED        0x03\r
+#define BIOS_SECTOR_NOT_FOUND       0x04\r
+#define BIOS_RESET_FAILED           0x05\r
+#define BIOS_DISK_CHANGED           0x06\r
+#define BIOS_DRIVE_DOES_NOT_EXIST   0x07\r
+#define BIOS_DMA_ERROR              0x08\r
+#define BIOS_DATA_BOUNDRY_ERROR     0x09\r
+#define BIOS_BAD_SECTOR             0x0a\r
+#define BIOS_BAD_TRACK              0x0b\r
+#define BIOS_MEADIA_TYPE_NOT_FOUND  0x0c\r
+#define BIOS_INVALED_FORMAT         0x0d\r
+#define BIOS_ECC_ERROR              0x10\r
+#define BIOS_ECC_CORRECTED_ERROR    0x11\r
+#define BIOS_HARD_DRIVE_FAILURE     0x20\r
+#define BIOS_SEEK_FAILED            0x40\r
+#define BIOS_DRIVE_TIMEOUT          0x80\r
+#define BIOS_DRIVE_NOT_READY        0xaa\r
+#define BIOS_UNDEFINED_ERROR        0xbb\r
+#define BIOS_WRITE_FAULT            0xcc\r
+#define BIOS_SENSE_FAILED           0xff\r
+\r
+#define MAX_EDD11_XFER              0xfe00\r
+\r
+#pragma pack()\r
+//\r
+// Internal Data Structures\r
+//\r
+typedef struct {\r
+  CHAR8                 Letter;\r
+  UINT8                 Number;\r
+  UINT8                 EddVersion;\r
+  BOOLEAN               ExtendedInt13;\r
+  BOOLEAN               DriveLockingAndEjecting;\r
+  BOOLEAN               Edd;\r
+  BOOLEAN               Extensions64Bit;\r
+  BOOLEAN               ParametersValid;\r
+  UINT8                 ErrorCode;\r
+  VOID                  *FdptPointer;\r
+  BOOLEAN               Floppy;\r
+  BOOLEAN               AtapiFloppy;\r
+  UINT8                 MaxHead;\r
+  UINT8                 MaxSector;\r
+  UINT16                MaxCylinder;\r
+  UINT16                Pad;\r
+  EDD_DRIVE_PARAMETERS  Parameters;\r
+} BIOS_LEGACY_DRIVE;\r
+\r
+#define BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE SIGNATURE_32 ('b', 'b', 'i', 'o')\r
+typedef struct {\r
+  UINTN                     Signature;\r
+\r
+  EFI_HANDLE                Handle;\r
+  EFI_HANDLE                ControllerHandle;\r
+  EFI_BLOCK_IO_PROTOCOL     BlockIo;\r
+  EFI_BLOCK_IO_MEDIA        BlockMedia;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+\r
+  BIOS_LEGACY_DRIVE         Bios;\r
+\r
+} BIOS_BLOCK_IO_DEV;\r
+\r
+#define BIOS_BLOCK_IO_FROM_THIS(a)  CR (a, BIOS_BLOCK_IO_DEV, BlockIo, BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE)\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
new file mode 100644 (file)
index 0000000..06ef9d3
--- /dev/null
@@ -0,0 +1,2365 @@
+/** @file\r
+  ConsoleOut Routines that speak VGA.\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosKeyboard.h"\r
+\r
+//\r
+// EFI Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = {\r
+  BiosKeyboardDriverBindingSupported,\r
+  BiosKeyboardDriverBindingStart,\r
+  BiosKeyboardDriverBindingStop,\r
+  0x3,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
+/**\r
+  Enqueue the key.\r
+\r
+  @param  Queue                 The queue to be enqueued.\r
+  @param  KeyData               The key data to be enqueued.\r
+\r
+  @retval EFI_NOT_READY         The queue is full.\r
+  @retval EFI_SUCCESS           Successfully enqueued the key data.\r
+\r
+**/\r
+EFI_STATUS\r
+Enqueue (\r
+  IN SIMPLE_QUEUE         *Queue,\r
+  IN EFI_KEY_DATA         *KeyData\r
+  )\r
+{\r
+  if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));\r
+  Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Dequeue the key.\r
+  \r
+  @param  Queue                 The queue to be dequeued.\r
+  @param  KeyData               The key data to be dequeued.\r
+\r
+  @retval EFI_NOT_READY         The queue is empty.\r
+  @retval EFI_SUCCESS           Successfully dequeued the key data.\r
+\r
+**/\r
+EFI_STATUS\r
+Dequeue (\r
+  IN SIMPLE_QUEUE         *Queue,\r
+  IN EFI_KEY_DATA         *KeyData\r
+  )\r
+{\r
+  if (Queue->Front == Queue->Rear) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));\r
+  Queue->Front  = (Queue->Front + 1) % QUEUE_MAX_COUNT;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the queue is empty.\r
+  \r
+  @param  Queue                 The queue to be checked.\r
+\r
+  @retval EFI_NOT_READY         The queue is empty.\r
+  @retval EFI_SUCCESS           The queue is not empty.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckQueue (\r
+  IN SIMPLE_QUEUE         *Queue\r
+  )\r
+{\r
+  if (Queue->Front == Queue->Rear) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// EFI Driver Binding Protocol Functions\r
+//\r
+\r
+/**\r
+  Check whether the driver supports this device.\r
+\r
+  @param  This                   The Udriver binding protocol.\r
+  @param  Controller             The controller handle to check.\r
+  @param  RemainingDevicePath    The remaining device path.\r
+\r
+  @retval EFI_SUCCESS            The driver supports this controller.\r
+  @retval other                  This device isn't supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL                  *LegacyBios;\r
+  EFI_ISA_IO_PROTOCOL                       *IsaIo;\r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiLegacyBiosProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &LegacyBios\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiIsaIoProtocolGuid,\r
+                  (VOID **) &IsaIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Use the ISA I/O Protocol to see if Controller is the Keyboard controller\r
+  //\r
+  if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiIsaIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Starts the device with this driver.\r
+\r
+  @param  This                   The driver binding instance.\r
+  @param  Controller             Handle of device to bind driver to.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCESS            The controller is controlled by the driver.\r
+  @retval Other                  This controller cannot be started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL                  *LegacyBios;\r
+  EFI_ISA_IO_PROTOCOL                       *IsaIo;\r
+  BIOS_KEYBOARD_DEV                         *BiosKeyboardPrivate;\r
+  EFI_IA32_REGISTER_SET                     Regs;\r
+  BOOLEAN                                   CarryFlag;\r
+  EFI_PS2_POLICY_PROTOCOL                   *Ps2Policy;\r
+  UINT8                                     Command;\r
+  EFI_STATUS_CODE_VALUE                     StatusCode;\r
+\r
+  BiosKeyboardPrivate = NULL;\r
+  IsaIo = NULL;\r
+  StatusCode          = 0;\r
+\r
+  //\r
+  // Get Ps2 policy to set. Will be use if present.\r
+  //\r
+  gBS->LocateProtocol (\r
+        &gEfiPs2PolicyProtocolGuid,\r
+        NULL,\r
+        (VOID **) &Ps2Policy\r
+        );\r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiLegacyBiosProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &LegacyBios\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Open the IO Abstraction(s) needed\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiIsaIoProtocolGuid,\r
+                  (VOID **) &IsaIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Allocate the private device structure\r
+  //\r
+    BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV));\r
+  if (NULL == BiosKeyboardPrivate) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Initialize the private device structure\r
+  //\r
+  BiosKeyboardPrivate->Signature                  = BIOS_KEYBOARD_DEV_SIGNATURE;\r
+  BiosKeyboardPrivate->Handle                     = Controller;\r
+  BiosKeyboardPrivate->LegacyBios                 = LegacyBios;\r
+  BiosKeyboardPrivate->IsaIo                      = IsaIo;\r
+\r
+  BiosKeyboardPrivate->SimpleTextIn.Reset         = BiosKeyboardReset;\r
+  BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke;\r
+\r
+  BiosKeyboardPrivate->DataRegisterAddress        = KEYBOARD_8042_DATA_REGISTER;\r
+  BiosKeyboardPrivate->StatusRegisterAddress      = KEYBOARD_8042_STATUS_REGISTER;\r
+  BiosKeyboardPrivate->CommandRegisterAddress     = KEYBOARD_8042_COMMAND_REGISTER;\r
+  BiosKeyboardPrivate->ExtendedKeyboard           = TRUE;\r
+  \r
+  BiosKeyboardPrivate->Queue.Front                = 0;\r
+  BiosKeyboardPrivate->Queue.Rear                 = 0;\r
+  BiosKeyboardPrivate->SimpleTextInputEx.Reset               = BiosKeyboardResetEx;\r
+  BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx     = BiosKeyboardReadKeyStrokeEx;\r
+  BiosKeyboardPrivate->SimpleTextInputEx.SetState            = BiosKeyboardSetState;\r
+  BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify   = BiosKeyboardRegisterKeyNotify;  \r
+  BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify;    \r
+  InitializeListHead (&BiosKeyboardPrivate->NotifyList);\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &BiosKeyboardPrivate->DevicePath\r
+                  );\r
+\r
+  //\r
+  // Report that the keyboard is being enabled\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,\r
+    BiosKeyboardPrivate->DevicePath\r
+    );\r
+\r
+  //\r
+  // Setup the WaitForKey event\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  BiosKeyboardWaitForKey,\r
+                  &(BiosKeyboardPrivate->SimpleTextIn),\r
+                  &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey)\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;\r
+    goto Done;\r
+  }\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  BiosKeyboardWaitForKeyEx,\r
+                  &(BiosKeyboardPrivate->SimpleTextInputEx),\r
+                  &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;\r
+    goto Done;\r
+  } \r
+\r
+  //\r
+  // Setup a periodic timer, used for reading keystrokes at a fixed interval\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  BiosKeyboardTimerHandler,\r
+                  BiosKeyboardPrivate,\r
+                  &BiosKeyboardPrivate->TimerEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Status      = EFI_OUT_OF_RESOURCES;\r
+    StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
+    goto Done;\r
+  }\r
+\r
+  Status = gBS->SetTimer (\r
+                  BiosKeyboardPrivate->TimerEvent,\r
+                  TimerPeriodic,\r
+                  KEYBOARD_TIMER_INTERVAL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Status      = EFI_OUT_OF_RESOURCES;\r
+    StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,\r
+    BiosKeyboardPrivate->DevicePath\r
+    );\r
+\r
+  //\r
+  // Reset the keyboard device\r
+  //\r
+  Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset (\r
+                                                    &BiosKeyboardPrivate->SimpleTextInputEx,\r
+                                                    FALSE\r
+                                                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Do platform specific policy like port swapping and keyboard light default\r
+  //\r
+  if (Ps2Policy != NULL) {\r
+\r
+    Ps2Policy->Ps2InitHardware (Controller);\r
+\r
+    Command = 0;\r
+    if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {\r
+      Command |= 4;\r
+    }\r
+\r
+    if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {\r
+      Command |= 2;\r
+    }\r
+\r
+    if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {\r
+      Command |= 1;\r
+    }\r
+\r
+    KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
+    KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
+    KeyboardWrite (BiosKeyboardPrivate, Command);\r
+    //\r
+    // Call Legacy BIOS Protocol to set whatever is necessary\r
+    //\r
+    LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);\r
+  }\r
+  //\r
+  // Get Configuration\r
+  //\r
+  Regs.H.AH = 0xc0;\r
+  CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (\r
+                                                 BiosKeyboardPrivate->LegacyBios,\r
+                                                 0x15,\r
+                                                 &Regs\r
+                                                 );\r
+\r
+  if (!CarryFlag) {\r
+    //\r
+    // Check bit 6 of Feature Byte 2.\r
+    // If it is set, then Int 16 Func 09 is supported\r
+    //\r
+    if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {\r
+      //\r
+      // Get Keyboard Functionality\r
+      //\r
+      Regs.H.AH = 0x09;\r
+      CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (\r
+                                                     BiosKeyboardPrivate->LegacyBios,\r
+                                                     0x16,\r
+                                                     &Regs\r
+                                                     );\r
+\r
+      if (!CarryFlag) {\r
+        //\r
+        // Check bit 5 of AH.\r
+        // If it is set, then INT 16 Finc 10-12 are supported.\r
+        //\r
+        if ((Regs.H.AL & 0x40) != 0) {\r
+          //\r
+          // Set the flag to use INT 16 Func 10-12\r
+          //\r
+          BiosKeyboardPrivate->ExtendedKeyboard = TRUE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Install protocol interfaces for the keyboard device.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Controller,\r
+                  &gEfiSimpleTextInProtocolGuid,\r
+                  &BiosKeyboardPrivate->SimpleTextIn,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  &BiosKeyboardPrivate->SimpleTextInputEx,\r
+                  NULL\r
+                  );\r
+\r
+Done:\r
+  if (StatusCode != 0) {\r
+    //\r
+    // Report an Error Code for failing to start the keyboard device\r
+    //\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      StatusCode,\r
+      BiosKeyboardPrivate->DevicePath\r
+      );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    if (BiosKeyboardPrivate != NULL) {    \r
+      if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {\r
+        gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
+      }\r
+\r
+      if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {\r
+        gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);    \r
+      }\r
+      BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
+\r
+      if (BiosKeyboardPrivate->TimerEvent != NULL) {\r
+        gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);    \r
+      }\r
+\r
+      FreePool (BiosKeyboardPrivate);\r
+    }\r
+\r
+    if (IsaIo != NULL) {\r
+      gBS->CloseProtocol (\r
+             Controller,\r
+             &gEfiIsaIoProtocolGuid,\r
+             This->DriverBindingHandle,\r
+             Controller\r
+             );\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop the device handled by this driver.\r
+\r
+  @param  This                   The driver binding protocol.\r
+  @param  Controller             The controller to release.\r
+  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.\r
+  @param  ChildHandleBuffer      The array of child handle.\r
+\r
+  @retval EFI_SUCCESS            The device was stopped.\r
+  @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.\r
+  @retval Others                 Fail to uninstall protocols attached on the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;\r
+  BIOS_KEYBOARD_DEV              *BiosKeyboardPrivate;\r
+\r
+  //\r
+  // Disable Keyboard\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSimpleTextInProtocolGuid,\r
+                  (VOID **) &SimpleTextIn,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn);\r
+\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  Controller,\r
+                  &gEfiSimpleTextInProtocolGuid,\r
+                  &BiosKeyboardPrivate->SimpleTextIn,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  &BiosKeyboardPrivate->SimpleTextInputEx,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Release the IsaIo protocol on the controller handle\r
+  //\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiIsaIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  //\r
+  // Free other resources\r
+  //\r
+  gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
+  gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);\r
+  gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);\r
+  BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
+\r
+  FreePool (BiosKeyboardPrivate);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+\r
+  @return  The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.\r
+\r
+**/\r
+UINT8\r
+KeyReadDataRegister (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate\r
+  )\r
+{\r
+  UINT8 Data;\r
+\r
+  //\r
+  // Use IsaIo protocol to perform IO operations\r
+  //\r
+  BiosKeyboardPrivate->IsaIo->Io.Read (\r
+                                   BiosKeyboardPrivate->IsaIo,\r
+                                   EfiIsaIoWidthUint8,\r
+                                   BiosKeyboardPrivate->DataRegisterAddress,\r
+                                   1,\r
+                                   &Data\r
+                                   );\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+\r
+  @return  The status byte read from status register of Keyboard Controller from command port which often is port 64H.\r
+\r
+**/\r
+UINT8\r
+KeyReadStatusRegister (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate\r
+  )\r
+{\r
+  UINT8 Data;\r
+\r
+  //\r
+  // Use IsaIo protocol to perform IO operations\r
+  //\r
+  BiosKeyboardPrivate->IsaIo->Io.Read (\r
+                                   BiosKeyboardPrivate->IsaIo,\r
+                                   EfiIsaIoWidthUint8,\r
+                                   BiosKeyboardPrivate->StatusRegisterAddress,\r
+                                   1,\r
+                                   &Data\r
+                                   );\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Data                 Data byte to write.\r
+\r
+**/\r
+VOID\r
+KeyWriteCommandRegister (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  IN UINT8              Data\r
+  )\r
+{\r
+  //\r
+  // Use IsaIo protocol to perform IO operations\r
+  //\r
+  BiosKeyboardPrivate->IsaIo->Io.Write (\r
+                                   BiosKeyboardPrivate->IsaIo,\r
+                                   EfiIsaIoWidthUint8,\r
+                                   BiosKeyboardPrivate->CommandRegisterAddress,\r
+                                   1,\r
+                                   &Data\r
+                                   );\r
+}\r
+\r
+/**\r
+  Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Data                 Data byte to write.\r
+\r
+**/\r
+VOID\r
+KeyWriteDataRegister (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  IN UINT8              Data\r
+  )\r
+{\r
+  //\r
+  // Use IsaIo protocol to perform IO operations\r
+  //\r
+  BiosKeyboardPrivate->IsaIo->Io.Write (\r
+                                   BiosKeyboardPrivate->IsaIo,\r
+                                   EfiIsaIoWidthUint8,\r
+                                   BiosKeyboardPrivate->DataRegisterAddress,\r
+                                   1,\r
+                                   &Data\r
+                                   );\r
+}\r
+\r
+/**\r
+  Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Data                 The pointer for data that being read out.\r
+\r
+  @retval  EFI_SUCCESS          The data byte read out successfully.\r
+  @retval  EFI_TIMEOUT          Timeout occurred during reading out data byte.\r
+\r
+**/\r
+EFI_STATUS\r
+KeyboardRead (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  OUT UINT8             *Data\r
+  )\r
+{\r
+  UINT32  TimeOut;\r
+  UINT32  RegFilled;\r
+\r
+  TimeOut   = 0;\r
+  RegFilled = 0;\r
+\r
+  //\r
+  // wait till output buffer full then perform the read\r
+  //\r
+  for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+    if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {\r
+      RegFilled = 1;\r
+      *Data     = KeyReadDataRegister (BiosKeyboardPrivate);\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (30);\r
+  }\r
+\r
+  if (RegFilled == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Data                 Data byte to write.\r
+\r
+  @retval  EFI_SUCCESS          The data byte is written successfully.\r
+  @retval  EFI_TIMEOUT          Timeout occurred during writing.\r
+\r
+**/\r
+EFI_STATUS\r
+KeyboardWrite (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  IN UINT8              Data\r
+  )\r
+{\r
+  UINT32  TimeOut;\r
+  UINT32  RegEmptied;\r
+\r
+  TimeOut     = 0;\r
+  RegEmptied  = 0;\r
+\r
+  //\r
+  // wait for input buffer empty\r
+  //\r
+  for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+    if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
+      RegEmptied = 1;\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (30);\r
+  }\r
+\r
+  if (RegEmptied == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+  //\r
+  // Write it\r
+  //\r
+  KeyWriteDataRegister (BiosKeyboardPrivate, Data);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Data                 Command byte to write.\r
+\r
+  @retval  EFI_SUCCESS          The command byte is written successfully.\r
+  @retval  EFI_TIMEOUT          Timeout occurred during writing.\r
+\r
+**/\r
+EFI_STATUS\r
+KeyboardCommand (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  IN UINT8              Data\r
+  )\r
+{\r
+  UINT32  TimeOut;\r
+  UINT32  RegEmptied;\r
+\r
+  TimeOut     = 0;\r
+  RegEmptied  = 0;\r
+\r
+  //\r
+  // Wait For Input Buffer Empty\r
+  //\r
+  for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+    if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
+      RegEmptied = 1;\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (30);\r
+  }\r
+\r
+  if (RegEmptied == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+  //\r
+  // issue the command\r
+  //\r
+  KeyWriteCommandRegister (BiosKeyboardPrivate, Data);\r
+\r
+  //\r
+  // Wait For Input Buffer Empty again\r
+  //\r
+  RegEmptied = 0;\r
+  for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+    if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
+      RegEmptied = 1;\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (30);\r
+  }\r
+\r
+  if (RegEmptied == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Wait for a specific value to be presented in\r
+  Data register of Keyboard Controller by keyboard and then read it,\r
+  used in keyboard commands ack\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Value                The value to be waited for\r
+  @param   WaitForValueTimeOut  The limit of microseconds for timeout\r
+\r
+  @retval  EFI_SUCCESS          The command byte is written successfully.\r
+  @retval  EFI_TIMEOUT          Timeout occurred during writing.\r
+\r
+**/\r
+EFI_STATUS\r
+KeyboardWaitForValue (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  IN UINT8              Value,\r
+  IN UINTN              WaitForValueTimeOut\r
+  )\r
+{\r
+  UINT8   Data;\r
+  UINT32  TimeOut;\r
+  UINT32  SumTimeOut;\r
+  UINT32  GotIt;\r
+\r
+  GotIt       = 0;\r
+  TimeOut     = 0;\r
+  SumTimeOut  = 0;\r
+\r
+  //\r
+  // Make sure the initial value of 'Data' is different from 'Value'\r
+  //\r
+  Data = 0;\r
+  if (Data == Value) {\r
+    Data = 1;\r
+  }\r
+  //\r
+  // Read from 8042 (multiple times if needed)\r
+  // until the expected value appears\r
+  // use SumTimeOut to control the iteration\r
+  //\r
+  while (1) {\r
+    //\r
+    // Perform a read\r
+    //\r
+    for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+      if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {\r
+        Data = KeyReadDataRegister (BiosKeyboardPrivate);\r
+        break;\r
+      }\r
+\r
+      gBS->Stall (30);\r
+    }\r
+\r
+    SumTimeOut += TimeOut;\r
+\r
+    if (Data == Value) {\r
+      GotIt = 1;\r
+      break;\r
+    }\r
+\r
+    if (SumTimeOut >= WaitForValueTimeOut) {\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // Check results\r
+  //\r
+  if (GotIt != 0) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can \r
+  be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+  @param  BiosKeyboardPrivate   Bioskeyboard driver private structure.\r
+  @param  KeyData               A pointer to a buffer that is filled in with the keystroke \r
+                                state data for the key that was pressed.\r
+\r
+  @retval EFI_SUCCESS           The keystroke information was returned.\r
+  @retval EFI_NOT_READY         There was no keystroke data availiable.\r
+  @retval EFI_DEVICE_ERROR      The keystroke information was not returned due to \r
+                                hardware errors.\r
+  @retval EFI_INVALID_PARAMETER KeyData is NULL.                        \r
+    \r
+**/\r
+EFI_STATUS\r
+KeyboardReadKeyStrokeWorker (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  OUT EFI_KEY_DATA      *KeyData\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_TPL                               OldTpl;\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Use TimerEvent callback funciton to check whether there's any key pressed\r
+  //\r
+  \r
+  //\r
+  // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.\r
+  // Csm will be used to check whether there is a key pending, but the csm will disable all \r
+  // interrupt before switch to compatibility16, which mean all the efiCompatibility timer\r
+  // event will stop work during the compatibility16. And If a caller recursivly invoke this function, \r
+  // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period, \r
+  // e.g. usb keyboard driver. \r
+  // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.\r
+  // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.\r
+  //\r
+  gBS->Stall (1000);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate);\r
+  //\r
+  // If there's no key, just return\r
+  //\r
+  Status = CheckQueue (&BiosKeyboardPrivate->Queue);\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData);\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// EFI Simple Text In Protocol Functions\r
+//\r
+/**\r
+  Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.\r
+\r
+  @param  This                  Pointer of simple text Protocol.\r
+  @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.\r
+\r
+  @retval EFI_SUCCESS           The command byte is written successfully.\r
+  @retval EFI_DEVICE_ERROR      Errors occurred during reseting keyboard.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardReset (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
+  IN  BOOLEAN                         ExtendedVerification\r
+  )\r
+{\r
+  BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
+  EFI_STATUS        Status;\r
+  EFI_TPL           OldTpl;\r
+  UINT8             CommandByte;\r
+  BOOLEAN           MouseEnable;\r
+  EFI_INPUT_KEY     Key;\r
+\r
+  MouseEnable         = FALSE;\r
+  BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // 1\r
+  // Report reset progress code\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,\r
+    BiosKeyboardPrivate->DevicePath\r
+    );\r
+\r
+  //\r
+  // Report a Progress Code for clearing the keyboard buffer\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,\r
+    BiosKeyboardPrivate->DevicePath\r
+    );\r
+\r
+  //\r
+  // 2\r
+  // Raise TPL to avoid mouse operation impact\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  //\r
+  //\r
+  // Exhaust output buffer data\r
+  //\r
+  do {\r
+    Status = BiosKeyboardReadKeyStroke (\r
+               This,\r
+               &Key\r
+               );\r
+  } while (!EFI_ERROR (Status));\r
+  //\r
+  // 3\r
+  // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H\r
+  // if not skip step 4&5 and jump to step 6 to selftest KBC and report this\r
+  // else   go step 4\r
+  //\r
+  if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {\r
+    //\r
+    // 4\r
+    // CheckMouseStatus to decide enable it later or not\r
+    //\r
+    //\r
+    // Read the command byte of KBC\r
+    //\r
+    Status = KeyboardCommand (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDREG_VIA64_CMDBYTE_R\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardRead (\r
+               BiosKeyboardPrivate,\r
+               &CommandByte\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // Check mouse enabled or not before\r
+    //\r
+    if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {\r
+      MouseEnable = FALSE;\r
+    } else {\r
+      MouseEnable = TRUE;\r
+    }\r
+    //\r
+    // 5\r
+    // disable mouse (via KBC) and Keyborad device\r
+    //\r
+    Status = KeyboardCommand (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDREG_VIA64_AUX_DISABLE\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardCommand (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDREG_VIA64_KB_DISABLE\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // 6\r
+    // KBC Self Test\r
+    //\r
+    //\r
+    // Report a Progress Code for performing a self test on the keyboard controller\r
+    //\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_PROGRESS_CODE,\r
+      EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,\r
+      BiosKeyboardPrivate->DevicePath\r
+      );\r
+\r
+    Status = KeyboardCommand (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDREG_VIA64_KBC_SLFTEST\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_KBCSLFTEST_OK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+  }\r
+  //\r
+  // 7\r
+  // Disable  Mouse interface, enable  Keyboard interface and declare selftest success\r
+  //\r
+  // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.\r
+  //\r
+  Status = KeyboardCommand (\r
+             BiosKeyboardPrivate,\r
+             KBC_CMDREG_VIA64_CMDBYTE_W\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status    = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Write 8042 Command Byte, set System Flag\r
+  // While at the same time:\r
+  //  1. disable mouse interface,\r
+  //  2. enable kbd interface,\r
+  //  3. enable PC/XT kbd translation mode\r
+  //  4. enable mouse and kbd interrupts\r
+  //\r
+  //Command Byte bits:\r
+  //  7: Reserved\r
+  //  6: PC/XT translation mode\r
+  //  5: Disable Auxiliary device interface\r
+  //  4: Disable keyboard interface\r
+  //  3: Reserved\r
+  //  2: System Flag\r
+  //  1: Enable Auxiliary device interrupt\r
+  //  0: Enable Keyboard interrupt\r
+  //\r
+  CommandByte = 0;\r
+  Status = KeyboardWrite (\r
+             BiosKeyboardPrivate,\r
+             (UINT8) ((CommandByte &\r
+              (~KB_CMMBYTE_DISABLE_KB)) |\r
+              KB_CMMBYTE_KSCAN2UNI_COV |\r
+              KB_CMMBYTE_ENABLE_AUXINT |\r
+              KB_CMMBYTE_ENABLE_KBINT  |\r
+              KB_CMMBYTE_SLFTEST_SUCC  |\r
+              KB_CMMBYTE_DISABLE_AUX)\r
+             );\r
+\r
+  //\r
+  // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
+  // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.\r
+  // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,\r
+  // Real reset will not do.\r
+  //\r
+  if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) {\r
+    //\r
+    // 8\r
+    // Send keyboard reset command then read ACK\r
+    //\r
+    Status = KeyboardWrite (\r
+               BiosKeyboardPrivate,\r
+               KBC_INPBUF_VIA60_KBRESET\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_ACK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // 9\r
+    // Wait for keyboard return test OK.\r
+    //\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_BATTEST_OK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // 10\r
+    // set keyboard scan code set = 02 (standard configuration)\r
+    //\r
+    Status = KeyboardWrite (\r
+               BiosKeyboardPrivate,\r
+               KBC_INPBUF_VIA60_KBSCODE\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_ACK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardWrite (\r
+               BiosKeyboardPrivate,\r
+               KBC_INPBUF_VIA60_SCODESET2\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_ACK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // 11\r
+    // enable keyboard itself (not via KBC) by writing CMD F4 via 60H\r
+    //\r
+    Status = KeyboardWrite (\r
+               BiosKeyboardPrivate,\r
+               KBC_INPBUF_VIA60_KBEN\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_ACK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // 12\r
+    // Additional validation, do it as follow:\r
+    // 1). check for status register of PARE && TIM via 64H\r
+    // 2). perform KB checking by writing ABh via 64H\r
+    //\r
+    if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardCommand (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDREG_VIA64_KB_CKECK\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_KBCHECK_OK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+  }\r
+  //\r
+  // 13\r
+  // Done for validating keyboard. Enable keyboard (via KBC)\r
+  // and recover the command byte to proper value\r
+  //\r
+  Status = KeyboardCommand (\r
+             BiosKeyboardPrivate,\r
+             KBC_CMDREG_VIA64_KB_ENABLE\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status    = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // 14\r
+  // conditionally enable mouse (via KBC)\r
+  //\r
+  if (MouseEnable) {\r
+    Status = KeyboardCommand (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDREG_VIA64_AUX_ENABLE\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+\r
+    }\r
+  }\r
+\r
+Exit:\r
+  //\r
+  // 15\r
+  // resume priority of task level\r
+  //\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+  Read out the scan code of the key that has just been stroked.\r
+\r
+  @param  This        Pointer of simple text Protocol.\r
+  @param  Key         Pointer for store the key that read out.\r
+\r
+  @retval EFI_SUCCESS The key is read out successfully.\r
+  @retval other       The key reading failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardReadKeyStroke (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
+  OUT EFI_INPUT_KEY                   *Key\r
+  )\r
+{\r
+  BIOS_KEYBOARD_DEV     *BiosKeyboardPrivate;\r
+  EFI_STATUS            Status;\r
+  EFI_KEY_DATA          KeyData;\r
+\r
+  BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
+\r
+  Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));  \r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
+\r
+  @param  Event       The event that be siganlled when any key has been stroked.\r
+  @param  Context     Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BiosKeyboardWaitForKey (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
+  )\r
+{\r
+  //\r
+  // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.\r
+  // Csm will be used to check whether there is a key pending, but the csm will disable all\r
+  // interrupt before switch to compatibility16, which mean all the efiCompatibility timer\r
+  // event will stop work during the compatibility16. And If a caller recursivly invoke this function,\r
+  // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,\r
+  // e.g. usb keyboard driver.\r
+  // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.\r
+  // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.\r
+  //\r
+  gBS->Stall (1000);\r
+  //\r
+  // Use TimerEvent callback funciton to check whether there's any key pressed\r
+  //\r
+  BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));\r
+\r
+  if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) {\r
+    gBS->SignalEvent (Event);\r
+  }\r
+}\r
+\r
+/**\r
+  Check key buffer to get the key stroke status.\r
+\r
+  @param  This         Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.\r
+  \r
+  @retval EFI_SUCCESS  A key is being pressed now.\r
+  @retval Other        No key is now pressed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardCheckForKey (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This\r
+  )\r
+{\r
+  BIOS_KEYBOARD_DEV     *BiosKeyboardPrivate;\r
+\r
+  BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
+\r
+  return CheckQueue (&BiosKeyboardPrivate->Queue);\r
+}\r
+//\r
+// Private worker functions\r
+//\r
+#define TABLE_END 0x0\r
+\r
+typedef struct _CONVERT_TABLE_ENTRY {\r
+  UINT16  ScanCode;\r
+  UINT16  EfiScanCode;\r
+} CONVERT_TABLE_ENTRY;\r
+\r
+CONVERT_TABLE_ENTRY mConvertTable[] = {\r
+  {\r
+    0x47,\r
+    SCAN_HOME\r
+  },\r
+  {\r
+    0x48,\r
+    SCAN_UP\r
+  },\r
+  {\r
+    0x49,\r
+    SCAN_PAGE_UP\r
+  },\r
+  {\r
+    0x4b,\r
+    SCAN_LEFT\r
+  },\r
+  {\r
+    0x4d,\r
+    SCAN_RIGHT\r
+  },\r
+  {\r
+    0x4f,\r
+    SCAN_END\r
+  },\r
+  {\r
+    0x50,\r
+    SCAN_DOWN\r
+  },\r
+  {\r
+    0x51,\r
+    SCAN_PAGE_DOWN\r
+  },\r
+  {\r
+    0x52,\r
+    SCAN_INSERT\r
+  },\r
+  {\r
+    0x53,\r
+    SCAN_DELETE\r
+  },\r
+  //\r
+  // Function Keys are only valid if KeyChar == 0x00\r
+  //  This function does not require KeyChar to be 0x00\r
+  //\r
+  {\r
+    0x3b,\r
+    SCAN_F1\r
+  },\r
+  {\r
+    0x3c,\r
+    SCAN_F2\r
+  },\r
+  {\r
+    0x3d,\r
+    SCAN_F3\r
+  },\r
+  {\r
+    0x3e,\r
+    SCAN_F4\r
+  },\r
+  {\r
+    0x3f,\r
+    SCAN_F5\r
+  },\r
+  {\r
+    0x40,\r
+    SCAN_F6\r
+  },\r
+  {\r
+    0x41,\r
+    SCAN_F7\r
+  },\r
+  {\r
+    0x42,\r
+    SCAN_F8\r
+  },\r
+  {\r
+    0x43,\r
+    SCAN_F9\r
+  },\r
+  {\r
+    0x44,\r
+    SCAN_F10\r
+  },\r
+  {\r
+    0x85,\r
+    SCAN_F11\r
+  },\r
+  {\r
+    0x86,\r
+    SCAN_F12\r
+  },\r
+  //\r
+  // Convert ALT + Fn keys\r
+  //\r
+  {\r
+    0x68,\r
+    SCAN_F1\r
+  },\r
+  {\r
+    0x69,\r
+    SCAN_F2\r
+  },\r
+  {\r
+    0x6a,\r
+    SCAN_F3\r
+  },\r
+  {\r
+    0x6b,\r
+    SCAN_F4\r
+  },\r
+  {\r
+    0x6c,\r
+    SCAN_F5\r
+  },\r
+  {\r
+    0x6d,\r
+    SCAN_F6\r
+  },\r
+  {\r
+    0x6e,\r
+    SCAN_F7\r
+  },\r
+  {\r
+    0x6f,\r
+    SCAN_F8\r
+  },\r
+  {\r
+    0x70,\r
+    SCAN_F9\r
+  },\r
+  {\r
+    0x71,\r
+    SCAN_F10\r
+  },\r
+  {\r
+    TABLE_END,\r
+    SCAN_NULL\r
+  },\r
+};\r
+\r
+/**\r
+  Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.\r
+\r
+  @param  KeyChar      Unicode of key.\r
+  @param  ScanCode     Scan code of key.\r
+\r
+  @return The value of EFI Scancode for the key.    \r
+  @retval SCAN_NULL   No corresponding value in the EFI convert table is found for the key.\r
+\r
+**/\r
+UINT16\r
+ConvertToEFIScanCode (\r
+  IN  CHAR16  KeyChar,\r
+  IN  UINT16  ScanCode\r
+  )\r
+{\r
+  UINT16  EfiScanCode;\r
+  UINT16  Index;\r
+\r
+  if (KeyChar == CHAR_ESC) {\r
+    EfiScanCode = SCAN_ESC;\r
+  } else if (KeyChar == 0x00 || KeyChar == 0xe0) {\r
+    //\r
+    // Movement & Function Keys\r
+    //\r
+    for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) {\r
+      if (ScanCode == mConvertTable[Index].ScanCode) {\r
+        return mConvertTable[Index].EfiScanCode;\r
+      }\r
+    }\r
+    //\r
+    // Reach Table end, return default value\r
+    //\r
+    return SCAN_NULL;\r
+  } else {\r
+    return SCAN_NULL;\r
+  }\r
+\r
+  return EfiScanCode;\r
+}\r
+\r
+/**\r
+  Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command\r
+  If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device\r
+  should not be in system. \r
+\r
+  @param  BiosKeyboardPrivate  Keyboard Private Data Struture\r
+\r
+  @retval TRUE  Keyboard in System.\r
+  @retval FALSE Keyboard not in System.\r
+\r
+**/\r
+BOOLEAN\r
+CheckKeyboardConnect (\r
+  IN  BIOS_KEYBOARD_DEV     *BiosKeyboardPrivate\r
+  )\r
+{\r
+  EFI_STATUS     Status;\r
+\r
+  Status         = EFI_SUCCESS;\r
+  //\r
+  // enable keyboard itself and wait for its ack\r
+  // If can't receive ack, Keyboard should not be connected.\r
+  //\r
+  Status = KeyboardWrite (\r
+             BiosKeyboardPrivate,\r
+             KBC_INPBUF_VIA60_KBEN\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Status = KeyboardWaitForValue (\r
+             BiosKeyboardPrivate,\r
+             KBC_CMDECHO_ACK,\r
+             KEYBOARD_WAITFORVALUE_TIMEOUT\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Timer event handler: read a series of key stroke from 8042\r
+  and put them into memory key buffer. \r
+  It is registered as running under TPL_NOTIFY\r
+  \r
+  @param  Event   The timer event\r
+  @param  Context A BIOS_KEYBOARD_DEV pointer\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BiosKeyboardTimerHandler (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  EFI_TPL                            OldTpl;\r
+  BIOS_KEYBOARD_DEV                  *BiosKeyboardPrivate;\r
+  EFI_IA32_REGISTER_SET              Regs;\r
+  UINT8                              KbFlag1;  // 0040h:0017h - KEYBOARD - STATUS FLAGS 1\r
+  UINT8                              KbFlag2;  // 0040h:0018h - KEYBOARD - STATUS FLAGS 2\r
+  EFI_KEY_DATA                       KeyData;\r
+  LIST_ENTRY                         *Link;\r
+  BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
+\r
+  BiosKeyboardPrivate = Context;\r
+\r
+  //\r
+  // Enter critical section\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  //\r
+  // if there is no key present, just return\r
+  //\r
+  if (BiosKeyboardPrivate->ExtendedKeyboard) {\r
+    Regs.H.AH = 0x11;\r
+  } else {\r
+    Regs.H.AH = 0x01;\r
+  }\r
+\r
+  BiosKeyboardPrivate->LegacyBios->Int86 (\r
+                                     BiosKeyboardPrivate->LegacyBios,\r
+                                     0x16,\r
+                                     &Regs\r
+                                     );\r
+  if (Regs.X.Flags.ZF != 0) {\r
+    gBS->RestoreTPL (OldTpl);\r
+    return;\r
+  }  \r
+\r
+  //\r
+  // Read the key\r
+  //\r
+  if (BiosKeyboardPrivate->ExtendedKeyboard) {\r
+    Regs.H.AH = 0x10;\r
+  } else {\r
+    Regs.H.AH = 0x00;\r
+  }\r
+\r
+  BiosKeyboardPrivate->LegacyBios->Int86 (\r
+                                     BiosKeyboardPrivate->LegacyBios,\r
+                                     0x16,\r
+                                     &Regs\r
+                                     );\r
+\r
+  KeyData.Key.ScanCode            = (UINT16) Regs.H.AH;\r
+  KeyData.Key.UnicodeChar         = (UINT16) Regs.H.AL;\r
+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
+  KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
+  //\r
+  // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB  buffer in BDA (BIOS DATE AREA),  then \r
+  // Int 16 depend  KB buffer and some key bits in BDA to translate the scancode to ASCII code, and  return both the scancode and ASCII \r
+  // code to Int 16 caller. This translation process works well if the Int 9  could response user input in time. But in Tiano enviorment,  the Int 9 \r
+  // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when \r
+  // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit \r
+  // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode \r
+  // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers \r
+  // performance, like USB.\r
+  //\r
+  // 1. If CTRL or ALT release code is missed,  all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In \r
+  //     this case, the KB input seems fail to work, and user input is blocked. To solve the problem, we can help to clear the CTRL or ALT flag in BDA \r
+  //    after every Int 16 finish. Thus persist to press CTRL or ALT has same effection as only press one time. It is Ok, since user not often use the \r
+  //    CTRL and ALT.\r
+  //\r
+  // 2. If SHIFT release code is missed, all later lowercase input will become capital. This is ugly, but not block user input. If user press the lost \r
+  //     SHIFT again,  the lowercase will come back to normal. Since user often use the SHIFT, it is not reasonable to help to clear the SHIFT flag in BDA,\r
+  //     which will let persist to press SHIFT has same effection as only press one time. \r
+  //\r
+  //0040h:0017h - KEYBOARD - STATUS FLAGS 1\r
+  //   7 INSert active\r
+  //   6 Caps Lock active\r
+  //   5 Num Lock active\r
+  //   4 Scroll Lock active\r
+  //   3 either Alt pressed\r
+  //   2 either Ctrl pressed\r
+  //   1 Left Shift pressed\r
+  //   0 Right Shift pressed\r
+\r
+\r
+  //\r
+  // Clear the CTRL and ALT BDA flag\r
+  //\r
+  KbFlag1 = *((UINT8 *) (UINTN) 0x417);  // read the STATUS FLAGS 1\r
+  KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2\r
+\r
+  //\r
+  // Record toggle state\r
+  //\r
+  if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {\r
+    KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
+  }\r
+  if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {\r
+    KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;\r
+  }\r
+  if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {\r
+    KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;\r
+  }\r
+  //\r
+  // Record shift state\r
+  // BUGBUG: Need add Menu key and Left/Right Logo key state in the future\r
+  //  \r
+  if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {\r
+    KeyData.KeyState.KeyShiftState  |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED;\r
+  }  \r
+  if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {\r
+    KeyData.KeyState.KeyShiftState  |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED;\r
+  }  \r
+  if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {\r
+    KeyData.KeyState.KeyShiftState  |= EFI_LEFT_SHIFT_PRESSED;\r
+  }\r
+  if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {\r
+    KeyData.KeyState.KeyShiftState  |= EFI_RIGHT_SHIFT_PRESSED;\r
+  }\r
+\r
+  //\r
+  // Clear left alt and left ctrl BDA flag\r
+  //\r
+  KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);\r
+  *((UINT8 *) (UINTN) 0x418) = KbFlag2;\r
+  KbFlag1 &= ~0x0C;                      \r
+  *((UINT8 *) (UINTN) 0x417) = KbFlag1; \r
+\r
+  \r
+  //\r
+  // Output EFI input key and shift/toggle state\r
+  //\r
+  if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) {\r
+    KeyData.Key.ScanCode     = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode);\r
+    KeyData.Key.UnicodeChar  = CHAR_NULL;\r
+  } else {\r
+    KeyData.Key.ScanCode     = SCAN_NULL;\r
+  }\r
+\r
+  //\r
+  // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.\r
+  //\r
+  if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
+    if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) {\r
+      if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ==\r
+          ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)\r
+          ) {\r
+        KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1);\r
+      } else {\r
+        KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Need not return associated shift state if a class of printable characters that\r
+  // are normally adjusted by shift modifiers.\r
+  // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.\r
+  //\r
+  if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') ||\r
+      (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z')\r
+     ) {\r
+    KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
+  }\r
+\r
+  //\r
+  // Invoke notification functions if exist\r
+  //\r
+  for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link, \r
+                      BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
+                      NotifyEntry, \r
+                      BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { \r
+      CurrentNotify->KeyNotificationFn (&KeyData);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Convert the Ctrl+[a-z] to Ctrl+[1-26]\r
+  //\r
+  if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
+    if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {\r
+      KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
+    } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
+      KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
+    }\r
+  }\r
+  Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);\r
+  //\r
+  // Leave critical section and return\r
+  //\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return ;  \r
+}\r
+\r
+/**\r
+  Free keyboard notify list.\r
+\r
+  @param  ListHead   The list head\r
+\r
+  @retval EFI_SUCCESS           Free the notify list successfully\r
+  @retval EFI_INVALID_PARAMETER ListHead is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+BiosKeyboardFreeNotifyList (\r
+  IN OUT LIST_ENTRY           *ListHead\r
+  )\r
+{\r
+  BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
+\r
+  if (ListHead == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  while (!IsListEmpty (ListHead)) {\r
+    NotifyNode = CR (\r
+                   ListHead->ForwardLink, \r
+                   BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
+                   NotifyEntry, \r
+                   BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                   );\r
+    RemoveEntryList (ListHead->ForwardLink);\r
+    gBS->FreePool (NotifyNode);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if key is registered.\r
+\r
+  @param  RegsiteredData    A pointer to a buffer that is filled in with the keystroke \r
+                            state data for the key that was registered.\r
+  @param  InputData         A pointer to a buffer that is filled in with the keystroke \r
+                            state data for the key that was pressed.\r
+\r
+  @retval TRUE              Key be pressed matches a registered key.\r
+  @retval FLASE             Match failed. \r
+  \r
+**/\r
+BOOLEAN\r
+IsKeyRegistered (\r
+  IN EFI_KEY_DATA  *RegsiteredData,\r
+  IN EFI_KEY_DATA  *InputData\r
+  )\r
+{\r
+  ASSERT (RegsiteredData != NULL && InputData != NULL);\r
+  \r
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
+    return FALSE;  \r
+  }      \r
+  \r
+  //\r
+  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
+  //\r
+  if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
+      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
+    return FALSE;    \r
+  }   \r
+  if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
+      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
+    return FALSE;    \r
+  }     \r
+  \r
+  return TRUE;\r
+\r
+}\r
+\r
+/**\r
+  Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
+\r
+  @param  Event    The event that be siganlled when any key has been stroked.\r
+  @param  Context  Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+BiosKeyboardWaitForKeyEx (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
+  )\r
+{  \r
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+  \r
+  BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context); \r
+  BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn);\r
+\r
+}\r
+\r
+/**\r
+  Reset the input device and optionaly run diagnostics\r
\r
+  @param  This                  Protocol instance pointer.\r
+  @param  ExtendedVerification  Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS           The device was reset.\r
+  @retval EFI_DEVICE_ERROR      The device is not functioning properly and could \r
+                                not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardResetEx (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN BOOLEAN                            ExtendedVerification\r
+  )\r
+{\r
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+  EFI_STATUS                            Status;\r
+  EFI_TPL                               OldTpl;\r
+  \r
+  BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This); \r
+\r
+  Status = BiosKeyboardPrivate->SimpleTextIn.Reset (\r
+                                               &BiosKeyboardPrivate->SimpleTextIn, \r
+                                               ExtendedVerification\r
+                                               );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  \r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can \r
+  be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+  @param  This         Protocol instance pointer.\r
+  @param  KeyData      A pointer to a buffer that is filled in with the keystroke \r
+                       state data for the key that was pressed.\r
+  \r
+  @retval  EFI_SUCCESS           The keystroke information was returned.\r
+  @retval  EFI_NOT_READY         There was no keystroke data availiable.\r
+  @retval  EFI_DEVICE_ERROR      The keystroke information was not returned due to \r
+                                 hardware errors.\r
+  @retval  EFI_INVALID_PARAMETER KeyData is NULL.                        \r
+    \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardReadKeyStrokeEx (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+  OUT EFI_KEY_DATA                      *KeyData\r
+  )\r
+{\r
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
+\r
+  return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData);\r
+  \r
+}\r
+\r
+/**\r
+  Set certain state for the input device.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  KeyToggleState    A pointer to the EFI_KEY_TOGGLE_STATE to set the \r
+                            state for the input device.\r
+\r
+  @retval EFI_SUCCESS           The device state was set successfully.\r
+  @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could \r
+                                not have the setting adjusted.\r
+  @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.\r
+  @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.                       \r
+\r
+**/   \r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardSetState (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+  EFI_TPL                               OldTpl;\r
+  EFI_LEGACY_BIOS_PROTOCOL              *LegacyBios;\r
+  UINT8                                 Command;\r
+\r
+  if (KeyToggleState == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiLegacyBiosProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &LegacyBios\r
+                  );\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Enter critical section\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  Command = 0;\r
+  if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
+    Command |= 4;\r
+  }\r
+  if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
+    Command |= 2;\r
+  }\r
+  if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
+    Command |= 1;\r
+  }\r
+\r
+  Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }  \r
+  Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  Status = KeyboardWrite (BiosKeyboardPrivate, Command);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }  \r
+  //\r
+  // Call Legacy BIOS Protocol to set whatever is necessary\r
+  //\r
+  LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Leave critical section and return\r
+  //\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+  Register a notification function for a particular keystroke for the input device.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  KeyData                 A pointer to a buffer that is filled in with the keystroke \r
+                                  information data for the key that was pressed.\r
+  @param  KeyNotificationFunction Points to the function to be called when the key \r
+                                  sequence is typed specified by KeyData.                        \r
+  @param  NotifyHandle            Points to the unique handle assigned to the registered notification.                          \r
+\r
+  \r
+  @retval EFI_SUCCESS             The notification function was registered successfully.\r
+  @retval EFI_OUT_OF_RESOURCES    Unable to allocate resources for necesssary data structures.\r
+  @retval EFI_INVALID_PARAMETER   KeyData or NotifyHandle is NULL.\r
+                                                  \r
+**/   \r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardRegisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_DATA                       *KeyData,\r
+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
+  OUT EFI_HANDLE                        *NotifyHandle\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+  EFI_TPL                               OldTpl;\r
+  BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *NewNotify;\r
+  LIST_ENTRY                            *Link;\r
+  BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;  \r
+\r
+  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Enter critical section\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  //\r
+  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
+  //\r
+  for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link, \r
+                      BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
+                      NotifyEntry, \r
+                      BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { \r
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
+        *NotifyHandle = CurrentNotify->NotifyHandle;        \r
+        Status = EFI_SUCCESS;\r
+        goto Exit;\r
+      }\r
+    }  \r
+  }\r
+\r
+  //\r
+  // Allocate resource to save the notification function\r
+  //\r
+  \r
+  NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY));\r
+  if (NewNotify == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Exit;\r
+  }\r
+\r
+  NewNotify->Signature         = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
+  NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
+  NewNotify->NotifyHandle      = (EFI_HANDLE) NewNotify;\r
+  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
+  InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);\r
+\r
+  *NotifyHandle                = NewNotify->NotifyHandle;  \r
+  Status                       = EFI_SUCCESS;\r
+  \r
+Exit:\r
+  //\r
+  // Leave critical section and return\r
+  //\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;  \r
+}\r
+\r
+/**\r
+  Remove a registered notification function from a particular keystroke.\r
+\r
+  @param  This                 Protocol instance pointer.    \r
+  @param  NotificationHandle   The handle of the notification function being unregistered.\r
+  \r
+  @retval EFI_SUCCESS             The notification function was unregistered successfully.\r
+  @retval EFI_INVALID_PARAMETER   The NotificationHandle is invalid.\r
+                              \r
+**/   \r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardUnregisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_HANDLE                         NotificationHandle\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+  EFI_TPL                               OldTpl;\r
+  LIST_ENTRY                            *Link;\r
+  BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;\r
+\r
+  //\r
+  // Check incoming notification handle\r
+  //\r
+  if (NotificationHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  } \r
+  \r
+  BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
+  \r
+  //\r
+  // Enter critical section\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);  \r
+\r
+  for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link, \r
+                      BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
+                      NotifyEntry, \r
+                      BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );    \r
+    if (CurrentNotify->NotifyHandle == NotificationHandle) {\r
+      //\r
+      // Remove the notification function from NotifyList and free resources\r
+      //\r
+      RemoveEntryList (&CurrentNotify->NotifyEntry);      \r
+\r
+      Status = EFI_SUCCESS;\r
+      goto Exit;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Can not find the specified Notification Handle\r
+  //\r
+  Status = EFI_INVALID_PARAMETER;\r
+\r
+Exit:\r
+  //\r
+  // Leave critical section and return\r
+  //\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The user Entry Point for module BiosKeyboard. The user code starts with this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeBiosKeyboard(\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gBiosKeyboardDriverBinding,\r
+             ImageHandle,\r
+             &gBiosKeyboardComponentName,\r
+             &gBiosKeyboardComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h
new file mode 100644 (file)
index 0000000..c9f86a1
--- /dev/null
@@ -0,0 +1,744 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _BIOS_KEYBOARD_H_\r
+#define _BIOS_KEYBOARD_H_\r
+\r
+\r
+#include <FrameworkDxe.h>\r
+\r
+#include <Guid/StatusCodeDataTypeId.h>\r
+#include <Protocol/SimpleTextIn.h>\r
+#include <Protocol/SimpleTextInEx.h>\r
+#include <Protocol/LegacyBios.h>\r
+#include <Protocol/IsaIo.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/Ps2Policy.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseLib.h>\r
+\r
+//\r
+// Driver Binding Externs\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gBiosKeyboardDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL  gBiosKeyboardComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2;\r
+\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+//\r
+// BISO Keyboard Defines\r
+//\r
+#define CHAR_SCANCODE                   0xe0\r
+#define CHAR_ESC                        0x1b\r
+\r
+#define KEYBOARD_8042_DATA_REGISTER     0x60\r
+#define KEYBOARD_8042_STATUS_REGISTER   0x64\r
+#define KEYBOARD_8042_COMMAND_REGISTER  0x64\r
+\r
+#define KEYBOARD_TIMEOUT                65536   // 0.07s\r
+#define KEYBOARD_WAITFORVALUE_TIMEOUT   1000000 // 1s\r
+#define KEYBOARD_BAT_TIMEOUT            4000000 // 4s\r
+#define KEYBOARD_TIMER_INTERVAL         200000  // 0.02s\r
+//  KEYBOARD COMMAND BYTE -- read by writing command KBC_CMDREG_VIA64_CMDBYTE_R to 64H, then read from 60H\r
+//                           write by wrting command KBC_CMDREG_VIA64_CMDBYTE_W to 64H, then write to  60H\r
+//  7: Reserved\r
+//  6: PC/XT translation mode convert\r
+//  5: Disable Auxiliary device interface\r
+//  4: Disable keyboard interface\r
+//  3: Reserved\r
+//  2: System Flag: selftest successful\r
+//  1: Enable Auxiliary device interrupt\r
+//  0: Enable Keyboard interrupt )\r
+//\r
+#define KB_CMMBYTE_KSCAN2UNI_COV  (0x1 << 6)\r
+#define KB_CMMBYTE_DISABLE_AUX    (0x1 << 5)\r
+#define KB_CMMBYTE_DISABLE_KB     (0x1 << 4)\r
+#define KB_CMMBYTE_SLFTEST_SUCC   (0x1 << 2)\r
+#define KB_CMMBYTE_ENABLE_AUXINT  (0x1 << 1)\r
+#define KB_CMMBYTE_ENABLE_KBINT   (0x1 << 0)\r
+\r
+//\r
+//  KEYBOARD CONTROLLER STATUS REGISTER - read from 64h\r
+//  7: Parity error\r
+//  6: General time out\r
+//  5: Output buffer holds data for AUX\r
+//  4: Keyboard is not locked\r
+//  3: Command written via 64h  / Data written via 60h\r
+//  2: KBC self-test successful / Power-on reset\r
+//  1: Input buffer holds CPU data / empty\r
+//  0: Output buffer holds keyboard data / empty\r
+//\r
+#define KBC_STSREG_VIA64_PARE (0x1 << 7)\r
+#define KBC_STSREG_VIA64_TIM  (0x1 << 6)\r
+#define KBC_STSREG_VIA64_AUXB (0x1 << 5)\r
+#define KBC_STSREG_VIA64_KEYL (0x1 << 4)\r
+#define KBC_STSREG_VIA64_C_D  (0x1 << 3)\r
+#define KBC_STSREG_VIA64_SYSF (0x1 << 2)\r
+#define KBC_STSREG_VIA64_INPB (0x1 << 1)\r
+#define KBC_STSREG_VIA64_OUTB (0x1 << 0)\r
+\r
+//\r
+//  COMMANDs of KEYBOARD CONTROLLER COMMAND REGISTER - write to 64h\r
+//\r
+#define KBC_CMDREG_VIA64_CMDBYTE_R    0x20\r
+#define KBC_CMDREG_VIA64_CMDBYTE_W    0x60\r
+#define KBC_CMDREG_VIA64_AUX_DISABLE  0xA7\r
+#define KBC_CMDREG_VIA64_AUX_ENABLE   0xA8\r
+#define KBC_CMDREG_VIA64_KBC_SLFTEST  0xAA\r
+#define KBC_CMDREG_VIA64_KB_CKECK     0xAB\r
+#define KBC_CMDREG_VIA64_KB_DISABLE   0xAD\r
+#define KBC_CMDREG_VIA64_KB_ENABLE    0xAE\r
+#define KBC_CMDREG_VIA64_INTP_LOW_R   0xC0\r
+#define KBC_CMDREG_VIA64_INTP_HIGH_R  0xC2\r
+#define KBC_CMDREG_VIA64_OUTP_R       0xD0\r
+#define KBC_CMDREG_VIA64_OUTP_W       0xD1\r
+#define KBC_CMDREG_VIA64_OUTB_KB_W    0xD2\r
+#define KBC_CMDREG_VIA64_OUTB_AUX_W   0xD3\r
+#define KBC_CMDREG_VIA64_AUX_W        0xD4\r
+\r
+//\r
+//  echos of KEYBOARD CONTROLLER COMMAND - read from 60h\r
+//\r
+#define KBC_CMDECHO_KBCSLFTEST_OK 0x55\r
+#define KBC_CMDECHO_KBCHECK_OK    0x00\r
+#define KBC_CMDECHO_ACK           0xFA\r
+#define KBC_CMDECHO_BATTEST_OK    0xAA\r
+#define KBC_CMDECHO_BATTEST_FAILE 0xFC\r
+\r
+//\r
+// OUTPUT PORT COMMANDs - write port by writing KBC_CMDREG_VIA64_OUTP_W via 64H, then write the command to 60H\r
+// drive data and clock of KB to high for at least 500us for BAT needs\r
+//\r
+#define KBC_OUTPORT_DCHIGH_BAT  0xC0\r
+//\r
+// scan code set type\r
+//\r
+#define KBC_INPBUF_VIA60_SCODESET1  0x01\r
+#define KBC_INPBUF_VIA60_SCODESET2  0x02\r
+#define KBC_INPBUF_VIA60_SCODESET3  0x03\r
+\r
+//\r
+//  COMMANDs written to INPUT BUFFER - write to 60h\r
+//\r
+#define KBC_INPBUF_VIA60_KBECHO   0xEE\r
+#define KBC_INPBUF_VIA60_KBSCODE  0xF0\r
+#define KBC_INPBUF_VIA60_KBTYPE   0xF2\r
+#define KBC_INPBUF_VIA60_KBDELAY  0xF3\r
+#define KBC_INPBUF_VIA60_KBEN     0xF4\r
+#define KBC_INPBUF_VIA60_KBSTDDIS 0xF5\r
+#define KBC_INPBUF_VIA60_KBSTDEN  0xF6\r
+#define KBC_INPBUF_VIA60_KBRESEND 0xFE\r
+#define KBC_INPBUF_VIA60_KBRESET  0xFF\r
+\r
+//\r
+// 0040h:0017h - KEYBOARD - STATUS FLAGS 1\r
+//   7 INSert active\r
+//   6 Caps Lock active\r
+//   5 Num Lock active\r
+//   4 Scroll Lock active\r
+//   3 either Alt pressed\r
+//   2 either Ctrl pressed\r
+//   1 Left Shift pressed\r
+//   0 Right Shift pressed\r
+//\r
+// 0040h:0018h - KEYBOARD - STATUS FLAGS 2\r
+//   7: insert key is depressed\r
+//   6: caps-lock key is depressed (does not work well)\r
+//   5: num-lock key is depressed (does not work well)\r
+//   4: scroll lock key is depressed (does not work well)\r
+//   3: suspend key has been toggled (does not work well)\r
+//   2: system key is pressed and held (does not work well)\r
+//   1: left ALT key is pressed\r
+//   0: left CTRL key is pressed\r
+//\r
+#define KB_INSERT_BIT             (0x1 << 7)\r
+#define KB_CAPS_LOCK_BIT          (0x1 << 6)\r
+#define KB_NUM_LOCK_BIT           (0x1 << 5)\r
+#define KB_SCROLL_LOCK_BIT        (0x1 << 4)\r
+#define KB_ALT_PRESSED            (0x1 << 3)\r
+#define KB_CTRL_PRESSED           (0x1 << 2)\r
+#define KB_LEFT_SHIFT_PRESSED     (0x1 << 1)\r
+#define KB_RIGHT_SHIFT_PRESSED    (0x1 << 0)\r
+\r
+#define KB_SUSPEND_PRESSED        (0x1 << 3)\r
+#define KB_SYSREQ_PRESSED         (0x1 << 2)\r
+#define KB_LEFT_ALT_PRESSED       (0x1 << 1)\r
+#define KB_LEFT_CTRL_PRESSED      (0x1 << 0)\r
+\r
+//\r
+// BIOS Keyboard Device Structure\r
+//\r
+#define BIOS_KEYBOARD_DEV_SIGNATURE SIGNATURE_32 ('B', 'K', 'B', 'D')\r
+#define BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('c', 'b', 'k', 'h')\r
+\r
+typedef struct _BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY {\r
+  UINTN                                      Signature;\r
+  EFI_HANDLE                                 NotifyHandle;\r
+  EFI_KEY_DATA                               KeyData;\r
+  EFI_KEY_NOTIFY_FUNCTION                    KeyNotificationFn;\r
+  LIST_ENTRY                                 NotifyEntry;\r
+} BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY;\r
+\r
+#define QUEUE_MAX_COUNT         32\r
+typedef struct {\r
+  UINTN             Front;\r
+  UINTN             Rear;\r
+  EFI_KEY_DATA      Buffer[QUEUE_MAX_COUNT];\r
+} SIMPLE_QUEUE;\r
+\r
+typedef struct {\r
+  UINTN                                       Signature;\r
+  EFI_HANDLE                                  Handle;\r
+  EFI_LEGACY_BIOS_PROTOCOL                    *LegacyBios;\r
+  EFI_ISA_IO_PROTOCOL                         *IsaIo;\r
+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL              SimpleTextIn;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL           SimpleTextInputEx;\r
+  UINT16                                      DataRegisterAddress;\r
+  UINT16                                      StatusRegisterAddress;\r
+  UINT16                                      CommandRegisterAddress;\r
+  BOOLEAN                                     ExtendedKeyboard;\r
+  EFI_DEVICE_PATH_PROTOCOL                    *DevicePath;\r
+  \r
+  //\r
+  // Buffer storing EFI_KEY_DATA\r
+  //\r
+  SIMPLE_QUEUE                                Queue;\r
+\r
+  //\r
+  // Notification Function List\r
+  //\r
+  LIST_ENTRY                                  NotifyList;\r
+  EFI_EVENT                                   TimerEvent;\r
+  \r
+} BIOS_KEYBOARD_DEV;\r
+\r
+#define BIOS_KEYBOARD_DEV_FROM_THIS(a)  CR (a, BIOS_KEYBOARD_DEV, SimpleTextIn, BIOS_KEYBOARD_DEV_SIGNATURE)\r
+#define TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS(a) \\r
+  CR (a, \\r
+      BIOS_KEYBOARD_DEV, \\r
+      SimpleTextInputEx, \\r
+      BIOS_KEYBOARD_DEV_SIGNATURE \\r
+      )\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL   gBiosKeyboardDriverBinding;\r
+\r
+//\r
+// Driver Binding Protocol functions\r
+//\r
+\r
+/**\r
+  Check whether the driver supports this device.\r
+\r
+  @param  This                   The Udriver binding protocol.\r
+  @param  Controller             The controller handle to check.\r
+  @param  RemainingDevicePath    The remaining device path.\r
+\r
+  @retval EFI_SUCCESS            The driver supports this controller.\r
+  @retval other                  This device isn't supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starts the device with this driver.\r
+\r
+  @param  This                   The driver binding instance.\r
+  @param  Controller             Handle of device to bind driver to.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCESS            The controller is controlled by the driver.\r
+  @retval Other                  This controller cannot be started.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stop the device handled by this driver.\r
+\r
+  @param  This                   The driver binding protocol.\r
+  @param  Controller             The controller to release.\r
+  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.\r
+  @param  ChildHandleBuffer      The array of child handle.\r
+\r
+  @retval EFI_SUCCESS            The device was stopped.\r
+  @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.\r
+  @retval Others                 Fail to uninstall protocols attached on the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   Controller,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+\r
+//\r
+// Simple Text Input Protocol functions\r
+//\r
+/**\r
+  Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.\r
+\r
+  @param  This                  Pointer of simple text Protocol.\r
+  @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.\r
+\r
+  @retval EFI_SUCCESS           The command byte is written successfully.\r
+  @retval EFI_DEVICE_ERROR      Errors occurred during reseting keyboard.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardReset (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
+  IN  BOOLEAN                         ExtendedVerification\r
+  );\r
+\r
+/**\r
+  Read out the scan code of the key that has just been stroked.\r
+\r
+  @param  This        Pointer of simple text Protocol.\r
+  @param  Key         Pointer for store the key that read out.\r
+\r
+  @retval EFI_SUCCESS The key is read out successfully.\r
+  @retval other       The key reading failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardReadKeyStroke (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
+  OUT EFI_INPUT_KEY                   *Key\r
+  );\r
+\r
+//\r
+// Private worker functions\r
+//\r
+/**\r
+  Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
+\r
+  @param  Event       The event that be siganlled when any key has been stroked.\r
+  @param  Context     Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BiosKeyboardWaitForKey (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
+  );\r
+\r
+/**\r
+  Check key buffer to get the key stroke status.\r
+\r
+  @param  This         Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.\r
+  \r
+  @retval EFI_SUCCESS  A key is being pressed now.\r
+  @retval Other        No key is now pressed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardCheckForKey (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This\r
+  );\r
+\r
+/**\r
+  Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.\r
+\r
+  @param  KeyChar      Unicode of key.\r
+  @param  ScanCode     Scan code of key.\r
+\r
+  @return The value of EFI Scancode for the key.    \r
+  @retval SCAN_NULL   No corresponding value in the EFI convert table is found for the key.\r
+\r
+**/\r
+UINT16\r
+ConvertToEFIScanCode (\r
+  IN  CHAR16  KeyChar,\r
+  IN  UINT16  ScanCode\r
+  );\r
+\r
+/**\r
+  Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command\r
+  If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device\r
+  should not be in system. \r
+\r
+  @param  BiosKeyboardPrivate  Keyboard Private Data Struture\r
+\r
+  @retval TRUE  Keyboard in System.\r
+  @retval FALSE Keyboard not in System.\r
+\r
+**/\r
+BOOLEAN\r
+CheckKeyboardConnect (\r
+  IN  BIOS_KEYBOARD_DEV     *BiosKeyboardPrivate\r
+  );\r
+\r
+/**\r
+  Timer event handler: read a series of key stroke from 8042\r
+  and put them into memory key buffer. \r
+  It is registered as running under TPL_NOTIFY\r
+  \r
+  @param  Event   The timer event\r
+  @param  Context A BIOS_KEYBOARD_DEV pointer\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BiosKeyboardTimerHandler (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  );\r
+\r
+/**\r
+  Reset the input device and optionaly run diagnostics\r
\r
+  @param  This                  Protocol instance pointer.\r
+  @param  ExtendedVerification  Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS           The device was reset.\r
+  @retval EFI_DEVICE_ERROR      The device is not functioning properly and could \r
+                                not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardResetEx (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN BOOLEAN                            ExtendedVerification\r
+  );\r
+\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can \r
+  be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+  @param  This         Protocol instance pointer.\r
+  @param  KeyData      A pointer to a buffer that is filled in with the keystroke \r
+                       state data for the key that was pressed.\r
+  \r
+  @retval  EFI_SUCCESS           The keystroke information was returned.\r
+  @retval  EFI_NOT_READY         There was no keystroke data availiable.\r
+  @retval  EFI_DEVICE_ERROR      The keystroke information was not returned due to \r
+                                 hardware errors.\r
+  @retval  EFI_INVALID_PARAMETER KeyData is NULL.                        \r
+    \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardReadKeyStrokeEx (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+  OUT EFI_KEY_DATA                      *KeyData\r
+  );\r
+\r
+/**\r
+  Set certain state for the input device.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  KeyToggleState    A pointer to the EFI_KEY_TOGGLE_STATE to set the \r
+                            state for the input device.\r
+\r
+  @retval EFI_SUCCESS           The device state was set successfully.\r
+  @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could \r
+                                not have the setting adjusted.\r
+  @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.\r
+  @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.                       \r
+\r
+**/   \r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardSetState (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState\r
+  );\r
+\r
+/**\r
+  Register a notification function for a particular keystroke for the input device.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  KeyData                 A pointer to a buffer that is filled in with the keystroke \r
+                                  information data for the key that was pressed.\r
+  @param  KeyNotificationFunction Points to the function to be called when the key \r
+                                  sequence is typed specified by KeyData.                        \r
+  @param  NotifyHandle            Points to the unique handle assigned to the registered notification.                          \r
+\r
+  \r
+  @retval EFI_SUCCESS             The notification function was registered successfully.\r
+  @retval EFI_OUT_OF_RESOURCES    Unable to allocate resources for necesssary data structures.\r
+  @retval EFI_INVALID_PARAMETER   KeyData or NotifyHandle is NULL.\r
+                                                  \r
+**/   \r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardRegisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_DATA                       *KeyData,\r
+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
+  OUT EFI_HANDLE                        *NotifyHandle\r
+  );\r
+\r
+/**\r
+  Remove a registered notification function from a particular keystroke.\r
+\r
+  @param  This                 Protocol instance pointer.    \r
+  @param  NotificationHandle   The handle of the notification function being unregistered.\r
+  \r
+  @retval EFI_SUCCESS             The notification function was unregistered successfully.\r
+  @retval EFI_INVALID_PARAMETER   The NotificationHandle is invalid.\r
+                              \r
+**/   \r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardUnregisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_HANDLE                         NotificationHandle\r
+  );\r
+\r
+/**\r
+  Wait for a specific value to be presented in\r
+  Data register of Keyboard Controller by keyboard and then read it,\r
+  used in keyboard commands ack\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Value                The value to be waited for\r
+  @param   WaitForValueTimeOut  The limit of microseconds for timeout\r
+\r
+  @retval  EFI_SUCCESS          The command byte is written successfully.\r
+  @retval  EFI_TIMEOUT          Timeout occurred during writing.\r
+\r
+**/\r
+EFI_STATUS\r
+KeyboardWaitForValue (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  IN UINT8              Value,\r
+  IN UINTN              WaitForValueTimeOut\r
+  );\r
+\r
+/**\r
+  Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.\r
+\r
+  @param   BiosKeyboardPrivate  Keyboard instance pointer.\r
+  @param   Data                 Data byte to write.\r
+\r
+  @retval  EFI_SUCCESS          The data byte is written successfully.\r
+  @retval  EFI_TIMEOUT          Timeout occurred during writing.\r
+\r
+**/\r
+EFI_STATUS\r
+KeyboardWrite (\r
+  IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,\r
+  IN UINT8              Data\r
+  );\r
+\r
+/**\r
+  Free keyboard notify list.\r
+\r
+  @param  ListHead   The list head\r
+\r
+  @retval EFI_SUCCESS           Free the notify list successfully\r
+  @retval EFI_INVALID_PARAMETER ListHead is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+BiosKeyboardFreeNotifyList (\r
+  IN OUT LIST_ENTRY           *ListHead\r
+  );  \r
+\r
+/**\r
+  Check if key is registered.\r
+\r
+  @param  RegsiteredData    A pointer to a buffer that is filled in with the keystroke \r
+                            state data for the key that was registered.\r
+  @param  InputData         A pointer to a buffer that is filled in with the keystroke \r
+                            state data for the key that was pressed.\r
+\r
+  @retval TRUE              Key be pressed matches a registered key.\r
+  @retval FLASE             Match failed. \r
+  \r
+**/\r
+BOOLEAN\r
+IsKeyRegistered (\r
+  IN EFI_KEY_DATA  *RegsiteredData,\r
+  IN EFI_KEY_DATA  *InputData\r
+  );\r
+\r
+/**\r
+  Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
+\r
+  @param  Event    The event that be siganlled when any key has been stroked.\r
+  @param  Context  Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+BiosKeyboardWaitForKeyEx (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..caeecf7
--- /dev/null
@@ -0,0 +1,183 @@
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosKeyboard.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gBiosKeyboardComponentName = {\r
+  BiosKeyboardComponentNameGetDriverName,\r
+  BiosKeyboardComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosKeyboardComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosKeyboardComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosKeyboardDriverNameTable[] = {\r
+  {\r
+    "eng;en",\r
+    L"BIOS[INT16] Keyboard Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mBiosKeyboardDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gBiosKeyboardComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h
new file mode 100644 (file)
index 0000000..a20061b
--- /dev/null
@@ -0,0 +1,153 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _BIOS_KEYBOARD_COMPONENT_NAME_H_\r
+#define _BIOS_KEYBOARD_COMPONENT_NAME_H_\r
+\r
+\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gBiosKeyboardComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL  gBiosKeyboardComponentName2;\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosKeyboardComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf
new file mode 100644 (file)
index 0000000..6166ba3
--- /dev/null
@@ -0,0 +1,68 @@
+## @file\r
+# Component description file for BiosKeyboard module.\r
+#\r
+# Ps2 Keyboard driver by using Legacy Bios protocol service and IsaIo protocol service.\r
+# This dirver uses legacy INT16 to get the key stroke status.\r
+#\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution.  The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = KeyboardDxe\r
+  FILE_GUID                      = 5479662B-6AE4-49e8-A6BD-6DE4B625811F\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = InitializeBiosKeyboard\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gBiosKeyboardDriverBinding\r
+#  COMPONENT_NAME                =  gBiosKeyboardComponentName\r
+#\r
+\r
+[Sources]\r
+  ComponentName.c\r
+  ComponentName.h\r
+  BiosKeyboard.c\r
+  BiosKeyboard.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  ReportStatusCodeLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  DebugLib\r
+  BaseLib\r
+\r
+[Protocols]\r
+  gEfiIsaIoProtocolGuid                         # PROTOCOL TO_START\r
+  gEfiSimpleTextInProtocolGuid                  # PROTOCOL BY_START\r
+  gEfiSimpleTextInputExProtocolGuid             # PROTOCOL BY_START\r
+  gEfiLegacyBiosProtocolGuid                    # PROTOCOL TO_START\r
+  gEfiPs2PolicyProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c
new file mode 100644 (file)
index 0000000..2ae8dac
--- /dev/null
@@ -0,0 +1,3507 @@
+/** @file\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosSnp16.h"\r
+\r
+\r
+///\r
+/// EFI Driver Binding Protocol Instance\r
+///\r
+EFI_DRIVER_BINDING_PROTOCOL gBiosSnp16DriverBinding = {\r
+  BiosSnp16DriverBindingSupported,\r
+  BiosSnp16DriverBindingStart,\r
+  BiosSnp16DriverBindingStop,\r
+  0x3,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+///\r
+///  This boolean is used to determine if we should release the cached vector during an error condition.\r
+///\r
+BOOLEAN     mCachedInt1A = FALSE;\r
+\r
+//\r
+// Private worker functions;\r
+//\r
+\r
+/**\r
+  Start the UNDI interface.\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  @param Ax                  PCI address of Undi device.\r
+  \r
+  @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM. \r
+  @retval Others           Status of start 16 bit UNDI ROM. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkStartUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  UINT16                  Ax\r
+  );\r
+\r
+/**\r
+  Start the UNDI interface\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM. \r
+  @retval Others           Status of start 16 bit UNDI ROM. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkStopUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  );\r
+\r
+/**\r
+  Stop the UNDI interface\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM. \r
+  @retval Others           Status of stop 16 bit UNDI ROM. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkCleanupUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  );\r
+\r
+/**\r
+  Get runtime information for Undi network interface\r
+\r
+  @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_SUCCESS Sucess operation. \r
+  @retval Others      Fail to get runtime information for Undi network interface. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkGetInformation (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  );\r
+\r
+/**\r
+  Get NIC type\r
+\r
+  @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_SUCCESS Sucess operation. \r
+  @retval Others      Fail to get NIC type.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkGetNicType (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  );\r
+\r
+/**\r
+  Get NDIS information\r
+\r
+  @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_SUCCESS Sucess operation. \r
+  @retval Others      Fail to get NDIS information.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkGetNdisInfo (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  );\r
+\r
+/**\r
+  Signal handlers for ExitBootServices event.\r
+  \r
+  Clean up any Real-mode UNDI residue from the system \r
+   \r
+  @param Event      ExitBootServices event\r
+  @param Context \r
+**/\r
+VOID\r
+EFIAPI\r
+Undi16SimpleNetworkEvent (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+/**\r
+  Loads the undi driver.\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @retval   EFI_SUCCESS   - Successfully loads undi driver.\r
+  @retval   EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkLoadUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  );\r
+\r
+/**\r
+  Unload 16 bit UNDI Option ROM from memory\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @return EFI_STATUS \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkUnloadUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  );\r
+\r
+/**\r
+  Entry point for EFI drivers.\r
+\r
+  @param ImageHandle Handle that identifies the loaded image.\r
+  @param SystemTable System Table for this image.\r
+  \r
+  @return EFI_STATUS Return status from EfiLibInstallAllDriverProtocols. \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16DriverEntryPoint (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  return EfiLibInstallDriverBindingComponentName2 (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gBiosSnp16DriverBinding,\r
+           ImageHandle,\r
+           &gBiosSnp16ComponentName,\r
+           &gBiosSnp16ComponentName2\r
+           );\r
+}\r
+\r
+//\r
+// EFI Driver Binding Protocol Functions\r
+//\r
+/**\r
+  Tests to see if this driver supports a given controller.\r
+\r
+  @param This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param Controller           The handle of the controller to test.\r
+  @param RemainingDevicePath  A pointer to the remaining portion of a device path.\r
+  \r
+  @retval EFI_SUCCESS    The driver supports given controller.\r
+  @retval EFI_UNSUPPORT  The driver doesn't support given controller.\r
+  @retval Other          Other errors prevent driver finishing to test\r
+                         if the driver supports given controller.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  PCI_TYPE00                Pci;\r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &DevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiDevicePathProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // See if this is a PCI Network Controller by looking at the Command register and\r
+  // Class Code Register\r
+  //\r
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+  if (Pci.Hdr.ClassCode[2] == PCI_CLASS_NETWORK) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Done:\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiPciIoProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Starts the Snp device controller\r
+\r
+  @param This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param Controller           The handle of the controller to test.\r
+  @param RemainingDevicePath  A pointer to the remaining portion of a device path.\r
+  \r
+  @retval  EFI_SUCCESS          - The device was started.   \r
+  @retval  EFI_DEVICE_ERROR     - The device could not be started due to a device error.\r
+  @retval  EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  EFI_SIMPLE_NETWORK_DEV    *SimpleNetworkDevice;\r
+  EFI_DEV_PATH              Node;\r
+  UINTN                     Index;\r
+  UINTN                     Index2;\r
+  UINTN                     Segment;\r
+  UINTN                     Bus;\r
+  UINTN                     Device;\r
+  UINTN                     Function;\r
+  UINTN                     Flags;\r
+  UINT64                    Supports;\r
+\r
+  SimpleNetworkDevice = NULL;\r
+  PciIo               = NULL;\r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Open the IO Abstraction(s) needed\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &DevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check to see if there is a legacy option ROM image associated with this PCI device\r
+  //\r
+  Status = LegacyBios->CheckPciRom (\r
+                         LegacyBios,\r
+                         Controller,\r
+                         NULL,\r
+                         NULL,\r
+                         &Flags\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Post the legacy option ROM if it is available.\r
+  //\r
+  Status = LegacyBios->InstallPciRom (\r
+                         LegacyBios,\r
+                         Controller,\r
+                         NULL,\r
+                         &Flags,\r
+                         NULL,\r
+                         NULL,\r
+                         NULL,\r
+                         NULL\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Allocate memory for this SimpleNetwork device instance\r
+  //\r
+  Status = gBS->AllocatePool (\r
+                  EfiBootServicesData,\r
+                  sizeof (EFI_SIMPLE_NETWORK_DEV),\r
+                  (VOID **) &SimpleNetworkDevice\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  ZeroMem (SimpleNetworkDevice, sizeof (EFI_SIMPLE_NETWORK_DEV));\r
+\r
+  //\r
+  // Initialize the SimpleNetwork device instance\r
+  //\r
+  SimpleNetworkDevice->Signature      = EFI_SIMPLE_NETWORK_DEV_SIGNATURE;\r
+  SimpleNetworkDevice->LegacyBios     = LegacyBios;\r
+  SimpleNetworkDevice->BaseDevicePath = DevicePath;\r
+  SimpleNetworkDevice->PciIo          = PciIo;\r
+\r
+  //\r
+  // Initialize the Nii Protocol\r
+  //\r
+  SimpleNetworkDevice->Nii.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;\r
+  SimpleNetworkDevice->Nii.Type     = EfiNetworkInterfaceUndi;\r
+\r
+  CopyMem (&SimpleNetworkDevice->Nii.StringId, "UNDI", 4);\r
+\r
+  //\r
+  // Load 16 bit UNDI Option ROM into Memory\r
+  //\r
+  Status = Undi16SimpleNetworkLoadUndi (SimpleNetworkDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_NET, "ERROR : Could not load UNDI.  Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  SimpleNetworkDevice->UndiLoaded = TRUE;\r
+\r
+  //\r
+  // Call PXENV_START_UNDI - Initilizes the UNID interface for use.\r
+  //\r
+  PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);\r
+  Status = Undi16SimpleNetworkStartUndi (\r
+             SimpleNetworkDevice,\r
+             (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function))\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_NET, "ERROR : Could not StartUndi.  Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+  //\r
+  // Initialize the Simple Network Protocol\r
+  //\r
+  DEBUG ((DEBUG_NET, "Initialize SimpleNetworkDevice instance\n"));\r
+\r
+  SimpleNetworkDevice->SimpleNetwork.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
+  SimpleNetworkDevice->SimpleNetwork.Start          = Undi16SimpleNetworkStart;\r
+  SimpleNetworkDevice->SimpleNetwork.Stop           = Undi16SimpleNetworkStop;\r
+  SimpleNetworkDevice->SimpleNetwork.Initialize     = Undi16SimpleNetworkInitialize;\r
+  SimpleNetworkDevice->SimpleNetwork.Reset          = Undi16SimpleNetworkReset;\r
+  SimpleNetworkDevice->SimpleNetwork.Shutdown       = Undi16SimpleNetworkShutdown;\r
+  SimpleNetworkDevice->SimpleNetwork.ReceiveFilters = Undi16SimpleNetworkReceiveFilters;\r
+  SimpleNetworkDevice->SimpleNetwork.StationAddress = Undi16SimpleNetworkStationAddress;\r
+  SimpleNetworkDevice->SimpleNetwork.Statistics     = Undi16SimpleNetworkStatistics;\r
+  SimpleNetworkDevice->SimpleNetwork.MCastIpToMac   = Undi16SimpleNetworkMCastIpToMac;\r
+  SimpleNetworkDevice->SimpleNetwork.NvData         = Undi16SimpleNetworkNvData;\r
+  SimpleNetworkDevice->SimpleNetwork.GetStatus      = Undi16SimpleNetworkGetStatus;\r
+  SimpleNetworkDevice->SimpleNetwork.Transmit       = Undi16SimpleNetworkTransmit;\r
+  SimpleNetworkDevice->SimpleNetwork.Receive        = Undi16SimpleNetworkReceive;\r
+  SimpleNetworkDevice->SimpleNetwork.Mode           = &(SimpleNetworkDevice->SimpleNetworkMode);\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  Undi16SimpleNetworkWaitForPacket,\r
+                  &SimpleNetworkDevice->SimpleNetwork,\r
+                  &SimpleNetworkDevice->SimpleNetwork.WaitForPacket\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR : Could not create event.  Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+  //\r
+  // Create an event to be signalled when ExitBootServices occurs in order\r
+  // to clean up nicely\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  Undi16SimpleNetworkEvent,\r
+                  NULL,\r
+                  &gEfiEventExitBootServicesGuid,\r
+                  &SimpleNetworkDevice->EfiBootEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR : Could not create event.  Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Create an event to be signalled when Legacy Boot occurs to clean up the IVT\r
+  //\r
+  Status = EfiCreateEventLegacyBootEx(\r
+             TPL_NOTIFY, \r
+             Undi16SimpleNetworkEvent, \r
+             NULL, \r
+             &SimpleNetworkDevice->LegacyBootEvent\r
+             );\r
+  \r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((DEBUG_ERROR,"ERROR : Could not create event.  Status = %r\n",Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Initialize the SimpleNetwork Mode Information\r
+  //\r
+  DEBUG ((DEBUG_NET, "Initialize Mode Information\n"));\r
+\r
+  SimpleNetworkDevice->SimpleNetworkMode.State                = EfiSimpleNetworkStopped;\r
+  SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize      = 14;\r
+  SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable = TRUE;\r
+  SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported  = TRUE;\r
+  SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |\r
+    EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |\r
+    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |\r
+    EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |\r
+    EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+  SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount = MAXNUM_MCADDR;\r
+\r
+  //\r
+  // Initialize the SimpleNetwork Private Information\r
+  //\r
+  DEBUG ((DEBUG_NET, "Initialize Private Information\n"));\r
+\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+             sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1,\r
+             (VOID **) &SimpleNetworkDevice->Xmit\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+             1,\r
+             &SimpleNetworkDevice->TxRealModeMediaHeader\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+             1,\r
+             &SimpleNetworkDevice->TxRealModeDataBuffer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+             1,\r
+             &SimpleNetworkDevice->TxDestAddr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  SimpleNetworkDevice->Xmit->XmitOffset               = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) & 0x000f);\r
+\r
+  SimpleNetworkDevice->Xmit->XmitSegment              = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) >> 4);\r
+\r
+  SimpleNetworkDevice->Xmit->DataBlkCount             = 1;\r
+\r
+  SimpleNetworkDevice->Xmit->DataBlock[0].TDPtrType   = 1;\r
+  SimpleNetworkDevice->Xmit->DataBlock[0].TDRsvdByte  = 0;\r
+\r
+  SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrOffset = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) & 0x000f);\r
+\r
+  SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrSegment = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) >> 4);\r
+\r
+  SimpleNetworkDevice->TxBufferFifo.First = 0;\r
+  SimpleNetworkDevice->TxBufferFifo.Last  = 0;\r
+\r
+  //\r
+  // Start() the SimpleNetwork device\r
+  //\r
+  DEBUG ((DEBUG_NET, "Start()\n"));\r
+\r
+  Status = Undi16SimpleNetworkStart (&SimpleNetworkDevice->SimpleNetwork);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // GetInformation() the SimpleNetwork device\r
+  //\r
+  DEBUG ((DEBUG_NET, "GetInformation()\n"));\r
+\r
+  Status = Undi16SimpleNetworkGetInformation (&SimpleNetworkDevice->SimpleNetwork);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Build the device path for the child device\r
+  //\r
+  ZeroMem (&Node, sizeof (Node));\r
+  Node.DevPath.Type     = MESSAGING_DEVICE_PATH;\r
+  Node.DevPath.SubType  = MSG_MAC_ADDR_DP;\r
+  SetDevicePathNodeLength (&Node.DevPath, sizeof (MAC_ADDR_DEVICE_PATH));\r
+  CopyMem (\r
+    &Node.MacAddr.MacAddress,\r
+    &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,\r
+    sizeof (EFI_MAC_ADDRESS)\r
+    );\r
+  SimpleNetworkDevice->DevicePath = AppendDevicePathNode (\r
+                                      SimpleNetworkDevice->BaseDevicePath,\r
+                                      &Node.DevPath\r
+                                      );\r
+\r
+  //\r
+  // GetNicType()  the SimpleNetwork device\r
+  //\r
+  DEBUG ((DEBUG_NET, "GetNicType()\n"));\r
+\r
+  Status = Undi16SimpleNetworkGetNicType (&SimpleNetworkDevice->SimpleNetwork);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // GetNdisInfo() the SimpleNetwork device\r
+  //\r
+  DEBUG ((DEBUG_NET, "GetNdisInfo()\n"));\r
+\r
+  Status = Undi16SimpleNetworkGetNdisInfo (&SimpleNetworkDevice->SimpleNetwork);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Stop() the SimpleNetwork device\r
+  //\r
+  DEBUG ((DEBUG_NET, "Stop()\n"));\r
+\r
+  Status = SimpleNetworkDevice->SimpleNetwork.Stop (&SimpleNetworkDevice->SimpleNetwork);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Print Mode information\r
+  //\r
+  DEBUG ((DEBUG_NET, "Mode->State                = %d\n", SimpleNetworkDevice->SimpleNetworkMode.State));\r
+  DEBUG ((DEBUG_NET, "Mode->HwAddressSize        = %d\n", SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize));\r
+  DEBUG ((DEBUG_NET, "Mode->MacAddressChangeable = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable));\r
+  DEBUG ((DEBUG_NET, "Mode->MultiplTxSupported   = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported));\r
+  DEBUG ((DEBUG_NET, "Mode->NvRamSize            = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamSize));\r
+  DEBUG ((DEBUG_NET, "Mode->NvRamAccessSize      = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamAccessSize));\r
+  DEBUG ((DEBUG_NET, "Mode->ReceiveFilterSetting = %d\n", SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting));\r
+  DEBUG ((DEBUG_NET, "Mode->IfType               = %d\n", SimpleNetworkDevice->SimpleNetworkMode.IfType));\r
+  DEBUG ((DEBUG_NET, "Mode->MCastFilterCount     = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount));\r
+  for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; Index++) {\r
+    DEBUG ((DEBUG_NET, "  Filter[%02d] = ", Index));\r
+    for (Index2 = 0; Index2 < 16; Index2++) {\r
+      DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index].Addr[Index2]));\r
+    }\r
+\r
+    DEBUG ((DEBUG_NET, "\n"));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "CurrentAddress = "));\r
+  for (Index2 = 0; Index2 < 16; Index2++) {\r
+    DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress.Addr[Index2]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n"));\r
+\r
+  DEBUG ((DEBUG_NET, "BroadcastAddress = "));\r
+  for (Index2 = 0; Index2 < 16; Index2++) {\r
+    DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress.Addr[Index2]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n"));\r
+\r
+  DEBUG ((DEBUG_NET, "PermanentAddress = "));\r
+  for (Index2 = 0; Index2 < 16; Index2++) {\r
+    DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress.Addr[Index2]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n"));\r
+\r
+  //\r
+  // The network device was started, information collected, and stopped.\r
+  // Install protocol interfaces for the SimpleNetwork device.\r
+  //\r
+  DEBUG ((DEBUG_NET, "Install Protocol Interfaces on network interface\n"));\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &SimpleNetworkDevice->Handle,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  &SimpleNetworkDevice->SimpleNetwork,\r
+                  &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+                  &SimpleNetworkDevice->Nii,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  SimpleNetworkDevice->DevicePath,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Open PCI I/O from the newly created child handle\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  SimpleNetworkDevice->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+\r
+  DEBUG ((DEBUG_INIT, "UNDI16 Driver : EFI_SUCCESS\n"));\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    if (SimpleNetworkDevice != NULL) {\r
+\r
+      Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);\r
+      //\r
+      // CLOSE + SHUTDOWN\r
+      //\r
+      Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);\r
+      //\r
+      // CLEANUP\r
+      //\r
+      Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);\r
+      //\r
+      // STOP\r
+      //\r
+      if (SimpleNetworkDevice->UndiLoaded) {\r
+        Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);\r
+      }\r
+\r
+      if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {\r
+        gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);\r
+      }\r
+\r
+      if (SimpleNetworkDevice->LegacyBootEvent != NULL) {\r
+        gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);\r
+      }\r
+      \r
+      if (SimpleNetworkDevice->EfiBootEvent != NULL) {\r
+        gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);\r
+      }\r
+\r
+      if (SimpleNetworkDevice->Xmit != NULL) {\r
+        gBS->FreePages (\r
+               (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,\r
+               sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1\r
+               );\r
+      }\r
+\r
+      if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {\r
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);\r
+      }\r
+\r
+      if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {\r
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);\r
+      }\r
+\r
+      if (SimpleNetworkDevice->TxDestAddr != NULL) {\r
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);\r
+      }\r
+\r
+      gBS->FreePool (SimpleNetworkDevice);\r
+      \r
+      //\r
+      //  Only restore the vector if it was cached.\r
+      //\r
+      if (mCachedInt1A) {\r
+        RestoreCachedVectorAddress (0x1A);\r
+        mCachedInt1A = FALSE;\r
+      }\r
+    }\r
+\r
+    if (PciIo != NULL) {\r
+      Status = PciIo->Attributes (\r
+                        PciIo,\r
+                        EfiPciIoAttributeOperationSupported,\r
+                        0,\r
+                        &Supports\r
+                        );\r
+      if (!EFI_ERROR (Status)) {\r
+        Supports &= EFI_PCI_DEVICE_ENABLE;\r
+        Status = PciIo->Attributes (\r
+                          PciIo,\r
+                          EfiPciIoAttributeOperationDisable,\r
+                          Supports,\r
+                          NULL\r
+                          );\r
+      }\r
+    }\r
+\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiDevicePathProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+    if (Status != EFI_OUT_OF_RESOURCES) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+  }  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stops the device by given device controller.\r
+\r
+  @param This               A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param Controller         The handle of the controller to test.\r
+  @param NumberOfChildren   The number of child device handles in ChildHandleBuffer.\r
+  @param ChildHandleBuffer  An array of child handles to be freed. May be NULL if\r
+                            NumberOfChildren is 0.\r
+  \r
+  @retval  EFI_SUCCESS      - The device was stopped.\r
+  @retval  EFI_DEVICE_ERROR - The device could not be stopped due to a device error.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16DriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINTN                       Index;\r
+  BOOLEAN                     AllChildrenStopped;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;\r
+  EFI_SIMPLE_NETWORK_DEV      *SimpleNetworkDevice;\r
+  EFI_PCI_IO_PROTOCOL         *PciIo;\r
+  UINT64                      Supports;\r
+\r
+  //\r
+  // Complete all outstanding transactions to Controller.\r
+  // Don't allow any new transaction to Controller to be started.\r
+  //\r
+  if (NumberOfChildren == 0) {\r
+    //\r
+    // Close the bus driver\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = PciIo->Attributes (\r
+                        PciIo,\r
+                        EfiPciIoAttributeOperationSupported,\r
+                        0,\r
+                        &Supports\r
+                        );\r
+      if (!EFI_ERROR (Status)) {\r
+        Supports &= EFI_PCI_DEVICE_ENABLE;\r
+        Status = PciIo->Attributes (\r
+                          PciIo,\r
+                          EfiPciIoAttributeOperationDisable,\r
+                          Supports,\r
+                          NULL\r
+                          );\r
+      }\r
+    }\r
+\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+                    \r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  AllChildrenStopped = TRUE;\r
+\r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiSimpleNetworkProtocolGuid,\r
+                    (VOID **) &SimpleNetwork,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+\r
+      SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SimpleNetwork);\r
+\r
+      Status = gBS->CloseProtocol (\r
+                      Controller,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      This->DriverBindingHandle,\r
+                      ChildHandleBuffer[Index]\r
+                      );\r
+\r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                      SimpleNetworkDevice->Handle,\r
+                      &gEfiSimpleNetworkProtocolGuid,\r
+                      &SimpleNetworkDevice->SimpleNetwork,\r
+                      &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+                      &SimpleNetworkDevice->Nii,\r
+                      &gEfiDevicePathProtocolGuid,\r
+                      SimpleNetworkDevice->DevicePath,\r
+                      NULL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->OpenProtocol (\r
+               Controller,\r
+               &gEfiPciIoProtocolGuid,\r
+               (VOID **) &PciIo,\r
+               This->DriverBindingHandle,\r
+               ChildHandleBuffer[Index],\r
+               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+               );\r
+      } else {\r
+\r
+        Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);\r
+        //\r
+        // CLOSE + SHUTDOWN\r
+        //\r
+        Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);\r
+        //\r
+        // CLEANUP\r
+        //\r
+        Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);\r
+        //\r
+        // STOP\r
+        //\r
+        if (SimpleNetworkDevice->UndiLoaded) {\r
+          Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);\r
+        }\r
+\r
+        if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {\r
+          gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);\r
+        }\r
+\r
+        if (SimpleNetworkDevice->LegacyBootEvent != NULL) {\r
+          gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);\r
+        }\r
+      \r
+        if (SimpleNetworkDevice->EfiBootEvent != NULL) {\r
+          gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);\r
+        }\r
+\r
+        if (SimpleNetworkDevice->Xmit != NULL) {\r
+          gBS->FreePages (\r
+                 (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,\r
+                 sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1\r
+                 );\r
+        }\r
+\r
+        if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {\r
+          gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);\r
+        }\r
+\r
+        if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {\r
+          gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);\r
+        }\r
+\r
+        if (SimpleNetworkDevice->TxDestAddr != NULL) {\r
+          gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);\r
+        }\r
+\r
+        gBS->FreePool (SimpleNetworkDevice);\r
+      }\r
+\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      AllChildrenStopped = FALSE;\r
+    }\r
+  }\r
+\r
+  if (!AllChildrenStopped) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// FIFO Support Functions\r
+//\r
+/**\r
+  Judge whether transmit FIFO is full.\r
+\r
+  @param Fifo Point to trasmit FIFO structure.\r
+  \r
+  @return BOOLEAN whether transmit FIFO is full.\r
+**/\r
+BOOLEAN\r
+SimpleNetworkTransmitFifoFull (\r
+  EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo\r
+  )\r
+{\r
+  if (((Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE) == Fifo->First) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Judge whether transmit FIFO is empty.\r
+\r
+  @param Fifo Point to trasmit FIFO structure.\r
+  \r
+  @return BOOLEAN whether transmit FIFO is empty.\r
+**/\r
+BOOLEAN\r
+SimpleNetworkTransmitFifoEmpty (\r
+  EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo\r
+  )\r
+{\r
+  if (Fifo->Last == Fifo->First) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Add data into transmit buffer.\r
+\r
+  @param Fifo Point to trasmit FIFO structure.\r
+  @param Data The data point want to be added.\r
+  \r
+  @retval EFI_OUT_OF_RESOURCES  FIFO is full \r
+  @retval EFI_SUCCESS           Success operation. \r
+**/\r
+EFI_STATUS\r
+SimpleNetworkTransmitFifoAdd (\r
+  EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,\r
+  VOID                        *Data\r
+  )\r
+{\r
+  if (SimpleNetworkTransmitFifoFull (Fifo)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Fifo->Data[Fifo->Last]  = Data;\r
+  Fifo->Last              = (Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get a data and remove it from network transmit FIFO.\r
+\r
+  @param Fifo Point to trasmit FIFO structure.\r
+  @param Data On return, point to the data point want to be got and removed.\r
+  \r
+  @retval EFI_OUT_OF_RESOURCES network transmit buffer is empty. \r
+  @retval EFI_SUCCESS           Success operation. \r
+**/\r
+EFI_STATUS\r
+SimpleNetworkTransmitFifoRemove (\r
+  EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,\r
+  VOID                        **Data\r
+  )\r
+{\r
+  if (SimpleNetworkTransmitFifoEmpty (Fifo)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  *Data       = Fifo->Data[Fifo->First];\r
+  Fifo->First = (Fifo->First + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get recive filter setting according to EFI mask value.\r
+\r
+  @param ReceiveFilterSetting  filter setting EFI mask value.\r
+  \r
+  @return UINT16 Undi filter setting value.\r
+**/\r
+UINT16\r
+Undi16GetPacketFilterSetting (\r
+  UINTN ReceiveFilterSetting\r
+  )\r
+{\r
+  UINT16  PktFilter;\r
+\r
+  PktFilter = 0;\r
+  if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {\r
+    PktFilter |= FLTR_DIRECTED;\r
+  }\r
+\r
+  if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+    PktFilter |= FLTR_DIRECTED;\r
+  }\r
+\r
+  if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {\r
+    PktFilter |= FLTR_BRDCST;\r
+  }\r
+\r
+  if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
+    PktFilter |= FLTR_PRMSCS;\r
+  }\r
+\r
+  if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
+    PktFilter |= FLTR_PRMSCS;\r
+    //\r
+    // @bug : Do not know if this is right????\r
+    //\r
+  }\r
+  //\r
+  // @bug : What is FLTR_SRC_RTG?\r
+  //\r
+  return PktFilter;\r
+}\r
+\r
+/**\r
+  Get filter setting from multi cast buffer .\r
+   \r
+  @param Mode           Point to mode structure.\r
+  @param McastBuffer    The multi cast buffer \r
+  @param HwAddressSize  Size of filter value.\r
+  \r
+**/\r
+VOID\r
+Undi16GetMCastFilters (\r
+  IN EFI_SIMPLE_NETWORK_MODE      *Mode,\r
+  IN OUT PXENV_UNDI_MCAST_ADDR_T  *McastBuffer,\r
+  IN UINTN                        HwAddressSize\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  //\r
+  // @bug : What if Mode->MCastFilterCount > MAXNUM_MCADDR?\r
+  //\r
+  McastBuffer->MCastAddrCount = (UINT16) Mode->MCastFilterCount;\r
+  for (Index = 0; Index < MAXNUM_MCADDR; Index++) {\r
+    if (Index < McastBuffer->MCastAddrCount) {\r
+      CopyMem (&McastBuffer->MCastAddr[Index], &Mode->MCastFilter[Index], HwAddressSize);\r
+    } else {\r
+      ZeroMem (&McastBuffer->MCastAddr[Index], HwAddressSize);\r
+    }\r
+  }\r
+}\r
+//\r
+// Load 16 bit UNDI Option ROM into memory\r
+//\r
+/**\r
+  Loads the undi driver.\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @retval   EFI_SUCCESS   - Successfully loads undi driver.\r
+  @retval   EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkLoadUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  UINTN                     RomAddress;\r
+  PCI_EXPANSION_ROM_HEADER  *PciExpansionRomHeader;\r
+  PCI_DATA_STRUCTURE        *PciDataStructure;\r
+  PCI_TYPE00                Pci;\r
+  \r
+  if (!mCachedInt1A) {\r
+    Status = CacheVectorAddress (0x1A);\r
+    if (!EFI_ERROR (Status)) {\r
+      mCachedInt1A = TRUE;    \r
+    }\r
+  }\r
+\r
+  PciIo = SimpleNetworkDevice->PciIo;\r
+\r
+  PciIo->Pci.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               0,\r
+               sizeof (Pci) / sizeof (UINT32),\r
+               &Pci\r
+               );\r
+\r
+  for (RomAddress = 0xc0000; RomAddress < 0xfffff; RomAddress += 0x800) {\r
+\r
+    PciExpansionRomHeader = (PCI_EXPANSION_ROM_HEADER *) RomAddress;\r
+\r
+    if (PciExpansionRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
+      continue;\r
+    }\r
+\r
+    DEBUG ((DEBUG_INIT, "Option ROM found at %X\n", RomAddress));\r
+\r
+    PciDataStructure = (PCI_DATA_STRUCTURE *) (RomAddress + PciExpansionRomHeader->PcirOffset);\r
+\r
+    if (PciDataStructure->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
+      continue;\r
+    }\r
+\r
+    DEBUG ((DEBUG_INIT, "PCI Data Structure found at %X\n", PciDataStructure));\r
+\r
+    if (PciDataStructure->VendorId != Pci.Hdr.VendorId || PciDataStructure->DeviceId != Pci.Hdr.DeviceId) {\r
+      continue;\r
+    }\r
+\r
+    DEBUG (\r
+        (DEBUG_INIT, \r
+         "PCI device with matchinng VendorId and DeviceId (%d,%d)\n",\r
+         (UINTN) PciDataStructure->VendorId,\r
+         (UINTN) PciDataStructure->DeviceId)\r
+        );\r
+\r
+    Status = LaunchBaseCode (SimpleNetworkDevice, RomAddress);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Unload 16 bit UNDI Option ROM from memory\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @return EFI_STATUS \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkUnloadUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  )\r
+{\r
+  if (SimpleNetworkDevice->UndiLoaderTable != NULL) {\r
+    ZeroMem (SimpleNetworkDevice->UndiLoaderTable, SimpleNetworkDevice->UndiLoaderTablePages << EFI_PAGE_SHIFT);\r
+    gBS->FreePages (\r
+          (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->UndiLoaderTable,\r
+          SimpleNetworkDevice->UndiLoaderTablePages\r
+          );\r
+  }\r
+\r
+  if (SimpleNetworkDevice->DestinationDataSegment != NULL) {\r
+    ZeroMem (\r
+      SimpleNetworkDevice->DestinationDataSegment,\r
+      SimpleNetworkDevice->DestinationDataSegmentPages << EFI_PAGE_SHIFT\r
+      );\r
+    gBS->FreePages (\r
+          (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationDataSegment,\r
+          SimpleNetworkDevice->DestinationDataSegmentPages\r
+          );\r
+  }\r
+\r
+  if (SimpleNetworkDevice->DestinationStackSegment != NULL) {\r
+    ZeroMem (\r
+      SimpleNetworkDevice->DestinationStackSegment,\r
+      SimpleNetworkDevice->DestinationStackSegmentPages << EFI_PAGE_SHIFT\r
+      );\r
+    gBS->FreePages (\r
+          (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationStackSegment,\r
+          SimpleNetworkDevice->DestinationStackSegmentPages\r
+          );\r
+  }\r
+\r
+  if (SimpleNetworkDevice->DestinationCodeSegment != NULL) {\r
+    ZeroMem (\r
+      SimpleNetworkDevice->DestinationCodeSegment,\r
+      SimpleNetworkDevice->DestinationCodeSegmentPages << EFI_PAGE_SHIFT\r
+      );\r
+    gBS->FreePages (\r
+          (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationCodeSegment,\r
+          SimpleNetworkDevice->DestinationCodeSegmentPages\r
+          );\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Start the UNDI interface.\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  @param Ax                  PCI address of Undi device.\r
+  \r
+  @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM. \r
+  @retval Others           Status of start 16 bit UNDI ROM. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkStartUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  UINT16                  Ax\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  PXENV_START_UNDI_T  Start;\r
+\r
+  //\r
+  // Call 16 bit UNDI ROM to start the network interface\r
+  //\r
+  //\r
+  // @bug : What is this state supposed to be???\r
+  //\r
+  Start.Status  = INIT_PXE_STATUS;\r
+  Start.Ax      = Ax;\r
+  Start.Bx      = 0x0000;\r
+  Start.Dx      = 0x0000;\r
+  Start.Di      = 0x0000;\r
+  Start.Es      = 0x0000;\r
+\r
+  Status        = PxeStartUndi (SimpleNetworkDevice, &Start);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Start.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop the UNDI interface\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM. \r
+  @retval Others           Status of stop 16 bit UNDI ROM. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkStopUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  PXENV_STOP_UNDI_T Stop;\r
+\r
+  //\r
+  // Call 16 bit UNDI ROM to start the network interface\r
+  //\r
+  Stop.Status = INIT_PXE_STATUS;\r
+\r
+  Status      = PxeUndiStop (SimpleNetworkDevice, &Stop);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Stop.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Cleanup Unid network interface\r
+\r
+  @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Fail to cleanup 16 bit UNDI ROM. \r
+  @retval Others           Status of cleanup 16 bit UNDI ROM. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkCleanupUndi (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PXENV_UNDI_CLEANUP_T  Cleanup;\r
+\r
+  //\r
+  // Call 16 bit UNDI ROM to cleanup the network interface\r
+  //\r
+  Cleanup.Status  = INIT_PXE_STATUS;\r
+\r
+  Status          = PxeUndiCleanup (SimpleNetworkDevice, &Cleanup);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Cleanup.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get runtime information for Undi network interface\r
+\r
+  @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_SUCCESS Sucess operation. \r
+  @retval Others      Fail to get runtime information for Undi network interface. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkGetInformation (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  UINTN                   Index;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStarted:\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to start the network interface\r
+  //\r
+  ZeroMem (&SimpleNetworkDevice->GetInformation, sizeof (PXENV_UNDI_GET_INFORMATION_T));\r
+\r
+  SimpleNetworkDevice->GetInformation.Status  = INIT_PXE_STATUS;\r
+\r
+  Status = PxeUndiGetInformation (SimpleNetworkDevice, &SimpleNetworkDevice->GetInformation);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "  GetInformation.Status      = %d\n", SimpleNetworkDevice->GetInformation.Status));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.BaseIo      = %d\n", SimpleNetworkDevice->GetInformation.BaseIo));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.IntNumber   = %d\n", SimpleNetworkDevice->GetInformation.IntNumber));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.MaxTranUnit = %d\n", SimpleNetworkDevice->GetInformation.MaxTranUnit));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.HwType      = %d\n", SimpleNetworkDevice->GetInformation.HwType));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.HwAddrLen   = %d\n", SimpleNetworkDevice->GetInformation.HwAddrLen));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.ROMAddress  = %d\n", SimpleNetworkDevice->GetInformation.ROMAddress));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.RxBufCt     = %d\n", SimpleNetworkDevice->GetInformation.RxBufCt));\r
+  DEBUG ((DEBUG_NET, "  GetInformation.TxBufCt     = %d\n", SimpleNetworkDevice->GetInformation.TxBufCt));\r
+\r
+  DEBUG ((DEBUG_NET, "  GetInformation.CurNodeAddr ="));\r
+  for (Index = 0; Index < 16; Index++) {\r
+    DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.CurrentNodeAddress[Index]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n"));\r
+\r
+  DEBUG ((DEBUG_NET, "  GetInformation.PermNodeAddr ="));\r
+  for (Index = 0; Index < 16; Index++) {\r
+    DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.PermNodeAddress[Index]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n"));\r
+\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (SimpleNetworkDevice->GetInformation.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // The information has been retrieved.  Fill in Mode data.\r
+  //\r
+  SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize  = SimpleNetworkDevice->GetInformation.HwAddrLen;\r
+\r
+  SimpleNetworkDevice->SimpleNetworkMode.MaxPacketSize  = SimpleNetworkDevice->GetInformation.MaxTranUnit;\r
+\r
+  SimpleNetworkDevice->SimpleNetworkMode.IfType         = (UINT8) SimpleNetworkDevice->GetInformation.HwType;\r
+\r
+  ZeroMem (\r
+    &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,\r
+    sizeof SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress\r
+    );\r
+\r
+  CopyMem (\r
+    &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,\r
+    &SimpleNetworkDevice->GetInformation.CurrentNodeAddress,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+  ZeroMem (\r
+    &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,\r
+    sizeof SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress\r
+    );\r
+\r
+  CopyMem (\r
+    &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,\r
+    &SimpleNetworkDevice->GetInformation.PermNodeAddress,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+  //\r
+  // hard code broadcast address - not avail in PXE2.1\r
+  //\r
+  ZeroMem (\r
+    &SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,\r
+    sizeof SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress\r
+    );\r
+\r
+  SetMem (\r
+    &SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,\r
+    0xff\r
+    );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get NIC type\r
+\r
+  @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_SUCCESS Sucess operation. \r
+  @retval Others      Fail to get NIC type.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkGetNicType (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ZeroMem (&SimpleNetworkDevice->GetNicType, sizeof (PXENV_UNDI_GET_NIC_TYPE_T));\r
+\r
+  SimpleNetworkDevice->GetNicType.Status  = INIT_PXE_STATUS;\r
+\r
+  Status = PxeUndiGetNicType (SimpleNetworkDevice, &SimpleNetworkDevice->GetNicType);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "  GetNicType.Status      = %d\n", SimpleNetworkDevice->GetNicType.Status));\r
+  DEBUG ((DEBUG_NET, "  GetNicType.NicType     = %d\n", SimpleNetworkDevice->GetNicType.NicType));\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (SimpleNetworkDevice->GetNicType.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // The information has been retrieved.  Fill in Mode data.\r
+  //\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get NDIS information\r
+\r
+  @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_SUCCESS Sucess operation. \r
+  @retval Others      Fail to get NDIS information.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkGetNdisInfo (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ZeroMem (&SimpleNetworkDevice->GetNdisInfo, sizeof (PXENV_UNDI_GET_NDIS_INFO_T));\r
+\r
+  SimpleNetworkDevice->GetNdisInfo.Status = INIT_PXE_STATUS;\r
+\r
+  Status = PxeUndiGetNdisInfo (SimpleNetworkDevice, &SimpleNetworkDevice->GetNdisInfo);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "  GetNdisInfo.Status       = %d\n", SimpleNetworkDevice->GetNdisInfo.Status));\r
+  DEBUG ((DEBUG_NET, "  GetNdisInfo.IfaceType    = %a\n", SimpleNetworkDevice->GetNdisInfo.IfaceType));\r
+  DEBUG ((DEBUG_NET, "  GetNdisInfo.LinkSpeed    = %d\n", SimpleNetworkDevice->GetNdisInfo.LinkSpeed));\r
+  DEBUG ((DEBUG_NET, "  GetNdisInfo.ServiceFlags = %08x\n", SimpleNetworkDevice->GetNdisInfo.ServiceFlags));\r
+\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (SimpleNetworkDevice->GetNdisInfo.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // The information has been retrieved.  Fill in Mode data.\r
+  //\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Call Undi ROM 16bit ISR() to check interrupt cause.\r
+\r
+  @param This               A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param FrameLength        The length of frame buffer.\r
+  @param FrameHeaderLength  The length of frame buffer's header if has.\r
+  @param Frame              The frame buffer to process network interrupt.\r
+  @param ProtType           The type network transmit protocol\r
+  @param PktType            The type of package.\r
+  \r
+  @retval EFI_DEVICE_ERROR  Fail to execute 16 bit ROM's ISR, or status is invalid. \r
+  @retval EFI_SUCCESS       Success operation. \r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkIsr (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * This,\r
+  IN UINTN                       *FrameLength,\r
+  IN UINTN                       *FrameHeaderLength, OPTIONAL\r
+  IN UINT8                       *Frame, OPTIONAL\r
+  IN UINT8                       *ProtType, OPTIONAL\r
+  IN UINT8                       *PktType OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  BOOLEAN                 FrameReceived;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  FrameReceived = FALSE;\r
+\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "Isr() IsrValid = %d\n", SimpleNetworkDevice->IsrValid));\r
+\r
+  if (!SimpleNetworkDevice->IsrValid) {\r
+    //\r
+    // Call 16 bit UNDI ROM to open the network interface\r
+    //\r
+    ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));\r
+    SimpleNetworkDevice->Isr.Status   = INIT_PXE_STATUS;\r
+    SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_START;\r
+\r
+    DEBUG ((DEBUG_NET, "Isr() START\n"));\r
+\r
+    Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Check the status code from the 16 bit UNDI ROM\r
+    //\r
+    if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // There have been no events on this UNDI interface, so return EFI_NOT_READY\r
+    //\r
+    if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OURS) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // There is data to process, so call until all events processed.\r
+    //\r
+    ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));\r
+    SimpleNetworkDevice->Isr.Status   = INIT_PXE_STATUS;\r
+    SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;\r
+\r
+    DEBUG ((DEBUG_NET, "Isr() PROCESS\n"));\r
+\r
+    Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    SimpleNetworkDevice->IsrValid = TRUE;\r
+  }\r
+  //\r
+  // Call UNDI GET_NEXT until DONE\r
+  //\r
+  while (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_DONE) {\r
+    //\r
+    // Check the status code from the 16 bit UNDI ROM\r
+    //\r
+    if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // UNDI is busy.  Caller will have to call again.\r
+    // This should never happen with a polled mode driver.\r
+    //\r
+    if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) {\r
+      DEBUG ((DEBUG_NET, "  BUSY\n"));\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // Check for invalud UNDI FuncFlag\r
+    //\r
+    if (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE &&\r
+        SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_TRANSMIT\r
+        ) {\r
+      DEBUG ((DEBUG_NET, "  Invalid SimpleNetworkDevice->Isr.FuncFlag value %d\n", SimpleNetworkDevice->Isr.FuncFlag));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // Check for Transmit Event\r
+    //\r
+    if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {\r
+      DEBUG ((DEBUG_NET, "  TRANSMIT\n"));\r
+      SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
+    }\r
+    //\r
+    // Check for Receive Event\r
+    //\r
+    else if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE) {\r
+      //\r
+      // note - this code will hang on a receive interrupt in a GetStatus loop\r
+      //\r
+      DEBUG ((DEBUG_NET, "  RECEIVE\n"));\r
+      SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
+\r
+      DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.BufferLength      = %d\n", SimpleNetworkDevice->Isr.BufferLength));\r
+      DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameLength       = %d\n", SimpleNetworkDevice->Isr.FrameLength));\r
+      DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameHeaderLength = %d\n", SimpleNetworkDevice->Isr.FrameHeaderLength));\r
+      DEBUG (\r
+        (\r
+        DEBUG_NET, "SimpleNetworkDevice->Isr.Frame             = %04x:%04x\n", SimpleNetworkDevice->Isr.FrameSegSel,\r
+        SimpleNetworkDevice->Isr.FrameOffset\r
+        )\r
+        );\r
+      DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.ProtType          = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));\r
+      DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.PktType           = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));\r
+\r
+      if (FrameReceived) {\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      if ((Frame == NULL) || (SimpleNetworkDevice->Isr.FrameLength > *FrameLength)) {\r
+        DEBUG ((DEBUG_NET, "return EFI_BUFFER_TOO_SMALL   *FrameLength = %08x\n", *FrameLength));\r
+        *FrameLength = SimpleNetworkDevice->Isr.FrameLength;\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+\r
+      *FrameLength = SimpleNetworkDevice->Isr.FrameLength;\r
+      if (FrameHeaderLength != NULL) {\r
+        *FrameHeaderLength = SimpleNetworkDevice->Isr.FrameHeaderLength;\r
+      }\r
+\r
+      if (ProtType != NULL) {\r
+        *ProtType = SimpleNetworkDevice->Isr.ProtType;\r
+      }\r
+\r
+      if (PktType != NULL) {\r
+        *PktType = SimpleNetworkDevice->Isr.PktType;\r
+      }\r
+\r
+      CopyMem (\r
+        Frame,\r
+        (VOID *)(UINTN) ((SimpleNetworkDevice->Isr.FrameSegSel << 4) + SimpleNetworkDevice->Isr.FrameOffset),\r
+        SimpleNetworkDevice->Isr.BufferLength\r
+        );\r
+      Frame = Frame + SimpleNetworkDevice->Isr.BufferLength;\r
+      if (SimpleNetworkDevice->Isr.BufferLength == SimpleNetworkDevice->Isr.FrameLength) {\r
+        FrameReceived = TRUE;\r
+      }\r
+    }\r
+    //\r
+    // There is data to process, so call until all events processed.\r
+    //\r
+    ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));\r
+    SimpleNetworkDevice->Isr.Status   = INIT_PXE_STATUS;\r
+    SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;\r
+\r
+    DEBUG ((DEBUG_NET, "Isr() GET NEXT\n"));\r
+\r
+    Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Check the status code from the 16 bit UNDI ROM\r
+    //\r
+    //        if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {\r
+    //            return EFI_DEVICE_ERROR;\r
+    //        }\r
+    //\r
+  }\r
+\r
+  SimpleNetworkDevice->IsrValid = FALSE;\r
+  return EFI_SUCCESS;\r
+}\r
+//\r
+// ///////////////////////////////////////////////////////////////////////////////////////\r
+// Simple Network Protocol Interface Functions using 16 bit UNDI Option ROMs\r
+/////////////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Start()\r
+//\r
+/**\r
+  Call 16 bit UNDI ROM to start the network interface\r
+\r
+  @param This       A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Network interface has not be initialized.\r
+  @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.\r
+  @retval EFI_SUCESS       Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStart (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  PXENV_UNDI_STARTUP_T    Startup;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStopped:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  case EfiSimpleNetworkInitialized:\r
+    return EFI_ALREADY_STARTED;\r
+\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to start the network interface\r
+  //\r
+  Startup.Status  = INIT_PXE_STATUS;\r
+\r
+  Status          = PxeUndiStartup (SimpleNetworkDevice, &Startup);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Startup.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // The UNDI interface has been started, so update the State.\r
+  //\r
+  SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;\r
+\r
+  //\r
+  //\r
+  //\r
+  SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = 0;\r
+  SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount     = 0;\r
+\r
+  return Status;\r
+}\r
+//\r
+// Stop()\r
+//\r
+/**\r
+  Call 16 bit UNDI ROM to stop the network interface\r
+\r
+  @param This       A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Network interface has not be initialized.\r
+  @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.\r
+  @retval EFI_SUCESS       Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStop (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStarted:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkInitialized:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStopped;\r
+\r
+  return Status;\r
+}\r
+\r
+//\r
+// Initialize()\r
+//\r
+/**\r
+  Initialize network interface \r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param ExtraRxBufferSize    The size of extra request receive buffer.\r
+  @param ExtraTxBufferSize    The size of extra request transmit buffer.\r
\r
+  @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.\r
+  @retval EFI_SUCESS       Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkInitialize (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL            *This,\r
+  IN UINTN                                  ExtraRxBufferSize  OPTIONAL,\r
+  IN UINTN                                  ExtraTxBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  PXENV_UNDI_INITIALIZE_T Initialize;\r
+  PXENV_UNDI_OPEN_T       Open;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+    break;\r
+\r
+  case EfiSimpleNetworkInitialized:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to start the network interface\r
+  //\r
+  Initialize.Status       = INIT_PXE_STATUS;\r
+  Initialize.ProtocolIni  = 0;\r
+\r
+  Status                  = PxeUndiInitialize (SimpleNetworkDevice, &Initialize);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Status = %r\n", Status));\r
+    DEBUG ((DEBUG_ERROR, "Initialize.Status == %xh\n", Initialize.Status));\r
+\r
+    if (Initialize.Status == PXENV_STATUS_UNDI_MEDIATEST_FAILED) {\r
+      Status = EFI_NO_MEDIA;\r
+    }\r
+\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Initialize.Status != PXENV_STATUS_SUCCESS) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Initialize.Status = %04x\n", Initialize.Status));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to open the network interface\r
+  //\r
+  Open.Status     = INIT_PXE_STATUS;\r
+  Open.OpenFlag   = 0;\r
+  Open.PktFilter  = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);\r
+  Undi16GetMCastFilters (\r
+    &SimpleNetworkDevice->SimpleNetworkMode,\r
+    &Open.McastBuffer,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+  Status = PxeUndiOpen (SimpleNetworkDevice, &Open);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Open.Status != PXENV_STATUS_SUCCESS) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Open.Status = %04x\n", Open.Status));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // The UNDI interface has been initialized, so update the State.\r
+  //\r
+  SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkInitialized;\r
+\r
+  //\r
+  // If initialize succeeds, then assume that media is present.\r
+  //\r
+  SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = TRUE;\r
+\r
+  //\r
+  // Reset the recycled transmit buffer FIFO\r
+  //\r
+  SimpleNetworkDevice->TxBufferFifo.First = 0;\r
+  SimpleNetworkDevice->TxBufferFifo.Last  = 0;\r
+  SimpleNetworkDevice->IsrValid           = FALSE;\r
+\r
+  return Status;\r
+}\r
+//\r
+// Reset()\r
+//\r
+/**\r
+  Reset network interface.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param ExtendedVerification Need extended verfication.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkReset (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL   *This,\r
+  IN BOOLEAN                       ExtendedVerification\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  PXENV_UNDI_RESET_T      Reset;\r
+  UINT16                  Rx_filter;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Reset.Status  = INIT_PXE_STATUS;\r
+\r
+  Rx_filter     = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);\r
+\r
+  Undi16GetMCastFilters (\r
+    &SimpleNetworkDevice->SimpleNetworkMode,\r
+    &Reset.R_Mcast_Buf,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+  Status = PxeUndiResetNic (SimpleNetworkDevice, &Reset, Rx_filter);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Reset.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Reset the recycled transmit buffer FIFO\r
+  //\r
+  SimpleNetworkDevice->TxBufferFifo.First = 0;\r
+  SimpleNetworkDevice->TxBufferFifo.Last  = 0;\r
+  SimpleNetworkDevice->IsrValid           = FALSE;\r
+\r
+  return Status;\r
+}\r
+//\r
+// Shutdown()\r
+//\r
+/**\r
+  Shutdown network interface.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkShutdown (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  PXENV_UNDI_CLOSE_T      Close;\r
+  PXENV_UNDI_SHUTDOWN_T   Shutdown;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  SimpleNetworkDevice->IsrValid = FALSE;\r
+\r
+  //\r
+  // Call 16 bit UNDI ROM to start the network interface\r
+  //\r
+  Close.Status  = INIT_PXE_STATUS;\r
+\r
+  Status        = PxeUndiClose (SimpleNetworkDevice, &Close);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Close.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to open the network interface\r
+  //\r
+  Shutdown.Status = INIT_PXE_STATUS;\r
+\r
+  Status          = PxeUndiShutdown (SimpleNetworkDevice, &Shutdown);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Shutdown.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // The UNDI interface has been initialized, so update the State.\r
+  //\r
+  SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;\r
+\r
+  //\r
+  // If shutdown succeeds, then assume that media is not present.\r
+  //\r
+  SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = FALSE;\r
+\r
+  //\r
+  // Reset the recycled transmit buffer FIFO\r
+  //\r
+  SimpleNetworkDevice->TxBufferFifo.First = 0;\r
+  SimpleNetworkDevice->TxBufferFifo.Last  = 0;\r
+\r
+  //\r
+  // A short delay.  Without this an initialize immediately following\r
+  // a shutdown will cause some versions of UNDI-16 to stop operating.\r
+  //\r
+  gBS->Stall (250000);\r
+\r
+  return Status;\r
+}\r
+//\r
+// ReceiveFilters()\r
+//\r
+/**\r
+  Reset network interface.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param Enable               Enable mask value\r
+  @param Disable              Disable mask value\r
+  @param ResetMCastFilter     Whether reset multi cast filter or not\r
+  @param MCastFilterCnt       Count of mutli cast filter for different MAC address\r
+  @param MCastFilter          Buffer for mustli cast filter for different MAC address.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkReceiveFilters (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL                     * This,\r
+  IN UINT32                                          Enable,\r
+  IN UINT32                                          Disable,\r
+  IN BOOLEAN                                         ResetMCastFilter,\r
+  IN UINTN                                           MCastFilterCnt     OPTIONAL,\r
+  IN EFI_MAC_ADDRESS                                 * MCastFilter OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   Index;\r
+  UINT32                  NewFilter;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  PXENV_UNDI_CLOSE_T      Close;\r
+  PXENV_UNDI_OPEN_T       Open;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // First deal with possible filter setting changes\r
+  //\r
+  if ((Enable == 0) && (Disable == 0) && !ResetMCastFilter) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  NewFilter = (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting | Enable) &~Disable;\r
+\r
+  if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+    if ((MCastFilterCnt == 0) || (MCastFilter == 0) || MCastFilterCnt > SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to close the network interface\r
+  //\r
+  Close.Status  = INIT_PXE_STATUS;\r
+\r
+  Status        = PxeUndiClose (SimpleNetworkDevice, &Close);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Close.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to open the network interface\r
+  //\r
+  //\r
+  // Reset the recycled transmit buffer FIFO\r
+  //\r
+  SimpleNetworkDevice->TxBufferFifo.First = 0;\r
+  SimpleNetworkDevice->TxBufferFifo.Last  = 0;\r
+\r
+  //\r
+  // Call 16 bit UNDI ROM to open the network interface\r
+  //\r
+  ZeroMem (&Open, sizeof Open);\r
+\r
+  Open.Status     = INIT_PXE_STATUS;\r
+  Open.PktFilter  = Undi16GetPacketFilterSetting (NewFilter);\r
+\r
+  if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+    //\r
+    // Copy the MAC addresses into the UNDI open parameter structure\r
+    //\r
+    Open.McastBuffer.MCastAddrCount = (UINT16) MCastFilterCnt;\r
+    for (Index = 0; Index < MCastFilterCnt; ++Index) {\r
+      CopyMem (\r
+        Open.McastBuffer.MCastAddr[Index],\r
+        &MCastFilter[Index],\r
+        sizeof Open.McastBuffer.MCastAddr[Index]\r
+        );\r
+    }\r
+  } else if (!ResetMCastFilter) {\r
+    for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; ++Index) {\r
+      CopyMem (\r
+        Open.McastBuffer.MCastAddr[Index],\r
+        &SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],\r
+        sizeof Open.McastBuffer.MCastAddr[Index]\r
+        );\r
+    }\r
+  }\r
+\r
+  Status = PxeUndiOpen (SimpleNetworkDevice, &Open);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (Open.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  SimpleNetworkDevice->IsrValid = FALSE;\r
+  SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = NewFilter;\r
+\r
+  if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+    SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount = (UINT32) MCastFilterCnt;\r
+    for (Index = 0; Index < MCastFilterCnt; ++Index) {\r
+      CopyMem (\r
+        &SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],\r
+        &MCastFilter[Index],\r
+        sizeof (EFI_MAC_ADDRESS)\r
+        );      \r
+    }\r
+  }\r
+  //\r
+  // Read back multicast addresses.\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+//\r
+// StationAddress()\r
+//\r
+/**\r
+  Set new MAC address.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param Reset                Whether reset station MAC address to permenent address\r
+  @param New                  A pointer to New address\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStationAddress (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL           * This,\r
+  IN BOOLEAN                               Reset,\r
+  IN EFI_MAC_ADDRESS                       * New OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_SIMPLE_NETWORK_DEV        *SimpleNetworkDevice;\r
+  PXENV_UNDI_SET_STATION_ADDR_T SetStationAddr;\r
+  //\r
+  // EFI_DEVICE_PATH_PROTOCOL     *OldDevicePath;\r
+  //\r
+  PXENV_UNDI_CLOSE_T            Close;\r
+  PXENV_UNDI_OPEN_T             Open;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to open the network interface\r
+  //\r
+  SetStationAddr.Status = INIT_PXE_STATUS;\r
+\r
+  if (Reset) {\r
+    //\r
+    // If we are reseting the Station Address to the permanent address, and the\r
+    // Station Address is not programmable, then just return EFI_SUCCESS.\r
+    //\r
+    if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // If the address is already the permanent address, then just return success.\r
+    //\r
+    if (CompareMem (\r
+          &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,\r
+          &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,\r
+          SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+          ) == 0) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // Copy the adapters permanent address to the new station address\r
+    //\r
+    CopyMem (\r
+      &SetStationAddr.StationAddress,\r
+      &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,\r
+      SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+      );\r
+  } else {\r
+    //\r
+    // If we are setting the Station Address, and the\r
+    // Station Address is not programmable, return invalid parameter.\r
+    //\r
+    if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // If the address is already the new address, then just return success.\r
+    //\r
+    if (CompareMem (\r
+          &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,\r
+          New,\r
+          SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+          ) == 0) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // Copy New to the new station address\r
+    //\r
+    CopyMem (\r
+      &SetStationAddr.StationAddress,\r
+      New,\r
+      SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+      );\r
+\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to stop the network interface\r
+  //\r
+  Close.Status = INIT_PXE_STATUS;\r
+\r
+  PxeUndiClose (SimpleNetworkDevice, &Close);\r
+\r
+  //\r
+  // Call 16-bit UNDI ROM to set the station address\r
+  //\r
+  SetStationAddr.Status = PXENV_STATUS_SUCCESS;\r
+\r
+  Status                = PxeUndiSetStationAddr (SimpleNetworkDevice, &SetStationAddr);\r
+\r
+  //\r
+  // Call 16-bit UNDI ROM to start the network interface\r
+  //\r
+  Open.Status     = PXENV_STATUS_SUCCESS;\r
+  Open.OpenFlag   = 0;\r
+  Open.PktFilter  = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);\r
+  Undi16GetMCastFilters (\r
+    &SimpleNetworkDevice->SimpleNetworkMode,\r
+    &Open.McastBuffer,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+  PxeUndiOpen (SimpleNetworkDevice, &Open);\r
+\r
+  //\r
+  // Check status from station address change\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (SetStationAddr.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CopyMem (\r
+    &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,\r
+    &SetStationAddr.StationAddress,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+#if 0 /* The device path is based on the permanent address not the current address. */\r
+  //\r
+  // The station address was changed, so update the device path with the new MAC address.\r
+  //\r
+  OldDevicePath                   = SimpleNetworkDevice->DevicePath;\r
+  SimpleNetworkDevice->DevicePath = DuplicateDevicePath (SimpleNetworkDevice->BaseDevicePath);\r
+  SimpleNetworkAppendMacAddressDevicePath (\r
+    &SimpleNetworkDevice->DevicePath,\r
+    &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress\r
+    );\r
+\r
+  Status = LibReinstallProtocolInterfaces (\r
+            SimpleNetworkDevice->Handle,\r
+            &DevicePathProtocol,\r
+            OldDevicePath,\r
+            SimpleNetworkDevice->DevicePath,\r
+            NULL\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Failed to reinstall the DevicePath protocol for the Simple Network Device\n"));\r
+    DEBUG ((DEBUG_ERROR, "  Status = %r\n", Status));\r
+  }\r
+\r
+  FreePool (OldDevicePath);\r
+#endif /* 0 */\r
+\r
+  return Status;\r
+}\r
+//\r
+// Statistics()\r
+//\r
+/**\r
+  Resets or collects the statistics on a network interface.\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  Reset           Set to TRUE to reset the statistics for the network interface.\r
+  @param  StatisticsSize  On input the size, in bytes, of StatisticsTable. On\r
+                          output the size, in bytes, of the resulting table of\r
+                          statistics.\r
+  @param  StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that\r
+                          contains the statistics.\r
+\r
+  @retval EFI_SUCCESS           The statistics were collected from the network interface.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer\r
+                                size needed to hold the statistics is returned in\r
+                                StatisticsSize.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStatistics (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL       * This,\r
+  IN BOOLEAN                           Reset,\r
+  IN OUT UINTN                         *StatisticsSize OPTIONAL,\r
+  OUT EFI_NETWORK_STATISTICS           * StatisticsTable OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_SIMPLE_NETWORK_DEV        *SimpleNetworkDevice;\r
+  PXENV_UNDI_CLEAR_STATISTICS_T ClearStatistics;\r
+  PXENV_UNDI_GET_STATISTICS_T   GetStatistics;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((StatisticsSize != NULL) && (*StatisticsSize != 0) && (StatisticsTable == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If Reset is TRUE, then clear all the statistics.\r
+  //\r
+  if (Reset) {\r
+\r
+    DEBUG ((DEBUG_NET, "  RESET Statistics\n"));\r
+\r
+    //\r
+    // Call 16 bit UNDI ROM to open the network interface\r
+    //\r
+    ClearStatistics.Status  = INIT_PXE_STATUS;\r
+\r
+    Status                  = PxeUndiClearStatistics (SimpleNetworkDevice, &ClearStatistics);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Check the status code from the 16 bit UNDI ROM\r
+    //\r
+    if (ClearStatistics.Status != PXENV_STATUS_SUCCESS) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    DEBUG ((DEBUG_NET, "  RESET Statistics Complete"));\r
+  }\r
+\r
+  if (StatisticsSize != NULL) {\r
+    EFI_NETWORK_STATISTICS  LocalStatisticsTable;\r
+\r
+    DEBUG ((DEBUG_NET, "  GET Statistics\n"));\r
+\r
+    //\r
+    // If the size if valid, then see if the table is valid\r
+    //\r
+    if (StatisticsTable == NULL) {\r
+      DEBUG ((DEBUG_NET, "  StatisticsTable is NULL\n"));\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // Call 16 bit UNDI ROM to open the network interface\r
+    //\r
+    GetStatistics.Status            = INIT_PXE_STATUS;\r
+    GetStatistics.XmtGoodFrames     = 0;\r
+    GetStatistics.RcvGoodFrames     = 0;\r
+    GetStatistics.RcvCRCErrors      = 0;\r
+    GetStatistics.RcvResourceErrors = 0;\r
+\r
+    Status                          = PxeUndiGetStatistics (SimpleNetworkDevice, &GetStatistics);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Check the status code from the 16 bit UNDI ROM\r
+    //\r
+    if (GetStatistics.Status != PXENV_STATUS_SUCCESS) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // Fill in the Statistics Table with the collected values.\r
+    //\r
+    SetMem (&LocalStatisticsTable, sizeof LocalStatisticsTable, 0xff);\r
+\r
+    LocalStatisticsTable.TxGoodFrames     = GetStatistics.XmtGoodFrames;\r
+    LocalStatisticsTable.RxGoodFrames     = GetStatistics.RcvGoodFrames;\r
+    LocalStatisticsTable.RxCrcErrorFrames = GetStatistics.RcvCRCErrors;\r
+    LocalStatisticsTable.RxDroppedFrames  = GetStatistics.RcvResourceErrors;\r
+\r
+    CopyMem (StatisticsTable, &LocalStatisticsTable, *StatisticsSize);\r
+\r
+    DEBUG (\r
+      (DEBUG_NET,\r
+      "  Statistics Collected : Size=%d  Buf=%08x\n",\r
+      *StatisticsSize,\r
+      StatisticsTable)\r
+      );\r
+\r
+    DEBUG ((DEBUG_NET, "  GET Statistics Complete"));\r
+\r
+    if (*StatisticsSize < sizeof LocalStatisticsTable) {\r
+      DEBUG ((DEBUG_NET, "  BUFFER TOO SMALL\n"));\r
+      Status = EFI_BUFFER_TOO_SMALL;\r
+    }\r
+\r
+    *StatisticsSize = sizeof LocalStatisticsTable;\r
+\r
+    return Status;\r
+\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+//\r
+// MCastIpToMac()\r
+//\r
+/**\r
+  Translate IP address to MAC address.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param IPv6                 IPv6 or IPv4\r
+  @param IP                   A pointer to given Ip address.\r
+  @param MAC                  On return, translated MAC address.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_INVALID_PARAMETER Invalid IP address.\r
+  @retval EFI_INVALID_PARAMETER Invalid return buffer for holding MAC address.\r
+  @retval EFI_UNSUPPORTED       Do not support IPv6 \r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkMCastIpToMac (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL            *This,\r
+  IN BOOLEAN                                IPv6,\r
+  IN EFI_IP_ADDRESS                         *IP,\r
+  OUT EFI_MAC_ADDRESS                       *MAC\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_SIMPLE_NETWORK_DEV      *SimpleNetworkDevice;\r
+  PXENV_UNDI_GET_MCAST_ADDR_T GetMcastAddr;\r
+\r
+  if (This == NULL || IP == NULL || MAC == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // 16 bit UNDI Option ROMS do not support IPv6.  Check for IPv6 usage.\r
+  //\r
+  if (IPv6) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Call 16 bit UNDI ROM to open the network interface\r
+  //\r
+  GetMcastAddr.Status = INIT_PXE_STATUS;\r
+  CopyMem (&GetMcastAddr.InetAddr, IP, 4);\r
+\r
+  Status = PxeUndiGetMcastAddr (SimpleNetworkDevice, &GetMcastAddr);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  if (GetMcastAddr.Status != PXENV_STATUS_SUCCESS) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Copy the MAC address from the returned data structure.\r
+  //\r
+  CopyMem (\r
+    MAC,\r
+    &GetMcastAddr.MediaAddr,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+  return Status;\r
+}\r
+//\r
+// NvData()\r
+//\r
+/**\r
+  Performs read and write operations on the NVRAM device attached to a \r
+  network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  ReadWrite  TRUE for read operations, FALSE for write operations.\r
+  @param  Offset     Byte offset in the NVRAM device at which to start the read or\r
+                     write operation. This must be a multiple of NvRamAccessSize and\r
+                     less than NvRamSize.\r
+  @param  BufferSize The number of bytes to read or write from the NVRAM device.\r
+                     This must also be a multiple of NvramAccessSize.\r
+  @param  Buffer     A pointer to the data buffer.\r
+\r
+  @retval EFI_SUCCESS           The NVRAM access was performed.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkNvData (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This,\r
+  IN BOOLEAN                      ReadWrite,\r
+  IN UINTN                        Offset,\r
+  IN UINTN                        BufferSize,\r
+  IN OUT VOID                     *Buffer\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+//\r
+// GetStatus()\r
+//\r
+/**\r
+  Reads the current interrupt status and recycled transmit buffer status from \r
+  a network interface.\r
+\r
+  @param  This            The protocol instance pointer.\r
+  @param  InterruptStatus A pointer to the bit mask of the currently active interrupts\r
+                          If this is NULL, the interrupt status will not be read from\r
+                          the device. If this is not NULL, the interrupt status will\r
+                          be read from the device. When the  interrupt status is read,\r
+                          it will also be cleared. Clearing the transmit  interrupt\r
+                          does not empty the recycled transmit buffer array.\r
+  @param  TxBuf           Recycled transmit buffer address. The network interface will\r
+                          not transmit if its internal recycled transmit buffer array\r
+                          is full. Reading the transmit buffer does not clear the\r
+                          transmit interrupt. If this is NULL, then the transmit buffer\r
+                          status will not be read. If there are no transmit buffers to\r
+                          recycle and TxBuf is not NULL, * TxBuf will be set to NULL.\r
+\r
+  @retval EFI_SUCCESS           The status of the network interface was retrieved.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkGetStatus (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  * This,\r
+  OUT UINT32                      *InterruptStatus OPTIONAL,\r
+  OUT VOID                        **TxBuf OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  UINTN                   FrameLength;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (InterruptStatus == NULL && TxBuf == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  FrameLength = 0;\r
+  Status      = Undi16SimpleNetworkIsr (This, &FrameLength, NULL, NULL, NULL, NULL);\r
+\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // See if the caller wants interrupt info.\r
+  //\r
+  if (InterruptStatus != NULL) {\r
+    *InterruptStatus                      = SimpleNetworkDevice->InterruptStatus;\r
+    SimpleNetworkDevice->InterruptStatus  = 0;\r
+  }\r
+  //\r
+  // See if the caller wants transmit buffer status info.\r
+  //\r
+  if (TxBuf != NULL) {\r
+    *TxBuf = 0;\r
+    SimpleNetworkTransmitFifoRemove (&(SimpleNetworkDevice->TxBufferFifo), TxBuf);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Places a packet in the transmit queue of a network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  HeaderSize The size, in bytes, of the media header to be filled in by\r
+                     the Transmit() function. If HeaderSize is non-zero, then it\r
+                     must be equal to This->Mode->MediaHeaderSize and the DestAddr\r
+                     and Protocol parameters must not be NULL.\r
+  @param  BufferSize The size, in bytes, of the entire packet (media header and\r
+                     data) to be transmitted through the network interface.\r
+  @param  Buffer     A pointer to the packet (media header followed by data) to be\r
+                     transmitted. This parameter cannot be NULL. If HeaderSize is zero,\r
+                     then the media header in Buffer must already be filled in by the\r
+                     caller. If HeaderSize is non-zero, then the media header will be\r
+                     filled in by the Transmit() function.\r
+  @param  SrcAddr    The source HW MAC address. If HeaderSize is zero, then this parameter\r
+                     is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then\r
+                     This->Mode->CurrentAddress is used for the source HW MAC address.\r
+  @param  DestAddr   The destination HW MAC address. If HeaderSize is zero, then this\r
+                     parameter is ignored.\r
+  @param  Protocol   The type of header to build. If HeaderSize is zero, then this\r
+                     parameter is ignored. See RFC 1700, section "Ether Types", for\r
+                     examples.\r
+\r
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.                      \r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkTransmit (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL           *This,\r
+  IN UINTN                                 HeaderSize,\r
+  IN UINTN                                 BufferSize,\r
+  IN VOID                                  *Buffer,\r
+  IN EFI_MAC_ADDRESS                       *SrcAddr OPTIONAL,\r
+  IN EFI_MAC_ADDRESS                       *DestAddr OPTIONAL,\r
+  IN UINT16                                *Protocol OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  PXENV_UNDI_TRANSMIT_T   XmitInfo;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize < SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  if (HeaderSize != 0) {\r
+    if (HeaderSize != SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (DestAddr == NULL || Protocol == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (DestAddr != NULL) {\r
+      CopyMem (\r
+        Buffer,\r
+        DestAddr,\r
+        SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+        );\r
+    }\r
+\r
+    if (SrcAddr == NULL) {\r
+      SrcAddr = &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress;\r
+    }\r
+\r
+    CopyMem (\r
+      (UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,\r
+      SrcAddr,\r
+      SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+      );\r
+\r
+    if (Protocol != NULL) {\r
+      *(UINT16 *) ((UINT8 *) Buffer + 2 * SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize) = (UINT16) (((*Protocol & 0xFF) << 8) | ((*Protocol >> 8) & 0xFF));\r
+    }\r
+  }\r
+  //\r
+  // See if the recycled transmit buffer FIFO is full.\r
+  // If it is full, then we can not transmit until the caller calls GetStatus() to pull\r
+  // off recycled transmit buffers.\r
+  //\r
+  if (SimpleNetworkTransmitFifoFull (&(SimpleNetworkDevice->TxBufferFifo))) {\r
+    return EFI_NOT_READY;\r
+  }\r
+  //\r
+  //  Output debug trace message.\r
+  //\r
+  DEBUG ((DEBUG_NET, "Undi16SimpleNetworkTransmit\n\r "));\r
+\r
+  //\r
+  // Initialize UNDI WRITE parameter structure.\r
+  //\r
+  XmitInfo.Status           = INIT_PXE_STATUS;\r
+  XmitInfo.Protocol         = P_UNKNOWN;\r
+  XmitInfo.XmitFlag         = XMT_DESTADDR;\r
+  XmitInfo.DestAddrOffset   = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr & 0x000f);\r
+  XmitInfo.DestAddrSegment  = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr >> 4);\r
+  XmitInfo.TBDOffset        = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit & 0x000f);\r
+  XmitInfo.TBDSegment       = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit >> 4);\r
+  XmitInfo.Reserved[0]      = 0;\r
+  XmitInfo.Reserved[1]      = 0;\r
+\r
+  CopyMem (\r
+    SimpleNetworkDevice->TxDestAddr,\r
+    Buffer,\r
+    SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize\r
+    );\r
+\r
+  CopyMem (\r
+    SimpleNetworkDevice->TxRealModeMediaHeader,\r
+    Buffer,\r
+    SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize\r
+    );\r
+\r
+  SimpleNetworkDevice->Xmit->ImmedLength            = (UINT16) SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize;\r
+\r
+  SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen = (UINT16) (BufferSize - SimpleNetworkDevice->Xmit->ImmedLength);\r
+\r
+  CopyMem (\r
+    SimpleNetworkDevice->TxRealModeDataBuffer,\r
+    (UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize,\r
+    SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen\r
+    );\r
+\r
+  //\r
+  // Make API call to UNDI TRANSMIT\r
+  //\r
+  XmitInfo.Status = 0;\r
+\r
+  Status          = PxeUndiTransmit (SimpleNetworkDevice, &XmitInfo);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the status code from the 16 bit UNDI ROM\r
+  //\r
+  switch (XmitInfo.Status) {\r
+  case PXENV_STATUS_OUT_OF_RESOURCES:\r
+    return EFI_NOT_READY;\r
+\r
+  case PXENV_STATUS_SUCCESS:\r
+    break;\r
+\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Add address of Buffer to the recycled transmit buffer FIFO\r
+  //\r
+  SimpleNetworkTransmitFifoAdd (&(SimpleNetworkDevice->TxBufferFifo), Buffer);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Receives a packet from a network interface.\r
+  \r
+  @param  This       The protocol instance pointer.\r
+  @param  HeaderSize The size, in bytes, of the media header received on the network\r
+                     interface. If this parameter is NULL, then the media header size\r
+                     will not be returned.\r
+  @param  BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in\r
+                     bytes, of the packet that was received on the network interface.\r
+  @param  Buffer     A pointer to the data buffer to receive both the media header and\r
+                     the data.\r
+  @param  SrcAddr    The source HW MAC address. If this parameter is NULL, the\r
+                     HW MAC source address will not be extracted from the media\r
+                     header.\r
+  @param  DestAddr   The destination HW MAC address. If this parameter is NULL,\r
+                     the HW MAC destination address will not be extracted from the\r
+                     media header.\r
+  @param  Protocol   The media header type. If this parameter is NULL, then the\r
+                     protocol will not be extracted from the media header. See\r
+                     RFC 1700 section "Ether Types" for examples.\r
+\r
+  @retval  EFI_SUCCESS           The received data was stored in Buffer, and BufferSize has\r
+                                 been updated to the number of bytes received.\r
+  @retval  EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval  EFI_NOT_READY         The network interface is too busy to accept this transmit\r
+                                 request.\r
+  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval  EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval  EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval  EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkReceive (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL            *This,\r
+  OUT UINTN                                 *HeaderSize OPTIONAL,\r
+  IN OUT UINTN                              *BufferSize,\r
+  OUT VOID                                  *Buffer,\r
+  OUT EFI_MAC_ADDRESS                       *SrcAddr OPTIONAL,\r
+  OUT EFI_MAC_ADDRESS                       *DestAddr OPTIONAL,\r
+  OUT UINT16                                *Protocol OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  UINTN                   MediaAddrSize;\r
+  UINT8                   ProtType;\r
+\r
+  if (This == NULL || BufferSize == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = Undi16SimpleNetworkIsr (\r
+            This,\r
+            BufferSize,\r
+            HeaderSize,\r
+            Buffer,\r
+            &ProtType,\r
+            NULL\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) == 0) {\r
+    return EFI_NOT_READY;\r
+\r
+  }\r
+\r
+  SimpleNetworkDevice->InterruptStatus &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
+\r
+  MediaAddrSize = This->Mode->HwAddressSize;\r
+\r
+  if (SrcAddr != NULL) {\r
+    CopyMem (SrcAddr, (UINT8 *) Buffer + MediaAddrSize, MediaAddrSize);\r
+  }\r
+\r
+  if (DestAddr != NULL) {\r
+    CopyMem (DestAddr, Buffer, MediaAddrSize);\r
+  }\r
+\r
+  if (Protocol != NULL) {\r
+    *((UINT8 *) Protocol)     = *((UINT8 *) Buffer + (2 * MediaAddrSize) + 1);\r
+    *((UINT8 *) Protocol + 1) = *((UINT8 *) Buffer + (2 * MediaAddrSize));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "Packet Received: BufferSize=%d  HeaderSize = %d\n", *BufferSize, *HeaderSize));\r
+\r
+  return Status;\r
+\r
+}\r
+//\r
+// WaitForPacket()\r
+//\r
+/**\r
+  wait for a packet to be received.\r
+\r
+  @param Event      Event used with WaitForEvent() to wait for a packet to be received.\r
+  @param Context    Event Context\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+Undi16SimpleNetworkWaitForPacket (\r
+  IN EFI_EVENT               Event,\r
+  IN VOID                    *Context\r
+  )\r
+{\r
+  //\r
+  // Someone is waiting on the receive packet event, if there's\r
+  // a packet pending, signal the event\r
+  //\r
+  if (!EFI_ERROR (Undi16SimpleNetworkCheckForPacket (Context))) {\r
+    gBS->SignalEvent (Event);\r
+  }\r
+}\r
+//\r
+// CheckForPacket()\r
+//\r
+/**\r
+  Check whether packet is ready for receive.\r
+\r
+  @param This The protocol instance pointer.\r
+  \r
+  @retval  EFI_SUCCESS           Receive data is ready.\r
+  @retval  EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval  EFI_NOT_READY         The network interface is too busy to accept this transmit\r
+                                 request.\r
+  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval  EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval  EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval  EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkCheckForPacket (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *This\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice;\r
+  UINTN                   FrameLength;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status              = EFI_SUCCESS;\r
+  SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  if (SimpleNetworkDevice == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Verify that the current state of the adapter is valid for this call.\r
+  //\r
+  switch (SimpleNetworkDevice->SimpleNetworkMode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    return EFI_NOT_STARTED;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  FrameLength = 0;\r
+  Status = Undi16SimpleNetworkIsr (\r
+            This,\r
+            &FrameLength,\r
+            NULL,\r
+            NULL,\r
+            NULL,\r
+            NULL\r
+            );\r
+\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) != 0) ? EFI_SUCCESS : EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+  Signal handlers for ExitBootServices event.\r
+  \r
+  Clean up any Real-mode UNDI residue from the system \r
+   \r
+  @param Event      ExitBootServices event\r
+  @param Context \r
+**/\r
+VOID\r
+EFIAPI\r
+Undi16SimpleNetworkEvent (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+{\r
+  //\r
+  // NOTE:  This is not the only way to effect this cleanup.  The prescribed mechanism\r
+  //        would be to perform an UNDI STOP command.  This strategam has been attempted\r
+  //        but results in problems making some of the EFI core services from TPL_CALLBACK.\r
+  //        This issue needs to be resolved, but the other alternative has been to perform\r
+  //        the unchain logic explicitly, as done below.\r
+  //\r
+  RestoreCachedVectorAddress (0x1A);\r
+}\r
+\r
+/**\r
+  Allocate buffer below 1M for real mode.\r
+\r
+  @param NumPages     The number pages want to be allocated.\r
+  @param Buffer       On return, allocated buffer.\r
+  \r
+  @return Status of allocating pages.\r
+**/\r
+EFI_STATUS\r
+BiosSnp16AllocatePagesBelowOneMb (\r
+  UINTN  NumPages,\r
+  VOID   **Buffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;\r
+\r
+  PhysicalAddress = 0x000fffff;\r
+  Status = gBS->AllocatePages (\r
+                  AllocateMaxAddress,\r
+                  EfiRuntimeServicesData,\r
+                  NumPages,\r
+                  &PhysicalAddress\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *Buffer = (VOID *) (UINTN) PhysicalAddress;\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h
new file mode 100644 (file)
index 0000000..b29059f
--- /dev/null
@@ -0,0 +1,1655 @@
+/** @file\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _BIOS_SNP_16_H_\r
+#define _BIOS_SNP_16_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/LegacyBios.h>\r
+#include <Protocol/SimpleNetwork.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/NetworkInterfaceIdentifier.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include "Pxe.h"\r
+\r
+//\r
+// BIOS Simple Network Protocol Device Structure\r
+//\r
+#define EFI_SIMPLE_NETWORK_DEV_SIGNATURE    SIGNATURE_32 ('s', 'n', '1', '6')\r
+\r
+#define INIT_PXE_STATUS                     0xabcd\r
+\r
+#define EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE 64\r
+\r
+typedef struct {\r
+  UINT32  First;\r
+  UINT32  Last;\r
+  VOID *  Data[EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE];\r
+} EFI_SIMPLE_NETWORK_DEV_FIFO;\r
+\r
+typedef struct {\r
+  UINTN                                     Signature;\r
+  EFI_HANDLE                                Handle;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL               SimpleNetwork;\r
+  EFI_SIMPLE_NETWORK_MODE                   SimpleNetworkMode;\r
+  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL Nii;\r
+  EFI_DEVICE_PATH_PROTOCOL                  *DevicePath;\r
+  EFI_PCI_IO_PROTOCOL                       *PciIo;\r
+  EFI_LEGACY_BIOS_PROTOCOL                  *LegacyBios;\r
+\r
+  //\r
+  // Local Data for Simple Network Protocol interface goes here\r
+  //\r
+  BOOLEAN                                   UndiLoaded;\r
+  EFI_EVENT                                 EfiBootEvent;\r
+  EFI_EVENT                                 LegacyBootEvent;\r
+  UINT16                                    PxeEntrySegment;\r
+  UINT16                                    PxeEntryOffset;\r
+  EFI_SIMPLE_NETWORK_DEV_FIFO               TxBufferFifo;\r
+  EFI_DEVICE_PATH_PROTOCOL                  *BaseDevicePath;\r
+  PXE_T                                     *Pxe;                   ///< Pointer to !PXE structure\r
+  PXENV_UNDI_GET_INFORMATION_T              GetInformation;         ///< Data from GET INFORMATION\r
+  PXENV_UNDI_GET_NIC_TYPE_T                 GetNicType;             ///< Data from GET NIC TYPE\r
+  PXENV_UNDI_GET_NDIS_INFO_T                GetNdisInfo;            ///< Data from GET NDIS INFO\r
+  BOOLEAN                                   IsrValid;               ///< TRUE if Isr contains valid data\r
+  PXENV_UNDI_ISR_T                          Isr;                    ///< Data from ISR\r
+  PXENV_UNDI_TBD_T                          *Xmit;                  //\r
+  VOID                                      *TxRealModeMediaHeader; ///< < 1 MB Size = 0x100\r
+  VOID                                      *TxRealModeDataBuffer;  ///< < 1 MB Size = GetInformation.MaxTranUnit\r
+  VOID                                      *TxDestAddr;            ///< < 1 MB Size = 16\r
+  UINT8                                     InterruptStatus;        ///< returned/cleared by GetStatus, set in ISR\r
+  UINTN                                     UndiLoaderTablePages;\r
+  UINTN                                     DestinationDataSegmentPages;\r
+  UINTN                                     DestinationStackSegmentPages;\r
+  UINTN                                     DestinationCodeSegmentPages;\r
+  VOID                                      *UndiLoaderTable;\r
+  VOID                                      *DestinationDataSegment;\r
+  VOID                                      *DestinationStackSegment;\r
+  VOID                                      *DestinationCodeSegment;\r
+} EFI_SIMPLE_NETWORK_DEV;\r
+\r
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) \\r
+  CR (a, \\r
+      EFI_SIMPLE_NETWORK_DEV, \\r
+      SimpleNetwork, \\r
+      EFI_SIMPLE_NETWORK_DEV_SIGNATURE \\r
+      )\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gBiosSnp16DriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL  gBiosSnp16ComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosSnp16ComponentName2;\r
+\r
+\r
+//\r
+// Driver Binding Protocol functions\r
+//\r
+/**\r
+  Tests to see if this driver supports a given controller.\r
+\r
+  @param This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param Controller           The handle of the controller to test.\r
+  @param RemainingDevicePath  A pointer to the remaining portion of a device path.\r
+  \r
+  @retval EFI_SUCCESS    The driver supports given controller.\r
+  @retval EFI_UNSUPPORT  The driver doesn't support given controller.\r
+  @retval Other          Other errors prevent driver finishing to test\r
+                         if the driver supports given controller.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+;\r
+\r
+/**\r
+  Starts the Snp device controller\r
+\r
+  @param This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param Controller           The handle of the controller to test.\r
+  @param RemainingDevicePath  A pointer to the remaining portion of a device path.\r
+  \r
+  @retval  EFI_SUCCESS          - The device was started.   \r
+  @retval  EFI_DEVICE_ERROR     - The device could not be started due to a device error.\r
+  @retval  EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+;\r
+\r
+/**\r
+  Stops the device by given device controller.\r
+\r
+  @param This               A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param Controller         The handle of the controller to test.\r
+  @param NumberOfChildren   The number of child device handles in ChildHandleBuffer.\r
+  @param ChildHandleBuffer  An array of child handles to be freed. May be NULL if\r
+                            NumberOfChildren is 0.\r
+  \r
+  @retval  EFI_SUCCESS      - The device was stopped.\r
+  @retval  EFI_DEVICE_ERROR - The device could not be stopped due to a device error.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16DriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   Controller,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+;\r
+\r
+//\r
+// Simple Network Protocol functions\r
+//\r
+/**\r
+  Call 16 bit UNDI ROM to start the network interface\r
+\r
+  @param This       A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Network interface has not be initialized.\r
+  @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.\r
+  @retval EFI_SUCESS       Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStart (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+;\r
+\r
+/**\r
+  Call 16 bit UNDI ROM to stop the network interface\r
+\r
+  @param This       A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_DEVICE_ERROR Network interface has not be initialized.\r
+  @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.\r
+  @retval EFI_SUCESS       Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStop (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+;\r
+\r
+/**\r
+  Initialize network interface \r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param ExtraRxBufferSize    The size of extra request receive buffer.\r
+  @param ExtraTxBufferSize    The size of extra request transmit buffer.\r
\r
+  @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.\r
+  @retval EFI_SUCESS       Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkInitialize (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL                     *This,\r
+  IN UINTN                                           ExtraRxBufferSize  OPTIONAL,\r
+  IN UINTN                                           ExtraTxBufferSize  OPTIONAL\r
+  )\r
+;\r
+\r
+/**\r
+  Reset network interface.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param ExtendedVerification Need extended verfication.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkReset (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This,\r
+  IN BOOLEAN                      ExtendedVerification\r
+  )\r
+;\r
+\r
+/**\r
+  Shutdown network interface.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkShutdown (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This\r
+  )\r
+;\r
+\r
+/**\r
+  Reset network interface.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param Enable               Enable mask value\r
+  @param Disable              Disable mask value\r
+  @param ResetMCastFilter     Whether reset multi cast filter or not\r
+  @param MCastFilterCnt       Count of mutli cast filter for different MAC address\r
+  @param MCastFilter          Buffer for mustli cast filter for different MAC address.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkReceiveFilters (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL                     * This,\r
+  IN UINT32                                          Enable,\r
+  IN UINT32                                          Disable,\r
+  IN BOOLEAN                                         ResetMCastFilter,\r
+  IN UINTN                                           MCastFilterCnt     OPTIONAL,\r
+  IN EFI_MAC_ADDRESS                                 * MCastFilter OPTIONAL\r
+  )\r
+;\r
+\r
+/**\r
+  Set new MAC address.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param Reset                Whether reset station MAC address to permenent address\r
+  @param New                  A pointer to New address\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStationAddress (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  * This,\r
+  IN BOOLEAN                      Reset,\r
+  IN EFI_MAC_ADDRESS              * New OPTIONAL\r
+  )\r
+;\r
+\r
+/**\r
+  Collect statistics.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param Reset                Whether cleanup old statistics data.\r
+  @param StatisticsSize       The buffer of statistics table.\r
+  @param StatisticsTable      A pointer to statistics buffer.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkStatistics (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  * This,\r
+  IN BOOLEAN                      Reset,\r
+  IN OUT UINTN                    *StatisticsSize OPTIONAL,\r
+  OUT EFI_NETWORK_STATISTICS      * StatisticsTable OPTIONAL\r
+  )\r
+;\r
+\r
+/**\r
+  Translate IP address to MAC address.\r
+\r
+  @param This                 A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.\r
+  @param IPv6                 IPv6 or IPv4\r
+  @param IP                   A pointer to given Ip address.\r
+  @param MAC                  On return, translated MAC address.\r
+  \r
+  @retval EFI_INVALID_PARAMETER Invalid This paramter.\r
+  @retval EFI_INVALID_PARAMETER Invalid IP address.\r
+  @retval EFI_INVALID_PARAMETER Invalid return buffer for holding MAC address.\r
+  @retval EFI_UNSUPPORTED       Do not support IPv6 \r
+  @retval EFI_DEVICE_ERROR      Network device has not been initialized.\r
+  @retval EFI_NOT_STARTED       Network device has been stopped.\r
+  @retval EFI_DEVICE_ERROR      Invalid status for network device\r
+  @retval EFI_SUCCESS           Success operation.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkMCastIpToMac (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This,\r
+  IN BOOLEAN                      IPv6,\r
+  IN EFI_IP_ADDRESS               *IP,\r
+  OUT EFI_MAC_ADDRESS             *MAC\r
+  )\r
+;\r
+\r
+/**\r
+  Performs read and write operations on the NVRAM device attached to a \r
+  network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  ReadWrite  TRUE for read operations, FALSE for write operations.\r
+  @param  Offset     Byte offset in the NVRAM device at which to start the read or\r
+                     write operation. This must be a multiple of NvRamAccessSize and\r
+                     less than NvRamSize.\r
+  @param  BufferSize The number of bytes to read or write from the NVRAM device.\r
+                     This must also be a multiple of NvramAccessSize.\r
+  @param  Buffer     A pointer to the data buffer.\r
+\r
+  @retval EFI_SUCCESS           The NVRAM access was performed.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkNvData (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This,\r
+  IN BOOLEAN                      Write,\r
+  IN UINTN                        Offset,\r
+  IN UINTN                        BufferSize,\r
+  IN OUT VOID                     *Buffer\r
+  )\r
+;\r
+\r
+/**\r
+  Reads the current interrupt status and recycled transmit buffer status from \r
+  a network interface.\r
+\r
+  @param  This            The protocol instance pointer.\r
+  @param  InterruptStatus A pointer to the bit mask of the currently active interrupts\r
+                          If this is NULL, the interrupt status will not be read from\r
+                          the device. If this is not NULL, the interrupt status will\r
+                          be read from the device. When the  interrupt status is read,\r
+                          it will also be cleared. Clearing the transmit  interrupt\r
+                          does not empty the recycled transmit buffer array.\r
+  @param  TxBuf           Recycled transmit buffer address. The network interface will\r
+                          not transmit if its internal recycled transmit buffer array\r
+                          is full. Reading the transmit buffer does not clear the\r
+                          transmit interrupt. If this is NULL, then the transmit buffer\r
+                          status will not be read. If there are no transmit buffers to\r
+                          recycle and TxBuf is not NULL, * TxBuf will be set to NULL.\r
+\r
+  @retval EFI_SUCCESS           The status of the network interface was retrieved.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkGetStatus (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  * This,\r
+  OUT UINT32                      *InterruptStatus OPTIONAL,\r
+  OUT VOID                        **TxBuf OPTIONAL\r
+  )\r
+;\r
+\r
+/**\r
+  Places a packet in the transmit queue of a network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  HeaderSize The size, in bytes, of the media header to be filled in by\r
+                     the Transmit() function. If HeaderSize is non-zero, then it\r
+                     must be equal to This->Mode->MediaHeaderSize and the DestAddr\r
+                     and Protocol parameters must not be NULL.\r
+  @param  BufferSize The size, in bytes, of the entire packet (media header and\r
+                     data) to be transmitted through the network interface.\r
+  @param  Buffer     A pointer to the packet (media header followed by data) to be\r
+                     transmitted. This parameter cannot be NULL. If HeaderSize is zero,\r
+                     then the media header in Buffer must already be filled in by the\r
+                     caller. If HeaderSize is non-zero, then the media header will be\r
+                     filled in by the Transmit() function.\r
+  @param  SrcAddr    The source HW MAC address. If HeaderSize is zero, then this parameter\r
+                     is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then\r
+                     This->Mode->CurrentAddress is used for the source HW MAC address.\r
+  @param  DestAddr   The destination HW MAC address. If HeaderSize is zero, then this\r
+                     parameter is ignored.\r
+  @param  Protocol   The type of header to build. If HeaderSize is zero, then this\r
+                     parameter is ignored. See RFC 1700, section "Ether Types", for\r
+                     examples.\r
+\r
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.                      \r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkTransmit (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This,\r
+  IN UINTN                        HeaderSize,\r
+  IN UINTN                        BufferSize,\r
+  IN VOID                         *Buffer,\r
+  IN EFI_MAC_ADDRESS              *SrcAddr OPTIONAL,\r
+  IN EFI_MAC_ADDRESS              *DestAddr OPTIONAL,\r
+  IN UINT16                       *Protocol OPTIONAL\r
+  )\r
+;\r
+\r
+/**\r
+  Receives a packet from a network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  HeaderSize The size, in bytes, of the media header received on the network\r
+                     interface. If this parameter is NULL, then the media header size\r
+                     will not be returned.\r
+  @param  BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in\r
+                     bytes, of the packet that was received on the network interface.\r
+  @param  Buffer     A pointer to the data buffer to receive both the media header and\r
+                     the data.\r
+  @param  SrcAddr    The source HW MAC address. If this parameter is NULL, the\r
+                     HW MAC source address will not be extracted from the media\r
+                     header.\r
+  @param  DestAddr   The destination HW MAC address. If this parameter is NULL,\r
+                     the HW MAC destination address will not be extracted from the\r
+                     media header.\r
+  @param  Protocol   The media header type. If this parameter is NULL, then the\r
+                     protocol will not be extracted from the media header. See\r
+                     RFC 1700 section "Ether Types" for examples.\r
+\r
+  @retval  EFI_SUCCESS           The received data was stored in Buffer, and BufferSize has\r
+                                 been updated to the number of bytes received.\r
+  @retval  EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval  EFI_NOT_READY         The network interface is too busy to accept this transmit\r
+                                 request.\r
+  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval  EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval  EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval  EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Undi16SimpleNetworkReceive (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This,\r
+  OUT UINTN                       *HeaderSize OPTIONAL,\r
+  IN OUT UINTN                    *BufferSize,\r
+  OUT VOID                        *Buffer,\r
+  OUT EFI_MAC_ADDRESS             *SrcAddr OPTIONAL,\r
+  OUT EFI_MAC_ADDRESS             *DestAddr OPTIONAL,\r
+  OUT UINT16                      *Protocol OPTIONAL\r
+  )\r
+;\r
+\r
+/**\r
+  wait for a packet to be received.\r
+\r
+  @param Event      Event used with WaitForEvent() to wait for a packet to be received.\r
+  @param Context    Event Context\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+Undi16SimpleNetworkWaitForPacket (\r
+  IN EFI_EVENT               Event,\r
+  IN VOID                    *Context\r
+  )\r
+;\r
+\r
+/**\r
+  Check whether packet is ready for receive.\r
+\r
+  @param This The protocol instance pointer.\r
+  \r
+  @retval  EFI_SUCCESS           Receive data is ready.\r
+  @retval  EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval  EFI_NOT_READY         The network interface is too busy to accept this transmit\r
+                                 request.\r
+  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval  EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval  EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval  EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+**/\r
+EFI_STATUS\r
+Undi16SimpleNetworkCheckForPacket (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *This\r
+  )\r
+;\r
+\r
+/**\r
+ Cache Interrupt verctor address converted from IVT number.\r
+\r
+ @param VectorNumber  IVT number\r
\r
+ @retval EFI_SUCCESS Success to operation.\r
+**/\r
+EFI_STATUS\r
+CacheVectorAddress (\r
+  UINT8   VectorNumber\r
+  )\r
+;\r
+\r
+/**\r
+ Get interrupt vector address according to IVT number. \r
+  \r
+ @param VectorNumber    Given IVT number\r
\r
+ @return cached interrupt vector address.\r
+**/\r
+EFI_STATUS\r
+RestoreCachedVectorAddress (\r
+  UINT8   VectorNumber\r
+  )\r
+;\r
+\r
+/**\r
+  If available, launch the BaseCode from a NIC option ROM.\r
+  This should install the !PXE and PXENV+ structures in memory for\r
+  subsequent use.\r
+  \r
+\r
+  @param SimpleNetworkDevice    Simple network device instance\r
+  @param RomAddress             The ROM base address for NIC rom.\r
+  \r
+  @retval EFI_NOT_FOUND         The check sum does not match \r
+  @retval EFI_NOT_FOUND         Rom ID offset is wrong \r
+  @retval EFI_NOT_FOUND         No Rom ID structure is found \r
+**/\r
+EFI_STATUS\r
+LaunchBaseCode (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  UINTN                   RomAddress\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  START UNDI\r
+  Op-Code: PXENV_START_UNDI (0000h)\r
+  Input: Far pointer to a PXENV_START_UNDI_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This service is used to pass the BIOS parameter registers to the UNDI driver. The UNDI driver is\r
+  responsible for saving the information it needs to communicate with the hardware.\r
+  This service is also responsible for hooking the Int 1Ah service routine\r
+  Note: This API service must be called only once during UNDI Option ROM boot.\r
+  The UNDI driver is responsible for saving this information and using it every time\r
+  PXENV_UNDI_STARTUP is called.\r
+  Service cannot be used in protected mode.\r
+  typedef struct  {\r
+      PXENV_STATUS Status;\r
+      UINT16 AX;\r
+      UINT16 BX;\r
+      UINT16 DX;\r
+      UINT16 DI;\r
+      UINT16 ES;\r
+  } PXENV_START_UNDI_T;\r
+  Set before calling API service\r
+  AX, BX, DX, DI, ES: BIOS initialization parameter registers. These\r
+  fields should contain the same information passed to the option ROM\r
+  initialization routine by the Host System BIOS. Information about the\r
+  contents of these registers can be found in the [PnP], [PCI] and\r
+  [BBS] specifications.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.    \r
+\r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call.                                \r
+**/\r
+EFI_STATUS\r
+PxeStartUndi (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_START_UNDI_T               *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI STARTUP    \r
+  Op-Code: PXENV_UNDI_STARTUP (0001h)\r
+  Input: Far pointer to a PXENV_UNDI_STARTUP_T parameter structure that has been initialized by the\r
+  caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This API is responsible for initializing the contents of the UNDI code & data segment for proper\r
+  operation. Information from the !PXE structure and the first PXENV_START_UNDI API call is used\r
+  to complete this initialization. The rest of the UNDI APIs will not be available until this call has\r
+  been completed.\r
+  Note: PXENV_UNDI_STARTUP must not be called again without first calling\r
+  PXENV_UNDI_SHUTDOWN.\r
+  PXENV_UNDI_STARTUP and PXENV_UNDI_SHUTDOWN are no longer responsible for\r
+  chaining interrupt 1Ah. This must be done by the PXENV_START_UNDI and\r
+  PXENV_STOP_UNDI API calls.\r
+  This service cannot be used in protected mode.\r
+  typedef struct \r
+  {\r
+      PXENV_STATUS Status;\r
+  } PXENV_UNDI_STARTUP_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+\r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call.    \r
+**/\r
+EFI_STATUS\r
+PxeUndiStartup (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_STARTUP_T             *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI CLEANUP\r
+  Op-Code: PXENV_UNDI_CLEANUP (0002h)\r
+  Input: Far pointer to a PXENV_UNDI_CLEANUP_T parameter structure.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field\r
+  in the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call will prepare the network adapter driver to be unloaded from memory. This call must be\r
+  made just before unloading the Universal NIC Driver. The rest of the API will not be available\r
+  after this call executes.\r
+  This service cannot be used in protected mode.\r
+  typedef struct {\r
+      PXENX_STATUS Status;\r
+  } PXENV_UNDI_CLEANUP_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+\r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call. \r
+**/\r
+EFI_STATUS\r
+PxeUndiCleanup (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_CLEANUP_T             *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI INITIALIZE\r
+  Op-Code: PXENV_UNDI_INITIALIZE (0003h)\r
+  Input: Far pointer to a PXENV_UNDI_INITIALIZE_T parameter structure that has been initialized by the\r
+  caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets the adapter and programs it with default parameters. The default parameters used\r
+  are those supplied to the most recent UNDI_STARTUP call. This routine does not enable the\r
+  receive and transmit units of the network adapter to readily receive or transmit packets. The\r
+  application must call PXENV_UNDI_OPEN to logically connect the network adapter to the network.\r
+  This call must be made by an application to establish an interface to the network adapter driver.\r
+  Note: When the PXE code makes this call to initialize the network adapter, it passes a NULL pointer for\r
+  the Protocol field in the parameter structure.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    ADDR32 ProtocolIni;\r
+    UINT8 reserved[8];\r
+  } PXENV_UNDI_INITIALIZE_T;\r
+  Set before calling API service\r
+  ProtocolIni: Physical address of a memory copy of the driver\r
+  module from the protocol.ini file obtained from the protocol manager\r
+  driver (refer to the NDIS 2.0 specification). This parameter is\r
+  supported for the universal NDIS driver to pass the information\r
+  contained in the protocol.ini file to the NIC driver for any specific\r
+  configuration of the NIC. (Note that the module identification in the\r
+  protocol.ini file was done by NDIS.) This value can be NULL for any\r
+  other application interfacing to the universal NIC driver\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.    \r
+  \r
+  @param  SimpleNetworkDevice   Device instance.\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call. \r
+**/\r
+EFI_STATUS\r
+PxeUndiInitialize (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_INITIALIZE_T          *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  Wrapper routine for reset adapter.\r
+  \r
+  PXE \r
+  UNDI RESET ADAPTER\r
+  Op-Code: PXENV_UNDI_RESET_ADAPTER (0004h)\r
+  Input: Far pointer to a PXENV_UNDI_RESET_ADAPTER_t parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets and reinitializes the network adapter with the same set of parameters supplied to\r
+  Initialize Routine. Unlike Initialize, this call opens the adapter that is, it connects logically to the\r
+  network. This routine cannot be used to replace Initialize or Shutdown calls.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    PXENV_UNDI_MCAST_ADDRESS_t    R_Mcast_Buf;\r
+  } PXENV_UNDI_RESET_T;\r
+\r
+  #define MAXNUM_MCADDR 8\r
+\r
+  typedef struct {\r
+    UINT16 MCastAddrCount;\r
+    MAC_ADDR McastAddr[MAXNUM_MCADDR];\r
+  } PXENV_UNDI_MCAST_ADDRESS_t;\r
+\r
+  Set before calling API service\r
+  R_Mcast_Buf: This is a structure of MCastAddrCount and\r
+  McastAddr.\r
+  MCastAddrCount: Number of multicast MAC addresses in the\r
+  buffer.\r
+  McastAddr: List of up to MAXNUM_MCADDR multicast MAC\r
+  addresses.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance.\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+  @param  RxFilter             Filter setting mask value for PXE recive .     \r
+                               \r
+  @return Return value of PXE option ROM far call. \r
+**/\r
+EFI_STATUS\r
+PxeUndiResetNic (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_RESET_T               *PxeUndiTable,\r
+  IN UINT16                               RxFilter\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI SHUTDOWN\r
+  Op-Code: PXENV_UNDI_SHUTDOWN (0005h)\r
+  Input: Far pointer to a PXENV_UNDI_SHUTDOWN_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets the network adapter and leaves it in a safe state for another driver to program it.\r
+  Note: The contents of the PXENV_UNDI_STARTUP parameter structure need to be saved by the\r
+  Universal NIC Driver in case PXENV_UNDI_INITIALIZE is called again.\r
+  typedef struct \r
+  {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_SHUTDOWN_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.   \r
+**/\r
+EFI_STATUS\r
+PxeUndiShutdown (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SHUTDOWN_T            *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI OPEN\r
+  Op-Code: PXENV_UNDI_OPEN (0006h)\r
+  Input: Far pointer to a PXENV_UNDI_OPEN_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call activates the adapter network connection and sets the adapter ready to accept packets\r
+  for transmit and receive.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT16 OpenFlag;\r
+    UINT16 PktFilter;\r
+      #define FLTR_DIRECTED 0x0001\r
+      #define FLTR_BRDCST 0x0002\r
+      #define FLTR_PRMSCS 0x0004\r
+      #define FLTR_SRC_RTG 0x0008\r
+    PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;\r
+  } PXENV_UNDI_OPEN_T;\r
+  Set before calling API service\r
+  OpenFlag: This is an adapter specific input parameter. This is\r
+  supported for the universal NDIS 2.0 driver to pass in the open flags\r
+  provided by the protocol driver. (See the NDIS 2.0 specification.)\r
+  This can be zero.\r
+  PktFilter: Filter for receiving packets. This can be one, or more, of\r
+  the FLTR_xxx constants. Multiple values are arithmetically or-ed\r
+  together.\r
+  directed packets are packets that may come to your MAC address\r
+  or the multicast MAC address.\r
+  R_Mcast_Buf: See definition in UNDI RESET ADAPTER (0004h).\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiOpen (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_OPEN_T                *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI CLOSE\r
+  Op-Code: PXENV_UNDI_CLOSE (0007h)\r
+  Input: Far pointer to a PXENV_UNDI_CLOSE_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call disconnects the network adapter from the network. Packets cannot be transmitted or\r
+  received until the network adapter is open again.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_CLOSE_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiClose (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_CLOSE_T               *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI TRANSMIT PACKET\r
+  Op-Code: PXENV_UNDI_TRANSMIT (0008h)\r
+  Input: Far pointer to a PXENV_UNDI_TRANSMIT_T parameter structure that\r
+  has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX.\r
+  The status code must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call transmits a buffer to the network. The media header\r
+  for the packet can be filled by the calling protocol, but it might not be.\r
+  The network adapter driver will fill it if required by the values in the\r
+  parameter block. The packet is buffered for transmission provided there is\r
+  an available buffer, and the function returns PXENV_EXIT_SUCCESS. If no\r
+  buffer is available the function returns PXENV_EXIT_FAILURE with a status\r
+  code of PXE_UNDI_STATUS__OUT OF_RESOURCE. The number of buffers is\r
+  implementation-dependent. An interrupt is generated on completion of the\r
+  transmission of one or more packets. A call to PXENV_UNDI_TRANSMIT is\r
+  permitted in the context of a transmit complete interrupt.\r
+\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT8 Protocol;\r
+      #define P_UNKNOWN 0\r
+      #define P_IP 1\r
+      #define P_ARP 2\r
+      #define P_RARP 3\r
+    UINT8 XmitFlag;\r
+      #define XMT_DESTADDR 0x0000\r
+      #define XMT_BROADCAST 0x0001\r
+    SEGOFF16 DestAddr;\r
+    SEGOFF16 TBD;\r
+    UINT32 Reserved[2];\r
+  } t_PXENV_UNDI_TRANSMIT;\r
+\r
+  #define MAX_DATA_BLKS 8\r
+\r
+  typedef struct {\r
+    UINT16 ImmedLength;\r
+    SEGOFF16 Xmit;\r
+    UINT16 DataBlkCount;\r
+    struct DataBlk {\r
+      UINT8 TDPtrType;\r
+      UINT8 TDRsvdByte;\r
+      UINT16 TDDataLen;\r
+      SEGOFF16 TDDataPtr;\r
+    } DataBlock[MAX_DATA_BLKS];\r
+  } PXENV_UNDI_TBD_T\r
+\r
+  Set before calling API service\r
+  Protocol: This is the protocol of the upper layer that is calling UNDI\r
+  TRANSMIT call. If the upper layer has filled the media header, this\r
+  field must be P_UNKNOWN.\r
+  XmitFlag: If this flag is XMT_DESTADDR, the NIC driver expects a\r
+  pointer to the destination media address in the field DestAddr. If\r
+  XMT_BROADCAST, the NIC driver fills the broadcast address for the\r
+  destination.\r
+  TBD: Segment:Offset address of the transmit buffer descriptor.\r
+  ImmedLength: Length of the immediate transmit buffer: Xmit.\r
+  Xmit: Segment:Offset of the immediate transmit buffer.\r
+  DataBlkCount: Number of blocks in this transmit buffer.\r
+  TDPtrType:\r
+  0 => 32-bit physical address in TDDataPtr (not supported in this\r
+  version of PXE)\r
+  1 => segment:offset in TDDataPtr which can be a real mode or 16-bit\r
+  protected mode pointer\r
+  TDRsvdByte: Reserved must be zero.\r
+  TDDatalen: Data block length in bytes.\r
+  TDDataPtr: Segment:Offset of the transmit block.\r
+  DataBlock: Array of transmit data blocks.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants  \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiTransmit (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_TRANSMIT_T            *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI SET MULTICAST ADDRESS\r
+  Op-Code: PXENV_UNDI_SET_MCAST_ADDRESS (0009h)\r
+  Input: Far pointer to a PXENV_TFTP_SET_MCAST_ADDRESS_t parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call changes the current list of multicast addresses to the input list and resets the network\r
+  adapter to accept it. If the number of multicast addresses is zero, multicast is disabled.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;\r
+  } PXENV_UNDI_SET_MCAST_ADDR_T;\r
+  Set before calling API service\r
+  R_Mcast_Buf: See description in the UNDI RESET ADAPTER\r
+  (0004h) API.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants        \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiSetMcastAddr (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SET_MCAST_ADDR_T      *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI SET STATION ADDRESS\r
+  Op-Code: PXENV_UNDI_SET_STATION_ADDRESS (000Ah)\r
+  Input: Far pointer to a PXENV_UNDI_SET_STATION_ADDRESS_t parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call sets the MAC address to be the input value and is called before opening the network\r
+  adapter. Later, the open call uses this variable as a temporary MAC address to program the\r
+  adapter individual address registers.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    MAC_ADDR StationAddress;\r
+  } PXENV_UNDI_SET_STATION_ADDR_T;\r
+  Set before calling API service\r
+  StationAddress: Temporary MAC address to be used for\r
+  transmit and receive.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.     \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiSetStationAddr (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SET_STATION_ADDR_T    *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI SET PACKET FILTER\r
+  Op-Code: PXENV_UNDI_SET_PACKET_FILTER (000Bh)\r
+  Input: Far pointer to a PXENV_UNDI_SET_PACKET_FILTER_T parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets the adapter's receive unit to accept a new filter, different from the one provided with\r
+  the open call.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT8 filter;\r
+  } PXENV_UNDI_SET_PACKET_FILTER_T;\r
+  Set before calling API service\r
+  Filter: See the receive filter values in the UNDI OPEN\r
+  (0006h) API description.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.   \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiSetPacketFilter (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SET_PACKET_FILTER_T   *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI GET INFORMATION\r
+  Op-Code: PXENV_UNDI_GET_INFORMATION (000Ch)\r
+  Input: Far pointer to a PXENV_UNDI_GET_INFORMATION_T parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call copies the network adapter variables, including the MAC address, into the input buffer.\r
+  Note: The PermNodeAddress field must be valid after PXENV_START_UNDI and\r
+  PXENV_UNDI_STARTUP have been issued. All other fields must be valid after\r
+  PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE have been\r
+  called.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT16 BaseIo;\r
+    UINT16 IntNumber;\r
+    UINT16 MaxTranUnit;\r
+    UINT16 HwType;\r
+      #define ETHER_TYPE 1\r
+      #define EXP_ETHER_TYPE 2\r
+      #define IEEE_TYPE 6\r
+      #define ARCNET_TYPE 7\r
+    UINT16 HwAddrLen;\r
+    MAC_ADDR CurrentNodeAddress;\r
+    MAC_ADDR PermNodeAddress;\r
+    SEGSEL ROMAddress;\r
+    UINT16 RxBufCt;\r
+    UINT16 TxBufCt;\r
+  } PXENV_UNDI_GET_INFORMATION_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  BaseIO: Adapter base I/O address.\r
+  IntNumber: Adapter IRQ number.\r
+  MaxTranUnit: Adapter maximum transmit unit.\r
+  HWType: Type of protocol at the hardware level.\r
+  HWAddrLen: Length of the hardware address.\r
+  CurrentNodeAddress: Current hardware address.\r
+  PermNodeAddress: Permanent hardware address.\r
+  ROMAddress: Real mode ROM segment address.\r
+  RxBufCnt: Receive queue length.\r
+  TxBufCnt: Transmit queue length.  \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetInformation (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_INFORMATION_T     *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI GET STATISTICS\r
+  Op-Code: PXENV_UNDI_GET_STATISTICS (000Dh)\r
+  Input: Far pointer to a PXENV_UNDI_GET_STATISTICS_T parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call reads statistical information from the network adapter, and returns.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT32 XmtGoodFrames;\r
+    UINT32 RcvGoodFrames;\r
+    UINT32 RcvCRCErrors;\r
+    UINT32 RcvResourceErrors;\r
+  } PXENV_UNDI_GET_STATISTICS_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  XmtGoodFrames: Number of successful transmissions.\r
+  RcvGoodFrames: Number of good frames received.\r
+  RcvCRCErrors: Number of frames received with CRC\r
+  error.\r
+  RcvResourceErrors: Number of frames discarded\r
+  because receive queue was full.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetStatistics (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_STATISTICS_T      *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI CLEAR STATISTICS\r
+  Op-Code: PXENV_UNDI_CLEAR_STATISTICS (000Eh)\r
+  Input: Far pointer to a PXENV_UNDI_CLEAR_STATISTICS_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call clears the statistical information from the network adapter.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_CLEAR_STATISTICS_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiClearStatistics (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_CLEAR_STATISTICS_T    *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI INITIATE DIAGS\r
+  Op-Code: PXENV_UNDI_INITIATE_DIAGS (000Fh)\r
+  Input: Far pointer to a PXENV_UNDI_INITIATE_DIAGS_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call can be used to initiate the run-time diagnostics. It causes the network adapter to run\r
+  hardware diagnostics and to update its status information.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_INITIATE_DIAGS_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.    \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiInitiateDiags (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_INITIATE_DIAGS_T      *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI FORCE INTERRUPT\r
+  Op-Code: PXENV_UNDI_FORCE_INTERRUPT (0010h)\r
+  Input: Far pointer to a PXENV_UNDI_FORCE_INTERRUPT_T parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call forces the network adapter to generate an interrupt. When a receive interrupt occurs, the\r
+  network adapter driver usually queues the packet and calls the application's callback receive\r
+  routine with a pointer to the packet received. Then, the callback routine either can copy the packet\r
+  to its buffer or can decide to delay the copy to a later time. If the packet is not immediately copied,\r
+  the network adapter driver does not remove it from the input queue. When the application wants to\r
+  copy the packet, it can call the PXENV_UNDI_FORCE_INTERRUPT routine to simulate the receive\r
+  interrupt.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_FORCE_INTERRUPT_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.  \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiForceInterrupt (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_FORCE_INTERRUPT_T     *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI GET MULTICAST ADDRESS\r
+  Op-Code: PXENV_UNDI_GET_MCAST_ADDRESS (0011h)\r
+  Input: Far pointer to a PXENV_GET_MCAST_ADDRESS_t parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call converts the given IP multicast address to a hardware multicast address.\r
+  typedef struct  {\r
+    PXENV_STATUS Status;\r
+    IP4 InetAddr;\r
+    MAC_ADDR MediaAddr;\r
+  } PXENV_UNDI_GET_MCAST_ADDR_T;\r
+  Set before calling API service\r
+  InetAddr: IP multicast address.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  MediaAddr: MAC multicast address.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetMcastAddr (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_MCAST_ADDR_T      *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI GET NIC TYPE\r
+  Op-Code: PXENV_UNDI_GET_NIC_TYPE (0012h)\r
+  Input: Far pointer to a PXENV_UNDI_GET_NIC_TYPE_T parameter structure that has been initialized by\r
+  the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants. If the PXENV_EXIT_SUCCESS is returned the parameter structure must contain the\r
+  NIC information.\r
+  Description: This call, if successful, provides the NIC-specific information necessary to identify the network\r
+  adapter that is used to boot the system.\r
+  Note: The application first gets the DHCPDISCOVER packet using GET_CACHED_INFO and checks if\r
+  the UNDI is supported before making this call. If the UNDI is not supported, the NIC-specific\r
+  information can be obtained from the DHCPDISCOVER packet itself.\r
+  PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called\r
+  before the information provided is valid.\r
+  typedef {\r
+    PXENV_STATUS Status;\r
+    UINT8 NicType;\r
+      #define PCI_NIC 2\r
+      #define PnP_NIC 3\r
+      #define CardBus_NIC 4\r
+    Union {\r
+      Struct {\r
+        UINT16 Vendor_ID;\r
+        UINT16 Dev_ID;\r
+        UINT8 Base_Class;\r
+        UINT8 Sub_Class;\r
+        UINT8 Prog_Intf;\r
+        UINT8 Rev;\r
+        UINT16 BusDevFunc;\r
+        UINT16 SubVendor_ID;\r
+        UINT16 SubDevice_ID;\r
+      } pci, cardbus;\r
+      struct {\r
+        UINT32 EISA_Dev_ID;\r
+        UINT8 Base_Class;\r
+        UINT8 Sub_Class;\r
+        UINT8 Prog_Intf;\r
+        UINT16 CardSelNum;\r
+      } pnp;\r
+    } info;\r
+  } PXENV_UNDI_GET_NIC_TYPE_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  NICType: Type of NIC information stored in the parameter\r
+  structure.\r
+  Info: Information about the fields in this union can be found\r
+  in the [PnP] and [PCI] specifications    \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetNicType (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_NIC_TYPE_T        *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI GET IFACE INFO\r
+  Op-Code: PXENV_UNDI_GET_IFACE_INFO (0013h)\r
+  Input: Far pointer to a PXENV_UNDI_GET_IFACE_INFO_t parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants. If the PXENV_EXIT_SUCCESS is returned, the parameter structure must contain the\r
+  interface specific information.\r
+  Description: This call, if successful, provides the network interface specific information such as the interface\r
+  type at the link layer (Ethernet, Tokenring) and the link speed. This information can be used in the\r
+  universal drivers such as NDIS or Miniport to communicate to the upper protocol modules.\r
+  Note: UNDI follows the NDIS2 specification in giving this information. It is the responsibility of the\r
+  universal driver to translate/convert this information into a format that is required in its specification\r
+  or to suit the expectation of the upper level protocol modules.\r
+  PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called\r
+  before the information provided is valid.\r
+  typedef struct {\r
+    PXENV_STATUS Status\r
+    UINT8 IfaceType[16];\r
+    UINT32 LinkSpeed;\r
+    UINT32 ServiceFlags;\r
+    UINT32 Reserved[4];\r
+  } PXENV_UNDI_GET_NDIS_INFO_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  IfaceType: Name of MAC type in ASCIIZ format. This is\r
+  used by the universal NDIS driver to specify its driver type\r
+  to the protocol driver.\r
+  LinkSpeed: Defined in the NDIS 2.0 specification.\r
+  ServiceFlags: Defined in the NDIS 2.0 specification.\r
+  Reserved: Must be zero.       \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetNdisInfo (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_NDIS_INFO_T       *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI ISR\r
+  Op-Code: PXENV_UNDI_ISR (0014h)\r
+  Input: Far pointer to a PXENV_UNDI_ISR_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in\r
+  the parameter block indicates the operation to be performed for the call. This field is filled with the\r
+  status of that operation on return.\r
+  Note: Interrupt Service Routine Operation:\r
+  In this design the UNDI does not hook the interrupt for the Network Interface. Instead, the\r
+  application or the protocol driver hooks the interrupt and calls UNDI with the PXENV_UNDI_ISR\r
+  API call for interrupt verification (PXENV_UNDI_ISR_IN_START) and processing\r
+  (PXENV_UNDI_ISR_IN_PROCESS and PXENV_UNDI_ISR_GET_NEXT).\r
+  When the Network Interface HW generates an interrupt the protocol driver interrupt service\r
+  routine (ISR) gets control and takes care of the interrupt processing at the PIC level. The ISR then\r
+  calls the UNDI using the PXENV_UNDI_ISR API with the value PXENV_UNDI_ISR_IN_START for\r
+  the FuncFlag parameter. At this time UNDI must disable the interrupts at the Network Interface\r
+  level and read any status values required to further process the interrupt. UNDI must return as\r
+  quickly as possible with one of the two values, PXENV_UNDI_ISR_OUT_OURS or\r
+  PXENV_UNDI_ISR_OUT_NOT_OURS, for the parameter FuncFlag depending on whether the\r
+  interrupt was generated by this particular Network Interface or not.\r
+  If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_NOT_OURS, then the interrupt was\r
+  not generated by our NIC, and interrupt processing is complete.\r
+  If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_OURS, the protocol driver must start\r
+  a handler thread and send an end-of-interrupt (EOI) command to the PIC. Interrupt processing is\r
+  now complete.\r
+  The protocol driver strategy routine will call UNDI using this same API with FuncFlag equal to\r
+  PXENV_UNDI_ISR_IN_PROCESS. At this time UNDI must find the cause of this interrupt and\r
+  return the status in the FuncFlag. It first checks if there is a frame received and if so it returns the\r
+  first buffer pointer of that frame in the parameter block.\r
+  The protocol driver calls UNDI repeatedly with the FuncFlag equal to\r
+  PXENV_UNDI_ISR_IN_GET_NEXT to get all the buffers in a frame and also all the received\r
+  frames in the queue. On this call, UNDI must remember the previous buffer given to the protoco,l\r
+  remove it from the receive queue and recycle it. In case of a multi-buffered frame, if the previous\r
+  buffer is not the last buffer in the frame it must return the next buffer in the frame in the parameter\r
+  block. Otherwise it must return the first buffer in the next frame.\r
+  If there is no received frame pending to be processed, UNDI processes the transmit completes and\r
+  if there is no other interrupt status to be processed, UNDI re-enables the interrupt at the\r
+  NETWORK INTERFACE level and returns PXENV_UNDI_ISR_OUT_DONE in the FuncFlag.\r
+  IMPORTANT: It is possible for the protocol driver to be interrupted again while in the\r
+  strategy routine when the UNDI re-enables interrupts.   \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiIsr (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_ISR_T                 *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  STOP UNDI\r
+  Op-Code: PXENV_STOP_UNDI (0015h)\r
+  Input: Far pointer to a PXENV_STOP_UNDI_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This routine is responsible for unhooking the Int 1Ah service routine.\r
+  Note: This API service must be called only once at the end of UNDI Option ROM boot. One of the valid\r
+  status codes is PXENV_STATUS_KEEP. If this status is returned, UNDI must not be removed from\r
+  base memory. Also, UNDI must not be removed from base memory if BC is not removed from base\r
+  memory.\r
+  Service cannot be used in protected mode.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_STOP_UNDI_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.      \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiStop (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_STOP_UNDI_T                *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  PXE \r
+  UNDI GET STATE\r
+  Op-Code: PXENV_UNDI_GET_STATE (0015h)\r
+  Input: Far pointer to a PXENV_UNDI_GET_STATE_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants. The UNDI_STATE field in the parameter structure must be set to one of the valid state\r
+  constants\r
+  Description: This call can be used to obtain state of the UNDI engine in order to avoid issuing adverse call\r
+  sequences\r
+  typedef struct {\r
+    #define PXE_UNDI_GET_STATE_STARTED 1\r
+    #define PXE_UNDI_GET_STATE_INITIALIZED 2\r
+    #define PXE_UNDI_GET_STATE_OPENED 3\r
+    PXENV_STATUS Status;\r
+    UINT8 UNDIstate;\r
+  } PXENV_UNDI_GET_STATE_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  State: See definitions of the state constants.\r
+  Note. UNDI implementation is responsible for maintaining\r
+  internal state machine.\r
+  UNDI ISR\r
+  Op-Code: PXENV_UNDI_ISR (0014h)\r
+  Input: Far pointer to a t_PXENV_UNDI_ISR parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in\r
+  the parameter block indicates the operation to be performed for the call. This field is filled with the\r
+  status of that operation on return.     \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetState (\r
+  IN EFI_SIMPLE_NETWORK_DEV               *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_STATE_T           *PxeUndiTable\r
+  )\r
+;\r
+\r
+/**\r
+  Effect the Far Call into the PXE Layer\r
+\r
+  Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API\r
+  services will not work, unless there are three 16-bit parameters pushed onto the stack.\r
+      push DS                                 ;Far pointer to parameter structure\r
+      push offset pxe_data_call_struct        ;is pushed onto stack.\r
+      push Index                              ;UINT16 is pushed onto stack.\r
+      call dword ptr (s_PXE ptr es:[di]).EntryPointSP\r
+      add sp, 6 ;Caller cleans up stack.  \r
+\r
+  @param SimpleNetworkDevice    Device instance for simple network\r
+  @param Table                 Point to parameter/retun value table for legacy far call\r
+  @param TableSize              The size of paramter/return value table\r
+  @param CallIndex              The index of legacy call.\r
+  \r
+  @return EFI_STATUS \r
+**/\r
+EFI_STATUS\r
+MakePxeCall (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT VOID             *Table,\r
+  IN UINTN                TableSize,\r
+  IN UINT16               CallIndex\r
+  )\r
+;\r
+\r
+/**\r
+  Allocate buffer below 1M for real mode.\r
+\r
+  @param NumPages     The number pages want to be allocated.\r
+  @param Buffer       On return, allocated buffer.\r
+  \r
+  @return Status of allocating pages.\r
+**/\r
+EFI_STATUS\r
+BiosSnp16AllocatePagesBelowOneMb (\r
+  UINTN  NumPages,\r
+  VOID   **Buffer\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c
new file mode 100644 (file)
index 0000000..a95d834
--- /dev/null
@@ -0,0 +1,309 @@
+/** @file\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosSnp16.h"\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16ComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16ComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gBiosSnp16ComponentName = {\r
+  BiosSnp16ComponentNameGetDriverName,\r
+  BiosSnp16ComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosSnp16ComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosSnp16ComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosSnp16ComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosSnp16DriverNameTable[] = {\r
+  {\r
+    "eng;en",\r
+    L"BIOS[UNDI] Simple Network Protocol Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16ComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mBiosSnp16DriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gBiosSnp16ComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosSnp16ComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c
new file mode 100644 (file)
index 0000000..0b3543e
--- /dev/null
@@ -0,0 +1,956 @@
+/** @file\r
+  Helper Routines that use a PXE-enabled NIC option ROM.\r
\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosSnp16.h"\r
+\r
+#define TO_SEGMENT(x)   ((UINT16) (RShiftU64 ((UINT32)(UINTN) (x), 4) & 0xF000))\r
+#define TO_OFFSET(x)    ((UINT16) ((UINT32)(UINTN) (x) & 0xFFFF))\r
+#define PARAGRAPH_SIZE  0x10\r
+#define IVT_BASE        0x00000000\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT16  Signature;          ///< 0xaa55\r
+  UINT8   ROMlength;          ///< size of this ROM in 512 byte blocks\r
+  UINT8   InitEntryPoint[4];  ///< a jump to the initialization routine\r
+  UINT8   Reserved[0xf];      ///< various\r
+  UINT16  PxeRomIdOffset;     ///< offset of UNDI, $BC$, or BUSD ROM ID structure\r
+  UINT16  PcirHeaderOffset;   ///< offset of PCI Expansion Header\r
+  UINT16  PnpHeaderOffset;    ///< offset of Plug and Play Expansion Header\r
+} OPTION_ROM_HEADER;\r
+#pragma pack()\r
+\r
+UINT32 CachedVectorAddress[0x100];\r
+\r
+/**\r
+ Cache Interrupt verctor address converted from IVT number.\r
+\r
+ @param VectorNumber  IVT number\r
\r
+ @retval EFI_SUCCESS Success to operation.\r
+**/\r
+EFI_STATUS\r
+CacheVectorAddress (\r
+  UINT8   VectorNumber\r
+  )\r
+{\r
+  UINT32  *Address;\r
+\r
+  Address                          = (UINT32 *)(UINTN) (IVT_BASE + VectorNumber * 4);\r
+  CachedVectorAddress[VectorNumber] = *Address;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get interrupt vector address according to IVT number. \r
+  \r
+ @param VectorNumber    Given IVT number\r
\r
+ @return cached interrupt vector address.\r
+**/\r
+EFI_STATUS\r
+RestoreCachedVectorAddress (\r
+  UINT8   VectorNumber\r
+  )\r
+{\r
+  UINT32  *Address;\r
+\r
+  Address  = (UINT32 *)(UINTN) (IVT_BASE + VectorNumber * 4);\r
+  *Address = CachedVectorAddress[VectorNumber];\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Print Undi loader table. \r
+\r
+ @param UndiLoaderStructure Point to Undi Loader table structure. \r
\r
+**/\r
+VOID\r
+Print_Undi_Loader_Table (\r
+  VOID *UndiLoaderStructure\r
+  )\r
+{\r
+  UNDI_LOADER_T *DisplayPointer;\r
+\r
+  DisplayPointer = (UNDI_LOADER_T *) UndiLoaderStructure;\r
+\r
+  DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));\r
+  DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) UndiLoaderStructure));\r
+\r
+  DEBUG ((DEBUG_NET, "\n\rStatus = 0x%X\n\r", DisplayPointer->Status));\r
+  DEBUG ((DEBUG_NET, "\t_AX_= 0x%X\n\r", DisplayPointer->Ax));\r
+  DEBUG ((DEBUG_NET, "\t_BX_= 0x%X\n\r", DisplayPointer->Bx));\r
+  DEBUG ((DEBUG_NET, "\t_DX_= 0x%X\n\r", DisplayPointer->Dx));\r
+  DEBUG ((DEBUG_NET, "\t_DI_= 0x%X\n\r", DisplayPointer->Di));\r
+  DEBUG ((DEBUG_NET, "\t_ES_= 0x%X\n\r", DisplayPointer->Es));\r
+  DEBUG ((DEBUG_NET, "\tUNDI_DS= 0x%X\n\r", DisplayPointer->Undi_Ds));\r
+  DEBUG ((DEBUG_NET, "\tUNDI_CS= 0x%X\n\r", DisplayPointer->Undi_Cs));\r
+  DEBUG ((DEBUG_NET, "\tPXEptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Segment));\r
+  DEBUG ((DEBUG_NET, "\tPXEptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Offset));\r
+  DEBUG ((DEBUG_NET, "\tPXENVptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Segment));\r
+  DEBUG ((DEBUG_NET, "\tPXENVptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Offset));\r
+}\r
+\r
+/**\r
+  Simple table dumper.  The ROMID table is necessary in order to effect\r
+  the "Early UNDI" trick.  Herein, the UNDI layer can be loaded in the\r
+  pre-boot phase without having to download a Network Boot Program \r
+  across the wire.  It is required in the implementation in that we\r
+  are not using PXE.\r
+\r
+  @param RomIDStructure Point to RomID structure.\r
\r
+**/\r
+VOID\r
+Print_ROMID_Table (\r
+  IN VOID *RomIDStructure\r
+  )\r
+{\r
+  UNDI_ROMID_T  *DisplayPointer;\r
+\r
+  DisplayPointer = (UNDI_ROMID_T *) RomIDStructure;\r
+\r
+  DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));\r
+  DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) RomIDStructure));\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "\n\rROMID %c%c%c%c\n\r",\r
+    DisplayPointer->Signature[0],\r
+    DisplayPointer->Signature[1],\r
+    DisplayPointer->Signature[2],\r
+    DisplayPointer->Signature[3])\r
+    );\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Length of this structure in bytes = 0x%X\n\r",\r
+    DisplayPointer->StructLength)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Use to make byte checksum of this structure == zero is = 0x%X\n\r",\r
+    DisplayPointer->StructCksum)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Structure format revision number= 0x%X\n\r",\r
+    DisplayPointer->StructRev)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "API Revision number = 0x%X 0x%X 0x%X\n\r",\r
+    DisplayPointer->UNDI_Rev[0],\r
+    DisplayPointer->UNDI_Rev[1],\r
+    DisplayPointer->UNDI_Rev[2])\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",\r
+    DisplayPointer->UNDI_Loader)\r
+    );\r
+  DEBUG ((DEBUG_NET, "From the data above, the absolute entry point of the UNDI loader is\n\r"));\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "\tat address 0x%X\n\r",\r
+    (UINT32) (DisplayPointer->UNDI_Loader + ((UINT32) (UINTN)(DisplayPointer - 0x20) & 0xFFFF0)))\r
+    );\r
+  DEBUG ((DEBUG_NET, "Minimum stack segment size, in bytes,\n\r"));\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "needed to load and run the UNDI= 0x%X \n\r",\r
+    DisplayPointer->StackSize)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "UNDI runtime code and data = 0x%X\n\r",\r
+    DisplayPointer->DataSize)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Segment size = 0x%X\n\r",\r
+    DisplayPointer->CodeSize)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "\n\rBus Type =  %c%c%c%c\n\r",\r
+    DisplayPointer->BusType[0],\r
+    DisplayPointer->BusType[1],\r
+    DisplayPointer->BusType[2],\r
+    DisplayPointer->BusType[3])\r
+    );\r
+}\r
+\r
+/**\r
+  Print PXE table.\r
+\r
+  @param PxeTable Point to PXE table structure\r
+  \r
+**/\r
+VOID\r
+Print_PXE_Table (\r
+  IN VOID*  PxeTable\r
+  )\r
+{\r
+  PXE_T *DisplayPointer;\r
+  UINTN Index;\r
+  UINT8 *Dptr;\r
+\r
+  DisplayPointer  = (PXE_T *) PxeTable;\r
+  Dptr            = (UINT8 *) PxeTable;\r
+\r
+  DEBUG ((DEBUG_NET, "This is the PXE table at address 0x%X\n\r", PxeTable));\r
+\r
+  DEBUG ((DEBUG_NET, "A dump of the 0x%X bytes is:\n\r", sizeof (PXE_T)));\r
+\r
+  for (Index = 0; Index < sizeof (PXE_T); Index++) {\r
+    if ((Index % 0x10) == 0) {\r
+      DEBUG ((DEBUG_NET, "\t\n\r"));\r
+    }\r
+\r
+    DEBUG ((DEBUG_NET, " 0x%X  ", *Dptr++));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n\r"));\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "\n\rPXE %c%c%c%c%c%c\n\r",\r
+    DisplayPointer->Signature[0],\r
+    DisplayPointer->Signature[1],\r
+    DisplayPointer->Signature[2],\r
+    DisplayPointer->Signature[3])\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Length of this structure in bytes = 0x%X\n\r",\r
+    DisplayPointer->StructLength)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Use to make byte checksum of this  structure == zero is = 0x%X\n\r",\r
+    DisplayPointer->StructCksum)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Structure format revision number = 0x%X\n\r",\r
+    DisplayPointer->StructRev)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Must be zero, is equal to 0x%X\n\r",\r
+    DisplayPointer->Reserved1)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Far pointer to UNDI ROMID = 0x%X\n\r",\r
+    (UINT32) (DisplayPointer->Undi.Segment << 0x4 | DisplayPointer->Undi.Offset))\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Far pointer to base-code ROMID = 0x%X\n\r",\r
+    (UINT32) ((DisplayPointer->Base.Segment << 0x04) | DisplayPointer->Base.Offset))\r
+    );\r
+  DEBUG ((DEBUG_NET, "16bit stack segment API entry point.  This will be seg:off in \n\r"));\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "real mode and sel:off in 16:16 protected mode = 0x%X:0x%X\n\r",\r
+    DisplayPointer->EntryPointSP.Segment,\r
+    DisplayPointer->EntryPointSP.Offset)\r
+    );\r
+\r
+  DEBUG ((DEBUG_NET, "\n\tNOTE to the implementer\n\tThis is the entry to use for call-ins\n\r"));\r
+\r
+  DEBUG ((DEBUG_NET, "32bit stack Segment API entry point.  This will be sel:off. \n\r"));\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "In real mode, sel == 0 = 0x%X:0x%X\n\r",\r
+    DisplayPointer->EntryPointESP.Segment,\r
+    DisplayPointer->EntryPointESP.Offset)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Reserved2 value, must be zero, is equal to 0x%X\n\r",\r
+    DisplayPointer->Reserved2)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Number of segment descriptors in this structur = 0x%X\n\r",\r
+    (UINT8) DisplayPointer->SegDescCnt)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "First segment descriptor in GDT assigned to PXE = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->FirstSelector)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->Stack.Seg_Addr,\r
+    (UINT32) DisplayPointer->Stack.Phy_Addr,\r
+    (UINT16) DisplayPointer->Stack.Seg_Size)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The UNDIData is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->UNDIData.Seg_Addr,\r
+    (UINT32) DisplayPointer->UNDIData.Phy_Addr,\r
+    (UINT16) DisplayPointer->UNDIData.Seg_Size)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The UNDICodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->UNDICode.Seg_Addr,\r
+    (UINT32) DisplayPointer->UNDICode.Phy_Addr,\r
+    (UINT16) DisplayPointer->UNDICode.Seg_Size)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->UNDICodeWrite.Seg_Addr,\r
+    (UINT32) DisplayPointer->UNDICodeWrite.Phy_Addr,\r
+    (UINT16) DisplayPointer->UNDICodeWrite.Seg_Size)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The BC_Data is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->BC_Data.Seg_Addr,\r
+    (UINT32) DisplayPointer->BC_Data.Phy_Addr,\r
+    (UINT16) DisplayPointer->BC_Data.Seg_Size)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The BC_Code is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->BC_Code.Seg_Addr,\r
+    (UINT32) DisplayPointer->BC_Code.Phy_Addr,\r
+    (UINT16) DisplayPointer->BC_Code.Seg_Size)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The BC_CodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
+    (UINT16) DisplayPointer->BC_CodeWrite.Seg_Addr,\r
+    (UINT32) DisplayPointer->BC_CodeWrite.Phy_Addr,\r
+    (UINT16) DisplayPointer->BC_CodeWrite.Seg_Size)\r
+    );\r
+}\r
+\r
+/**\r
+  Print PXENV table.\r
+\r
+  @param PxenvTable Point to PXENV\r
+  \r
+**/\r
+VOID\r
+Print_PXENV_Table (\r
+  IN VOID *PxenvTable\r
+  )\r
+{\r
+  PXENV_T *DisplayPointer;\r
+\r
+  DisplayPointer = (PXENV_T *) PxenvTable;\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "\n\rPXENV+ %c%c%c%c%c%c\n\r",\r
+    DisplayPointer->Signature[0],\r
+    DisplayPointer->Signature[1],\r
+    DisplayPointer->Signature[2],\r
+    DisplayPointer->Signature[3],\r
+    DisplayPointer->Signature[4],\r
+    DisplayPointer->Signature[5])\r
+    );\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "PXE version number.  \n\r\tLSB is minor version.  \n\r\tMSB is major version = 0x%X\n\r",\r
+    DisplayPointer->Version)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",\r
+    DisplayPointer->StructLength)\r
+    );\r
+  DEBUG ((DEBUG_NET, "Used to make structure checksum equal zero is now = 0x%X\n\r", DisplayPointer->StructCksum));\r
+  DEBUG ((DEBUG_NET, "Real mode API entry point  segment:Offset.  = 0x%X\n\r", DisplayPointer->RMEntry));\r
+  DEBUG ((DEBUG_NET, "Protected mode API entry point = 0x%X\n\r", DisplayPointer->PMEntryOff));\r
+  DEBUG ((DEBUG_NET, " segment:Offset.  This will always be zero.  \n\r"));\r
+  DEBUG ((DEBUG_NET, "Protected mode API calls = 0x%X\n\r", DisplayPointer->PMEntrySeg));\r
+  DEBUG ((DEBUG_NET, "Real mode stack segment = 0x%X\n\r", DisplayPointer->StackSeg));\r
+  DEBUG ((DEBUG_NET, "Stack segment size in bytes = 0x%X\n\r", DisplayPointer->StackSize));\r
+  DEBUG ((DEBUG_NET, "Real mode base-code code segment = 0x%X\n\r", DisplayPointer->BaseCodeSeg));\r
+  DEBUG ((DEBUG_NET, "Base-code code segment size = 0x%X\n\r", DisplayPointer->BaseCodeSize));\r
+  DEBUG ((DEBUG_NET, "Real mode base-code data segment = 0x%X\n\r", DisplayPointer->BaseDataSeg));\r
+  DEBUG ((DEBUG_NET, "Base-code data segment size = 0x%X\n\r", DisplayPointer->BaseDataSize));\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "UNDI code segment size in bytes = 0x%X\n\r",\r
+    DisplayPointer->UNDICodeSize)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",\r
+    DisplayPointer->RuntimePtr)\r
+    );\r
+  DEBUG (\r
+    (\r
+    DEBUG_NET,\r
+    "From above, we have a linear address of 0x%X\n\r",\r
+    (UINT32)\r
+    (\r
+    ((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF) +\r
+    (((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF0000) >> 12)\r
+    )\r
+    )\r
+    );\r
+}\r
+\r
+\r
+#define OPTION_ROM_PTR  ((OPTION_ROM_HEADER *) RomAddress)\r
+\r
+/**\r
+  If available, launch the BaseCode from a NIC option ROM.\r
+  This should install the !PXE and PXENV+ structures in memory for\r
+  subsequent use.\r
+  \r
+\r
+  @param SimpleNetworkDevice    Simple network device instance\r
+  @param RomAddress             The ROM base address for NIC rom.\r
+  \r
+  @retval EFI_NOT_FOUND         The check sum does not match \r
+  @retval EFI_NOT_FOUND         Rom ID offset is wrong \r
+  @retval EFI_NOT_FOUND         No Rom ID structure is found \r
+**/\r
+EFI_STATUS\r
+LaunchBaseCode (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  UINTN                   RomAddress\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_IA32_REGISTER_SET InOutRegs;\r
+  UNDI_ROMID_T          *RomIdTableAddress;\r
+  UNDI_LOADER_T         *UndiLoaderTable;\r
+  UINT16                Segment;\r
+  UINT16                *StackPointer;\r
+  VOID                  *Buffer;\r
+  UINTN                 Size;\r
+  PXE_T                 *Pxe;\r
+  UINT32                RomLength;\r
+  UINTN                 PciSegment;\r
+  UINTN                 Bus;\r
+  UINTN                 Device;\r
+  UINTN                 Function;\r
+  BOOLEAN               ThunkFailed;\r
+\r
+  DEBUG ((DEBUG_NET, "\n\r\n\rCheck for the UNDI ROMID Signature\n\r"));\r
+\r
+  //\r
+  // paranoia - check structures for validity\r
+  //\r
+  RomLength = OPTION_ROM_PTR->ROMlength << 9;\r
+  if (CalculateSum8 ((UINT8 *) RomAddress, RomLength) != 0) {\r
+    DEBUG ((DEBUG_ERROR, "ROM Header Checksum Error\n\r"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  RomIdTableAddress = (UNDI_ROMID_T *) (RomAddress + OPTION_ROM_PTR->PxeRomIdOffset);\r
+\r
+  if ((UINTN) (OPTION_ROM_PTR->PxeRomIdOffset + RomIdTableAddress->StructLength) > RomLength) {\r
+    DEBUG ((DEBUG_ERROR, "ROM ID Offset Error\n\r"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // see if this is a header for an UNDI ROM ID structure (vs. a $BC$ or BUSD type)\r
+  //\r
+  if (CompareMem (RomIdTableAddress->Signature, UNDI_ROMID_SIG, sizeof RomIdTableAddress->Signature) != 0) {\r
+    DEBUG ((DEBUG_ERROR, "No ROM ID Structure found....\n\r"));\r
+    return EFI_NOT_FOUND;\r
+    //\r
+    // its not - keep looking\r
+    //\r
+  }\r
+\r
+  if (CalculateSum8 ((UINT8 *) RomIdTableAddress, RomIdTableAddress->StructLength) != 0) {\r
+    DEBUG ((DEBUG_ERROR, "ROM ID Checksum Error\n\r"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Print_ROMID_Table (RomIdTableAddress);\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The ROM ID is located at 0x%X\n\r",\r
+    RomIdTableAddress)\r
+    );\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "With an UNDI Loader located at 0x%X\n\r",\r
+    RomAddress + RomIdTableAddress->UNDI_Loader)\r
+    );\r
+\r
+  //\r
+  // found an UNDI ROM ID structure\r
+  //\r
+  SimpleNetworkDevice->Nii.ImageAddr  = RomAddress;\r
+  SimpleNetworkDevice->Nii.ImageSize  = RomLength;\r
+  SimpleNetworkDevice->Nii.MajorVer   = RomIdTableAddress->UNDI_Rev[2];\r
+  SimpleNetworkDevice->Nii.MinorVer   = RomIdTableAddress->UNDI_Rev[1];\r
+\r
+  DEBUG ((DEBUG_NET, "Allocate area for the UNDI_LOADER_T structure\n\r"));\r
+  //\r
+  // Allocate 1 page below 1MB to put real mode thunk code in\r
+  //\r
+  // Undi Loader Table is a PXE Specification prescribed data structure\r
+  // that is used to transfer information into and out of the Undi layer.\r
+  // Note how it must be located below 1 MB.\r
+  //\r
+  SimpleNetworkDevice->UndiLoaderTablePages = EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE + sizeof (UNDI_LOADER_T));\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+            SimpleNetworkDevice->UndiLoaderTablePages,\r
+            &SimpleNetworkDevice->UndiLoaderTable\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  UndiLoaderTable = SimpleNetworkDevice->UndiLoaderTable;\r
+\r
+  DEBUG ((DEBUG_NET, "Allocate area for the real-mode stack whose sole purpose\n\r"));\r
+  DEBUG ((DEBUG_NET, "in life right now is to store a SEG:OFFSET combo pair that\n\r"));\r
+  DEBUG ((DEBUG_NET, "points to an Undi_Loader_t table structure\n\r"));\r
+\r
+  Size    = 0x100;\r
+  Status  = gBS->AllocatePool (EfiLoaderData, Size, &Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Now we want to put a pointer to the Under Loader Table in our MemPage\r
+  // Buffer.  This will be the argument stack for the call into the Undi Loader\r
+  //\r
+  StackPointer    = (UINT16 *) Buffer;\r
+  *StackPointer++ = TO_OFFSET (UndiLoaderTable);\r
+  //\r
+  // push the OFFSET\r
+  //\r
+  *StackPointer++ = TO_SEGMENT (UndiLoaderTable);\r
+  //\r
+  // push the SEGMENT\r
+  //\r
+  StackPointer = (UINT16 *) Buffer;\r
+  //\r
+  // reset the stack pointer\r
+  //\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "After the fixups, the stack pointer is 0x%X\n\r",\r
+    (UINT64)(UINTN) StackPointer)\r
+    );\r
+\r
+  //\r
+  // Allocate memory for the Deployed UNDI.\r
+  // The UNDI is essentially telling us how much space it needs, and\r
+  // it is up to the EFI driver to allocate sufficient, boot-time\r
+  // persistent resources for the call\r
+  //\r
+  SimpleNetworkDevice->DestinationDataSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->DataSize);\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+            SimpleNetworkDevice->DestinationDataSegmentPages,\r
+            &SimpleNetworkDevice->DestinationDataSegment\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  UndiLoaderTable->Undi_Ds = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationDataSegment >> 4);\r
+\r
+  //\r
+  // Allocate memory for the Deployed UNDI stack\r
+  // The UNDI is essentially telling us how much space it needs, and\r
+  // it is up to the EFI driver to allocate sufficient, boot-time\r
+  // persistent resources for the call\r
+  //\r
+  SimpleNetworkDevice->DestinationStackSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->StackSize);\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+            SimpleNetworkDevice->DestinationStackSegmentPages,\r
+            &SimpleNetworkDevice->DestinationStackSegment\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Allocate memory for the Deployed UNDI.\r
+  // The UNDI is essentially telling us how much space it needs, and\r
+  // it is up to the EFI driver to allocate sufficient, boot-time\r
+  // persistent resources for the call\r
+  //\r
+  SimpleNetworkDevice->DestinationCodeSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->CodeSize);\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+            SimpleNetworkDevice->DestinationCodeSegmentPages,\r
+            &SimpleNetworkDevice->DestinationCodeSegment\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  UndiLoaderTable->Undi_Cs = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationCodeSegment >> 4);\r
+\r
+  //\r
+  // these are in the Input and Output Parameter to be sent to the UNDI Loader code\r
+  //\r
+  UndiLoaderTable->Status = 0xAA55;\r
+  //\r
+  // -------------------- Changed by Michael_Huang@3Com.com -----------------\r
+  // UndiLoaderTable->_AX is AX value when UNDI ROM is initialized by BIOS, it is the PCI bus device\r
+  // function of the NIC. Please refer to PXE Spec for detail info.\r
+  // old code is:\r
+  // UndiLoaderTable->Ax       = 0x0;\r
+  // -----------------------------------------------------------------------\r
+  //\r
+  SimpleNetworkDevice->PciIo->GetLocation (\r
+                                SimpleNetworkDevice->PciIo,\r
+                                &PciSegment,\r
+                                &Bus,\r
+                                &Device,\r
+                                &Function\r
+                                );\r
+  UndiLoaderTable->Ax = (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function));\r
+  UndiLoaderTable->Bx = 0x0;\r
+  UndiLoaderTable->Dx = 0x0;\r
+  UndiLoaderTable->Di = 0x0;\r
+  UndiLoaderTable->Es = 0x0;\r
+\r
+  //\r
+  // set these OUT values to zero in order to ensure that\r
+  // uninitialized memory is not mistaken for display data\r
+  //\r
+  UndiLoaderTable->PXEptr.Offset    = 0;\r
+  UndiLoaderTable->PXEptr.Segment   = 0;\r
+  UndiLoaderTable->PXENVptr.Segment = 0;\r
+  UndiLoaderTable->PXENVptr.Offset  = 0;\r
+\r
+  DEBUG (\r
+    (DEBUG_INIT,\r
+    "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",\r
+    Bus,\r
+    Device,\r
+    Function)\r
+    );\r
+\r
+  //\r
+  // These are the values that set up the ACTUAL IA32 machine state, whether in\r
+  // Real16 in EFI32 or the IVE for IA64\r
+  // register values are unused except for CS:IP and SS:SP\r
+  //\r
+  InOutRegs.X.AX  = 0;\r
+  InOutRegs.X.BX  = 0;\r
+  InOutRegs.X.CX  = 0;\r
+  InOutRegs.X.DX  = 0;\r
+  InOutRegs.X.SI  = 0;\r
+  InOutRegs.X.DI  = 0;\r
+  InOutRegs.X.BP  = 0;\r
+  InOutRegs.X.DS  = 0;\r
+  InOutRegs.X.ES  = 0;\r
+  //\r
+  // just to be clean\r
+  //\r
+  DEBUG ((DEBUG_NET, "The way this game works is that the SS:SP +4 should point\n\r"));\r
+  DEBUG ((DEBUG_NET, "to the contents of the UndiLoaderTable\n\r"));\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The Undi Loader Table is at address = 0x%X\n\r",\r
+    (UINT32)(UINTN) UndiLoaderTable)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The segment and offsets are 0x%X and 0x%X, resp\n",\r
+    TO_SEGMENT (UndiLoaderTable),\r
+    TO_OFFSET (UndiLoaderTable))\r
+    );\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The Linear Address of the UNDI Loader entry is 0x%X\n",\r
+    RomAddress + RomIdTableAddress->UNDI_Loader)\r
+    );\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The Address offset of the UNDI Loader entry is 0x%X\n",\r
+    RomIdTableAddress->UNDI_Loader)\r
+    );\r
+\r
+  DEBUG ((DEBUG_NET, "Before the call, we have...\n\r"));\r
+  Print_Undi_Loader_Table (UndiLoaderTable);\r
+\r
+  Segment = ((UINT16) (RShiftU64 (RomAddress, 4) & 0xFFFF));\r
+  DEBUG ((DEBUG_NET, "The Segment of the call is 0x%X\n\r", Segment));\r
+\r
+  //\r
+  // make the call into the UNDI Code\r
+  //\r
+  DEBUG ((DEBUG_INIT, "Make the call into the UNDI code now\n\r"));\r
+\r
+  DEBUG ((DEBUG_NET, "\nThe 20-BIt address of the Call, and the location \n\r"));\r
+  DEBUG ((DEBUG_NET, "\twhere we should be able to set a breakpoint is \n\r"));\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",\r
+    Segment * 0x10 + RomIdTableAddress->UNDI_Loader,\r
+    Segment,\r
+    RomIdTableAddress->UNDI_Loader)\r
+    );\r
+\r
+  ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (\r
+                                                   SimpleNetworkDevice->LegacyBios,\r
+                                                   Segment,  // Input segment\r
+                                                   (UINT16) RomIdTableAddress->UNDI_Loader,  // Offset\r
+                                                   &InOutRegs,                               // Ptr to Regs\r
+                                                   Buffer,                                   // Reference to Stack\r
+                                                   Size                                      // Size of the Stack\r
+                                                   );\r
+  if (ThunkFailed) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "The return code UndiLoaderTable->Status is = 0x%X\n\r",\r
+    UndiLoaderTable->Status)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_NET,\r
+    "This error code should match eax, which is = 0x%X\n\r",\r
+    InOutRegs.X.AX)\r
+    );\r
+\r
+  DEBUG ((DEBUG_NET, "Now returned from the UNDI code\n\r"));\r
+\r
+  DEBUG ((DEBUG_NET, "After the call, we have...\n\r"));\r
+  Print_Undi_Loader_Table (UndiLoaderTable);\r
+\r
+  DEBUG ((DEBUG_NET, "Display the PXENV+ and !PXE tables exported by NIC\n\r"));\r
+  Print_PXENV_Table ((VOID *)(UINTN)((UndiLoaderTable->PXENVptr.Segment << 4) | UndiLoaderTable->PXENVptr.Offset));\r
+  Print_PXE_Table ((VOID *)(UINTN)((UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset));\r
+\r
+  Pxe = (PXE_T *)(UINTN)((UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset);\r
+  SimpleNetworkDevice->Nii.Id = (UINT64)(UINTN) Pxe;\r
+\r
+  //\r
+  //  FreePool (Buffer);\r
+  // paranoia - make sure a valid !PXE structure\r
+  //\r
+  if (CompareMem (Pxe->Signature, PXE_SIG, sizeof Pxe->Signature) != 0) {\r
+    DEBUG ((DEBUG_ERROR, "!PXE Structure not found....\n\r"));\r
+    return EFI_NOT_FOUND;\r
+    //\r
+    // its not - keep looking\r
+    //\r
+  }\r
+\r
+  if (CalculateSum8 ((UINT8 *) Pxe, Pxe->StructLength) != 0) {\r
+    DEBUG ((DEBUG_ERROR, "!PXE Checksum Error\n\r"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Pxe->StructLength < (UINT8 *) &Pxe->FirstSelector - (UINT8 *) Pxe->Signature) {\r
+    DEBUG ((DEBUG_ERROR, "!PXE Length Error\n\r"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if ((((UINTN) Pxe->Undi.Segment) << 4) + Pxe->Undi.Offset != (UINTN) RomIdTableAddress) {\r
+    DEBUG ((DEBUG_ERROR, "!PXE RomId Address Error\n\r"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // This is the magic to bind the global PXE interface\r
+  // This dirtiness is for non-protocol shrouded access\r
+  //\r
+  SimpleNetworkDevice->PxeEntrySegment = Pxe->EntryPointSP.Segment;\r
+\r
+  if (SimpleNetworkDevice->PxeEntrySegment == 0) {\r
+    DEBUG ((DEBUG_ERROR, "!PXE EntryPointSP segment Error\n\r"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  SimpleNetworkDevice->PxeEntryOffset = Pxe->EntryPointSP.Offset;\r
+\r
+  DEBUG (\r
+    (\r
+    DEBUG_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment, SimpleNetworkDevice->\r
+    PxeEntryOffset\r
+    )\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Effect the Far Call into the PXE Layer\r
+\r
+  Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API\r
+  services will not work, unless there are three 16-bit parameters pushed onto the stack.\r
+      push DS                                 ;Far pointer to parameter structure\r
+      push offset pxe_data_call_struct        ;is pushed onto stack.\r
+      push Index                              ;UINT16 is pushed onto stack.\r
+      call dword ptr (s_PXE ptr es:[di]).EntryPointSP\r
+      add sp, 6 ;Caller cleans up stack.  \r
+\r
+  @param SimpleNetworkDevice    Device instance for simple network\r
+  @param Table                 Point to parameter/retun value table for legacy far call\r
+  @param TableSize              The size of paramter/return value table\r
+  @param CallIndex              The index of legacy call.\r
+  \r
+  @return EFI_STATUS \r
+**/\r
+EFI_STATUS\r
+MakePxeCall (\r
+  EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT VOID             *Table,\r
+  IN UINTN                TableSize,\r
+  IN UINT16               CallIndex\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_IA32_REGISTER_SET InOutRegs;\r
+  UINT16                *BPtr;\r
+  VOID                  *Buffer;\r
+  UINTN                 Size;\r
+  VOID                  *MemPageAddress;\r
+  UINTN                 Index;\r
+  BOOLEAN               ThunkFailed;\r
+\r
+  DEBUG ((DEBUG_NET, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex, Table, TableSize));\r
+\r
+  if (SimpleNetworkDevice->PxeEntrySegment == 0 && SimpleNetworkDevice->PxeEntryOffset == 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Allocate a transient data structure for the argument table\r
+  // This table needs to have the input XXX_t structure copied into here.\r
+  // The PXE UNDI can only grab this table when it's below one-MB, and\r
+  // this implementation will not try to push this table on the stack\r
+  // (although this is a possible optimization path since EFI always allocates\r
+  // 4K as a minimum page size...............)\r
+  //\r
+  Status = BiosSnp16AllocatePagesBelowOneMb (\r
+            TableSize / EFI_PAGE_SIZE + 1,\r
+            &MemPageAddress\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Copy the > 1MB pool table to a sub-1MB buffer\r
+  //\r
+  CopyMem (MemPageAddress, Table, TableSize);\r
+\r
+  //\r
+  // Allocate space for IA-32 register context\r
+  //\r
+  ZeroMem (&InOutRegs, sizeof (InOutRegs));\r
+  InOutRegs.X.ES  = SimpleNetworkDevice->PxeEntrySegment;\r
+  InOutRegs.X.DI  = SimpleNetworkDevice->PxeEntryOffset;\r
+\r
+  //\r
+  // The game here is to build the stack which will subsequently\r
+  // get copied down below 1 MB by the FarCall primitive.\r
+  // This is now our working stack\r
+  //\r
+  Size = 6;\r
+  Status = gBS->AllocatePool (\r
+                  EfiRuntimeServicesData,\r
+                  Size,\r
+                  &Buffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BPtr    = (UINT16 *) Buffer;\r
+  *BPtr++ = CallIndex;\r
+  //\r
+  // SP + 2\r
+  //\r
+  *BPtr++ = TO_OFFSET (MemPageAddress);\r
+  *BPtr++ = TO_SEGMENT (MemPageAddress);\r
+\r
+  DEBUG ((DEBUG_NET, "State before FarCall86\n"));\r
+  DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));\r
+  BPtr = (UINT16 *) Buffer;\r
+  DEBUG ((DEBUG_NET, "  Buffer  = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));\r
+  DEBUG ((DEBUG_NET, "  MemPage = "));\r
+  for (Index = 0; Index < TableSize; Index++) {\r
+    DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n"));\r
+\r
+  ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (\r
+                                                   SimpleNetworkDevice->LegacyBios,\r
+                                                   SimpleNetworkDevice->PxeEntrySegment, // Input segment\r
+                                                   SimpleNetworkDevice->PxeEntryOffset,\r
+                                                   &InOutRegs,                           // Ptr to Regs\r
+                                                   Buffer,                               // Reference to Stack\r
+                                                   6                                     // Size of the Stack\r
+                                                   );\r
+  if (ThunkFailed) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "State after FarCall86\n"));\r
+  DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));\r
+  BPtr = (UINT16 *) Buffer;\r
+  DEBUG ((DEBUG_NET, "  Buffer  = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));\r
+  DEBUG ((DEBUG_NET, "  MemPage = "));\r
+  for (Index = 0; Index < TableSize; Index++) {\r
+    DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));\r
+  }\r
+\r
+  DEBUG ((DEBUG_NET, "\n"));\r
+\r
+  //\r
+  // Copy the sub 1MB table to > 1MB table\r
+  //\r
+  CopyMem (Table, MemPageAddress, TableSize);\r
+\r
+  //\r
+  // For PXE UNDI call, AX contains the return status.\r
+  // Convert the PXE UNDI Status to EFI_STATUS type\r
+  //\r
+  if (InOutRegs.X.AX == PXENV_EXIT_SUCCESS) {\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Clean up house\r
+  //\r
+  gBS->FreePool (Buffer);\r
+  gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) MemPageAddress, TableSize / EFI_PAGE_SIZE + 1);\r
+\r
+  return Status;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h
new file mode 100644 (file)
index 0000000..54503a8
--- /dev/null
@@ -0,0 +1,613 @@
+/** @file\r
+  These are PXE Specification 2.1-compliant data structures and defines.\r
+\r
+  This file relies upon the existence of a PXE-compliant ROM\r
+  in memory, as defined by the Preboot Execution Environment \r
+  Specification (PXE), Version 2.1, located at\r
+\r
+  http://developer.intel.com/ial/wfm/wfmspecs.htm\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PXEDEF_H_\r
+#define _PXEDEF_H_\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+//    PXE structure signatures\r
+//\r
+#define BC_ROMID_SIG        "$BC$"\r
+#define UNDI_ROMID_SIG      "UNDI"\r
+#define BUSD_ROMID_SIG      "BUSD"\r
+\r
+#define PXE_SIG             "!PXE"\r
+#define PXENV_SIG           "PXENV+"\r
+\r
+#define BC_ROMID_REV        0x00\r
+#define UNDI_ROMID_REV      0x00\r
+#define BUSD_ROMID_REV      0x00\r
+\r
+#define PXE_REV             0x00\r
+#define PXENV_REV           0x0201\r
+\r
+#define PXENV_PTR           SIGNATURE_32 ('P', 'X', 'E', 'N')\r
+#define PXE_PTR             SIGNATURE_32 ('!', 'P', 'X', 'E')\r
+#define UNDI_ROMID_SIG_PTR  SIGNATURE_32 ('U', 'N', 'D', 'I')\r
+\r
+typedef UINT16  SEGSEL; // Real mode segment or protected mode selector.\r
+typedef UINT16  OFF16;  // Unsigned 16bit offset.\r
+typedef UINT32  ADDR32;\r
+\r
+//\r
+//    Bus types\r
+//\r
+#define PXENV_BUS_ISA     0\r
+#define PXENV_BUS_EISA    1\r
+#define PXENV_BUS_MCA     2\r
+#define PXENV_BUS_PCI     3\r
+#define PXENV_BUS_VESA    4\r
+#define PXENV_BUS_PCMCIA  5\r
+\r
+//\r
+//\r
+//    Result codes returned in AX by a PXENV API service.\r
+//\r
+#define PXENV_EXIT_SUCCESS  0x0000\r
+#define PXENV_EXIT_FAILURE  0x0001\r
+\r
+//\r
+//    Status codes returned in the status word of PXENV API parameter structures.\r
+// \r
+//    Generic API errors - these do not match up with the M0x or E0x messages\r
+//    that are reported by the loader.\r
+//\r
+#define PXENV_STATUS_SUCCESS          0x00\r
+#define PXENV_STATUS_FAILURE          0x01\r
+#define PXENV_STATUS_BAD_FUNC         0x02\r
+#define PXENV_STATUS_UNSUPPORTED      0x03\r
+#define PXENV_STATUS_KEEP_UNDI        0x04\r
+#define PXENV_STATUS_KEEP_ALL         0x05\r
+#define PXENV_STATUS_OUT_OF_RESOURCES 0x06\r
+\r
+typedef enum {\r
+  PxeEnvStatus_Success,\r
+  PxeEnvStatus_Failure,\r
+  PxeEnvStatus_BadFunc,\r
+  PxeEnvStatus_Unsupported,\r
+  PxeEnvStatus_KeepUndi,\r
+  PxeEnvStatus_KeepAll\r
+} EFI_PXE_STATUS;\r
+\r
+/* Driver errors (0x60 to 0x6F) */\r
+\r
+// These errors are for UNDI compatible NIC drivers. \r
+#define PXENV_STATUS_UNDI_INVALID_FUNCTION          0x60\r
+#define PXENV_STATUS_UNDI_MEDIATEST_FAILED          0x61\r
+#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62\r
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC     0x63\r
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY     0x64\r
+#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA   0x65\r
+#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA     0x66\r
+#define PXENV_STATUS_UNDI_BAD_MAC_ADDR              0x67\r
+#define PXENV_STATUS_UNDI_BAD_EEPROM_CKSUM          0x68\r
+#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR         0x69\r
+#define PXENV_STATUS_UNDI_INVALID_STATE             0x6A\r
+#define PXENV_STATUS_UNDI_TRANSMIT_ERROR            0x6B\r
+#define PXENV_STATUS_UNDI_INVALID_PARAMETER         0x6C\r
+\r
+typedef struct {\r
+  UINT16  Seg_Addr;\r
+  UINT32  Phy_Addr;\r
+  UINT16  Seg_Size;\r
+} NEWSEGDESC_T;\r
+\r
+typedef struct {\r
+  OFF16   Offset;\r
+  SEGSEL  Segment;\r
+} SEGOFF16;\r
+\r
+typedef struct {\r
+  UINT8   Signature[4]; ///< Structure signature is not NULL terminated.\r
+  UINT8   StructLength; ///< Length of this structure in bytes.\r
+  UINT8   StructCksum;  ///< Use to make byte checksum of this structure == zero.\r
+  UINT8   StructRev;    ///< Structure format revision number.\r
+  UINT8   UNDI_Rev[3];  ///< API revision number stored in Intel order.\r
+  //\r
+  // Revision 2.1.0 == 0x00, 0x01, 0x02\r
+  //\r
+  UINT16  UNDI_Loader;  ///< Offset of UNDI loader routine in the option ROM image.\r
+  UINT16  StackSize;    ///< Minimum stack segment size, in bytes, needed to load and run the UNDI.\r
+  UINT16  DataSize;     ///< UNDI runtime code and data\r
+  UINT16  CodeSize;     ///< segment sizes.\r
+  UINT8   BusType[4];   ///< 'ISAR', 'EISA', 'PCIR', 'PCCR'\r
+} UNDI_ROMID_T;\r
+\r
+typedef struct {\r
+  UINT8   Signature[4]; ///< Structure signature is not NULL terminated.\r
+  UINT8   StructLength; ///< Length of this structure in bytes.\r
+  UINT8   StructCksum;  ///< Use to make byte checksum of this structure == zero.\r
+  UINT8   StructRev;    ///< Structure format revision number.\r
+  UINT8   BC_Rev[3];    ///< API revision number stored in Intel order.\r
+  //\r
+  // Revision 2.1.0 == 0x00, 0x01, 0x02\r
+  //\r
+  UINT16  BC_Loader;          ///< Offset of base-code loader routine in the option ROM image.\r
+  UINT16  StackSize;          ///< Minimum stack segment size (bytes) needed to load/run base-code.\r
+  UINT16  DataSize;           ///< Base-code runtime code and data\r
+  UINT16  CodeSize;           ///< segment sizes.\r
+} BC_ROMID_T;\r
+\r
+typedef struct {\r
+  UINT8         Signature[4]; ///< Structure signature is not NULL terminated.\r
+  UINT8         StructLength; ///< Length of this structure in bytes.\r
+  UINT8         StructCksum;  ///< Use to make byte checksum of this  structure == zero.\r
+  UINT8         StructRev;    ///< Structure format revision number.\r
+  UINT8         Reserved1;    ///< must be zero\r
+  ///\r
+  ///   UNDI_ROMID_T __FAR *UNDI;// Far pointer to UNDI ROMID\r
+  ///\r
+  SEGOFF16      Undi;\r
+\r
+  ///\r
+  ///    BC_ROMID_T __FAR *Base;  //   Far pointer to base-code ROMID\r
+  ///\r
+  SEGOFF16      Base;\r
+\r
+  ///\r
+  ///    UINT16 (__FAR __CDECL *EntryPointSP)(UINT16 func, VOID __FAR *param);\r
+  /// 16bit stack segment API entry point.  This will be seg:off in\r
+  /// real mode and sel:off in 16:16 protected mode.\r
+  ///\r
+  SEGOFF16      EntryPointSP;\r
+\r
+  ///\r
+  ///    UINT16 (__FAR __CDECL *EntryPointESP)(UINT16 func, VOID __FAR *param);\r
+  /// 32bit stack segment API entry point.  This will be sel:off.\r
+  /// In real mode, sel == 0\r
+  ///\r
+  SEGOFF16      EntryPointESP;\r
+  ///\r
+  ///    UINT16 (__FAR __CDECL *StatusCallout)(UINT16 param);\r
+  /// Address of DHCP/TFTP status callout routine.\r
+  ///\r
+  SEGOFF16      StatusCallout;\r
+  UINT8         Reserved2;      ///< must be zero\r
+  UINT8         SegDescCnt;     ///< Number of segment descriptors in this structure.\r
+  UINT16        FirstSelector;  ///< First segment descriptor in GDT assigned to PXE.\r
+  NEWSEGDESC_T  Stack;\r
+  NEWSEGDESC_T  UNDIData;\r
+  NEWSEGDESC_T  UNDICode;\r
+  NEWSEGDESC_T  UNDICodeWrite;\r
+  NEWSEGDESC_T  BC_Data;\r
+  NEWSEGDESC_T  BC_Code;\r
+  NEWSEGDESC_T  BC_CodeWrite;\r
+} PXE_T;\r
+\r
+typedef struct {\r
+  CHAR8       Signature[6];     ///< "PXENV+"\r
+  UINT16      Version;          ///< PXE version number.  LSB is minor version.  MSB is major version.\r
+  UINT8       StructLength;     ///< Length of PXE-2.0 Entry Point structure in bytes.\r
+  UINT8       StructCksum;      ///< Used to make structure checksum equal zero.\r
+  UINT32      RMEntry;          ///< Real mode API entry point  segment:offset.\r
+  UINT32      PMEntryOff;       ///< Protected mode API entry point\r
+  UINT16      PMEntrySeg;       ///< segment:offset.  This will always be zero.  Protected mode API calls\r
+                                ///< must be made through the API entry points in the PXE Runtime ID structure.\r
+\r
+  UINT16      StackSeg;     ///< Real mode stack segment.\r
+  UINT16      StackSize;    ///< Stack segment size in bytes.\r
+  UINT16      BaseCodeSeg;  ///< Real mode base-code code segment.\r
+  UINT16      BaseCodeSize; ///< Base-code code segment size\r
+  UINT16      BaseDataSeg;  ///< Real mode base-code data segment.\r
+  UINT16      BaseDataSize; ///< Base-code data segment size\r
+  UINT16      UNDIDataSeg;  ///< Real mode UNDI data segment.\r
+  UINT16      UNDIDataSize; ///< UNDI data segment size in bytes.\r
+  UINT16      UNDICodeSeg;  ///< Real mode UNDI code segment.\r
+  UINT16      UNDICodeSize; ///< UNDI code segment size in bytes.\r
+  PXE_T       *RuntimePtr;  ///< Real mode segment:offset pointer to PXE Runtime ID structure.\r
+} PXENV_T;\r
+\r
+typedef struct {\r
+  OUT UINT16    Status;\r
+  IN OUT UINT16 Ax;\r
+  IN OUT UINT16 Bx;\r
+  IN OUT UINT16 Dx;\r
+  IN OUT UINT16 Di;\r
+  IN OUT UINT16 Es;\r
+  IN OUT UINT16 Undi_Ds;\r
+  IN OUT UINT16 Undi_Cs;\r
+  OUT SEGOFF16  PXEptr;\r
+  OUT SEGOFF16  PXENVptr;\r
+} UNDI_LOADER_T;\r
+\r
+//\r
+//  Put in some UNDI-specific arguments\r
+//\r
+#define PXENV_START_UNDI              0x0000\r
+#define PXENV_UNDI_STARTUP            0x0001\r
+#define PXENV_UNDI_CLEANUP            0x0002\r
+#define PXENV_UNDI_INITIALIZE         0x0003\r
+#define PXENV_UNDI_RESET_NIC          0x0004\r
+#define PXENV_UNDI_SHUTDOWN           0x0005\r
+#define PXENV_UNDI_OPEN               0x0006\r
+#define PXENV_UNDI_CLOSE              0x0007\r
+#define PXENV_UNDI_TRANSMIT           0x0008\r
+#define PXENV_UNDI_SET_MCAST_ADDR     0x0009\r
+#define PXENV_UNDI_SET_STATION_ADDR   0x000A\r
+#define PXENV_UNDI_SET_PACKET_FILTER  0x000B\r
+#define PXENV_UNDI_GET_INFORMATION    0x000C\r
+#define PXENV_UNDI_GET_STATISTICS     0x000D\r
+#define PXENV_UNDI_CLEAR_STATISTICS   0x000E\r
+#define PXENV_UNDI_INITIATE_DIAGS     0x000F\r
+#define PXENV_UNDI_FORCE_INTERRUPT    0x0010\r
+#define PXENV_UNDI_GET_MCAST_ADDR     0x0011\r
+#define PXENV_UNDI_GET_NIC_TYPE       0x0012\r
+#define PXENV_UNDI_GET_NDIS_INFO      0x0013\r
+#define PXENV_UNDI_ISR                0x0014\r
+#define PXENV_STOP_UNDI               0x0015\r
+#define PXENV_UNDI_GET_STATE          0x0016\r
+\r
+#define ADDR_LEN                      16\r
+#define MAXNUM_MCADDR                 8\r
+#define IPLEN                         4       ///< length of an IP address \r
+#define XMT_DESTADDR                  0x0000  ///< destination address given\r
+#define XMT_BROADCAST                 0x0001  ///< use broadcast address\r
+\r
+typedef struct {\r
+  UINT16  MCastAddrCount;                     ///< In: Number of multi-cast\r
+\r
+  /* addresses. */\r
+  UINT8   MCastAddr[MAXNUM_MCADDR][ADDR_LEN]; /* In: */\r
+\r
+  /* list of multi-cast addresses. */\r
+\r
+  /* Each address can take up to */\r
+\r
+  /* ADDR_LEN bytes and a maximum */\r
+\r
+  /* of MAXNUM_MCADDR address can */\r
+\r
+  /* be provided*/\r
+} PXENV_UNDI_MCAST_ADDR_T;\r
+\r
+/* Definitions of TFTP API parameter structures.\r
+ */\r
+typedef struct {\r
+  OUT UINT16  Status;       ///< Out: PXENV_STATUS_xxx\r
+  IN UINT16   Ax;           ///< In: These register fields must be\r
+  IN UINT16   Bx;           ///<     filled in with the same data\r
+  IN UINT16   Dx;           ///<     that was passed to the MLID\r
+  IN UINT16   Di;           ///<     option ROM boot code by the \r
+  IN UINT16   Es;           ///<     system BIOS.\r
+} PXENV_START_UNDI_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;       ///< Out: PXENV_STATUS_xxx\r
+} PXENV_UNDI_STARTUP_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;       ///< Out: PXENV_STATUS_xxx\r
+} PXENV_UNDI_CLEANUP_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;       ///< Out: PXENV_STATUS_xxx\r
+  \r
+  ///\r
+  ///  This is an input parameter and is a 32-bit physical address of\r
+  ///  a memory  copy of the  driver module in  the protocol.ini file\r
+  ///  obtained from the  Protocol Manager  driver(refer to  NDIS 2.0\r
+  ///  specifications).   This parameter  is basically  supported for\r
+  ///  the universal NDIS driver to pass the information contained in\r
+  ///  protocol.ini   file  to  the  NIC   driver  for  any  specific\r
+  ///  configuration of   the   NIC.      (Note   that   the   module\r
+  ///  identification in the  protocol.ini  file  was  done  by  NDIS\r
+  ///  itself.)  This value can be NULL for for any other application\r
+  ///  interfacing to the Universal NIC Driver.\r
+  ///\r
+  IN UINT32   ProtocolIni; \r
+  UINT8       Reserved[8];\r
+} PXENV_UNDI_INITIALIZE_T;\r
+\r
+typedef struct {\r
+  OUT UINT16                  Status;       ///< Out: PXENV_STATUS_xxx\r
+  IN PXENV_UNDI_MCAST_ADDR_T  R_Mcast_Buf;  ///< multicast address list\r
+  /* see note below  */\r
+} PXENV_UNDI_RESET_T;\r
+\r
+/*++\r
+    Note: The  NIC  driver  does  not  remember  the  multicast\r
+    addresses provided in any  call.    So  the  application  must\r
+    provide the multicast address  list with all  the calls that\r
+    reset the receive unit of the adapter.  \r
+  --*/\r
+typedef struct {\r
+  OUT UINT16  Status;                     ///< Out: PXENV_STATUS_xxx \r
+} PXENV_UNDI_SHUTDOWN_T;\r
+\r
+typedef struct {\r
+  OUT UINT16                  Status;     ///< Out: PXENV_STATUS_xxx\r
+  \r
+  ///\r
+  ///  This is  an input parameter and is  adapter specific.  This is\r
+  ///  supported  for Universal NDIS 2.0 driver to pass down the Open\r
+  ///  flags  provided  by   the  protocol   driver  (See   NDIS  2.0\r
+  ///  specifications).  This can be zero.  \r
+  ///    \r
+  IN UINT16                   OpenFlag;   ///< In: See description below \r
+  IN UINT16                   PktFilter;  ///< In: Filter for receiving \r
+\r
+  /* packet. It takes the following */\r
+\r
+  /* values, multiple values can be */\r
+\r
+  /* ORed together. */\r
+#define FLTR_DIRECTED 0x0001                ///< directed/multicast\r
+#define FLTR_BRDCST   0x0002                ///< broadcast packets\r
+#define FLTR_PRMSCS   0x0004                ///< any packet on LAN\r
+#define FLTR_SRC_RTG  0x0008                ///< source routing packet \r
+  IN PXENV_UNDI_MCAST_ADDR_T  McastBuffer;  /* In: */\r
+  /* See t_PXENV_UNDI_MCAST_ADDR. */\r
+} PXENV_UNDI_OPEN_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status; ///< Out: PXENV_STATUS_xxx\r
+} PXENV_UNDI_CLOSE_T;\r
+\r
+#define MAX_DATA_BLKS 8\r
+\r
+typedef struct {\r
+  IN UINT16 ImmedLength;  ///< In: Data buffer length in\r
+\r
+  /* bytes. */\r
+  UINT16    XmitOffset;   ///< 16-bit segment & offset of the \r
+  UINT16    XmitSegment;  ///< immediate data buffer. \r
+  UINT16    DataBlkCount; ///< In: Number of data blocks. \r
+  struct DataBlk {\r
+    UINT8   TDPtrType;    ///< 0 => 32 bit Phys pointer in TDDataPtr, not supported in this version of LSA \r
+                          ///< 1 => seg:offser in TDDataPtr which can be a real mode or 16-bit protected mode pointer\r
+    UINT8   TDRsvdByte;         ///< Reserved, must be zero. \r
+    UINT16  TDDataLen;          ///< Data block length in bytes. \r
+    UINT16  TDDataPtrOffset;    ///< Far pointer to data buffer. \r
+    UINT16  TDDataPtrSegment;   ///< Far pointer to data buffer. \r
+  } DataBlock[MAX_DATA_BLKS];\r
+}\r
+PXENV_UNDI_TBD_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;           ///< Out: PXENV_STATUS_xxx \r
+\r
+  ///\r
+  ///  This is the protocol  of  the  upper  layer  that  is  calling\r
+  ///  NICTransmit call.   If the  upper layer  has filled  the media\r
+  ///  header this field must be 0.\r
+  ///\r
+  IN UINT8    Protocol;\r
+#define P_UNKNOWN 0\r
+#define P_IP      1\r
+#define P_ARP     2\r
+#define P_RARP    3\r
+\r
+  ///\r
+  ///  If  this flag is  0, the NIC  driver expects a  pointer to the\r
+  ///  destination media  address in the field  DestMediaAddr.  If 1,\r
+  ///  the   NIC  driver   fills  the   broadcast  address   for  the\r
+  ///  destination.\r
+  ///  \r
+  IN UINT8    XmitFlag;   \r
+#define XMT_DESTADDR  0x0000    ///< destination address given \r
+#define XMT_BROADCAST 0x0001    ///< use broadcast address\r
+\r
+  ///\r
+  ///  This  is a pointer to the  hardware address of the destination\r
+  ///  media.  It  can be  null if  the destination  is not  known in\r
+  ///  which case the XmitFlag contains 1 for broadcast.  Destination\r
+  ///  media address  must be  obtained by  the upper  level protocol\r
+  ///  (with  Address Resolution Protocol) and NIC driver does not do\r
+  ///  any address resolution.\r
+  ///  \r
+  IN UINT16   DestAddrOffset;   ///< 16-bit segment & offset of the\r
+  IN UINT16   DestAddrSegment;  ///< destination media address\r
+\r
+  \r
+  IN UINT16   TBDOffset;  ///< 16-bit segment & offset of the \r
+  IN UINT16   TBDSegment; ///< transmit buffer descriptor of type \r
+\r
+  /// XmitBufferDesc  \r
+  IN UINT32   Reserved[2];\r
+} PXENV_UNDI_TRANSMIT_T;\r
+\r
+\r
+typedef struct {\r
+  OUT UINT16                  Status;       ///<  Out: PXENV_STATUS_xxx \r
+  IN PXENV_UNDI_MCAST_ADDR_T  McastBuffer;  ///<  In: \r
+} PXENV_UNDI_SET_MCAST_ADDR_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;                   ///< Out: PXENV_STATUS_xxx \r
+  IN UINT8    StationAddress[ADDR_LEN]; ///< new address to be set \r
+} PXENV_UNDI_SET_STATION_ADDR_T;\r
+\r
+typedef struct s_PXENV_UNDI_SET_PACKET_FILTER {\r
+  OUT UINT16  Status;                   ///< Out: PXENV_STATUS_xxx \r
+  IN UINT8    Filter;                   ///< In: Receive filter value. \r
+} PXENV_UNDI_SET_PACKET_FILTER_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;       ///< Out: PXENV_STATUS_xxx \r
+  OUT UINT16  BaseIo;       ///< Out: Adapter's Base IO \r
+  OUT UINT16  IntNumber;    ///< Out: IRQ number \r
+  OUT UINT16  MaxTranUnit;  ///< Out: MTU \r
+  OUT UINT16  HwType;       ///< Out: type of protocol at hardware level \r
+\r
+#define ETHER_TYPE      1\r
+#define EXP_ETHER_TYPE  2\r
+#define IEEE_TYPE       6\r
+#define ARCNET_TYPE     7\r
+  /*++  \r
+        other numbers can  be obtained from  rfc1010 for "Assigned\r
+        Numbers".  This number may not be validated by the application\r
+        and hence adding new numbers to the list should be fine at any\r
+        time.  \r
+    --*/\r
+  OUT UINT16  HwAddrLen;                    ///< Out: actual length of hardware address \r
+  OUT UINT8   CurrentNodeAddress[ADDR_LEN]; ///< Out: Current hardware address\r
+  OUT UINT8   PermNodeAddress[ADDR_LEN];    ///< Out: Permanent hardware address\r
+  OUT UINT16  ROMAddress;                   ///< Out: ROM address \r
+  OUT UINT16  RxBufCt;                      ///< Out: receive Queue length    \r
+  OUT UINT16  TxBufCt;                      ///< Out: Transmit Queue length \r
+} PXENV_UNDI_GET_INFORMATION_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;                       ///< Out: PXENV_STATUS_xxx \r
+  OUT UINT32  XmtGoodFrames;                ///< Out: No. of good transmissions \r
+  OUT UINT32  RcvGoodFrames;                ///< Out: No. of good frames received \r
+  OUT UINT32  RcvCRCErrors;                 ///< Out: No. of frames with CRC error \r
+  OUT UINT32  RcvResourceErrors;            ///< Out: no. of frames discarded \r
+  /* Out: receive Queue full */\r
+} PXENV_UNDI_GET_STATISTICS_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;               ///< Out: PXENV_STATUS_xxx \r
+} PXENV_UNDI_CLEAR_STATISTICS_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;               ///< Out: PXENV_STATUS_xxx\r
+} PXENV_UNDI_INITIATE_DIAGS_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;               ///< Out: PXENV_STATUS_xxx\r
+} PXENV_UNDI_FORCE_INTERRUPT_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;               ///< Out: PXENV_STATUS_xxx \r
+  IN UINT32   InetAddr;             ///< In: IP Multicast Address \r
+  OUT UINT8   MediaAddr[ADDR_LEN];  ///< Out: corresponding hardware \r
+  /*      multicast address */\r
+} PXENV_UNDI_GET_MCAST_ADDR_T;\r
+\r
+typedef struct {\r
+    OUT UINT16  Vendor_ID;  ///< OUT: \r
+    OUT UINT16  Dev_ID;     ///< OUT: \r
+    OUT UINT8   Base_Class; ///< OUT: \r
+    OUT UINT8   Sub_Class;  ///< OUT: \r
+    OUT UINT8   Prog_Intf;  ///< OUT: program interface \r
+    OUT UINT8   Rev;        ///< OUT: Revision number \r
+    OUT UINT16  BusDevFunc; ///< OUT: Bus, Device  & Function numbers \r
+    OUT UINT16  SubVendor_ID; ///< OUT: \r
+    OUT UINT16  SubDevice_ID; ///< OUT: \r
+} PCI_INFO_T;\r
+\r
+typedef struct {\r
+    OUT UINT32  EISA_Dev_ID;  ///< Out: \r
+    OUT UINT8   Base_Class;   ///< OUT: \r
+    OUT UINT8   Sub_Class;    ///< OUT: \r
+    OUT UINT8   Prog_Intf;    ///< OUT: program interface \r
+    OUT UINT16  CardSelNum;   ///< OUT: Card Selector Number \r
+    OUT UINT8   Reserved;     ///< to make it 10 bytes \r
+} PNP_INFO_T;\r
+\r
+\r
+typedef union {\r
+  PCI_INFO_T Pci;\r
+  PNP_INFO_T Pnp;\r
+} PCI_PNP_INFO_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;         ///< OUT: PXENV_STATUS_xxx \r
+  OUT UINT8   NicType;        ///< OUT: 2=PCI, 3=PnP \r
+  PCI_PNP_INFO_T PciPnpInfo;\r
+} PXENV_UNDI_GET_NIC_TYPE_T;\r
+\r
+typedef struct {\r
+  OUT UINT16  Status;           ///< OUT: PXENV_STATUS_xxx \r
+  OUT UINT8   IfaceType[16];    ///< OUT: Type name of MAC, AsciiZ \r
+\r
+  /*      format.  This is used by the */\r
+\r
+  /*      Universal NDIS Driver to fill */\r
+\r
+  /*      the driver type in it's MAC */\r
+\r
+  /*      Service specific */\r
+\r
+  /*      characteristic table */\r
+  OUT UINT32  LinkSpeed;    ///< OUT: \r
+  OUT UINT32  ServiceFlags; ///< OUT: as defined in NDIS Spec 2.0X \r
+  OUT UINT32  Reserved[4];  ///< OUT: will be filled with 0s till defined\r
+} PXENV_UNDI_GET_NDIS_INFO_T;\r
+\r
+typedef struct {\r
+  OUT UINT16    Status;   ///< OUT: PXENV_STATUS_xxx \r
+  IN OUT UINT16 FuncFlag; ///< In: PXENV_UNDI_ISR_IN_xxx \r
+\r
+  /* Out: PXENV_UNDI_ISR_OUT_xxx */\r
+  OUT UINT16    BufferLength;\r
+  OUT UINT16    FrameLength;\r
+  OUT UINT16    FrameHeaderLength;\r
+  OUT UINT16    FrameOffset;\r
+  OUT UINT16    FrameSegSel;\r
+  OUT UINT8     ProtType;\r
+  OUT UINT8     PktType;\r
+} PXENV_UNDI_ISR_T;\r
+\r
+#define PXENV_UNDI_ISR_IN_START 1 /* This function must be first */\r
+\r
+/* when an interrupt is received. */\r
+\r
+/* It will tell us if the intr */\r
+\r
+/* was generated by our device. */\r
+#define PXENV_UNDI_ISR_IN_PROCESS 2 /* Call to start processing one of */\r
+\r
+/* our interrupts. */\r
+#define PXENV_UNDI_ISR_IN_GET_NEXT  3 /* Call to start/continue receiving */\r
+\r
+/* data from receive buffer(s). */\r
+\r
+/*++\r
+\r
+     Possible responses from PXENV_UNDI_ISR_IN_START\r
+\r
+ --*/\r
+#define PXENV_UNDI_ISR_OUT_OURS 0 ///< This is our interrupt.  Deal  with it. \r
+#define PXENV_UNDI_ISR_OUT_NOT_OURS 1 ///< This is not our interrupt.\r
+\r
+/*++\r
+\r
+     Possible responses from PXENV_UNDI_ISR_IN_PROCESS and\r
+     PXENV_UNDI_ISR_IN_PROCESS\r
+\r
+--*/\r
+#define PXENV_UNDI_ISR_OUT_DONE 0       ///< We are done processing this  interrupt. \r
+#define PXENV_UNDI_ISR_OUT_TRANSMIT 2   ///< We completed a transmit interrupt. \r
+#define PXENV_UNDI_ISR_OUT_RECEIVE  3   ///< Get data from receive buffer. \r
+\r
+#define PXENV_UNDI_ISR_OUT_BUSY     4 /* ? */\r
+\r
+typedef struct {\r
+  UINT16  Status;                     ///< Out: PXENV_STATUS_xxx \r
+} PXENV_STOP_UNDI_T;\r
+\r
+#define PXENV_UNDI_STARTED      1     ///< not even initialized \r
+#define PXENV_UNDI_INITIALIZED  2     ///< initialized and closed (not opened) \r
+#define PXENV_UNDI_OPENED       3     ///< initialized & opened \r
+\r
+typedef struct {\r
+  OUT UINT16  Status;                 ///< Out: PXENV_STATUS_xxx \r
+  UINT16      UNDI_State;\r
+} PXENV_UNDI_GET_STATE_T;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c
new file mode 100644 (file)
index 0000000..d35fc3f
--- /dev/null
@@ -0,0 +1,1254 @@
+/** @file \r
+  Wrapper routines that use a PXE-enabled NIC option ROM to \r
+  supply internal routines for an EFI SNI (Simple Network \r
+  Interface) Protocol.\r
+\r
+  This file relies upon the existence of a PXE-compliant ROM\r
+  in memory, as defined by the Preboot Execution Environment \r
+  Specification (PXE), Version 2.1, located at\r
+\r
+  http://developer.intel.com/ial/wfm/wfmspecs.htm\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosSnp16.h"\r
+\r
+/**\r
+  PXE \r
+  START UNDI\r
+  Op-Code: PXENV_START_UNDI (0000h)\r
+  Input: Far pointer to a PXENV_START_UNDI_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This service is used to pass the BIOS parameter registers to the UNDI driver. The UNDI driver is\r
+  responsible for saving the information it needs to communicate with the hardware.\r
+  This service is also responsible for hooking the Int 1Ah service routine\r
+  Note: This API service must be called only once during UNDI Option ROM boot.\r
+  The UNDI driver is responsible for saving this information and using it every time\r
+  PXENV_UNDI_STARTUP is called.\r
+  Service cannot be used in protected mode.\r
+  typedef struct  {\r
+      PXENV_STATUS Status;\r
+      UINT16 AX;\r
+      UINT16 BX;\r
+      UINT16 DX;\r
+      UINT16 DI;\r
+      UINT16 ES;\r
+  } PXENV_START_UNDI_T;\r
+  Set before calling API service\r
+  AX, BX, DX, DI, ES: BIOS initialization parameter registers. These\r
+  fields should contain the same information passed to the option ROM\r
+  initialization routine by the Host System BIOS. Information about the\r
+  contents of these registers can be found in the [PnP], [PCI] and\r
+  [BBS] specifications.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.    \r
+\r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call.                                \r
+**/\r
+EFI_STATUS\r
+PxeStartUndi (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_START_UNDI_T      *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_START_UNDI_T),\r
+          PXENV_START_UNDI\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI STARTUP    \r
+  Op-Code: PXENV_UNDI_STARTUP (0001h)\r
+  Input: Far pointer to a PXENV_UNDI_STARTUP_T parameter structure that has been initialized by the\r
+  caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This API is responsible for initializing the contents of the UNDI code & data segment for proper\r
+  operation. Information from the !PXE structure and the first PXENV_START_UNDI API call is used\r
+  to complete this initialization. The rest of the UNDI APIs will not be available until this call has\r
+  been completed.\r
+  Note: PXENV_UNDI_STARTUP must not be called again without first calling\r
+  PXENV_UNDI_SHUTDOWN.\r
+  PXENV_UNDI_STARTUP and PXENV_UNDI_SHUTDOWN are no longer responsible for\r
+  chaining interrupt 1Ah. This must be done by the PXENV_START_UNDI and\r
+  PXENV_STOP_UNDI API calls.\r
+  This service cannot be used in protected mode.\r
+  typedef struct \r
+  {\r
+      PXENV_STATUS Status;\r
+  } PXENV_UNDI_STARTUP_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+\r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call.    \r
+**/\r
+EFI_STATUS\r
+PxeUndiStartup (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_STARTUP_T    *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_STARTUP_T),\r
+          PXENV_UNDI_STARTUP\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI CLEANUP\r
+  Op-Code: PXENV_UNDI_CLEANUP (0002h)\r
+  Input: Far pointer to a PXENV_UNDI_CLEANUP_T parameter structure.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field\r
+  in the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call will prepare the network adapter driver to be unloaded from memory. This call must be\r
+  made just before unloading the Universal NIC Driver. The rest of the API will not be available\r
+  after this call executes.\r
+  This service cannot be used in protected mode.\r
+  typedef struct {\r
+      PXENX_STATUS Status;\r
+  } PXENV_UNDI_CLEANUP_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+\r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call. \r
+**/\r
+EFI_STATUS\r
+PxeUndiCleanup (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_CLEANUP_T    *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_CLEANUP_T),\r
+          PXENV_UNDI_CLEANUP\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI INITIALIZE\r
+  Op-Code: PXENV_UNDI_INITIALIZE (0003h)\r
+  Input: Far pointer to a PXENV_UNDI_INITIALIZE_T parameter structure that has been initialized by the\r
+  caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets the adapter and programs it with default parameters. The default parameters used\r
+  are those supplied to the most recent UNDI_STARTUP call. This routine does not enable the\r
+  receive and transmit units of the network adapter to readily receive or transmit packets. The\r
+  application must call PXENV_UNDI_OPEN to logically connect the network adapter to the network.\r
+  This call must be made by an application to establish an interface to the network adapter driver.\r
+  Note: When the PXE code makes this call to initialize the network adapter, it passes a NULL pointer for\r
+  the Protocol field in the parameter structure.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    ADDR32 ProtocolIni;\r
+    UINT8 reserved[8];\r
+  } PXENV_UNDI_INITIALIZE_T;\r
+  Set before calling API service\r
+  ProtocolIni: Physical address of a memory copy of the driver\r
+  module from the protocol.ini file obtained from the protocol manager\r
+  driver (refer to the NDIS 2.0 specification). This parameter is\r
+  supported for the universal NDIS driver to pass the information\r
+  contained in the protocol.ini file to the NIC driver for any specific\r
+  configuration of the NIC. (Note that the module identification in the\r
+  protocol.ini file was done by NDIS.) This value can be NULL for any\r
+  other application interfacing to the universal NIC driver\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.    \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                                \r
+  @return Return value of PXE option ROM far call. \r
+**/\r
+EFI_STATUS\r
+PxeUndiInitialize (\r
+  IN     EFI_SIMPLE_NETWORK_DEV   *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_INITIALIZE_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_INITIALIZE_T),\r
+          PXENV_UNDI_INITIALIZE\r
+          );\r
+}\r
+\r
+/**\r
+  Wrapper routine for reset adapter.\r
+  \r
+  PXE \r
+  UNDI RESET ADAPTER\r
+  Op-Code: PXENV_UNDI_RESET_ADAPTER (0004h)\r
+  Input: Far pointer to a PXENV_UNDI_RESET_ADAPTER_t parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets and reinitializes the network adapter with the same set of parameters supplied to\r
+  Initialize Routine. Unlike Initialize, this call opens the adapter that is, it connects logically to the\r
+  network. This routine cannot be used to replace Initialize or Shutdown calls.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    PXENV_UNDI_MCAST_ADDRESS_t    R_Mcast_Buf;\r
+  } PXENV_UNDI_RESET_T;\r
+\r
+  #define MAXNUM_MCADDR 8\r
+\r
+  typedef struct {\r
+    UINT16 MCastAddrCount;\r
+    MAC_ADDR McastAddr[MAXNUM_MCADDR];\r
+  } PXENV_UNDI_MCAST_ADDRESS_t;\r
+\r
+  Set before calling API service\r
+  R_Mcast_Buf: This is a structure of MCastAddrCount and\r
+  McastAddr.\r
+  MCastAddrCount: Number of multicast MAC addresses in the\r
+  buffer.\r
+  McastAddr: List of up to MAXNUM_MCADDR multicast MAC\r
+  addresses.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance.\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+  @param  RxFilter             Filter setting mask value for PXE recive .     \r
+                               \r
+  @return Return value of PXE option ROM far call. \r
+**/\r
+EFI_STATUS\r
+PxeUndiResetNic (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_RESET_T      *PxeUndiTable,\r
+  IN     UINT16                  RxFilter\r
+  )\r
+{\r
+  PXENV_UNDI_OPEN_T   Open;\r
+  PXENV_UNDI_CLOSE_T  Close;\r
+  UINTN               Status;\r
+\r
+  Status = MakePxeCall (\r
+            SimpleNetworkDevice,\r
+            PxeUndiTable,\r
+            sizeof (PXENV_UNDI_RESET_T),\r
+            PXENV_UNDI_RESET_NIC\r
+            );\r
+  if (!EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Close.Status = PXENV_STATUS_SUCCESS;\r
+\r
+  Status = MakePxeCall (\r
+            SimpleNetworkDevice,\r
+            &Close,\r
+            sizeof (Close),\r
+            PXENV_UNDI_CLOSE\r
+            );\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = MakePxeCall (\r
+            SimpleNetworkDevice,\r
+            PxeUndiTable,\r
+            sizeof (PXENV_UNDI_RESET_T),\r
+            PXENV_UNDI_RESET_NIC\r
+            );\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Open.Status       = PXENV_STATUS_SUCCESS;\r
+  Open.OpenFlag     = 0;\r
+  Open.PktFilter    = RxFilter;\r
+  CopyMem (\r
+    &Open.McastBuffer,\r
+    &PxeUndiTable->R_Mcast_Buf,\r
+    sizeof (PXENV_UNDI_MCAST_ADDR_T)\r
+    );      \r
+  \r
+\r
+  Status = MakePxeCall (\r
+            SimpleNetworkDevice,\r
+            &Open,\r
+            sizeof (Open),\r
+            PXENV_UNDI_OPEN\r
+            );\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI SHUTDOWN\r
+  Op-Code: PXENV_UNDI_SHUTDOWN (0005h)\r
+  Input: Far pointer to a PXENV_UNDI_SHUTDOWN_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets the network adapter and leaves it in a safe state for another driver to program it.\r
+  Note: The contents of the PXENV_UNDI_STARTUP parameter structure need to be saved by the\r
+  Universal NIC Driver in case PXENV_UNDI_INITIALIZE is called again.\r
+  typedef struct \r
+  {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_SHUTDOWN_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.   \r
+**/\r
+EFI_STATUS\r
+PxeUndiShutdown (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SHUTDOWN_T   *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_SHUTDOWN_T),\r
+          PXENV_UNDI_SHUTDOWN\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI OPEN\r
+  Op-Code: PXENV_UNDI_OPEN (0006h)\r
+  Input: Far pointer to a PXENV_UNDI_OPEN_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call activates the adapter network connection and sets the adapter ready to accept packets\r
+  for transmit and receive.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT16 OpenFlag;\r
+    UINT16 PktFilter;\r
+      #define FLTR_DIRECTED 0x0001\r
+      #define FLTR_BRDCST 0x0002\r
+      #define FLTR_PRMSCS 0x0004\r
+      #define FLTR_SRC_RTG 0x0008\r
+    PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;\r
+  } PXENV_UNDI_OPEN_T;\r
+  Set before calling API service\r
+  OpenFlag: This is an adapter specific input parameter. This is\r
+  supported for the universal NDIS 2.0 driver to pass in the open flags\r
+  provided by the protocol driver. (See the NDIS 2.0 specification.)\r
+  This can be zero.\r
+  PktFilter: Filter for receiving packets. This can be one, or more, of\r
+  the FLTR_xxx constants. Multiple values are arithmetically or-ed\r
+  together.\r
+  directed packets are packets that may come to your MAC address\r
+  or the multicast MAC address.\r
+  R_Mcast_Buf: See definition in UNDI RESET ADAPTER (0004h).\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiOpen (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_OPEN_T       *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_OPEN_T),\r
+          PXENV_UNDI_OPEN\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI CLOSE\r
+  Op-Code: PXENV_UNDI_CLOSE (0007h)\r
+  Input: Far pointer to a PXENV_UNDI_CLOSE_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call disconnects the network adapter from the network. Packets cannot be transmitted or\r
+  received until the network adapter is open again.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_CLOSE_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiClose (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_CLOSE_T      *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_CLOSE_T),\r
+          PXENV_UNDI_CLOSE\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI TRANSMIT PACKET\r
+  Op-Code: PXENV_UNDI_TRANSMIT (0008h)\r
+  Input: Far pointer to a PXENV_UNDI_TRANSMIT_T parameter structure that\r
+  has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX.\r
+  The status code must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call transmits a buffer to the network. The media header\r
+  for the packet can be filled by the calling protocol, but it might not be.\r
+  The network adapter driver will fill it if required by the values in the\r
+  parameter block. The packet is buffered for transmission provided there is\r
+  an available buffer, and the function returns PXENV_EXIT_SUCCESS. If no\r
+  buffer is available the function returns PXENV_EXIT_FAILURE with a status\r
+  code of PXE_UNDI_STATUS__OUT OF_RESOURCE. The number of buffers is\r
+  implementation-dependent. An interrupt is generated on completion of the\r
+  transmission of one or more packets. A call to PXENV_UNDI_TRANSMIT is\r
+  permitted in the context of a transmit complete interrupt.\r
+\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT8 Protocol;\r
+      #define P_UNKNOWN 0\r
+      #define P_IP 1\r
+      #define P_ARP 2\r
+      #define P_RARP 3\r
+    UINT8 XmitFlag;\r
+      #define XMT_DESTADDR 0x0000\r
+      #define XMT_BROADCAST 0x0001\r
+    SEGOFF16 DestAddr;\r
+    SEGOFF16 TBD;\r
+    UINT32 Reserved[2];\r
+  } t_PXENV_UNDI_TRANSMIT;\r
+\r
+  #define MAX_DATA_BLKS 8\r
+\r
+  typedef struct {\r
+    UINT16 ImmedLength;\r
+    SEGOFF16 Xmit;\r
+    UINT16 DataBlkCount;\r
+    struct DataBlk {\r
+      UINT8 TDPtrType;\r
+      UINT8 TDRsvdByte;\r
+      UINT16 TDDataLen;\r
+      SEGOFF16 TDDataPtr;\r
+    } DataBlock[MAX_DATA_BLKS];\r
+  } PXENV_UNDI_TBD_T\r
+\r
+  Set before calling API service\r
+  Protocol: This is the protocol of the upper layer that is calling UNDI\r
+  TRANSMIT call. If the upper layer has filled the media header, this\r
+  field must be P_UNKNOWN.\r
+  XmitFlag: If this flag is XMT_DESTADDR, the NIC driver expects a\r
+  pointer to the destination media address in the field DestAddr. If\r
+  XMT_BROADCAST, the NIC driver fills the broadcast address for the\r
+  destination.\r
+  TBD: Segment:Offset address of the transmit buffer descriptor.\r
+  ImmedLength: Length of the immediate transmit buffer: Xmit.\r
+  Xmit: Segment:Offset of the immediate transmit buffer.\r
+  DataBlkCount: Number of blocks in this transmit buffer.\r
+  TDPtrType:\r
+  0 => 32-bit physical address in TDDataPtr (not supported in this\r
+  version of PXE)\r
+  1 => segment:offset in TDDataPtr which can be a real mode or 16-bit\r
+  protected mode pointer\r
+  TDRsvdByte: Reserved must be zero.\r
+  TDDatalen: Data block length in bytes.\r
+  TDDataPtr: Segment:Offset of the transmit block.\r
+  DataBlock: Array of transmit data blocks.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants  \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiTransmit (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_TRANSMIT_T   *PxeUndiTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = MakePxeCall (\r
+            SimpleNetworkDevice,\r
+            PxeUndiTable,\r
+            sizeof (PXENV_UNDI_TRANSMIT_T),\r
+            PXENV_UNDI_TRANSMIT\r
+            );\r
+  if (Status == EFI_SUCCESS) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  switch (PxeUndiTable->Status) {\r
+  case PXENV_STATUS_OUT_OF_RESOURCES:\r
+    return EFI_NOT_READY;\r
+\r
+  default:\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI SET MULTICAST ADDRESS\r
+  Op-Code: PXENV_UNDI_SET_MCAST_ADDRESS (0009h)\r
+  Input: Far pointer to a PXENV_TFTP_SET_MCAST_ADDRESS_t parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call changes the current list of multicast addresses to the input list and resets the network\r
+  adapter to accept it. If the number of multicast addresses is zero, multicast is disabled.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;\r
+  } PXENV_UNDI_SET_MCAST_ADDR_T;\r
+  Set before calling API service\r
+  R_Mcast_Buf: See description in the UNDI RESET ADAPTER\r
+  (0004h) API.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants        \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiSetMcastAddr (\r
+  IN     EFI_SIMPLE_NETWORK_DEV       *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SET_MCAST_ADDR_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_SET_MCAST_ADDR_T),\r
+          PXENV_UNDI_SET_MCAST_ADDR\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI SET STATION ADDRESS\r
+  Op-Code: PXENV_UNDI_SET_STATION_ADDRESS (000Ah)\r
+  Input: Far pointer to a PXENV_UNDI_SET_STATION_ADDRESS_t parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call sets the MAC address to be the input value and is called before opening the network\r
+  adapter. Later, the open call uses this variable as a temporary MAC address to program the\r
+  adapter individual address registers.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    MAC_ADDR StationAddress;\r
+  } PXENV_UNDI_SET_STATION_ADDR_T;\r
+  Set before calling API service\r
+  StationAddress: Temporary MAC address to be used for\r
+  transmit and receive.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.     \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiSetStationAddr (\r
+  IN     EFI_SIMPLE_NETWORK_DEV         *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SET_STATION_ADDR_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_SET_STATION_ADDR_T),\r
+          PXENV_UNDI_SET_STATION_ADDR\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI SET PACKET FILTER\r
+  Op-Code: PXENV_UNDI_SET_PACKET_FILTER (000Bh)\r
+  Input: Far pointer to a PXENV_UNDI_SET_PACKET_FILTER_T parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call resets the adapter's receive unit to accept a new filter, different from the one provided with\r
+  the open call.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT8 filter;\r
+  } PXENV_UNDI_SET_PACKET_FILTER_T;\r
+  Set before calling API service\r
+  Filter: See the receive filter values in the UNDI OPEN\r
+  (0006h) API description.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.   \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiSetPacketFilter (\r
+  IN     EFI_SIMPLE_NETWORK_DEV          *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_SET_PACKET_FILTER_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_SET_PACKET_FILTER_T),\r
+          PXENV_UNDI_SET_PACKET_FILTER\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI GET INFORMATION\r
+  Op-Code: PXENV_UNDI_GET_INFORMATION (000Ch)\r
+  Input: Far pointer to a PXENV_UNDI_GET_INFORMATION_T parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call copies the network adapter variables, including the MAC address, into the input buffer.\r
+  Note: The PermNodeAddress field must be valid after PXENV_START_UNDI and\r
+  PXENV_UNDI_STARTUP have been issued. All other fields must be valid after\r
+  PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE have been\r
+  called.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT16 BaseIo;\r
+    UINT16 IntNumber;\r
+    UINT16 MaxTranUnit;\r
+    UINT16 HwType;\r
+      #define ETHER_TYPE 1\r
+      #define EXP_ETHER_TYPE 2\r
+      #define IEEE_TYPE 6\r
+      #define ARCNET_TYPE 7\r
+    UINT16 HwAddrLen;\r
+    MAC_ADDR CurrentNodeAddress;\r
+    MAC_ADDR PermNodeAddress;\r
+    SEGSEL ROMAddress;\r
+    UINT16 RxBufCt;\r
+    UINT16 TxBufCt;\r
+  } PXENV_UNDI_GET_INFORMATION_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  BaseIO: Adapter base I/O address.\r
+  IntNumber: Adapter IRQ number.\r
+  MaxTranUnit: Adapter maximum transmit unit.\r
+  HWType: Type of protocol at the hardware level.\r
+  HWAddrLen: Length of the hardware address.\r
+  CurrentNodeAddress: Current hardware address.\r
+  PermNodeAddress: Permanent hardware address.\r
+  ROMAddress: Real mode ROM segment address.\r
+  RxBufCnt: Receive queue length.\r
+  TxBufCnt: Transmit queue length.  \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetInformation (\r
+  IN     EFI_SIMPLE_NETWORK_DEV        *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_INFORMATION_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_GET_INFORMATION_T),\r
+          PXENV_UNDI_GET_INFORMATION\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI GET STATISTICS\r
+  Op-Code: PXENV_UNDI_GET_STATISTICS (000Dh)\r
+  Input: Far pointer to a PXENV_UNDI_GET_STATISTICS_T parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call reads statistical information from the network adapter, and returns.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+    UINT32 XmtGoodFrames;\r
+    UINT32 RcvGoodFrames;\r
+    UINT32 RcvCRCErrors;\r
+    UINT32 RcvResourceErrors;\r
+  } PXENV_UNDI_GET_STATISTICS_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  XmtGoodFrames: Number of successful transmissions.\r
+  RcvGoodFrames: Number of good frames received.\r
+  RcvCRCErrors: Number of frames received with CRC\r
+  error.\r
+  RcvResourceErrors: Number of frames discarded\r
+  because receive queue was full.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetStatistics (\r
+  IN     EFI_SIMPLE_NETWORK_DEV       *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_STATISTICS_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_GET_STATISTICS_T),\r
+          PXENV_UNDI_GET_STATISTICS\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI CLEAR STATISTICS\r
+  Op-Code: PXENV_UNDI_CLEAR_STATISTICS (000Eh)\r
+  Input: Far pointer to a PXENV_UNDI_CLEAR_STATISTICS_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call clears the statistical information from the network adapter.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_CLEAR_STATISTICS_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiClearStatistics (\r
+  IN     EFI_SIMPLE_NETWORK_DEV         *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_CLEAR_STATISTICS_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_CLEAR_STATISTICS_T),\r
+          PXENV_UNDI_CLEAR_STATISTICS\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI INITIATE DIAGS\r
+  Op-Code: PXENV_UNDI_INITIATE_DIAGS (000Fh)\r
+  Input: Far pointer to a PXENV_UNDI_INITIATE_DIAGS_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the\r
+  PXENV_STATUS_xxx constants.\r
+  Description: This call can be used to initiate the run-time diagnostics. It causes the network adapter to run\r
+  hardware diagnostics and to update its status information.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_INITIATE_DIAGS_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.    \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiInitiateDiags (\r
+  IN     EFI_SIMPLE_NETWORK_DEV       *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_INITIATE_DIAGS_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_INITIATE_DIAGS_T),\r
+          PXENV_UNDI_INITIATE_DIAGS\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI FORCE INTERRUPT\r
+  Op-Code: PXENV_UNDI_FORCE_INTERRUPT (0010h)\r
+  Input: Far pointer to a PXENV_UNDI_FORCE_INTERRUPT_T parameter structure that has been\r
+  initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call forces the network adapter to generate an interrupt. When a receive interrupt occurs, the\r
+  network adapter driver usually queues the packet and calls the application's callback receive\r
+  routine with a pointer to the packet received. Then, the callback routine either can copy the packet\r
+  to its buffer or can decide to delay the copy to a later time. If the packet is not immediately copied,\r
+  the network adapter driver does not remove it from the input queue. When the application wants to\r
+  copy the packet, it can call the PXENV_UNDI_FORCE_INTERRUPT routine to simulate the receive\r
+  interrupt.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_UNDI_FORCE_INTERRUPT_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.  \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiForceInterrupt (\r
+  IN     EFI_SIMPLE_NETWORK_DEV        *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_FORCE_INTERRUPT_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_FORCE_INTERRUPT_T),\r
+          PXENV_UNDI_FORCE_INTERRUPT\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI GET MULTICAST ADDRESS\r
+  Op-Code: PXENV_UNDI_GET_MCAST_ADDRESS (0011h)\r
+  Input: Far pointer to a PXENV_GET_MCAST_ADDRESS_t parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This call converts the given IP multicast address to a hardware multicast address.\r
+  typedef struct  {\r
+    PXENV_STATUS Status;\r
+    IP4 InetAddr;\r
+    MAC_ADDR MediaAddr;\r
+  } PXENV_UNDI_GET_MCAST_ADDR_T;\r
+  Set before calling API service\r
+  InetAddr: IP multicast address.\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  MediaAddr: MAC multicast address.\r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetMcastAddr (\r
+  IN     EFI_SIMPLE_NETWORK_DEV       *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_MCAST_ADDR_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_GET_MCAST_ADDR_T),\r
+          PXENV_UNDI_GET_MCAST_ADDR\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI GET NIC TYPE\r
+  Op-Code: PXENV_UNDI_GET_NIC_TYPE (0012h)\r
+  Input: Far pointer to a PXENV_UNDI_GET_NIC_TYPE parameter structure that has been initialized by\r
+  the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants. If the PXENV_EXIT_SUCCESS is returned the parameter structure must contain the\r
+  NIC information.\r
+  Description: This call, if successful, provides the NIC-specific information necessary to identify the network\r
+  adapter that is used to boot the system.\r
+  Note: The application first gets the DHCPDISCOVER packet using GET_CACHED_INFO and checks if\r
+  the UNDI is supported before making this call. If the UNDI is not supported, the NIC-specific\r
+  information can be obtained from the DHCPDISCOVER packet itself.\r
+  PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called\r
+  before the information provided is valid.\r
+  typedef {\r
+    PXENV_STATUS Status;\r
+    UINT8 NicType;\r
+      #define PCI_NIC 2\r
+      #define PnP_NIC 3\r
+      #define CardBus_NIC 4\r
+    Union {\r
+      Struct {\r
+        UINT16 Vendor_ID;\r
+        UINT16 Dev_ID;\r
+        UINT8 Base_Class;\r
+        UINT8 Sub_Class;\r
+        UINT8 Prog_Intf;\r
+        UINT8 Rev;\r
+        UINT16 BusDevFunc;\r
+        UINT16 SubVendor_ID;\r
+        UINT16 SubDevice_ID;\r
+      } pci, cardbus;\r
+      struct {\r
+        UINT32 EISA_Dev_ID;\r
+        UINT8 Base_Class;\r
+        UINT8 Sub_Class;\r
+        UINT8 Prog_Intf;\r
+        UINT16 CardSelNum;\r
+      } pnp;\r
+    } info;\r
+  } PXENV_UNDI_GET_NIC_TYPE_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  NICType: Type of NIC information stored in the parameter\r
+  structure.\r
+  Info: Information about the fields in this union can be found\r
+  in the [PnP] and [PCI] specifications    \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetNicType (\r
+  IN     EFI_SIMPLE_NETWORK_DEV     *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_NIC_TYPE_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_GET_NIC_TYPE_T),\r
+          PXENV_UNDI_GET_NIC_TYPE\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI GET IFACE INFO\r
+  Op-Code: PXENV_UNDI_GET_IFACE_INFO (0013h)\r
+  Input: Far pointer to a PXENV_UNDI_GET_IFACE_INFO_t parameter structure that has been initialized\r
+  by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants. If the PXENV_EXIT_SUCCESS is returned, the parameter structure must contain the\r
+  interface specific information.\r
+  Description: This call, if successful, provides the network interface specific information such as the interface\r
+  type at the link layer (Ethernet, Tokenring) and the link speed. This information can be used in the\r
+  universal drivers such as NDIS or Miniport to communicate to the upper protocol modules.\r
+  Note: UNDI follows the NDIS2 specification in giving this information. It is the responsibility of the\r
+  universal driver to translate/convert this information into a format that is required in its specification\r
+  or to suit the expectation of the upper level protocol modules.\r
+  PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called\r
+  before the information provided is valid.\r
+  typedef struct {\r
+    PXENV_STATUS Status\r
+    UINT8 IfaceType[16];\r
+    UINT32 LinkSpeed;\r
+    UINT32 ServiceFlags;\r
+    UINT32 Reserved[4];\r
+  } PXENV_UNDI_GET_NDIS_INFO_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  IfaceType: Name of MAC type in ASCIIZ format. This is\r
+  used by the universal NDIS driver to specify its driver type\r
+  to the protocol driver.\r
+  LinkSpeed: Defined in the NDIS 2.0 specification.\r
+  ServiceFlags: Defined in the NDIS 2.0 specification.\r
+  Reserved: Must be zero.       \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetNdisInfo (\r
+  IN     EFI_SIMPLE_NETWORK_DEV      *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_NDIS_INFO_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_GET_NDIS_INFO_T),\r
+          PXENV_UNDI_GET_NDIS_INFO\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI ISR\r
+  Op-Code: PXENV_UNDI_ISR (0014h)\r
+  Input: Far pointer to a PXENV_UNDI_ISR_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in\r
+  the parameter block indicates the operation to be performed for the call. This field is filled with the\r
+  status of that operation on return.\r
+  Note: Interrupt Service Routine Operation:\r
+  In this design the UNDI does not hook the interrupt for the Network Interface. Instead, the\r
+  application or the protocol driver hooks the interrupt and calls UNDI with the PXENV_UNDI_ISR\r
+  API call for interrupt verification (PXENV_UNDI_ISR_IN_START) and processing\r
+  (PXENV_UNDI_ISR_IN_PROCESS and PXENV_UNDI_ISR_GET_NEXT).\r
+  When the Network Interface HW generates an interrupt the protocol driver interrupt service\r
+  routine (ISR) gets control and takes care of the interrupt processing at the PIC level. The ISR then\r
+  calls the UNDI using the PXENV_UNDI_ISR API with the value PXENV_UNDI_ISR_IN_START for\r
+  the FuncFlag parameter. At this time UNDI must disable the interrupts at the Network Interface\r
+  level and read any status values required to further process the interrupt. UNDI must return as\r
+  quickly as possible with one of the two values, PXENV_UNDI_ISR_OUT_OURS or\r
+  PXENV_UNDI_ISR_OUT_NOT_OURS, for the parameter FuncFlag depending on whether the\r
+  interrupt was generated by this particular Network Interface or not.\r
+  If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_NOT_OURS, then the interrupt was\r
+  not generated by our NIC, and interrupt processing is complete.\r
+  If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_OURS, the protocol driver must start\r
+  a handler thread and send an end-of-interrupt (EOI) command to the PIC. Interrupt processing is\r
+  now complete.\r
+  The protocol driver strategy routine will call UNDI using this same API with FuncFlag equal to\r
+  PXENV_UNDI_ISR_IN_PROCESS. At this time UNDI must find the cause of this interrupt and\r
+  return the status in the FuncFlag. It first checks if there is a frame received and if so it returns the\r
+  first buffer pointer of that frame in the parameter block.\r
+  The protocol driver calls UNDI repeatedly with the FuncFlag equal to\r
+  PXENV_UNDI_ISR_IN_GET_NEXT to get all the buffers in a frame and also all the received\r
+  frames in the queue. On this call, UNDI must remember the previous buffer given to the protoco,l\r
+  remove it from the receive queue and recycle it. In case of a multi-buffered frame, if the previous\r
+  buffer is not the last buffer in the frame it must return the next buffer in the frame in the parameter\r
+  block. Otherwise it must return the first buffer in the next frame.\r
+  If there is no received frame pending to be processed, UNDI processes the transmit completes and\r
+  if there is no other interrupt status to be processed, UNDI re-enables the interrupt at the\r
+  NETWORK INTERFACE level and returns PXENV_UNDI_ISR_OUT_DONE in the FuncFlag.\r
+  IMPORTANT: It is possible for the protocol driver to be interrupted again while in the\r
+  strategy routine when the UNDI re-enables interrupts.   \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiIsr (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_ISR_T        *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_ISR_T),\r
+          PXENV_UNDI_ISR\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  STOP UNDI\r
+  Op-Code: PXENV_STOP_UNDI (0015h)\r
+  Input: Far pointer to a PXENV_STOP_UNDI_T parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This routine is responsible for unhooking the Int 1Ah service routine.\r
+  Note: This API service must be called only once at the end of UNDI Option ROM boot. One of the valid\r
+  status codes is PXENV_STATUS_KEEP. If this status is returned, UNDI must not be removed from\r
+  base memory. Also, UNDI must not be removed from base memory if BC is not removed from base\r
+  memory.\r
+  Service cannot be used in protected mode.\r
+  typedef struct {\r
+    PXENV_STATUS Status;\r
+  } PXENV_STOP_UNDI_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.      \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiStop (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_STOP_UNDI_T       *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_STOP_UNDI_T),\r
+          PXENV_STOP_UNDI\r
+          );\r
+}\r
+\r
+/**\r
+  PXE \r
+  UNDI GET STATE\r
+  Op-Code: PXENV_UNDI_GET_STATE (0015h)\r
+  Input: Far pointer to a PXENV_UNDI_GET_STATE_T parameter.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants. The UNDI_STATE field in the parameter structure must be set to one of the valid state\r
+  constants\r
+  Description: This call can be used to obtain state of the UNDI engine in order to avoid issuing adverse call\r
+  sequences\r
+  typedef struct {\r
+    #define PXE_UNDI_GET_STATE_STARTED 1\r
+    #define PXE_UNDI_GET_STATE_INITIALIZED 2\r
+    #define PXE_UNDI_GET_STATE_OPENED 3\r
+    PXENV_STATUS Status;\r
+    UINT8 UNDIstate;\r
+  } PXENV_UNDI_GET_STATE_T;\r
+  Set before calling API service\r
+  N/A\r
+  Returned from API service\r
+  Status: See the PXENV_STATUS_xxx constants.\r
+  State: See definitions of the state constants.\r
+  Note. UNDI implementation is responsible for maintaining\r
+  internal state machine.\r
+  UNDI ISR\r
+  Op-Code: PXENV_UNDI_ISR (0014h)\r
+  Input: Far pointer to a t_PXENV_UNDI_ISR parameter structure that has been initialized by the caller.\r
+  Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in\r
+  the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx\r
+  constants.\r
+  Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in\r
+  the parameter block indicates the operation to be performed for the call. This field is filled with the\r
+  status of that operation on return.     \r
+  \r
+  @param  SimpleNetworkDevice   Device instance\r
+  @param  PxeUndiTable          Point to structure which hold paramter and return value \r
+                                for option ROM call.\r
+                              \r
+  @return Return value of PXE option ROM far call.  \r
+**/\r
+EFI_STATUS\r
+PxeUndiGetState (\r
+  IN     EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,\r
+  IN OUT PXENV_UNDI_GET_STATE_T  *PxeUndiTable\r
+  )\r
+{\r
+  return MakePxeCall (\r
+          SimpleNetworkDevice,\r
+          PxeUndiTable,\r
+          sizeof (PXENV_UNDI_GET_STATE_T),\r
+          PXENV_UNDI_GET_STATE\r
+          );\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf
new file mode 100644 (file)
index 0000000..c37c4ab
--- /dev/null
@@ -0,0 +1,67 @@
+## @file\r
+# Thunk wrapper UEFI driver to produce EFI SNP protocol based on legacy 16 NIC ROM.\r
+#\r
+# Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution.  The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  BASE_NAME                            = BiosSnp16\r
+  FILE_GUID                            = D0CAA91E-2DE4-4b0d-B3DC-09C67E854E34\r
+  MODULE_TYPE                          = UEFI_DRIVER\r
+  INF_VERSION                          = 0x00010005\r
+  VERSION_STRING                       = 1.0\r
+  \r
+  ENTRY_POINT                          = BiosSnp16DriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gBiosSnp16DriverBinding\r
+#  COMPONENT_NAME                =  gBiosSnp16ComponentName\r
+#\r
+\r
+[Sources]\r
+  BiosSnp16.h\r
+  BiosSnp16.c\r
+  Misc.c\r
+  Pxe.h\r
+  PxeUndi.c\r
+  ComponentName.c\r
+\r
+\r
+[Libraryclasses]\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+  BaseMemoryLib\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+  BaseLib\r
+  DevicePathLib\r
+  MemoryAllocationLib\r
+\r
+[Guids]\r
+  gEfiEventExitBootServicesGuid\r
+\r
+[Protocols]\r
+  gEfiNetworkInterfaceIdentifierProtocolGuid\r
+  gEfiDevicePathProtocolGuid\r
+  gEfiSimpleNetworkProtocolGuid\r
+  gEfiPciIoProtocolGuid\r
+  gEfiLegacyBiosProtocolGuid\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
new file mode 100644 (file)
index 0000000..76591e7
--- /dev/null
@@ -0,0 +1,3164 @@
+/** @file\r
+  ConsoleOut Routines that speak VGA.\r
+\r
+Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosVideo.h"\r
+\r
+//\r
+// EFI Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {\r
+  BiosVideoDriverBindingSupported,\r
+  BiosVideoDriverBindingStart,\r
+  BiosVideoDriverBindingStop,\r
+  0x3,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Global lookup tables for VGA graphics modes\r
+//\r
+UINT8                          mVgaLeftMaskTable[]   = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };\r
+\r
+UINT8                          mVgaRightMaskTable[]  = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };\r
+\r
+UINT8                          mVgaBitMaskTable[]    = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };\r
+\r
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL  mVgaColorToGraphicsOutputColor[] = {\r
+  { 0x00, 0x00, 0x00, 0x00 },\r
+  { 0x98, 0x00, 0x00, 0x00 },\r
+  { 0x00, 0x98, 0x00, 0x00 },\r
+  { 0x98, 0x98, 0x00, 0x00 },\r
+  { 0x00, 0x00, 0x98, 0x00 },\r
+  { 0x98, 0x00, 0x98, 0x00 },\r
+  { 0x00, 0x98, 0x98, 0x00 },\r
+  { 0x98, 0x98, 0x98, 0x00 },\r
+  { 0x10, 0x10, 0x10, 0x00 },\r
+  { 0xff, 0x10, 0x10, 0x00 },\r
+  { 0x10, 0xff, 0x10, 0x00 },\r
+  { 0xff, 0xff, 0x10, 0x00 },\r
+  { 0x10, 0x10, 0xff, 0x00 },\r
+  { 0xf0, 0x10, 0xff, 0x00 },\r
+  { 0x10, 0xff, 0xff, 0x00 },\r
+  { 0xff, 0xff, 0xff, 0x00 }\r
+};\r
+\r
+//\r
+// Standard timing defined by VESA EDID\r
+//\r
+VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = {\r
+  //\r
+  // Established Timing I\r
+  //\r
+  {800, 600, 60},\r
+  {800, 600, 56},\r
+  {640, 480, 75},\r
+  {640, 480, 72},\r
+  {640, 480, 67},\r
+  {640, 480, 60},\r
+  {720, 400, 88},\r
+  {720, 400, 70},\r
+  //\r
+  // Established Timing II\r
+  //\r
+  {1280, 1024, 75},\r
+  {1024,  768, 75},\r
+  {1024,  768, 70},\r
+  {1024,  768, 60},\r
+  {1024,  768, 87},\r
+  {832,   624, 75},\r
+  {800,   600, 75},\r
+  {800,   600, 72},\r
+  //\r
+  // Established Timing III\r
+  //\r
+  {1152, 870, 75}\r
+};\r
+\r
+/**\r
+  Supported.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  RemainingDevicePath    A pointer to the remaining portion of a device\r
+                                 path\r
+\r
+  @retval EFI_STATUS             EFI_SUCCESS:This controller can be managed by this\r
+                                 driver, Otherwise, this controller cannot be\r
+                                 managed by this driver\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  PCI_TYPE00                Pci;\r
+  EFI_DEV_PATH              *Node;\r
+\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    //\r
+    // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure,\r
+    // because VgaMiniPort protocol is installed on controller handle directly.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiVgaMiniPortProtocolGuid,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+  }\r
+  //\r
+  // See if this is a PCI Graphics Controller by looking at the Command register and\r
+  // Class Code Register\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        0,\r
+                        sizeof (Pci) / sizeof (UINT32),\r
+                        &Pci\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+  if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {\r
+\r
+    Status = EFI_SUCCESS;\r
+    //\r
+    // If this is a graphics controller,\r
+    // go further check RemainingDevicePath validation\r
+    //\r
+    if (RemainingDevicePath != NULL) {\r
+      Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
+      //\r
+      // Check if RemainingDevicePath is the End of Device Path Node, \r
+      // if yes, return EFI_SUCCESS\r
+      //\r
+      if (!IsDevicePathEnd (Node)) {\r
+        //\r
+        // If RemainingDevicePath isn't the End of Device Path Node,\r
+        // check its validation\r
+        //\r
+        if (Node->DevPath.Type != ACPI_DEVICE_PATH ||\r
+            Node->DevPath.SubType != ACPI_ADR_DP ||\r
+            DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {\r
+          Status = EFI_UNSUPPORTED;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+Done:\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Install Graphics Output Protocol onto VGA device handles.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  RemainingDevicePath    A pointer to the remaining portion of a device\r
+                                 path\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINTN                     Flags;\r
+  UINT64                    OriginalPciAttributes;\r
+  UINT64                    Supports;\r
+  BOOLEAN                   PciAttributesSaved;\r
+\r
+  //\r
+  // Initialize local variables\r
+  //\r
+  PciIo            = NULL;\r
+  ParentDevicePath = NULL;\r
+\r
+  //\r
+  //\r
+  // See if the Legacy BIOS Protocol is available\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    return Status;\r
+  }\r
+\r
+  PciAttributesSaved = FALSE;\r
+  //\r
+  // Save original PCI attributes\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationGet,\r
+                    0,\r
+                    &OriginalPciAttributes\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  PciAttributesSaved = TRUE;\r
+\r
+  //\r
+  // Get supported PCI attributes\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Supports &= (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
+  if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }  \r
+\r
+  //\r
+  // Prepare for status code\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,\r
+    ParentDevicePath\r
+    );\r
+  //\r
+  // Enable the device and make sure VGA cycles are being forwarded to this VGA device\r
+  //\r
+  Status = PciIo->Attributes (\r
+             PciIo,\r
+             EfiPciIoAttributeOperationEnable,\r
+             EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports,\r
+             NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,\r
+      ParentDevicePath\r
+      );\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check to see if there is a legacy option ROM image associated with this PCI device\r
+  //\r
+  Status = LegacyBios->CheckPciRom (\r
+                         LegacyBios,\r
+                         Controller,\r
+                         NULL,\r
+                         NULL,\r
+                         &Flags\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Post the legacy option ROM if it is available.\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    EFI_P_PC_RESET,\r
+    ParentDevicePath\r
+    );\r
+  Status = LegacyBios->InstallPciRom (\r
+                         LegacyBios,\r
+                         Controller,\r
+                         NULL,\r
+                         &Flags,\r
+                         NULL,\r
+                         NULL,\r
+                         NULL,\r
+                         NULL\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,\r
+      ParentDevicePath\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (RemainingDevicePath != NULL) {\r
+    if (IsDevicePathEnd (RemainingDevicePath) && \r
+        (FeaturePcdGet (PcdBiosVideoCheckVbeEnable) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable))) {\r
+      //\r
+      // If RemainingDevicePath is the End of Device Path Node,\r
+      // don't create any child device and return EFI_SUCESS\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create child handle and install GraphicsOutputProtocol on it\r
+  //\r
+  Status = BiosVideoChildHandleInstall (\r
+             This,\r
+             Controller,\r
+             PciIo,\r
+             LegacyBios,\r
+             ParentDevicePath,\r
+             RemainingDevicePath,\r
+             OriginalPciAttributes\r
+             );\r
+\r
+Done:\r
+  if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_PROGRESS_CODE,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,\r
+      ParentDevicePath\r
+      );\r
+\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_PROGRESS_CODE,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,\r
+      ParentDevicePath\r
+      );\r
+    if (PciAttributesSaved) {\r
+      //\r
+      // Restore original PCI attributes\r
+      //\r
+      PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationSet,\r
+                      OriginalPciAttributes,\r
+                      NULL\r
+                      );\r
+    }\r
+    //\r
+    // Release PCI I/O Protocols on the controller handle.\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  NumberOfChildren       Number of children handle created by this driver\r
+  @param  ChildHandleBuffer      Buffer containing child handle created\r
+\r
+  @retval EFI_SUCCESS            Driver disconnected successfully from controller\r
+  @retval EFI_UNSUPPORTED        Cannot find BIOS_VIDEO_DEV structure\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  BOOLEAN                      AllChildrenStopped;\r
+  UINTN                        Index;\r
+\r
+  AllChildrenStopped = TRUE;\r
+\r
+  if (NumberOfChildren == 0) {\r
+    //\r
+    // Close PCI I/O protocol on the controller handle\r
+    //\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+    Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      AllChildrenStopped = FALSE;\r
+    }\r
+  }\r
+\r
+  if (!AllChildrenStopped) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Install child handles if the Handle supports MBR format.\r
+\r
+  @param  This                   Calling context.\r
+  @param  ParentHandle           Parent Handle\r
+  @param  ParentPciIo            Parent PciIo interface\r
+  @param  ParentLegacyBios       Parent LegacyBios interface\r
+  @param  ParentDevicePath       Parent Device Path\r
+  @param  RemainingDevicePath    Remaining Device Path\r
+  @param  OriginalPciAttributes  Original PCI Attributes\r
+\r
+  @retval EFI_SUCCESS            If a child handle was added\r
+  @retval other                  A child handle was not added\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoChildHandleInstall (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ParentHandle,\r
+  IN  EFI_PCI_IO_PROTOCOL          *ParentPciIo,\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL     *ParentLegacyBios,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath,\r
+  IN  UINT64                       OriginalPciAttributes\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  BIOS_VIDEO_DEV           *BiosVideoPrivate;\r
+  PCI_TYPE00               Pci;\r
+  ACPI_ADR_DEVICE_PATH     AcpiDeviceNode;\r
+  BOOLEAN                  ProtocolInstalled;\r
+\r
+  //\r
+  // Allocate the private device structure for video device\r
+  //\r
+  BiosVideoPrivate = (BIOS_VIDEO_DEV *) AllocateZeroPool (\r
+                                                                                                                                                                       sizeof (BIOS_VIDEO_DEV)\r
+                                                                                                                                                                       );\r
+  if (NULL == BiosVideoPrivate) {\r
+               Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // See if this is a VGA compatible controller or not\r
+  //\r
+  Status = ParentPciIo->Pci.Read (\r
+                          ParentPciIo,\r
+                          EfiPciIoWidthUint32,\r
+                          0,\r
+                          sizeof (Pci) / sizeof (UINT32),\r
+                          &Pci\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,\r
+      ParentDevicePath\r
+      );\r
+    goto Done;\r
+  }\r
+  BiosVideoPrivate->VgaCompatible = FALSE;\r
+  if (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01) {\r
+    BiosVideoPrivate->VgaCompatible = TRUE;\r
+  }\r
+\r
+  if (Pci.Hdr.ClassCode[2] == 0x03 && Pci.Hdr.ClassCode[1] == 0x00 && Pci.Hdr.ClassCode[0] == 0x00) {\r
+    BiosVideoPrivate->VgaCompatible = TRUE;\r
+  }\r
+\r
+ if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {\r
+    //\r
+    // Create EXIT_BOOT_SERIVES Event\r
+    //\r
+    Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    BiosVideoNotifyExitBootServices,\r
+                    BiosVideoPrivate,\r
+                    &gEfiEventExitBootServicesGuid,\r
+                    &BiosVideoPrivate->ExitBootServicesEvent\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Initialize the child private structure\r
+  //\r
+  BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;\r
+\r
+  //\r
+  // Fill in Graphics Output specific mode structures\r
+  //\r
+  BiosVideoPrivate->HardwareNeedsStarting = TRUE;\r
+  BiosVideoPrivate->ModeData              = NULL;\r
+  BiosVideoPrivate->LineBuffer            = NULL;\r
+  BiosVideoPrivate->VgaFrameBuffer        = NULL;\r
+  BiosVideoPrivate->VbeFrameBuffer        = NULL;\r
+\r
+  //\r
+  // Fill in the Graphics Output Protocol\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;\r
+  BiosVideoPrivate->GraphicsOutput.SetMode   = BiosVideoGraphicsOutputSetMode;\r
+\r
+\r
+  //\r
+  // Allocate buffer for Graphics Output Protocol mode information\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (\r
+                                             sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)\r
+                                             );\r
+  if (NULL == BiosVideoPrivate->GraphicsOutput.Mode) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  BiosVideoPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (\r
+                                             sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)\r
+                                             );\r
+  if (NULL ==  BiosVideoPrivate->GraphicsOutput.Mode->Info) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Assume that Graphics Output Protocol will be produced until proven otherwise\r
+  //\r
+  BiosVideoPrivate->ProduceGraphicsOutput = TRUE;\r
+\r
+  //\r
+  // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.\r
+  //\r
+  if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {\r
+    if (RemainingDevicePath == NULL) {\r
+      ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
+      AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
+      AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
+      AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
+      SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
+    \r
+      BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (\r
+                                          ParentDevicePath,\r
+                                          (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode\r
+                                          );\r
+    } else {\r
+      BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);\r
+    }\r
+    \r
+    //\r
+    // Creat child handle and device path protocol firstly\r
+    //\r
+    BiosVideoPrivate->Handle = NULL;\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &BiosVideoPrivate->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    BiosVideoPrivate->GopDevicePath,\r
+                    NULL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Fill in the VGA Mini Port Protocol fields\r
+  //\r
+  BiosVideoPrivate->VgaMiniPort.SetMode                   = BiosVideoVgaMiniPortSetMode;\r
+  BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset           = 0xb8000;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset    = 0x3d5;\r
+  BiosVideoPrivate->VgaMiniPort.VgaMemoryBar              = EFI_PCI_IO_PASS_THROUGH_BAR;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar    = EFI_PCI_IO_PASS_THROUGH_BAR;\r
+  BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar       = EFI_PCI_IO_PASS_THROUGH_BAR;\r
+\r
+  //\r
+  // Child handle need to consume the Legacy Bios protocol\r
+  //\r
+  BiosVideoPrivate->LegacyBios = ParentLegacyBios;\r
+\r
+  //\r
+  // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally\r
+  //\r
+  BiosVideoPrivate->PciIo                 = ParentPciIo;\r
+  BiosVideoPrivate->OriginalPciAttributes = OriginalPciAttributes;\r
+\r
+  //\r
+  // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output\r
+  //\r
+  if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable)) {\r
+    Status = BiosVideoCheckForVbe (BiosVideoPrivate);\r
+    DEBUG ((EFI_D_INFO, "BiosVideoCheckForVbe - %r\n", Status));\r
+  } else {\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support\r
+    // for the standard 640x480 16 color VGA mode\r
+    //\r
+    DEBUG ((EFI_D_INFO, "VgaCompatible - %x\n", BiosVideoPrivate->VgaCompatible));\r
+    if (BiosVideoPrivate->VgaCompatible) {\r
+      if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable)) {\r
+        Status = BiosVideoCheckForVga (BiosVideoPrivate);\r
+        DEBUG ((EFI_D_INFO, "BiosVideoCheckForVga - %r\n", Status));\r
+      } else {\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do\r
+      // not produce the Graphics Output protocol.  Instead, produce the VGA MiniPort Protocol.\r
+      //\r
+      BiosVideoPrivate->ProduceGraphicsOutput = FALSE;\r
+\r
+      //\r
+      // INT services are available, so on the 80x25 and 80x50 text mode are supported\r
+      //\r
+      BiosVideoPrivate->VgaMiniPort.MaxMode = 2;\r
+    }\r
+  }\r
+\r
+  ProtocolInstalled = FALSE;\r
+\r
+  if (BiosVideoPrivate->ProduceGraphicsOutput) {\r
+    //\r
+    // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &BiosVideoPrivate->Handle,\r
+                    &gEfiGraphicsOutputProtocolGuid,\r
+                    &BiosVideoPrivate->GraphicsOutput,\r
+                    &gEfiEdidDiscoveredProtocolGuid,\r
+                    &BiosVideoPrivate->EdidDiscovered,\r
+                    &gEfiEdidActiveProtocolGuid,\r
+                    &BiosVideoPrivate->EdidActive,\r
+                    NULL\r
+                    );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Open the Parent Handle for the child\r
+      //\r
+      Status = gBS->OpenProtocol (\r
+                      ParentHandle,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      (VOID **) &BiosVideoPrivate->PciIo,\r
+                      This->DriverBindingHandle,\r
+                      BiosVideoPrivate->Handle,\r
+                      EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      ProtocolInstalled = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!ProtocolInstalled) {\r
+    //\r
+    // Install VGA Mini Port Protocol\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &ParentHandle,\r
+                    &gEfiVgaMiniPortProtocolGuid,\r
+                    &BiosVideoPrivate->VgaMiniPort,\r
+                    NULL\r
+                    );\r
+  }\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    if ((BiosVideoPrivate != NULL) && (BiosVideoPrivate->ExitBootServicesEvent != NULL)) {\r
+      gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);\r
+    }  \r
+    //\r
+    // Free private data structure\r
+    //\r
+    BiosVideoDeviceReleaseResource (BiosVideoPrivate);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Deregister an video child handle and free resources.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  Controller             Video controller handle\r
+  @param  Handle                 Video child handle\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoChildHandleUninstall (\r
+  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  EFI_HANDLE                     Controller,\r
+  EFI_HANDLE                     Handle\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_IA32_REGISTER_SET        Regs;\r
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+  EFI_VGA_MINI_PORT_PROTOCOL   *VgaMiniPort;\r
+  BIOS_VIDEO_DEV               *BiosVideoPrivate;\r
+  EFI_PCI_IO_PROTOCOL          *PciIo;\r
+\r
+  BiosVideoPrivate = NULL;\r
+  GraphicsOutput   = NULL;\r
+  PciIo            = NULL;\r
+  Status           = EFI_UNSUPPORTED;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Handle,\r
+                  &gEfiGraphicsOutputProtocolGuid,\r
+                  (VOID **) &GraphicsOutput,\r
+                  This->DriverBindingHandle,\r
+                  Handle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+      BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
+                   Handle,\r
+                   &gEfiVgaMiniPortProtocolGuid,\r
+                   (VOID **) &VgaMiniPort,\r
+                   This->DriverBindingHandle,\r
+                   Handle,\r
+                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                   );\r
+    if (!EFI_ERROR (Status)) {\r
+      BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);\r
+    }\r
+  }\r
+\r
+  if (BiosVideoPrivate == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Set the 80x25 Text VGA Mode\r
+  //\r
+  Regs.H.AH = 0x00;\r
+  Regs.H.AL = 0x03;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Regs.H.AH = 0x11;\r
+  Regs.H.AL = 0x14;\r
+  Regs.H.BL = 0;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+  Status = BiosVideoPrivate->PciIo->Attributes (\r
+                    BiosVideoPrivate->PciIo,\r
+                    EfiPciIoAttributeOperationSet,\r
+                    BiosVideoPrivate->OriginalPciAttributes,\r
+                    NULL\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Close PCI I/O protocol that opened by child handle\r
+  //\r
+  Status = gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Handle\r
+                  );\r
+\r
+  //\r
+  // Uninstall protocols on child handle\r
+  //\r
+  if (BiosVideoPrivate->ProduceGraphicsOutput) {\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    BiosVideoPrivate->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    BiosVideoPrivate->GopDevicePath,\r
+                    &gEfiGraphicsOutputProtocolGuid,\r
+                    &BiosVideoPrivate->GraphicsOutput,\r
+                    &gEfiEdidDiscoveredProtocolGuid,\r
+                    &BiosVideoPrivate->EdidDiscovered,\r
+                    &gEfiEdidActiveProtocolGuid,\r
+                    &BiosVideoPrivate->EdidActive,\r
+                    NULL\r
+                    );\r
+  }\r
+  if (!BiosVideoPrivate->ProduceGraphicsOutput) {\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    Controller,\r
+                    &gEfiVgaMiniPortProtocolGuid,\r
+                    &BiosVideoPrivate->VgaMiniPort,\r
+                    NULL\r
+                    );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->OpenProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           (VOID **) &PciIo,\r
+           This->DriverBindingHandle,\r
+           Handle,\r
+           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+           );\r
+    return Status;\r
+  }\r
+\r
+  if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {\r
+    //\r
+    // Close EXIT_BOOT_SERIVES Event\r
+    //\r
+    gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);\r
+  }\r
+\r
+  //\r
+  // Release all allocated resources\r
+  //\r
+  BiosVideoDeviceReleaseResource (BiosVideoPrivate);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Release resource for biso video instance.\r
+\r
+  @param  BiosVideoPrivate       Video child device private data structure\r
+\r
+**/\r
+VOID\r
+BiosVideoDeviceReleaseResource (\r
+  BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  )\r
+{\r
+  if (BiosVideoPrivate == NULL) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Release all the resourses occupied by the BIOS_VIDEO_DEV\r
+  //\r
+\r
+  //\r
+  // Free VGA Frame Buffer\r
+  //\r
+  if (BiosVideoPrivate->VgaFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VgaFrameBuffer);\r
+  }\r
+  //\r
+  // Free VBE Frame Buffer\r
+  //\r
+  if (BiosVideoPrivate->VbeFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VbeFrameBuffer);\r
+  }\r
+  //\r
+  // Free line buffer\r
+  //\r
+  if (BiosVideoPrivate->LineBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->LineBuffer);\r
+  }\r
+  //\r
+  // Free mode data\r
+  //\r
+  if (BiosVideoPrivate->ModeData != NULL) {\r
+    FreePool (BiosVideoPrivate->ModeData);\r
+  }\r
+  //\r
+  // Free memory allocated below 1MB\r
+  //\r
+  if (BiosVideoPrivate->PagesBelow1MB != 0) {\r
+    gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);\r
+  }\r
+\r
+  if (BiosVideoPrivate->VbeSaveRestorePages != 0) {\r
+    gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);\r
+  }\r
+\r
+  //\r
+  // Free graphics output protocol occupied resource\r
+  //\r
+  if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {\r
+    if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {\r
+        FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);\r
+    }\r
+    FreePool (BiosVideoPrivate->GraphicsOutput.Mode);\r
+  }\r
+  //\r
+  // Free EDID discovered protocol occupied resource\r
+  //\r
+  if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) {\r
+    FreePool (BiosVideoPrivate->EdidDiscovered.Edid);\r
+  }\r
+  //\r
+  // Free EDID active protocol occupied resource\r
+  //\r
+  if (BiosVideoPrivate->EdidActive.Edid != NULL) {\r
+    FreePool (BiosVideoPrivate->EdidActive.Edid);\r
+  }\r
+\r
+  if (BiosVideoPrivate->GopDevicePath!= NULL) {\r
+    FreePool (BiosVideoPrivate->GopDevicePath);\r
+  }\r
+\r
+  FreePool (BiosVideoPrivate);\r
+\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Generate a search key for a specified timing data.\r
+\r
+  @param  EdidTiming             Pointer to EDID timing\r
+\r
+  @return The 32 bit unique key for search.\r
+\r
+**/\r
+UINT32\r
+CalculateEdidKey (\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING       *EdidTiming\r
+  )\r
+{\r
+  UINT32 Key;\r
+\r
+  //\r
+  // Be sure no conflicts for all standard timing defined by VESA.\r
+  //\r
+  Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;\r
+  return Key;\r
+}\r
+\r
+\r
+/**\r
+  Parse the Established Timing and Standard Timing in EDID data block.\r
+\r
+  @param  EdidBuffer             Pointer to EDID data block\r
+  @param  ValidEdidTiming        Valid EDID timing information\r
+\r
+  @retval TRUE                   The EDID data is valid.\r
+  @retval FALSE                  The EDID data is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+ParseEdidData (\r
+  UINT8                                      *EdidBuffer,\r
+  VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING     *ValidEdidTiming\r
+  )\r
+{\r
+  UINT8  CheckSum;\r
+  UINT32 Index;\r
+  UINT32 ValidNumber;\r
+  UINT32 TimingBits;\r
+  UINT8  *BufferIndex;\r
+  UINT16 HorizontalResolution;\r
+  UINT16 VerticalResolution;\r
+  UINT8  AspectRatio;\r
+  UINT8  RefreshRate;\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING     TempTiming;\r
+  VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;\r
+\r
+  EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer;\r
+\r
+  //\r
+  // Check the checksum of EDID data\r
+  //\r
+  CheckSum = 0;\r
+  for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) {\r
+    CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);\r
+  }\r
+  if (CheckSum != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  ValidNumber = 0;\r
+  gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0);\r
+\r
+  if ((EdidDataBlock->EstablishedTimings[0] != 0) ||\r
+      (EdidDataBlock->EstablishedTimings[1] != 0) ||\r
+      (EdidDataBlock->EstablishedTimings[2] != 0)\r
+      ) {\r
+    //\r
+    // Established timing data\r
+    //\r
+    TimingBits = EdidDataBlock->EstablishedTimings[0] |\r
+                 (EdidDataBlock->EstablishedTimings[1] << 8) |\r
+                 ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;\r
+    for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {\r
+      if ((TimingBits & 0x1) != 0) {\r
+        ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);\r
+        ValidNumber ++;\r
+      }\r
+      TimingBits = TimingBits >> 1;\r
+    }\r
+  } else {\r
+    //\r
+    // If no Established timing data, read the standard timing data\r
+    //\r
+    BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];\r
+    for (Index = 0; Index < 8; Index ++) {\r
+      if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){\r
+        //\r
+        // A valid Standard Timing\r
+        //\r
+        HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);\r
+        AspectRatio = (UINT8) (BufferIndex[1] >> 6);\r
+        switch (AspectRatio) {\r
+          case 0:\r
+            VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);\r
+            break;\r
+          case 1:\r
+            VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
+            break;\r
+          case 2:\r
+            VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);\r
+            break;\r
+          case 3:\r
+            VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);\r
+            break;\r
+          default:\r
+            VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
+            break;\r
+        }\r
+        RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);\r
+        TempTiming.HorizontalResolution = HorizontalResolution;\r
+        TempTiming.VerticalResolution = VerticalResolution;\r
+        TempTiming.RefreshRate = RefreshRate;\r
+        ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);\r
+        ValidNumber ++;\r
+      }\r
+      BufferIndex += 2;\r
+    }\r
+  }\r
+\r
+  ValidEdidTiming->ValidNumber = ValidNumber;\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Search a specified Timing in all the valid EDID timings.\r
+\r
+  @param  ValidEdidTiming        All valid EDID timing information.\r
+  @param  EdidTiming             The Timing to search for.\r
+\r
+  @retval TRUE                   Found.\r
+  @retval FALSE                  Not found.\r
+\r
+**/\r
+BOOLEAN\r
+SearchEdidTiming (\r
+  VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming,\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING       *EdidTiming\r
+  )\r
+{\r
+  UINT32 Index;\r
+  UINT32 Key;\r
+\r
+  Key = CalculateEdidKey (EdidTiming);\r
+\r
+  for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {\r
+    if (Key == ValidEdidTiming->Key[Index]) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Check for VBE device.\r
+\r
+  @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure\r
+\r
+  @retval EFI_SUCCESS            VBE device found\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoCheckForVbe (\r
+  IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  )\r
+{\r
+  EFI_STATUS                             Status;\r
+  EFI_IA32_REGISTER_SET                  Regs;\r
+  UINT16                                 *ModeNumberPtr;\r
+  BOOLEAN                                ModeFound;\r
+  BOOLEAN                                EdidFound;\r
+  BIOS_VIDEO_MODE_DATA                   *ModeBuffer;\r
+  BIOS_VIDEO_MODE_DATA                   *CurrentModeData;\r
+  UINTN                                  PreferMode;\r
+  UINTN                                  ModeNumber;\r
+  VESA_BIOS_EXTENSIONS_EDID_TIMING       Timing;\r
+  VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;\r
+  EFI_EDID_OVERRIDE_PROTOCOL             *EdidOverride;\r
+  UINT32                                 EdidAttributes;\r
+  BOOLEAN                                EdidOverrideFound;\r
+  UINTN                                  EdidOverrideDataSize;\r
+  UINT8                                  *EdidOverrideDataBlock;\r
+  UINTN                                  EdidActiveDataSize;\r
+  UINT8                                  *EdidActiveDataBlock;\r
+\r
+  EdidFound             = TRUE;\r
+  EdidOverrideFound     = FALSE;\r
+  EdidOverrideDataBlock = NULL;\r
+  EdidActiveDataSize    = 0;\r
+  EdidActiveDataBlock   = NULL;\r
+\r
+  //\r
+  // Allocate buffer under 1MB for VBE data structures\r
+  //\r
+  BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +\r
+                                              sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)\r
+                                              );\r
+\r
+  BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;\r
+\r
+  Status = gBS->AllocatePages (\r
+                  AllocateMaxAddress,\r
+                  EfiBootServicesData,\r
+                  BiosVideoPrivate->NumberOfPagesBelow1MB,\r
+                  &BiosVideoPrivate->PagesBelow1MB\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));\r
+       \r
+  //\r
+  // Fill in the VBE related data structures\r
+  //\r
+  BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);\r
+  BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);\r
+  BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);\r
+  BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);\r
+  BiosVideoPrivate->VbeSaveRestorePages   = 0;\r
+  BiosVideoPrivate->VbeSaveRestoreBuffer  = 0;\r
+\r
+  //\r
+  // Test to see if the Video Adapter is compliant with VBE 3.0\r
+  //\r
+  gBS->SetMem (&Regs, sizeof (Regs), 0);\r
+  Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;\r
+  gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);\r
+  BiosVideoPrivate->VbeInformationBlock->VESASignature  = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;\r
+  Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);\r
+  Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);\r
+\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  //\r
+  // See if the VESA call succeeded\r
+  //\r
+  if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check for 'VESA' signature\r
+  //\r
+  if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check to see if this is VBE 2.0 or higher\r
+  //\r
+  if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {\r
+    return Status;\r
+  }\r
+\r
+  EdidFound            = FALSE;\r
+  EdidAttributes       = 0xff;\r
+  EdidOverrideDataSize = 0;\r
+\r
+  //\r
+  // Find EDID Override protocol firstly, this protocol is installed by platform if needed.\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                   &gEfiEdidOverrideProtocolGuid,\r
+                   NULL,\r
+                   (VOID **) &EdidOverride\r
+                   );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow\r
+    //\r
+    EdidOverrideDataBlock = AllocatePool (sizeof (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2));\r
+    if (NULL == EdidOverrideDataBlock) {\r
+               Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    Status = EdidOverride->GetEdid (\r
+                             EdidOverride,\r
+                             BiosVideoPrivate->Handle,\r
+                             &EdidAttributes,\r
+                             &EdidOverrideDataSize,\r
+                             (UINT8 **) &EdidOverrideDataBlock\r
+                             );\r
+    if (!EFI_ERROR (Status)  &&\r
+         EdidAttributes == 0 &&\r
+         EdidOverrideDataSize != 0) {\r
+      //\r
+      // Succeeded to get EDID Override Data\r
+      //\r
+      EdidOverrideFound = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {\r
+    //\r
+    // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,\r
+    // read EDID information through INT10 call\r
+    //\r
+\r
+    gBS->SetMem (&Regs, sizeof (Regs), 0);\r
+    Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;\r
+    Regs.X.BX = 1;\r
+    Regs.X.CX = 0;\r
+    Regs.X.DX = 0;\r
+    Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);\r
+    Regs.X.DI = EFI_OFFSET  ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);\r
+\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    //\r
+    // See if the VESA call succeeded\r
+    //\r
+    if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+      //\r
+      // Set EDID Discovered Data\r
+      //\r
+      BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;\r
+                 BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (\r
+                                                          VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,\r
+                                                          BiosVideoPrivate->VbeEdidDataBlock\r
+                                                                                                                                                                                                                                 );\r
+\r
+      if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {\r
+                         Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+\r
+      EdidFound = TRUE;\r
+    }\r
+  }\r
+\r
+  if (EdidFound) {\r
+    EdidActiveDataSize  = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;\r
+    EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;\r
+  } else if (EdidOverrideFound) {\r
+    EdidActiveDataSize  = EdidOverrideDataSize;\r
+    EdidActiveDataBlock = EdidOverrideDataBlock;\r
+    EdidFound = TRUE;\r
+       }\r
+\r
+       if (EdidFound) {\r
+    //\r
+    // Parse EDID data structure to retrieve modes supported by monitor\r
+    //\r
+    if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {\r
+      //\r
+      // Copy EDID Override Data to EDID Active Data\r
+      //\r
+      BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;\r
+      BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (\r
+                                                      EdidActiveDataSize,\r
+                                                      EdidActiveDataBlock\r
+                                                      );\r
+      if (NULL ==  BiosVideoPrivate->EdidActive.Edid) {\r
+                 Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+    }\r
+  } else {\r
+    BiosVideoPrivate->EdidActive.SizeOfEdid = 0;\r
+    BiosVideoPrivate->EdidActive.Edid = NULL;\r
+    EdidFound = FALSE;\r
+  }\r
+\r
+  //\r
+  // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode\r
+  //\r
+  ModeNumberPtr = (UINT16 *)\r
+    (\r
+      (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |\r
+        ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)\r
+    );\r
+\r
+  PreferMode = 0;\r
+  ModeNumber = 0;\r
+\r
+  for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) {\r
+    //\r
+    // Make sure this is a mode number defined by the VESA VBE specification.  If it isn'tm then skip this mode number.\r
+    //\r
+    if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // Get the information about the mode\r
+    //\r
+    gBS->SetMem (&Regs, sizeof (Regs), 0);\r
+    Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;\r
+    Regs.X.CX = *ModeNumberPtr;\r
+    gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);\r
+    Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);\r
+    Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);\r
+\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+    //\r
+    // See if the call succeeded.  If it didn't, then try the next mode.\r
+    //\r
+    if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports color.  If it doesn't then try the next mode.\r
+    //\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports graphics.  If it doesn't then try the next mode.\r
+    //\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports a linear frame buffer.  If it doesn't then try the next mode.\r
+    //\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the mode supports 32 bit color.  If it doesn't then try the next mode.\r
+    // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the\r
+    // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel\r
+    //\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {\r
+      continue;\r
+    }\r
+\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {\r
+      continue;\r
+    }\r
+\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // See if the physical base pointer for the linear mode is valid.  If it isn't then try the next mode.\r
+    //\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {\r
+      continue;\r
+    }\r
+\r
+    if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {\r
+      //\r
+      // EDID exist, check whether this mode match with any mode in EDID\r
+      //\r
+      Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
+      Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
+      if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {\r
+        continue;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Select a reasonable mode to be set for current display mode\r
+    //\r
+    ModeFound = FALSE;\r
+\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&\r
+        BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768\r
+        ) {\r
+      ModeFound = TRUE;\r
+    }\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&\r
+        BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600\r
+        ) {\r
+      ModeFound = TRUE;\r
+      PreferMode = ModeNumber;\r
+    }\r
+    if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&\r
+        BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480\r
+        ) {\r
+      ModeFound = TRUE;\r
+    }\r
+\r
+    if ((!EdidFound) && (!ModeFound)) {\r
+      //\r
+      // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480\r
+      //\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Add mode to the list of available modes\r
+    //\r
+    ModeNumber ++;\r
+    ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (\r
+                                                                                                                                                                               ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)\r
+                                                                                                                                                                               );\r
+    if (NULL == ModeBuffer) {\r
+                       Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    if (ModeNumber > 1) {\r
+      CopyMem (\r
+        ModeBuffer,\r
+        BiosVideoPrivate->ModeData,\r
+        (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)\r
+        );\r
+    }\r
+\r
+    if (BiosVideoPrivate->ModeData != NULL) {\r
+      FreePool (BiosVideoPrivate->ModeData);\r
+    }\r
+\r
+    CurrentModeData = &ModeBuffer[ModeNumber - 1];\r
+    CurrentModeData->VbeModeNumber = *ModeNumberPtr;\r
+    if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {\r
+      CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;\r
+      CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;\r
+      CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);\r
+      CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;\r
+      CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);\r
+      CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;\r
+      CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);\r
+      CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;\r
+      CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);\r
+    } else {\r
+      CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;\r
+      CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;\r
+      CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);\r
+      CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;\r
+      CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);\r
+      CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;\r
+      CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);\r
+      CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;\r
+      CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);\r
+    }\r
+\r
+    CurrentModeData->PixelFormat = PixelBitMask;\r
+    if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&\r
+        (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {\r
+      if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {\r
+        CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;\r
+      } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {\r
+        CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;\r
+      }\r
+    }\r
+\r
+    CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;\r
+    CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;\r
+    CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;\r
+    CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;\r
+    CurrentModeData->FrameBufferSize = BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024;\r
+\r
+    CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;\r
+    CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
+    CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
+\r
+    CurrentModeData->BitsPerPixel  = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;\r
+\r
+    BiosVideoPrivate->ModeData = ModeBuffer;\r
+  }\r
+  //\r
+  // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT\r
+  //\r
+  if (ModeNumber == 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Assign Gop's Blt function\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVbeBlt;\r
+\r
+  BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;\r
+  //\r
+  // Current mode is unknow till now, set it to an invalid mode.\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;\r
+\r
+  //\r
+  // Find the best mode to initialize\r
+  //\r
+  Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);\r
+  if (EFI_ERROR (Status)) {\r
+    for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {\r
+      Status = BiosVideoGraphicsOutputSetMode (\r
+                &BiosVideoPrivate->GraphicsOutput,\r
+                (UINT32) PreferMode\r
+                );\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    }\r
+    if (PreferMode == ModeNumber) {\r
+      //\r
+      // None mode is set successfully.\r
+      //\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+Done:\r
+  //\r
+  // If there was an error, then free the mode structure\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    if (BiosVideoPrivate->ModeData != NULL) {\r
+      FreePool (BiosVideoPrivate->ModeData);\r
+      BiosVideoPrivate->ModeData  = NULL;\r
+      BiosVideoPrivate->MaxMode   = 0;\r
+    }\r
+    if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {\r
+      if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {\r
+        FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);\r
+        BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;\r
+      }\r
+      FreePool (BiosVideoPrivate->GraphicsOutput.Mode);\r
+      BiosVideoPrivate->GraphicsOutput.Mode= NULL;\r
+    }\r
+    if (EdidOverrideDataBlock != NULL) {\r
+      FreePool (EdidOverrideDataBlock);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Check for VGA device.\r
+\r
+  @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure\r
+\r
+  @retval EFI_SUCCESS            Standard VGA device found\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoCheckForVga (\r
+  IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  BIOS_VIDEO_MODE_DATA  *ModeBuffer;\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  //\r
+  // Assign Gop's Blt function\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Blt     = BiosVideoGraphicsOutputVgaBlt;\r
+\r
+  //\r
+  // Add mode to the list of available modes\r
+  // caller should guarantee that Mode has been allocated.\r
+  //\r
+  ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);\r
+  BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;\r
+\r
+  ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (\r
+                                          sizeof (BIOS_VIDEO_MODE_DATA)\r
+                                          );\r
+  if (NULL == ModeBuffer) {\r
+               Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  ModeBuffer->VbeModeNumber         = 0x0012;\r
+  ModeBuffer->BytesPerScanLine      = 640;\r
+  ModeBuffer->LinearFrameBuffer     = (VOID *) (UINTN) (0xa0000);\r
+  ModeBuffer->HorizontalResolution  = 640;\r
+  ModeBuffer->VerticalResolution    = 480;\r
+  ModeBuffer->PixelFormat           = PixelBltOnly;\r
+  ModeBuffer->BitsPerPixel          = 8;\r
+  ModeBuffer->ColorDepth            = 32;\r
+  ModeBuffer->RefreshRate           = 60;\r
+\r
+  BiosVideoPrivate->ModeData = ModeBuffer;\r
+\r
+  //\r
+  // Test to see if the Video Adapter support the 640x480 16 color mode\r
+  //\r
+  BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;\r
+  Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);\r
+\r
+Done:\r
+  //\r
+  // If there was an error, then free the mode structure\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    if (BiosVideoPrivate->ModeData != NULL) {\r
+      FreePool (BiosVideoPrivate->ModeData);\r
+      BiosVideoPrivate->ModeData = NULL;\r
+    }\r
+    if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {\r
+      if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {\r
+        FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);\r
+        BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;\r
+      }\r
+      FreePool (BiosVideoPrivate->GraphicsOutput.Mode);\r
+      BiosVideoPrivate->GraphicsOutput.Mode = NULL;\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+//\r
+// Graphics Output Protocol Member Functions for VESA BIOS Extensions\r
+//\r
+\r
+/**\r
+  Graphics Output protocol interface to get video mode.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ModeNumber             The mode number to return information on.\r
+  @param  SizeOfInfo             A pointer to the size, in bytes, of the Info\r
+                                 buffer.\r
+  @param  Info                   Caller allocated buffer that returns information\r
+                                 about ModeNumber.\r
+\r
+  @retval EFI_SUCCESS            Mode information returned.\r
+  @retval EFI_DEVICE_ERROR       A hardware error occurred trying to retrieve the\r
+                                 video mode.\r
+  @retval EFI_NOT_STARTED        Video display is not initialized. Call SetMode ()\r
+  @retval EFI_INVALID_PARAMETER  One of the input args was NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputQueryMode (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,\r
+  IN  UINT32                                ModeNumber,\r
+  OUT UINTN                                 *SizeOfInfo,\r
+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV        *BiosVideoPrivate;\r
+  BIOS_VIDEO_MODE_DATA  *ModeData;\r
+\r
+  BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+\r
+  if (BiosVideoPrivate->HardwareNeedsStarting) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,\r
+      BiosVideoPrivate->GopDevicePath\r
+      );\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (\r
+                                                                                                                                                                                                               sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)\r
+                                                                                                                                                                                                               );\r
+  if (NULL == *Info) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
+\r
+  ModeData = &BiosVideoPrivate->ModeData[ModeNumber];\r
+  (*Info)->Version = 0;\r
+  (*Info)->HorizontalResolution = ModeData->HorizontalResolution;\r
+  (*Info)->VerticalResolution   = ModeData->VerticalResolution;\r
+  (*Info)->PixelFormat = ModeData->PixelFormat;\r
+  CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));\r
+\r
+  (*Info)->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Worker function to set video mode.\r
+\r
+  @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV.\r
+  @param  ModeData               The mode data to be set.\r
+  @param  DevicePath             Pointer to Device Path Protocol.\r
+\r
+  @retval EFI_SUCCESS            Graphics mode was changed.\r
+  @retval EFI_DEVICE_ERROR       The device had an error and could not complete the\r
+                                 request.\r
+  @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoSetModeWorker (\r
+  IN  BIOS_VIDEO_DEV               *BiosVideoPrivate,\r
+  IN  BIOS_VIDEO_MODE_DATA         *ModeData,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_IA32_REGISTER_SET   Regs;\r
+\r
+  if (BiosVideoPrivate->LineBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->LineBuffer);\r
+  }\r
+\r
+  if (BiosVideoPrivate->VgaFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VgaFrameBuffer);\r
+  }\r
+\r
+  if (BiosVideoPrivate->VbeFrameBuffer != NULL) {\r
+    FreePool (BiosVideoPrivate->VbeFrameBuffer);\r
+  }\r
+\r
+  BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (\r
+                                                                                                                                                                          ModeData->BytesPerScanLine\r
+                                                                                                                                                                          );\r
+  if (NULL == BiosVideoPrivate->LineBuffer) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Clear all registers\r
+  //\r
+  ZeroMem (&Regs, sizeof (Regs));\r
+\r
+  if (ModeData->VbeModeNumber < 0x100) {\r
+    //\r
+    // Allocate a working buffer for BLT operations to the VGA frame buffer\r
+    //\r
+    BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);\r
+    if (NULL == BiosVideoPrivate->VgaFrameBuffer) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Set VGA Mode\r
+    //\r
+    Regs.X.AX = ModeData->VbeModeNumber;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  } else {\r
+    //\r
+    // Allocate a working buffer for BLT operations to the VBE frame buffer\r
+    //\r
+    BiosVideoPrivate->VbeFrameBuffer =\r
+                       (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (\r
+                                                                                                                                                                       ModeData->BytesPerScanLine * ModeData->VerticalResolution\r
+                                                                                                                                                                 );\r
+    if (NULL == BiosVideoPrivate->VbeFrameBuffer) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Set VBE mode\r
+    //\r
+    Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;\r
+    Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);\r
+    ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));\r
+    Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);\r
+    Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+    //\r
+    // Check to see if the call succeeded\r
+    //\r
+    if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {\r
+      REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,\r
+        DevicePath\r
+        );\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // Initialize the state of the VbeFrameBuffer\r
+    //\r
+    Status = BiosVideoPrivate->PciIo->Mem.Read (\r
+                                            BiosVideoPrivate->PciIo,\r
+                                            EfiPciIoWidthUint32,\r
+                                            EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                                            (UINT64) (UINTN) ModeData->LinearFrameBuffer,\r
+                                            (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,\r
+                                            BiosVideoPrivate->VbeFrameBuffer\r
+                                            );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Graphics Output protocol interface to set video mode.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ModeNumber             The mode number to be set.\r
+\r
+  @retval EFI_SUCCESS            Graphics mode was changed.\r
+  @retval EFI_DEVICE_ERROR       The device had an error and could not complete the\r
+                                 request.\r
+  @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputSetMode (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,\r
+  IN  UINT32                       ModeNumber\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BIOS_VIDEO_DEV          *BiosVideoPrivate;\r
+  BIOS_VIDEO_MODE_DATA    *ModeData;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+\r
+  ModeData = &BiosVideoPrivate->ModeData[ModeNumber];\r
+\r
+  if (ModeNumber >= This->Mode->MaxMode) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  if (ModeNumber == This->Mode->Mode) {\r
+    //\r
+    // Clear screen to black\r
+    //    \r
+    ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+    BiosVideoGraphicsOutputVbeBlt (\r
+                        This,\r
+                        &Background,\r
+                        EfiBltVideoFill,\r
+                        0,\r
+                        0,\r
+                        0,\r
+                        0,\r
+                        ModeData->HorizontalResolution,\r
+                        ModeData->VerticalResolution,\r
+                        0\r
+    );\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  This->Mode->Mode = ModeNumber;\r
+  This->Mode->Info->Version = 0;\r
+  This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;\r
+  This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;\r
+  This->Mode->Info->PixelFormat = ModeData->PixelFormat;\r
+  CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));\r
+  This->Mode->Info->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;\r
+  This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
+\r
+  //\r
+  // Frame BufferSize remain unchanged\r
+  //\r
+  This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;\r
+  This->Mode->FrameBufferSize = ModeData->FrameBufferSize;\r
+\r
+  BiosVideoPrivate->HardwareNeedsStarting = FALSE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.\r
+\r
+  @param   PciIo              The pointer of EFI_PCI_IO_PROTOCOL\r
+  @param   VbeBuffer          The data to transfer to screen\r
+  @param   MemAddress         Physical frame buffer base address\r
+  @param   DestinationX       The X coordinate of the destination for BltOperation\r
+  @param   DestinationY       The Y coordinate of the destination for BltOperation\r
+  @param   TotalBytes         The total bytes of copy\r
+  @param   VbePixelWidth      Bytes per pixel\r
+  @param   BytesPerScanLine   Bytes per scan line\r
+\r
+**/\r
+VOID\r
+CopyVideoBuffer (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT8                 *VbeBuffer,\r
+  IN  VOID                  *MemAddress,\r
+  IN  UINTN                 DestinationX,\r
+  IN  UINTN                 DestinationY,\r
+  IN  UINTN                 TotalBytes,\r
+  IN  UINT32                VbePixelWidth,\r
+  IN  UINTN                 BytesPerScanLine\r
+  )\r
+{\r
+  UINTN                 FrameBufferAddr;\r
+  UINTN                 CopyBlockNum;\r
+  UINTN                 RemainingBytes;\r
+  UINTN                 UnalignedBytes;\r
+  EFI_STATUS            Status;\r
+\r
+  FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;\r
+\r
+  //\r
+  // If TotalBytes is less than 4 bytes, only start byte copy.\r
+  //\r
+  if (TotalBytes < 4) {\r
+    Status = PciIo->Mem.Write (\r
+                     PciIo,\r
+                     EfiPciIoWidthUint8,\r
+                     EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                     (UINT64) FrameBufferAddr,\r
+                     TotalBytes,\r
+                     VbeBuffer\r
+                     );\r
+    ASSERT_EFI_ERROR (Status);\r
+    return;\r
+  }\r
+\r
+  //\r
+  // If VbeBuffer is not 4-byte aligned, start byte copy.\r
+  //\r
+  UnalignedBytes  = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;\r
+\r
+  if (UnalignedBytes != 0) {\r
+    Status = PciIo->Mem.Write (\r
+                     PciIo,\r
+                     EfiPciIoWidthUint8,\r
+                     EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                     (UINT64) FrameBufferAddr,\r
+                     UnalignedBytes,\r
+                     VbeBuffer\r
+                     );\r
+    ASSERT_EFI_ERROR (Status);\r
+    FrameBufferAddr += UnalignedBytes;\r
+    VbeBuffer       += UnalignedBytes;\r
+  }\r
+\r
+  //\r
+  // Calculate 4-byte block count and remaining bytes.\r
+  //\r
+  CopyBlockNum   = (TotalBytes - UnalignedBytes) >> 2;\r
+  RemainingBytes = (TotalBytes - UnalignedBytes) &  3;\r
+\r
+  //\r
+  // Copy 4-byte block and remaining bytes to physical frame buffer.\r
+  //\r
+  if (CopyBlockNum != 0) {\r
+    Status = PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint32,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) FrameBufferAddr,\r
+                    CopyBlockNum,\r
+                    VbeBuffer\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (RemainingBytes != 0) {\r
+    FrameBufferAddr += (CopyBlockNum << 2);\r
+    VbeBuffer       += (CopyBlockNum << 2);\r
+    Status = PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) FrameBufferAddr,\r
+                    RemainingBytes,\r
+                    VbeBuffer\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+}\r
+\r
+/**\r
+  Worker function to block transfer for VBE device.\r
+\r
+  @param  BiosVideoPrivate       Instance of BIOS_VIDEO_DEV\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+  @param  Mode                   Mode data.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoVbeBltWorker (\r
+  IN  BIOS_VIDEO_DEV                     *BiosVideoPrivate,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta,\r
+  IN  BIOS_VIDEO_MODE_DATA               *Mode\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL            *PciIo;\r
+  EFI_TPL                        OriginalTPL;\r
+  UINTN                          DstY;\r
+  UINTN                          SrcY;\r
+  UINTN                          DstX;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *Blt;\r
+  VOID                           *MemAddress;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *VbeFrameBuffer;\r
+  UINTN                          BytesPerScanLine;\r
+  UINTN                          Index;\r
+  UINT8                          *VbeBuffer;\r
+  UINT8                          *VbeBuffer1;\r
+  UINT8                          *BltUint8;\r
+  UINT32                         VbePixelWidth;\r
+  UINT32                         Pixel;\r
+  UINTN                          TotalBytes;\r
+\r
+  PciIo             = BiosVideoPrivate->PciIo;\r
+\r
+  VbeFrameBuffer    = BiosVideoPrivate->VbeFrameBuffer;\r
+  MemAddress        = Mode->LinearFrameBuffer;\r
+  BytesPerScanLine  = Mode->BytesPerScanLine;\r
+  VbePixelWidth     = Mode->BitsPerPixel / 8;\r
+  BltUint8          = (UINT8 *) BltBuffer;\r
+  TotalBytes        = Width * VbePixelWidth;\r
+\r
+  if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Width == 0 || Height == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // We need to fill the Virtual Screen buffer with the blt data.\r
+  // The virtual screen is upside down, as the first row is the bootom row of\r
+  // the image.\r
+  //\r
+  if (BltOperation == EfiBltVideoToBltBuffer) {\r
+    //\r
+    // Video to BltBuffer: Source is Video, destination is BltBuffer\r
+    //\r
+    if (SourceY + Height > Mode->VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (SourceX + Width > Mode->HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    // BltBuffer to Video: Source is BltBuffer, destination is Video\r
+    //\r
+    if (DestinationY + Height > Mode->VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (DestinationX + Width > Mode->HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // If Delta is zero, then the entire BltBuffer is being used, so Delta\r
+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,\r
+  // the number of bytes in each row can be computed.\r
+  //\r
+  if (Delta == 0) {\r
+    Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
+  }\r
+  //\r
+  // We have to raise to TPL Notify, so we make an atomic write the frame buffer.\r
+  // We would not want a timer based event (Cursor, ...) to come in while we are\r
+  // doing this operation.\r
+  //\r
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  switch (BltOperation) {\r
+  case EfiBltVideoToBltBuffer:\r
+    for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {\r
+      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+      //\r
+      // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL\r
+      //\r
+      VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));\r
+      for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {\r
+        Pixel         = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;\r
+        Blt->Red      = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);\r
+        Blt->Blue     = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);\r
+        Blt->Green    = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);\r
+        Blt->Reserved = 0;\r
+        Blt++;\r
+        VbeBuffer += VbePixelWidth;\r
+      }\r
+\r
+    }\r
+    break;\r
+\r
+  case EfiBltVideoToVideo:\r
+    for (Index = 0; Index < Height; Index++) {\r
+      if (DestinationY <= SourceY) {\r
+        SrcY  = SourceY + Index;\r
+        DstY  = DestinationY + Index;\r
+      } else {\r
+        SrcY  = SourceY + Height - Index - 1;\r
+        DstY  = DestinationY + Height - Index - 1;\r
+      }\r
+\r
+      VbeBuffer   = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);\r
+      VbeBuffer1  = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);\r
+\r
+      gBS->CopyMem (\r
+            VbeBuffer,\r
+            VbeBuffer1,\r
+            TotalBytes\r
+            );\r
+\r
+      //\r
+      // Update physical frame buffer.\r
+      //\r
+      CopyVideoBuffer (\r
+        PciIo,\r
+        VbeBuffer,\r
+        MemAddress,\r
+        DestinationX,\r
+        DstY,\r
+        TotalBytes,\r
+        VbePixelWidth,\r
+        BytesPerScanLine\r
+        );\r
+    }\r
+    break;\r
+\r
+  case EfiBltVideoFill:\r
+    VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);\r
+    Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;\r
+    //\r
+    // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer\r
+    //\r
+    Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |\r
+      (\r
+        (Blt->Green & Mode->Green.Mask) <<\r
+        Mode->Green.Position\r
+      ) |\r
+          ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);\r
+\r
+    for (Index = 0; Index < Width; Index++) {\r
+      gBS->CopyMem (\r
+            VbeBuffer,\r
+            &Pixel,\r
+            VbePixelWidth\r
+            );\r
+      VbeBuffer += VbePixelWidth;\r
+    }\r
+\r
+    VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);\r
+    for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {\r
+      gBS->CopyMem (\r
+            (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),\r
+            VbeBuffer,\r
+            TotalBytes\r
+            );\r
+    }\r
+\r
+    for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {\r
+      //\r
+      // Update physical frame buffer.\r
+      //\r
+      CopyVideoBuffer (\r
+        PciIo,\r
+        VbeBuffer,\r
+        MemAddress,\r
+        DestinationX,\r
+        DstY,\r
+        TotalBytes,\r
+        VbePixelWidth,\r
+        BytesPerScanLine\r
+        );\r
+    }\r
+    break;\r
+\r
+  case EfiBltBufferToVideo:\r
+    for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {\r
+      Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+      VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));\r
+      for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {\r
+        //\r
+        // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer\r
+        //\r
+        Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |\r
+          ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |\r
+            ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);\r
+        gBS->CopyMem (\r
+              VbeBuffer,\r
+              &Pixel,\r
+              VbePixelWidth\r
+              );\r
+        Blt++;\r
+        VbeBuffer += VbePixelWidth;\r
+      }\r
+\r
+      VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));\r
+\r
+      //\r
+      // Update physical frame buffer.\r
+      //\r
+      CopyVideoBuffer (\r
+        PciIo,\r
+        VbeBuffer,\r
+        MemAddress,\r
+        DestinationX,\r
+        DstY,\r
+        TotalBytes,\r
+        VbePixelWidth,\r
+        BytesPerScanLine\r
+        );\r
+    }\r
+    break;\r
+\r
+    default: ;\r
+  }\r
+\r
+  gBS->RestoreTPL (OriginalTPL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Graphics Output protocol instance to block transfer for VBE device.\r
+\r
+  @param  This                   Pointer to Graphics Output protocol instance\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputVbeBlt (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV                 *BiosVideoPrivate;\r
+  BIOS_VIDEO_MODE_DATA           *Mode;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+  Mode              = &BiosVideoPrivate->ModeData[This->Mode->Mode];\r
+\r
+  return BiosVideoVbeBltWorker (\r
+           BiosVideoPrivate,\r
+           BltBuffer,\r
+           BltOperation,\r
+           SourceX,\r
+           SourceY,\r
+           DestinationX,\r
+           DestinationY,\r
+           Width,\r
+           Height,\r
+           Delta,\r
+           Mode\r
+           );\r
+}\r
+\r
+/**\r
+  Write graphics controller registers.\r
+\r
+  @param  PciIo                  Pointer to PciIo protocol instance of the\r
+                                 controller\r
+  @param  Address                Register address\r
+  @param  Data                   Data to be written to register\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+WriteGraphicsController (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  UINTN                Address,\r
+  IN  UINTN                Data\r
+  )\r
+{\r
+  Address = Address | (Data << 8);\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,\r
+              1,\r
+              &Address\r
+              );\r
+}\r
+\r
+\r
+/**\r
+  Read the four bit plane of VGA frame buffer.\r
+\r
+  @param  PciIo                  Pointer to PciIo protocol instance of the\r
+                                 controller\r
+  @param  HardwareBuffer         Hardware VGA frame buffer address\r
+  @param  MemoryBuffer           Memory buffer address\r
+  @param  WidthInBytes           Number of bytes in a line to read\r
+  @param  Height                 Height of the area to read\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+VgaReadBitPlanes (\r
+  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  UINT8                *HardwareBuffer,\r
+  UINT8                *MemoryBuffer,\r
+  UINTN                WidthInBytes,\r
+  UINTN                Height\r
+  )\r
+{\r
+  UINTN BitPlane;\r
+  UINTN Rows;\r
+  UINTN FrameBufferOffset;\r
+  UINT8 *Source;\r
+  UINT8 *Destination;\r
+\r
+  //\r
+  // Program the Mode Register Write mode 0, Read mode 0\r
+  //\r
+  WriteGraphicsController (\r
+    PciIo,\r
+    VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+    VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0\r
+    );\r
+\r
+  for (BitPlane = 0, FrameBufferOffset = 0;\r
+       BitPlane < VGA_NUMBER_OF_BIT_PLANES;\r
+       BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE\r
+      ) {\r
+    //\r
+    // Program the Read Map Select Register to select the correct bit plane\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,\r
+      BitPlane\r
+      );\r
+\r
+    Source      = HardwareBuffer;\r
+    Destination = MemoryBuffer + FrameBufferOffset;\r
+\r
+    for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {\r
+      PciIo->Mem.Read (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint8,\r
+                  EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                  (UINT64) (UINTN) Source,\r
+                  WidthInBytes,\r
+                  (VOID *) Destination\r
+                  );\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Internal routine to convert VGA color to Grahpics Output color.\r
+\r
+  @param  MemoryBuffer           Buffer containing VGA color\r
+  @param  CoordinateX            The X coordinate of pixel on screen\r
+  @param  CoordinateY            The Y coordinate of pixel on screen\r
+  @param  BltBuffer              Buffer to contain converted Grahpics Output color\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+VgaConvertToGraphicsOutputColor (\r
+  UINT8                          *MemoryBuffer,\r
+  UINTN                          CoordinateX,\r
+  UINTN                          CoordinateY,\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *BltBuffer\r
+  )\r
+{\r
+  UINTN Mask;\r
+  UINTN Bit;\r
+  UINTN Color;\r
+\r
+  MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));\r
+  Mask = mVgaBitMaskTable[CoordinateX & 0x07];\r
+  for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {\r
+    if ((*MemoryBuffer & Mask) != 0) {\r
+      Color |= Bit;\r
+    }\r
+  }\r
+\r
+  *BltBuffer = mVgaColorToGraphicsOutputColor[Color];\r
+}\r
+\r
+/**\r
+  Internal routine to convert Grahpics Output color to VGA color.\r
+\r
+  @param  BltBuffer              buffer containing Grahpics Output color\r
+\r
+  @return Converted VGA color\r
+\r
+**/\r
+UINT8\r
+VgaConvertColor (\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL          *BltBuffer\r
+  )\r
+{\r
+  UINT8 Color;\r
+\r
+  Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));\r
+  if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {\r
+    Color |= 0x08;\r
+  }\r
+\r
+  return Color;\r
+}\r
+\r
+\r
+/**\r
+  Grahpics Output protocol instance to block transfer for VGA device.\r
+\r
+  @param  This                   Pointer to Grahpics Output protocol instance\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputVgaBlt (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV      *BiosVideoPrivate;\r
+  EFI_TPL             OriginalTPL;\r
+  UINT8               *MemAddress;\r
+  UINTN               BytesPerScanLine;\r
+  UINTN               Bit;\r
+  UINTN               Index;\r
+  UINTN               Index1;\r
+  UINTN               StartAddress;\r
+  UINTN               Bytes;\r
+  UINTN               Offset;\r
+  UINT8               LeftMask;\r
+  UINT8               RightMask;\r
+  UINTN               Address;\r
+  UINTN               AddressFix;\r
+  UINT8               *Address1;\r
+  UINT8               *SourceAddress;\r
+  UINT8               *DestinationAddress;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  UINT8               Data;\r
+  UINT8               PixelColor;\r
+  UINT8               *VgaFrameBuffer;\r
+  UINTN               SourceOffset;\r
+  UINTN               SourceWidth;\r
+  UINTN               Rows;\r
+  UINTN               Columns;\r
+  UINTN               CoordinateX;\r
+  UINTN               CoordinateY;\r
+  UINTN               CurrentMode;\r
+\r
+  if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BiosVideoPrivate  = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);\r
+\r
+  CurrentMode = This->Mode->Mode;\r
+  PciIo             = BiosVideoPrivate->PciIo;\r
+  MemAddress        = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;\r
+  BytesPerScanLine  = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;\r
+  VgaFrameBuffer    = BiosVideoPrivate->VgaFrameBuffer;\r
+\r
+\r
+  if (Width == 0 || Height == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // We need to fill the Virtual Screen buffer with the blt data.\r
+  // The virtual screen is upside down, as the first row is the bootom row of\r
+  // the image.\r
+  //\r
+  if (BltOperation == EfiBltVideoToBltBuffer) {\r
+    //\r
+    // Video to BltBuffer: Source is Video, destination is BltBuffer\r
+    //\r
+    if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    // BltBuffer to Video: Source is BltBuffer, destination is Video\r
+    //\r
+    if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // If Delta is zero, then the entire BltBuffer is being used, so Delta\r
+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,\r
+  // the number of bytes in each row can be computed.\r
+  //\r
+  if (Delta == 0) {\r
+    Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
+  }\r
+  //\r
+  // We have to raise to TPL Notify, so we make an atomic write the frame buffer.\r
+  // We would not want a timer based event (Cursor, ...) to come in while we are\r
+  // doing this operation.\r
+  //\r
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  //\r
+  // Compute some values we need for VGA\r
+  //\r
+  switch (BltOperation) {\r
+  case EfiBltVideoToBltBuffer:\r
+\r
+    SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);\r
+    SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;\r
+\r
+    //\r
+    // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer\r
+    //\r
+    VgaReadBitPlanes (\r
+      PciIo,\r
+      MemAddress + SourceOffset,\r
+      VgaFrameBuffer + SourceOffset,\r
+      SourceWidth,\r
+      Height\r
+      );\r
+\r
+    //\r
+    // Convert VGA Bit Planes to a Graphics Output 32-bit color value\r
+    //\r
+    BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);\r
+    for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {\r
+      for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {\r
+        VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);\r
+      }\r
+\r
+      BltBuffer -= Width;\r
+    }\r
+\r
+    break;\r
+\r
+  case EfiBltVideoToVideo:\r
+    //\r
+    // Check for an aligned Video to Video operation\r
+    //\r
+    if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {\r
+      //\r
+      // Program the Mode Register Write mode 1, Read mode 0\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+        VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1\r
+        );\r
+\r
+      SourceAddress       = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));\r
+      DestinationAddress  = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));\r
+      Bytes               = Width >> 3;\r
+      for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {\r
+        PciIo->CopyMem (\r
+                PciIo,\r
+                EfiPciIoWidthUint8,\r
+                EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                (UINT64) (UINTN) (DestinationAddress + Offset),\r
+                EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                (UINT64) (UINTN) (SourceAddress + Offset),\r
+                Bytes\r
+                );\r
+      }\r
+    } else {\r
+      SourceOffset  = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);\r
+      SourceWidth   = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;\r
+\r
+      //\r
+      // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer\r
+      //\r
+      VgaReadBitPlanes (\r
+        PciIo,\r
+        MemAddress + SourceOffset,\r
+        VgaFrameBuffer + SourceOffset,\r
+        SourceWidth,\r
+        Height\r
+        );\r
+    }\r
+\r
+    break;\r
+\r
+  case EfiBltVideoFill:\r
+    StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));\r
+    Bytes         = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);\r
+    LeftMask      = mVgaLeftMaskTable[DestinationX & 0x07];\r
+    RightMask     = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];\r
+    if (Bytes == 0) {\r
+      LeftMask = (UINT8) (LeftMask & RightMask);\r
+      RightMask = 0;\r
+    }\r
+\r
+    if (LeftMask == 0xff) {\r
+      StartAddress--;\r
+      Bytes++;\r
+      LeftMask = 0;\r
+    }\r
+\r
+    if (RightMask == 0xff) {\r
+      Bytes++;\r
+      RightMask = 0;\r
+    }\r
+\r
+    PixelColor = VgaConvertColor (BltBuffer);\r
+\r
+    //\r
+    // Program the Mode Register Write mode 2, Read mode 0\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2\r
+      );\r
+\r
+    //\r
+    // Program the Data Rotate/Function Select Register to replace\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE\r
+      );\r
+\r
+    if (LeftMask != 0) {\r
+      //\r
+      // Program the BitMask register with the Left column mask\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+        LeftMask\r
+        );\r
+\r
+      for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {\r
+        //\r
+        // Read data from the bit planes into the latches\r
+        //\r
+        PciIo->Mem.Read (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &Data\r
+                    );\r
+        //\r
+        // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask\r
+        //\r
+        PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &PixelColor\r
+                    );\r
+      }\r
+    }\r
+\r
+    if (Bytes > 1) {\r
+      //\r
+      // Program the BitMask register with the middle column mask of 0xff\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+        0xff\r
+        );\r
+\r
+      for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {\r
+        PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthFillUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    Bytes - 1,\r
+                    &PixelColor\r
+                    );\r
+      }\r
+    }\r
+\r
+    if (RightMask != 0) {\r
+      //\r
+      // Program the BitMask register with the Right column mask\r
+      //\r
+      WriteGraphicsController (\r
+        PciIo,\r
+        VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+        RightMask\r
+        );\r
+\r
+      for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {\r
+        //\r
+        // Read data from the bit planes into the latches\r
+        //\r
+        PciIo->Mem.Read (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &Data\r
+                    );\r
+        //\r
+        // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask\r
+        //\r
+        PciIo->Mem.Write (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint8,\r
+                    EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                    (UINT64) (UINTN) Address,\r
+                    1,\r
+                    &PixelColor\r
+                    );\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EfiBltBufferToVideo:\r
+    StartAddress  = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));\r
+    LeftMask      = mVgaBitMaskTable[DestinationX & 0x07];\r
+\r
+    //\r
+    // Program the Mode Register Write mode 2, Read mode 0\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2\r
+      );\r
+\r
+    //\r
+    // Program the Data Rotate/Function Select Register to replace\r
+    //\r
+    WriteGraphicsController (\r
+      PciIo,\r
+      VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,\r
+      VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE\r
+      );\r
+\r
+    for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {\r
+      for (Index1 = 0; Index1 < Width; Index1++) {\r
+        BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);\r
+      }\r
+      AddressFix = Address;\r
+\r
+      for (Bit = 0; Bit < 8; Bit++) {\r
+        //\r
+        // Program the BitMask register with the Left column mask\r
+        //\r
+        WriteGraphicsController (\r
+          PciIo,\r
+          VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,\r
+          LeftMask\r
+          );\r
+\r
+        for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {\r
+          //\r
+          // Read data from the bit planes into the latches\r
+          //\r
+          PciIo->Mem.Read (\r
+                      PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      (UINT64) (UINTN) Address1,\r
+                      1,\r
+                      &Data\r
+                      );\r
+\r
+          PciIo->Mem.Write (\r
+                      PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      (UINT64) (UINTN) Address1,\r
+                      1,\r
+                      &BiosVideoPrivate->LineBuffer[Index1]\r
+                      );\r
+        }\r
+\r
+        LeftMask = (UINT8) (LeftMask >> 1);\r
+        if (LeftMask == 0) {\r
+          LeftMask = 0x80;\r
+          AddressFix++;\r
+        }\r
+      }\r
+    }\r
+\r
+    break;\r
+\r
+    default: ;\r
+  }\r
+\r
+  gBS->RestoreTPL (OriginalTPL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// VGA Mini Port Protocol Functions\r
+//\r
+\r
+/**\r
+  VgaMiniPort protocol interface to set mode.\r
+\r
+  @param  This                   Pointer to VgaMiniPort protocol instance\r
+  @param  ModeNumber             The index of the mode\r
+\r
+  @retval EFI_UNSUPPORTED        The requested mode is not supported\r
+  @retval EFI_SUCCESS            The requested mode is set successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoVgaMiniPortSetMode (\r
+  IN  EFI_VGA_MINI_PORT_PROTOCOL  *This,\r
+  IN  UINTN                       ModeNumber\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV        *BiosVideoPrivate;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Make sure the ModeNumber is a valid value\r
+  //\r
+  if (ModeNumber >= This->MaxMode) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Get the device structure for this device\r
+  //\r
+  BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);\r
+\r
+  switch (ModeNumber) {\r
+  case 0:\r
+    //\r
+    // Set the 80x25 Text VGA Mode\r
+    //\r
+    Regs.H.AH = 0x00;\r
+    Regs.H.AL = 0x83;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+    Regs.H.AH = 0x11;\r
+    Regs.H.AL = 0x14;\r
+    Regs.H.BL = 0;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    break;\r
+\r
+  case 1:\r
+    //\r
+    // Set the 80x50 Text VGA Mode\r
+    //\r
+    Regs.H.AH = 0x00;\r
+    Regs.H.AL = 0x83;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    Regs.H.AH = 0x11;\r
+    Regs.H.AL = 0x12;\r
+    Regs.H.BL = 0;\r
+    BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+    break;\r
+\r
+  default:\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Event handler for Exit Boot Service.\r
+\r
+  @param  Event       The event that be siganlled when exiting boot service.\r
+  @param  Context     Pointer to instance of BIOS_VIDEO_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BiosVideoNotifyExitBootServices (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  )\r
+{\r
+  BIOS_VIDEO_DEV         *BiosVideoPrivate;\r
+  EFI_IA32_REGISTER_SET  Regs;\r
+\r
+  BiosVideoPrivate  = (BIOS_VIDEO_DEV *)Context;\r
+\r
+  //\r
+  // Set the 80x25 Text VGA Mode\r
+  //\r
+  Regs.H.AH = 0x00;\r
+  Regs.H.AL = 0x03;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Regs.H.AH = 0x00;\r
+  Regs.H.AL = 0x83;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+\r
+  Regs.H.AH = 0x11;\r
+  Regs.H.AL = 0x04;\r
+  Regs.H.BL = 0;\r
+  BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
+}\r
+\r
+/**\r
+  The user Entry Point for module UefiBiosVideo. The user code starts with this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoEntryPoint(\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gBiosVideoDriverBinding,\r
+             ImageHandle,\r
+             &gBiosVideoComponentName,\r
+             &gBiosVideoComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver\r
+  //\r
+  return gBS->InstallMultipleProtocolInterfaces (\r
+                &ImageHandle,\r
+                &gEfiLegacyBiosGuid,\r
+                NULL,\r
+                NULL\r
+                );\r
+}\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h
new file mode 100644 (file)
index 0000000..45a75b9
--- /dev/null
@@ -0,0 +1,532 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _BIOS_GRAPHICS_OUTPUT_H_\r
+#define _BIOS_GRAPHICS_OUTPUT_H_\r
+\r
+#include <FrameworkDxe.h>\r
+\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/EdidActive.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/EdidDiscovered.h>\r
+#include <Protocol/LegacyBios.h>\r
+#include <Protocol/VgaMiniPort.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Protocol/EdidOverride.h>\r
+\r
+#include <Guid/StatusCodeDataTypeId.h>\r
+#include <Guid/LegacyBios.h>\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include "VesaBiosExtensions.h"\r
+\r
+//\r
+// Packed format support: The number of bits reserved for each of the colors and the actual\r
+// position of RGB in the frame buffer is specified in the VBE Mode information\r
+//\r
+typedef struct {\r
+  UINT8 Position; // Position of the color\r
+  UINT8 Mask;     // The number of bits expressed as a mask\r
+} BIOS_VIDEO_COLOR_PLACEMENT;\r
+\r
+//\r
+// BIOS Graphics Output Graphical Mode Data\r
+//\r
+typedef struct {\r
+  UINT16                      VbeModeNumber;\r
+  UINT16                      BytesPerScanLine;\r
+  VOID                        *LinearFrameBuffer;\r
+  UINTN                       FrameBufferSize;\r
+  UINT32                      HorizontalResolution;\r
+  UINT32                      VerticalResolution;\r
+  UINT32                      ColorDepth;\r
+  UINT32                      RefreshRate;\r
+  UINT32                      BitsPerPixel;\r
+  BIOS_VIDEO_COLOR_PLACEMENT  Red;\r
+  BIOS_VIDEO_COLOR_PLACEMENT  Green;\r
+  BIOS_VIDEO_COLOR_PLACEMENT  Blue;\r
+  BIOS_VIDEO_COLOR_PLACEMENT  Reserved;\r
+  EFI_GRAPHICS_PIXEL_FORMAT   PixelFormat;\r
+  EFI_PIXEL_BITMASK           PixelBitMask;\r
+} BIOS_VIDEO_MODE_DATA;\r
+\r
+//\r
+// BIOS video child handle private data Structure\r
+//\r
+#define BIOS_VIDEO_DEV_SIGNATURE    SIGNATURE_32 ('B', 'V', 'M', 'p')\r
+\r
+typedef struct {\r
+  UINTN                                       Signature;\r
+  EFI_HANDLE                                  Handle;\r
+\r
+  //\r
+  // Consumed Protocols\r
+  //\r
+  EFI_PCI_IO_PROTOCOL                         *PciIo;\r
+  EFI_LEGACY_BIOS_PROTOCOL                    *LegacyBios;\r
+  //\r
+  // Original PCI attributes\r
+  //\r
+  UINT64                                      OriginalPciAttributes;\r
+\r
+  //\r
+  // Produced Protocols\r
+  //\r
+  EFI_GRAPHICS_OUTPUT_PROTOCOL                GraphicsOutput;\r
+  EFI_EDID_DISCOVERED_PROTOCOL                EdidDiscovered;\r
+  EFI_EDID_ACTIVE_PROTOCOL                    EdidActive;\r
+  EFI_VGA_MINI_PORT_PROTOCOL                  VgaMiniPort;\r
+\r
+  //\r
+  // General fields\r
+  //\r
+  BOOLEAN                                     VgaCompatible;\r
+  BOOLEAN                                     ProduceGraphicsOutput;\r
+\r
+  //\r
+  // Graphics Output Protocol related fields\r
+  //\r
+  BOOLEAN                                     HardwareNeedsStarting;\r
+  UINTN                                       CurrentMode;\r
+  UINTN                                       MaxMode;\r
+  BIOS_VIDEO_MODE_DATA                        *ModeData;\r
+  UINT8                                       *LineBuffer;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL               *VbeFrameBuffer;\r
+  UINT8                                       *VgaFrameBuffer;\r
+\r
+  //\r
+  // VESA Bios Extensions related fields\r
+  //\r
+  UINTN                                       NumberOfPagesBelow1MB;     // Number of 4KB pages in PagesBelow1MB\r
+  EFI_PHYSICAL_ADDRESS                        PagesBelow1MB;             // Buffer for all VBE Information Blocks\r
+  VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK      *VbeInformationBlock;      // 0x200 bytes.  Must be allocated below 1MB\r
+  VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *VbeModeInformationBlock;  // 0x100 bytes.  Must be allocated below 1MB\r
+  VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK        *VbeEdidDataBlock;         // 0x80  bytes.  Must be allocated below 1MB\r
+  VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *VbeCrtcInformationBlock;  // 59 bytes.  Must be allocated below 1MB\r
+  UINTN                                       VbeSaveRestorePages;       // Number of 4KB pages in VbeSaveRestoreBuffer\r
+  EFI_PHYSICAL_ADDRESS                        VbeSaveRestoreBuffer;      // Must be allocated below 1MB\r
+  //\r
+  // Status code\r
+  //\r
+  EFI_DEVICE_PATH_PROTOCOL                    *GopDevicePath;\r
+\r
+  EFI_EVENT                                   ExitBootServicesEvent;\r
+} BIOS_VIDEO_DEV;\r
+\r
+#define BIOS_VIDEO_DEV_FROM_PCI_IO_THIS(a)           CR (a, BIOS_VIDEO_DEV, PciIo, BIOS_VIDEO_DEV_SIGNATURE)\r
+#define BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS(a)  CR (a, BIOS_VIDEO_DEV, GraphicsOutput, BIOS_VIDEO_DEV_SIGNATURE)\r
+#define BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS(a)    CR (a, BIOS_VIDEO_DEV, VgaMiniPort, BIOS_VIDEO_DEV_SIGNATURE)\r
+\r
+#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER  0xffff\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL   gBiosVideoDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gBiosVideoComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL  gBiosVideoComponentName2;\r
+\r
+//\r
+// Driver Binding Protocol functions\r
+//\r
+\r
+/**\r
+  Supported.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  RemainingDevicePath    A pointer to the remaining portion of a device\r
+                                 path\r
+\r
+  @retval EFI_STATUS             EFI_SUCCESS:This controller can be managed by this\r
+                                 driver, Otherwise, this controller cannot be\r
+                                 managed by this driver\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+\r
+/**\r
+  Install Graphics Output Protocol onto VGA device handles.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  RemainingDevicePath    A pointer to the remaining portion of a device\r
+                                 path\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+\r
+/**\r
+  Stop.\r
+\r
+  @param  This                   Pointer to driver binding protocol\r
+  @param  Controller             Controller handle to connect\r
+  @param  NumberOfChildren       Number of children handle created by this driver\r
+  @param  ChildHandleBuffer      Buffer containing child handle created\r
+\r
+  @retval EFI_SUCCESS            Driver disconnected successfully from controller\r
+  @retval EFI_UNSUPPORTED        Cannot find BIOS_VIDEO_DEV structure\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   Controller,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// Private worker functions\r
+//\r
+\r
+/**\r
+  Check for VBE device.\r
+\r
+  @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure\r
+\r
+  @retval EFI_SUCCESS            VBE device found\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoCheckForVbe (\r
+  IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  );\r
+\r
+\r
+/**\r
+  Check for VGA device.\r
+\r
+  @param  BiosVideoPrivate       Pointer to BIOS_VIDEO_DEV structure\r
+\r
+  @retval EFI_SUCCESS            Standard VGA device found\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoCheckForVga (\r
+  IN OUT BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  );\r
+\r
+\r
+\r
+\r
+/**\r
+  Release resource for biso video instance.\r
+\r
+  @param  BiosVideoPrivate       Video child device private data structure\r
+\r
+**/\r
+VOID\r
+BiosVideoDeviceReleaseResource (\r
+  BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  );\r
+\r
+//\r
+// BIOS Graphics Output Protocol functions\r
+//\r
+\r
+/**\r
+  Graphics Output protocol interface to get video mode.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ModeNumber             The mode number to return information on.\r
+  @param  SizeOfInfo             A pointer to the size, in bytes, of the Info\r
+                                 buffer.\r
+  @param  Info                   Caller allocated buffer that returns information\r
+                                 about ModeNumber.\r
+\r
+  @retval EFI_SUCCESS            Mode information returned.\r
+  @retval EFI_BUFFER_TOO_SMALL   The Info buffer was too small.\r
+  @retval EFI_DEVICE_ERROR       A hardware error occurred trying to retrieve the\r
+                                 video mode.\r
+  @retval EFI_NOT_STARTED        Video display is not initialized. Call SetMode ()\r
+  @retval EFI_INVALID_PARAMETER  One of the input args was NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputQueryMode (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,\r
+  IN  UINT32                                ModeNumber,\r
+  OUT UINTN                                 *SizeOfInfo,\r
+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info\r
+  );\r
+\r
+\r
+/**\r
+  Graphics Output protocol interface to set video mode.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ModeNumber             The mode number to be set.\r
+\r
+  @retval EFI_SUCCESS            Graphics mode was changed.\r
+  @retval EFI_DEVICE_ERROR       The device had an error and could not complete the\r
+                                 request.\r
+  @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputSetMode (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,\r
+  IN  UINT32                       ModeNumber\r
+  );\r
+\r
+\r
+/**\r
+  Graphics Output protocol instance to block transfer for VBE device.\r
+\r
+  @param  This                   Pointer to Graphics Output protocol instance\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputVbeBlt (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta\r
+  );\r
+\r
+\r
+/**\r
+  Grahpics Output protocol instance to block transfer for VGA device.\r
+\r
+  @param  This                   Pointer to Grahpics Output protocol instance\r
+  @param  BltBuffer              The data to transfer to screen\r
+  @param  BltOperation           The operation to perform\r
+  @param  SourceX                The X coordinate of the source for BltOperation\r
+  @param  SourceY                The Y coordinate of the source for BltOperation\r
+  @param  DestinationX           The X coordinate of the destination for\r
+                                 BltOperation\r
+  @param  DestinationY           The Y coordinate of the destination for\r
+                                 BltOperation\r
+  @param  Width                  The width of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Height                 The height of a rectangle in the blt rectangle in\r
+                                 pixels\r
+  @param  Delta                  Not used for EfiBltVideoFill and\r
+                                 EfiBltVideoToVideo operation. If a Delta of 0 is\r
+                                 used, the entire BltBuffer will be operated on. If\r
+                                 a subrectangle of the BltBuffer is used, then\r
+                                 Delta represents the number of bytes in a row of\r
+                                 the BltBuffer.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter passed in\r
+  @retval EFI_SUCCESS            Blt operation success\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoGraphicsOutputVgaBlt (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL\r
+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,\r
+  IN  UINTN                              SourceX,\r
+  IN  UINTN                              SourceY,\r
+  IN  UINTN                              DestinationX,\r
+  IN  UINTN                              DestinationY,\r
+  IN  UINTN                              Width,\r
+  IN  UINTN                              Height,\r
+  IN  UINTN                              Delta\r
+  );\r
+\r
+//\r
+// BIOS VGA Mini Port Protocol functions\r
+//\r
+\r
+/**\r
+  VgaMiniPort protocol interface to set mode.\r
+\r
+  @param  This                   Pointer to VgaMiniPort protocol instance\r
+  @param  ModeNumber             The index of the mode\r
+\r
+  @retval EFI_UNSUPPORTED        The requested mode is not supported\r
+  @retval EFI_SUCCESS            The requested mode is set successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoVgaMiniPortSetMode (\r
+  IN  EFI_VGA_MINI_PORT_PROTOCOL  *This,\r
+  IN  UINTN                       ModeNumber\r
+  );\r
+\r
+/**\r
+  Event handler for Exit Boot Service.\r
+\r
+  @param  Event       The event that be siganlled when exiting boot service.\r
+  @param  Context     Pointer to instance of BIOS_VIDEO_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BiosVideoNotifyExitBootServices (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  );\r
+\r
+//\r
+// Standard VGA Definitions\r
+//\r
+#define VGA_HORIZONTAL_RESOLUTION                         640\r
+#define VGA_VERTICAL_RESOLUTION                           480\r
+#define VGA_NUMBER_OF_BIT_PLANES                          4\r
+#define VGA_PIXELS_PER_BYTE                               8\r
+#define VGA_BYTES_PER_SCAN_LINE                           (VGA_HORIZONTAL_RESOLUTION / VGA_PIXELS_PER_BYTE)\r
+#define VGA_BYTES_PER_BIT_PLANE                           (VGA_VERTICAL_RESOLUTION * VGA_BYTES_PER_SCAN_LINE)\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER          0x3ce\r
+#define VGA_GRAPHICS_CONTROLLER_DATA_REGISTER             0x3cf\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_SET_RESET_REGISTER        0x00\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_ENABLE_SET_RESET_REGISTER 0x01\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_COLOR_COMPARE_REGISTER    0x02\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER      0x03\r
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE          0x00\r
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_AND              0x08\r
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_OR               0x10\r
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_XOR              0x18\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER  0x04\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_MODE_REGISTER             0x05\r
+#define VGA_GRAPHICS_CONTROLLER_READ_MODE_0               0x00\r
+#define VGA_GRAPHICS_CONTROLLER_READ_MODE_1               0x08\r
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0              0x00\r
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1              0x01\r
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2              0x02\r
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_3              0x03\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_MISCELLANEOUS_REGISTER    0x06\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_COLOR_DONT_CARE_REGISTER  0x07\r
+\r
+#define VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER         0x08\r
+\r
+/**\r
+  Install child handles if the Handle supports MBR format.\r
+\r
+  @param  This                   Calling context.\r
+  @param  ParentHandle           Parent Handle\r
+  @param  ParentPciIo            Parent PciIo interface\r
+  @param  ParentLegacyBios       Parent LegacyBios interface\r
+  @param  ParentDevicePath       Parent Device Path\r
+  @param  RemainingDevicePath    Remaining Device Path\r
+  @param  OriginalPciAttributes  Original PCI Attributes\r
+\r
+  @retval EFI_SUCCESS            If a child handle was added\r
+  @retval other                  A child handle was not added\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoChildHandleInstall (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ParentHandle,\r
+  IN  EFI_PCI_IO_PROTOCOL          *ParentPciIo,\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL     *ParentLegacyBios,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath,\r
+  IN  UINT64                       OriginalPciAttributes\r
+  );\r
+\r
+/**\r
+  Deregister an video child handle and free resources.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  Controller             Video controller handle\r
+  @param  Handle                 Video child handle\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+BiosVideoChildHandleUninstall (\r
+  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  EFI_HANDLE                     Controller,\r
+  EFI_HANDLE                     Handle\r
+  );\r
+\r
+/**\r
+  Release resource for biso video instance.\r
+\r
+  @param  BiosVideoPrivate       Video child device private data structure\r
+\r
+**/\r
+VOID\r
+BiosVideoDeviceReleaseResource (\r
+  BIOS_VIDEO_DEV  *BiosVideoPrivate\r
+  );\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..1d70e5c
--- /dev/null
@@ -0,0 +1,313 @@
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "BiosVideo.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gBiosVideoComponentName = {\r
+  BiosVideoComponentNameGetDriverName,\r
+  BiosVideoComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosVideoComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosVideoComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosVideoComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosVideoDriverNameTable[] = {\r
+  {\r
+    "eng;en",\r
+    L"BIOS[INT10] Video Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mBiosVideoDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gBiosVideoComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BiosVideoComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h
new file mode 100644 (file)
index 0000000..dcda3fc
--- /dev/null
@@ -0,0 +1,451 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _VESA_BIOS_EXTENSIONS_H_\r
+#define _VESA_BIOS_EXTENSIONS_H_\r
+\r
+//\r
+// Turn on byte packing of data structures\r
+//\r
+#pragma pack(1)\r
+//\r
+// VESA BIOS Extensions status codes\r
+//\r
+#define VESA_BIOS_EXTENSIONS_STATUS_SUCCESS 0x004f\r
+\r
+//\r
+// VESA BIOS Extensions Services\r
+//\r
+#define VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION  0x4f00\r
+\r
+/*++\r
+\r
+  Routine Description:\r
+    Function 00 : Return Controller Information\r
+\r
+  Arguments:\r
+    Inputs:\r
+      AX    = 0x4f00\r
+      ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK structure\r
+    Outputs:\r
+      AX    = Return Status\r
+\r
+--*/\r
+#define VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION  0x4f01\r
+\r
+/*++\r
+\r
+  Routine Description:\r
+    Function 01 : Return Mode Information\r
+\r
+  Arguments:\r
+    Inputs:\r
+      AX    = 0x4f01\r
+      CX    = Mode Number\r
+      ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK structure\r
+    Outputs:\r
+      AX    = Return Status\r
+\r
+--*/\r
+#define VESA_BIOS_EXTENSIONS_SET_MODE 0x4f02\r
+\r
+/*++\r
+\r
+  Routine Description:\r
+    Function 02 : Set Mode\r
+\r
+  Arguments:\r
+    Inputs:\r
+      AX    = 0x4f02\r
+      BX    = Desired mode to set\r
+        D0-D8   = Mode Number\r
+        D9-D10  = Reserved (must be 0)\r
+        D11     = 0 - Use current default refresh rate\r
+                = 1 - Use user specfieid CRTC values for refresh rate\r
+        D12-D13 = Reserved (must be 0)\r
+        D14     = 0 - Use windowed frame buffer model\r
+                = 1 - Use linear/flat frame buffer model\r
+        D15     = 0 - Clear display memory\r
+                = 1 - Don't clear display memory\r
+      ES:DI = Pointer to buffer to the VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK structure\r
+    Outputs:\r
+      AX    = Return Status\r
+\r
+--*/\r
+#define VESA_BIOS_EXTENSIONS_RETURN_CURRENT_MODE  0x4f03\r
+\r
+/*++\r
+\r
+  Routine Description:\r
+    Function 03 : Return Current Mode\r
+\r
+  Arguments:\r
+    Inputs:\r
+      AX    = 0x4f03\r
+    Outputs:\r
+      AX    = Return Status\r
+      BX    = Current mode\r
+        D0-D13  = Mode Number\r
+        D14     = 0 - Windowed frame buffer model\r
+                = 1 - Linear/flat frame buffer model\r
+        D15     = 0 - Memory cleared at last mode set\r
+                = 1 - Memory not cleared at last mode set\r
+\r
+--*/\r
+#define VESA_BIOS_EXTENSIONS_SAVE_RESTORE_STATE 0x4f04\r
+\r
+/*++\r
+\r
+  Routine Description:\r
+    Function 04 : Save/Restore State\r
+\r
+  Arguments:\r
+    Inputs:\r
+      AX    = 0x4f03\r
+      DL    = 0x00 - Return Save/Restore State buffer size\r
+            = 0x01 - Save State\r
+            = 0x02 - Restore State\r
+      CX    = Requested Status\r
+        D0  = Save/Restore controller hardware state\r
+        D1  = Save/Restore BIOS data state\r
+        D2  = Save/Restore DAC state\r
+        D3  = Save/Restore Regsiter state\r
+      ES:BX = Pointer to buffer if DL=1 or DL=2\r
+    Outputs:\r
+      AX    = Return Status\r
+      BX    = Number of 64 byte blocks to hold the state buffer if DL=0\r
+\r
+--*/\r
+#define VESA_BIOS_EXTENSIONS_EDID  0x4f15\r
+\r
+/*++\r
+\r
+  Routine Description:\r
+    Function 15 : implement VBE/DDC service\r
+\r
+  Arguments:\r
+    Inputs:\r
+      AX    = 0x4f15\r
+      BL    = 0x00 - Report VBE/DDC Capabilities\r
+      CX    = 0x00 - Controller unit number (00 = primary controller)\r
+      ES:DI = Null pointer, must be 0:0 in version 1.0\r
+    Outputs:\r
+      AX    = Return Status\r
+      BH    = Approx. time in seconds, rounded up, to transfer one EDID block(128 bytes)\r
+      BL    = DDC level supported\r
+        D0  = 0 DDC1 not supported\r
+            = 1 DDC1 supported\r
+        D1  = 0 DDC2 not supported\r
+            = 1 DDC2 supported\r
+        D2  = 0 Screen not blanked during data transfer\r
+            = 1 Screen blanked during data transfer\r
+\r
+    Inputs:\r
+      AX    = 0x4f15\r
+      BL    = 0x01 - Read EDID\r
+      CX    = 0x00 - Controller unit number (00 = primary controller)\r
+      DX    = 0x00 - EDID block number\r
+      ES:DI = Pointer to buffer in which the EDID block is returned\r
+    Outputs:\r
+      AX    = Return Status\r
+--*/\r
+\r
+//\r
+// Timing data from EDID data block\r
+//\r
+#define VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE                    128\r
+#define VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17\r
+\r
+typedef struct {\r
+  UINT16  HorizontalResolution;\r
+  UINT16  VerticalResolution;\r
+  UINT16  RefreshRate;\r
+} VESA_BIOS_EXTENSIONS_EDID_TIMING;\r
+\r
+typedef struct {\r
+  UINT32  ValidNumber;\r
+  UINT32  Key[VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER];\r
+} VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING;\r
+\r
+typedef struct {\r
+  UINT8   Header[8];                        //EDID header "00 FF FF FF FF FF FF 00"\r
+  UINT16  ManufactureName;                  //EISA 3-character ID\r
+  UINT16  ProductCode;                      //Vendor assigned code\r
+  UINT32  SerialNumber;                     //32-bit serial number\r
+  UINT8   WeekOfManufacture;                //Week number\r
+  UINT8   YearOfManufacture;                //Year\r
+  UINT8   EdidVersion;                      //EDID Structure Version\r
+  UINT8   EdidRevision;                     //EDID Structure Revision\r
+  UINT8   VideoInputDefinition;\r
+  UINT8   MaxHorizontalImageSize;           //cm\r
+  UINT8   MaxVerticalImageSize;             //cm\r
+  UINT8   DisplayTransferCharacteristic;\r
+  UINT8   FeatureSupport;\r
+  UINT8   RedGreenLowBits;                  //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0\r
+  UINT8   BlueWhiteLowBits;                 //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0\r
+  UINT8   RedX;                             //Red-x Bits 9 - 2\r
+  UINT8   RedY;                             //Red-y Bits 9 - 2\r
+  UINT8   GreenX;                           //Green-x Bits 9 - 2\r
+  UINT8   GreenY;                           //Green-y Bits 9 - 2\r
+  UINT8   BlueX;                            //Blue-x Bits 9 - 2\r
+  UINT8   BlueY;                            //Blue-y Bits 9 - 2\r
+  UINT8   WhiteX;                           //White-x Bits 9 - 2\r
+  UINT8   WhiteY;                           //White-x Bits 9 - 2\r
+  UINT8   EstablishedTimings[3];\r
+  UINT8   StandardTimingIdentification[16];\r
+  UINT8   DetailedTimingDescriptions[72];\r
+  UINT8   ExtensionFlag;                    //Number of (optional) 128-byte EDID extension blocks to follow\r
+  UINT8   Checksum;\r
+} VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK;\r
+\r
+//\r
+// Super VGA Information Block\r
+//\r
+typedef struct {\r
+  UINT32  VESASignature;      // 'VESA' 4 byte signature\r
+  UINT16  VESAVersion;        // VBE version number\r
+  UINT32  OEMStringPtr;      // Pointer to OEM string\r
+  UINT32  Capabilities;       // Capabilities of video card\r
+  UINT32  VideoModePtr;      // Pointer to an array of 16-bit supported modes values terminated by 0xFFFF\r
+  UINT16  TotalMemory;        // Number of 64kb memory blocks\r
+  UINT16  OemSoftwareRev;     // VBE implementation Software revision\r
+  UINT32  OemVendorNamePtr;  // VbeFarPtr to Vendor Name String\r
+  UINT32  OemProductNamePtr; // VbeFarPtr to Product Name String\r
+  UINT32  OemProductRevPtr;  // VbeFarPtr to Product Revision String\r
+  UINT8   Reserved[222];      // Reserved for VBE implementation scratch area\r
+  UINT8   OemData[256];       // Data area for OEM strings.  Pad to 512 byte block size\r
+} VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK;\r
+\r
+//\r
+// Super VGA Information Block VESASignature values\r
+//\r
+#define VESA_BIOS_EXTENSIONS_VESA_SIGNATURE SIGNATURE_32 ('V', 'E', 'S', 'A')\r
+#define VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE SIGNATURE_32 ('V', 'B', 'E', '2')\r
+\r
+//\r
+// Super VGA Information Block VESAVersion values\r
+//\r
+#define VESA_BIOS_EXTENSIONS_VERSION_1_2  0x0102\r
+#define VESA_BIOS_EXTENSIONS_VERSION_2_0  0x0200\r
+#define VESA_BIOS_EXTENSIONS_VERSION_3_0  0x0300\r
+\r
+//\r
+// Super VGA Information Block Capabilities field bit defintions\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_8_BIT_DAC 0x01  // 0: DAC width is fixed at 6 bits/color\r
+// 1: DAC width switchable to 8 bits/color\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_VGA 0x02  // 0: Controller is VGA compatible\r
+// 1: Controller is not VGA compatible\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_NORMAL_RAMDAC 0x04  // 0: Normal RAMDAC operation\r
+// 1: Use blank bit in function 9 to program RAMDAC\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_STEREOSCOPIC  0x08  // 0: No hardware stereoscopic signal support\r
+// 1: Hardware stereoscopic signal support\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_VESA_EVC  0x10  // 0: Stero signaling supported via external VESA stereo connector\r
+// 1: Stero signaling supported via VESA EVC connector\r
+//\r
+// Super VGA mode number bite field definitions\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA 0x0100  // 0: Not a VESA defined VBE mode\r
+// 1: A VESA defined VBE mode\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_REFRESH_CONTROL_USER 0x0800  // 0: Use current BIOS default referesh rate\r
+// 1: Use the user specified CRTC values for refresh rate\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER  0x4000  // 0: Use a banked/windowed frame buffer\r
+// 1: Use a linear/flat frame buffer\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_PRESERVE_MEMORY  0x8000  // 0: Clear display memory\r
+// 1: Preseve display memory\r
+//\r
+// Super VGA Information Block mode list terminator value\r
+//\r
+#define VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST 0xffff\r
+\r
+//\r
+// Window Function\r
+//\r
+typedef\r
+VOID\r
+(*VESA_BIOS_EXTENSIONS_WINDOW_FUNCTION) (\r
+  VOID\r
+  );\r
+\r
+//\r
+// Super VGA Mode Information Block\r
+//\r
+typedef struct {\r
+  //\r
+  // Manadory fields for all VESA Bios Extensions revisions\r
+  //\r
+  UINT16                                ModeAttributes;   // Mode attributes\r
+  UINT8                                 WinAAttributes;   // Window A attributes\r
+  UINT8                                 WinBAttributes;   // Window B attributes\r
+  UINT16                                WinGranularity;   // Window granularity in k\r
+  UINT16                                WinSize;          // Window size in k\r
+  UINT16                                WinASegment;      // Window A segment\r
+  UINT16                                WinBSegment;      // Window B segment\r
+  UINT32                                WindowFunction;   // Pointer to window function\r
+  UINT16                                BytesPerScanLine; // Bytes per scanline\r
+  //\r
+  // Manadory fields for VESA Bios Extensions 1.2 and above\r
+  //\r
+  UINT16                                XResolution;          // Horizontal resolution\r
+  UINT16                                YResolution;          // Vertical resolution\r
+  UINT8                                 XCharSize;            // Character cell width\r
+  UINT8                                 YCharSize;            // Character cell height\r
+  UINT8                                 NumberOfPlanes;       // Number of memory planes\r
+  UINT8                                 BitsPerPixel;         // Bits per pixel\r
+  UINT8                                 NumberOfBanks;        // Number of CGA style banks\r
+  UINT8                                 MemoryModel;          // Memory model type\r
+  UINT8                                 BankSize;             // Size of CGA style banks\r
+  UINT8                                 NumberOfImagePages;   // Number of images pages\r
+  UINT8                                 Reserved1;            // Reserved\r
+  UINT8                                 RedMaskSize;          // Size of direct color red mask\r
+  UINT8                                 RedFieldPosition;     // Bit posn of lsb of red mask\r
+  UINT8                                 GreenMaskSize;        // Size of direct color green mask\r
+  UINT8                                 GreenFieldPosition;   // Bit posn of lsb of green mask\r
+  UINT8                                 BlueMaskSize;         // Size of direct color blue mask\r
+  UINT8                                 BlueFieldPosition;    // Bit posn of lsb of blue mask\r
+  UINT8                                 RsvdMaskSize;         // Size of direct color res mask\r
+  UINT8                                 RsvdFieldPosition;    // Bit posn of lsb of res mask\r
+  UINT8                                 DirectColorModeInfo;  // Direct color mode attributes\r
+  //\r
+  // Manadory fields for VESA Bios Extensions 2.0 and above\r
+  //\r
+  UINT32                                PhysBasePtr;  // Physical Address for flat memory frame buffer\r
+  UINT32                                Reserved2;    // Reserved\r
+  UINT16                                Reserved3;    // Reserved\r
+  //\r
+  // Manadory fields for VESA Bios Extensions 3.0 and above\r
+  //\r
+  UINT16                                LinBytesPerScanLine;    // Bytes/scan line for linear modes\r
+  UINT8                                 BnkNumberOfImagePages;  // Number of images for banked modes\r
+  UINT8                                 LinNumberOfImagePages;  // Number of images for linear modes\r
+  UINT8                                 LinRedMaskSize;         // Size of direct color red mask (linear mode)\r
+  UINT8                                 LinRedFieldPosition;    // Bit posiiton of lsb of red mask (linear modes)\r
+  UINT8                                 LinGreenMaskSize;       // Size of direct color green mask (linear mode)\r
+  UINT8                                 LinGreenFieldPosition;  // Bit posiiton of lsb of green mask (linear modes)\r
+  UINT8                                 LinBlueMaskSize;        // Size of direct color blue mask (linear mode)\r
+  UINT8                                 LinBlueFieldPosition;   // Bit posiiton of lsb of blue mask (linear modes)\r
+  UINT8                                 LinRsvdMaskSize;        // Size of direct color reserved mask (linear mode)\r
+  UINT8                                 LinRsvdFieldPosition;   // Bit posiiton of lsb of reserved mask (linear modes)\r
+  UINT32                                MaxPixelClock;          // Maximum pixel clock (in Hz) for graphics mode\r
+  UINT8                                 Pad[190];               // Pad to 256 byte block size\r
+} VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK;\r
+\r
+//\r
+// Super VGA Mode Information Block ModeAttributes field bit defintions\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_HARDWARE  0x0001  // 0: Mode not supported in handware\r
+// 1: Mode supported in handware\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_TTY 0x0004  // 0: TTY Output functions not supported by BIOS\r
+// 1: TTY Output functions supported by BIOS\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR 0x0008  // 0: Monochrome mode\r
+// 1: Color mode\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS  0x0010  // 0: Text mode\r
+// 1: Graphics mode\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_VGA 0x0020  // 0: VGA compatible mode\r
+// 1: Not a VGA compatible mode\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_WINDOWED  0x0040  // 0: VGA compatible windowed memory mode\r
+// 1: Not a VGA compatible windowed memory mode\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER 0x0080  // 0: No linear fram buffer mode available\r
+// 1: Linear frame buffer mode available\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DOUBLE_SCAN 0x0100  // 0: No double scan mode available\r
+// 1: Double scan mode available\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_INTERLACED  0x0200  // 0: No interlaced mode is available\r
+// 1: Interlaced mode is available\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NO_TRIPPLE_BUFFER 0x0400  // 0: No hardware triple buffer mode support available\r
+// 1: Hardware triple buffer mode support available\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_STEREOSCOPIC  0x0800  // 0: No hardware steroscopic display support\r
+// 1: Hardware steroscopic display support\r
+//\r
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DUAL_DISPLAY  0x1000  // 0: No dual display start address support\r
+// 1: Dual display start address support\r
+//\r
+// Super VGA Mode Information Block WinAAttribite/WinBAttributes field bit defintions\r
+//\r
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_RELOCATABLE 0x01  // 0: Single non-relocatable window only\r
+// 1: Relocatable window(s) are supported\r
+//\r
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_READABLE  0x02  // 0: Window is not readable\r
+// 1: Window is readable\r
+//\r
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_WRITABLE  0x04  // 0: Window is not writable\r
+// 1: Window is writable\r
+//\r
+// Super VGA Mode Information Block DirectColorMode field bit defintions\r
+//\r
+#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_PROG_COLOR_RAMP  0x01  // 0: Color ram is fixed\r
+// 1: Color ramp is programmable\r
+//\r
+#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_RSVD_USABLE  0x02  // 0: Bits in Rsvd field are reserved\r
+// 1: Bits in Rsdv field are usable\r
+//\r
+// Super VGA Memory Models\r
+//\r
+typedef enum {\r
+  MemPL = 3,  // Planar memory model\r
+  MemPK = 4,  // Packed pixel memory model\r
+  MemRGB= 6,  // Direct color RGB memory model\r
+  MemYUV= 7   // Direct color YUV memory model\r
+} VESA_BIOS_EXTENSIONS_MEMORY_MODELS;\r
+\r
+//\r
+// Super VGA CRTC Information Block\r
+//\r
+typedef struct {\r
+  UINT16  HorizontalTotal;      // Horizontal total in pixels\r
+  UINT16  HorizontalSyncStart;  // Horizontal sync start in pixels\r
+  UINT16  HorizontalSyncEnd;    // Horizontal sync end in pixels\r
+  UINT16  VericalTotal;         // Vertical total in pixels\r
+  UINT16  VericalSyncStart;     // Vertical sync start in pixels\r
+  UINT16  VericalSyncEnd;       // Vertical sync end in pixels\r
+  UINT8   Flags;                // Flags (Interlaced/DoubleScan/etc).\r
+  UINT32  PixelClock;           // Pixel clock in units of Hz\r
+  UINT16  RefreshRate;          // Refresh rate in units of 0.01 Hz\r
+  UINT8   Reserved[40];         // Pad\r
+} VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK;\r
+\r
+#define VESA_BIOS_EXTENSIONS_CRTC_FLAGS_DOUBLE_SCAN 0x01  // 0: Graphics mode is not souble scanned\r
+// 1: Graphics mode is double scanned\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CRTC_FLAGSINTERLACED 0x02  // 0: Graphics mode is not interlaced\r
+// 1: Graphics mode is interlaced\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CRTC_HORIZONTAL_SYNC_NEGATIVE  0x04  // 0: Horizontal sync polarity is positive(+)\r
+// 0: Horizontal sync polarity is negative(-)\r
+//\r
+#define VESA_BIOS_EXTENSIONS_CRTC_VERITICAL_SYNC_NEGATIVE 0x08  // 0: Verical sync polarity is positive(+)\r
+// 0: Verical sync polarity is negative(-)\r
+//\r
+// Turn off byte packing of data structures\r
+//\r
+#pragma pack()\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
new file mode 100644 (file)
index 0000000..bf5f255
--- /dev/null
@@ -0,0 +1,80 @@
+## @file\r
+# Video driver based on legacy bios.\r
+#\r
+# This driver by using Legacy Bios protocol service to support csm Video\r
+# and produce Graphics Output Protocol.\r
+#\r
+# Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution.  The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = BiosVideoDxe\r
+  FILE_GUID                      = 0B04B2ED-861C-42cd-A22F-C3AAFACCB896\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = BiosVideoEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gBiosVideoDriverBinding\r
+#  COMPONENT_NAME                =  gBiosVideoComponentName\r
+#\r
+\r
+[Sources]\r
+  BiosVideo.c\r
+  BiosVideo.h\r
+  ComponentName.c\r
+  VesaBiosExtensions.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  DevicePathLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  ReportStatusCodeLib\r
+  DebugLib\r
+  PcdLib\r
+\r
+\r
+[Guids]\r
+  gEfiLegacyBiosGuid                            # ALWAYS_PRODUCED\r
+  gEfiEventExitBootServicesGuid\r
+\r
+[Protocols]\r
+  gEfiVgaMiniPortProtocolGuid                   # PROTOCOL BY_START\r
+  gEfiEdidDiscoveredProtocolGuid                # PROTOCOL BY_START\r
+  gEfiGraphicsOutputProtocolGuid                # PROTOCOL BY_START\r
+  gEfiEdidActiveProtocolGuid                    # PROTOCOL BY_START\r
+  gEfiLegacyBiosProtocolGuid                    # PROTOCOL TO_START\r
+  gEfiPciIoProtocolGuid                         # PROTOCOL TO_START\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL TO_START\r
+  gEfiEdidOverrideProtocolGuid                  # PROTOCOL TO_START\r
+\r
+[Pcd]\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoSetTextVgaModeEnable\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVbeEnable\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVgaEnable\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S
new file mode 100644 (file)
index 0000000..a785256
--- /dev/null
@@ -0,0 +1,67 @@
+## @file\r
+#  Interrupt Redirection Template\r
+#\r
+# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution.  The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+ASM_GLOBAL ASM_PFX(InterruptRedirectionTemplate)\r
+\r
+#----------------------------------------------------------------------------\r
+# Procedure:    InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F \r
+#\r
+# Input:        None\r
+#\r
+# Output:       None\r
+#\r
+# Prototype:    VOID\r
+#               InterruptRedirectionTemplate (  \r
+#                                VOID\r
+#                                );\r
+#\r
+# Saves:        None\r
+#\r
+# Modified:     None\r
+#\r
+# Description:  Contains the code that is copied into low memory (below 640K).\r
+#               This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.\r
+#               This template must be copied into low memory, and the IDT entries\r
+#               0x68-0x6F must be point to the low memory copy of this code.  Each\r
+#               entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily \r
+#               computed.\r
+#\r
+#----------------------------------------------------------------------------\r
+ASM_PFX(InterruptRedirectionTemplate):\r
+  int     $0x8\r
+  .byte   0xcf\r
+  nop\r
+  int     $0x9\r
+  .byte   0xcf\r
+  nop\r
+  int     $0xa\r
+  .byte   0xcf\r
+  nop\r
+  int     $0xb\r
+  .byte   0xcf\r
+  nop\r
+  int     $0xc\r
+  .byte   0xcf\r
+  nop\r
+  int     $0xd\r
+  .byte   0xcf\r
+  nop\r
+  int     $0xe\r
+  .byte   0xcf\r
+  nop\r
+  int     $0xf\r
+  .byte   0xcf\r
+  nop\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm
new file mode 100644 (file)
index 0000000..410ce5b
--- /dev/null
@@ -0,0 +1,73 @@
+;; @file\r
+;  Interrupt Redirection Template\r
+;\r
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+;\r
+; This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions\r
+; of the BSD License which accompanies this distribution.  The\r
+; full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;;\r
+\r
+.686P\r
+.MODEL FLAT, C\r
+.CODE\r
+\r
+;----------------------------------------------------------------------------\r
+; Procedure:    InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F \r
+;\r
+; Input:        None\r
+;\r
+; Output:       None\r
+;\r
+; Prototype:    VOID\r
+;               InterruptRedirectionTemplate (  \r
+;                                VOID\r
+;                                );\r
+;\r
+; Saves:        None\r
+;\r
+; Modified:     None\r
+;\r
+; Description:  Contains the code that is copied into low memory (below 640K).\r
+;               This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.\r
+;               This template must be copied into low memory, and the IDT entries\r
+;               0x68-0x6F must be point to the low memory copy of this code.  Each\r
+;               entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily \r
+;               computed.\r
+;\r
+;----------------------------------------------------------------------------\r
+\r
+InterruptRedirectionTemplate PROC  C\r
+  int     08h\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     09h\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0ah\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0bh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0ch\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0dh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0eh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0fh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+InterruptRedirectionTemplate ENDP\r
+\r
+END
\ No newline at end of file
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c
new file mode 100644 (file)
index 0000000..b6787ae
--- /dev/null
@@ -0,0 +1,277 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+\r
+/**\r
+  Assign drive number to legacy HDD drives prior to booting an EFI\r
+  aware OS so the OS can access drives without an EFI driver.\r
+  Note: BBS compliant drives ARE NOT available until this call by\r
+  either shell or EFI.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  BbsCount                Number of BBS_TABLE structures\r
+  @param  BbsTable                List BBS entries\r
+\r
+  @retval EFI_SUCCESS             Drive numbers assigned\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosPrepareToBootEfi (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  OUT UINT16                          *BbsCount,\r
+  OUT BBS_TABLE                       **BbsTable\r
+  )\r
+{\r
+  //\r
+  // Shadow All Opion ROM\r
+  //\r
+  LegacyBiosShadowAllLegacyOproms (This);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  To boot from an unconventional device like parties and/or execute\r
+  HDD diagnostics.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  Attributes              How to interpret the other input parameters\r
+  @param  BbsEntry                The 0-based index into the BbsTable for the\r
+                                  parent  device.\r
+  @param  BeerData                Pointer to the 128 bytes of ram BEER data.\r
+  @param  ServiceAreaData         Pointer to the 64 bytes of raw Service Area data.\r
+                                  The caller must provide a pointer to the specific\r
+                                  Service Area and not the start all Service Areas.\r
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosBootUnconventionalDevice (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  IN UDC_ATTRIBUTES                   Attributes,\r
+  IN UINTN                            BbsEntry,\r
+  IN VOID                             *BeerData,\r
+  IN VOID                             *ServiceAreaData\r
+  )\r
+{\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+\r
+/**\r
+  Attempt to legacy boot the BootOption. If the EFI contexted has been\r
+  compromised this function will not return.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  BbsDevicePath           EFI Device Path from BootXXXX variable.\r
+  @param  LoadOptionsSize         Size of LoadOption in size.\r
+  @param  LoadOptions             LoadOption from BootXXXX variable\r
+\r
+  @retval EFI_SUCCESS             Removable media not present\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosLegacyBoot (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  BBS_BBS_DEVICE_PATH               *BbsDevicePath,\r
+  IN  UINT32                            LoadOptionsSize,\r
+  IN  VOID                              *LoadOptions\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Build the E820 table.\r
+\r
+  @param  Private  Legacy BIOS Instance data\r
+  @param  Size     Size of E820 Table\r
+\r
+  @retval EFI_SUCCESS It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildE820 (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private,\r
+  OUT UINTN                   *Size\r
+  )\r
+{\r
+  *Size = 0;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get all BBS info\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  HddCount                Number of HDD_INFO structures\r
+  @param  HddInfo                 Onboard IDE controller information\r
+  @param  BbsCount                Number of BBS_TABLE structures\r
+  @param  BbsTable                List BBS entries\r
+\r
+  @retval EFI_SUCCESS             Tables returned\r
+  @retval EFI_NOT_FOUND           resource not found\r
+  @retval EFI_DEVICE_ERROR        can not get BBS table\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosGetBbsInfo (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  OUT UINT16                          *HddCount,\r
+  OUT HDD_INFO                        **HddInfo,\r
+  OUT UINT16                          *BbsCount,\r
+  OUT BBS_TABLE                       **BbsTable\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Fill in the standard BDA for Keyboard LEDs\r
+\r
+  @param  This         Protocol instance pointer.\r
+  @param  Leds         Current LED status\r
+\r
+  @retval EFI_SUCCESS  It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosUpdateKeyboardLedStatus (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  UINT8                             Leds\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Relocate this image under 4G memory for IPF.\r
+\r
+  @param  ImageHandle  Handle of driver image.\r
+  @param  SystemTable  Pointer to system table.\r
+\r
+  @retval EFI_SUCCESS  Image successfully relocated.\r
+  @retval EFI_ABORTED  Failed to relocate image.\r
+\r
+**/\r
+EFI_STATUS\r
+RelocateImageUnder4GIfNeeded (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;\r
+  UINTN                              NumberOfPages;\r
+  EFI_PHYSICAL_ADDRESS               LoadedImageBase;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT       ImageContext;\r
+  EFI_PHYSICAL_ADDRESS               MemoryAddress;\r
+  EFI_HANDLE                         NewImageHandle;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                    ImageHandle,\r
+                    &gEfiLoadedImageProtocolGuid,\r
+                    (VOID *) &LoadedImage\r
+                    );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    LoadedImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImage->ImageBase;\r
+    if (LoadedImageBase > 0xffffffff) {\r
+      NumberOfPages = (UINTN) (DivU64x32(LoadedImage->ImageSize, EFI_PAGE_SIZE) + 1);\r
+\r
+      //\r
+      // Allocate buffer below 4GB here\r
+      //\r
+      Status = AllocateLegacyMemory (\r
+                AllocateMaxAddress,\r
+                0x7FFFFFFF,\r
+                NumberOfPages,  // do we have to convert this to pages??\r
+                &MemoryAddress\r
+                );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      ZeroMem (&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
+      ImageContext.Handle    = (VOID *)(UINTN)LoadedImageBase;\r
+      ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+      //\r
+      // Get information about the image being loaded\r
+      //\r
+      Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      ImageContext.ImageAddress = (PHYSICAL_ADDRESS)MemoryAddress;\r
+      //\r
+      // Align buffer on section boundry\r
+      //\r
+      ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+      ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+\r
+      //\r
+      // Load the image to our new buffer\r
+      //\r
+      Status = PeCoffLoaderLoadImage (&ImageContext);\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->FreePages (MemoryAddress, NumberOfPages);\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Relocate the image in our new buffer\r
+      //\r
+      Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->FreePages (MemoryAddress, NumberOfPages);\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Create a new handle with gEfiCallerIdGuid to be used as the ImageHandle fore the reloaded image\r
+      // \r
+      NewImageHandle = NULL;\r
+      Status = gBS->InstallProtocolInterface (\r
+                      &NewImageHandle,\r
+                      &gEfiCallerIdGuid,\r
+                      EFI_NATIVE_INTERFACE,\r
+                      NULL\r
+                      );\r
+\r
+      //\r
+      // Flush the instruction cache so the image data is written before we execute it\r
+      //\r
+      InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
+\r
+      Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->FreePages (MemoryAddress, NumberOfPages);\r
+        return Status;\r
+      }\r
+      //\r
+      // return error directly the BS will unload this image\r
+      //\r
+      return EFI_ABORTED;\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h
new file mode 100644 (file)
index 0000000..26aa3a6
--- /dev/null
@@ -0,0 +1,102 @@
+/** @file\r
+\r
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _IPF_THUNK_H_\r
+#define _IPF_THUNK_H_\r
+\r
+#include "LegacyBiosInterface.h"\r
+#include <IndustryStandard/Sal.h>\r
+\r
+/**\r
+  Template of real mode code.\r
+\r
+  @param  CodeStart          Start address of code.\r
+  @param  CodeEnd            End address of code\r
+  @param  ReverseThunkStart  Start of reverse thunk.\r
+  @param  IntThunk           Low memory thunk.\r
+\r
+**/\r
+VOID\r
+RealModeTemplate (\r
+  OUT UINTN          *CodeStart,\r
+  OUT UINTN          *CodeEnd,\r
+  OUT UINTN          *ReverseThunkStart,\r
+  LOW_MEMORY_THUNK   *IntThunk\r
+  );\r
+\r
+/**\r
+  Register physical address of Esal Data Area\r
+\r
+  @param  ReverseThunkCodeAddress Reverse Thunk Address\r
+  @param  IntThunkAddress         IntThunk Address\r
+\r
+  @retval EFI_SUCCESS             ESAL data area set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EsalSetSalDataArea (\r
+  IN UINTN    ReverseThunkCodeAddress,\r
+  IN UINTN    IntThunkAddress\r
+  );\r
+\r
+/**\r
+ Get address of reverse thunk.\r
+\r
+ @retval EFI_SAL_SUCCESS  Address of reverse thunk returned successfully.\r
+\r
+**/\r
+SAL_RETURN_REGS\r
+EsalGetReverseThunkAddress (\r
+  VOID\r
+  );\r
+\r
+typedef struct {\r
+  UINT32  Eax;    // 0\r
+  UINT32  Ecx;    // 4\r
+  UINT32  Edx;    // 8\r
+  UINT32  Ebx;    // 12\r
+  UINT32  Esp;    // 16\r
+  UINT32  Ebp;    // 20\r
+  UINT32  Esi;    // 24\r
+  UINT32  Edi;    // 28\r
+  UINT32  Eflag;  // 32\r
+  UINT32  Eip;    // 36\r
+  UINT16  Cs;     // 40\r
+  UINT16  Ds;     // 42\r
+  UINT16  Es;     // 44\r
+  UINT16  Fs;     // 46\r
+  UINT16  Gs;     // 48\r
+  UINT16  Ss;     // 50\r
+} IPF_DWORD_REGS;\r
+\r
+/**\r
+  Entrypoint of IA32 code.\r
+\r
+  @param  CallTypeData  Data of call type\r
+  @param  DwordRegister Register set of IA32 general registers\r
+                        and segment registers\r
+  @param  StackPointer  Stack pointer.\r
+  @param  StackSize     Size of stack.\r
+\r
+**/\r
+VOID\r
+EfiIaEntryPoint (\r
+  UINT64           CallTypeData,\r
+  IPF_DWORD_REGS   *DwordRegister,\r
+  UINT64           StackPointer,\r
+  UINT64           StackSize\r
+  );\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i
new file mode 100644 (file)
index 0000000..441bb25
--- /dev/null
@@ -0,0 +1,89 @@
+//// @file\r
+//\r
+// Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution.  The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+////\r
+\r
+#define NUM_REAL_GDT_ENTRIES                                           3\r
+#define LOW_STACK_SIZE                                                         (8*1024)            // 8k?\r
+\r
+//\r
+// Low memory Thunk Structure\r
+//\r
+#define                Code                                                                    0\r
+#define                LowReverseThunkStart                                    Code + 4096\r
+#define                GdtDesc                                                                 LowReverseThunkStart + 4\r
+#define                IdtDesc                                                                 GdtDesc + 6\r
+#define                FlatSs                                                                  IdtDesc + 6\r
+#define                FlatEsp                                                                 FlatSs + 4\r
+#define                LowCodeSelector                                                 FlatEsp + 4\r
+#define                LowDataSelector                                                 LowCodeSelector + 4\r
+#define                LowStack                                                                LowDataSelector + 4\r
+#define                RealModeIdtDesc                                                 LowStack + 4\r
+#define                RealModeGdt                                                             RealModeIdtDesc + 6\r
+#define                RealModeGdtDesc                                                 RealModeGdt + (8 * NUM_REAL_GDT_ENTRIES)\r
+#define                RevRealDs                                                               RealModeGdtDesc + 6\r
+#define                RevRealSs                                                               RevRealDs + 2\r
+#define                RevRealEsp                                                              RevRealSs + 2\r
+#define                RevRealIdtDesc                                                  RevRealEsp + 4\r
+#define                RevFlatDataSelector                                             RevRealIdtDesc + 6\r
+#define                RevFlatStack                                                    RevFlatDataSelector + 2\r
+#define                Stack                                                                   RevFlatStack + 4\r
+#define                RevThunkStack                                                   Stack + LOW_STACK_SIZE\r
+\r
+#define                EfiToLegacy16InitTable                                  RevThunkStack + LOW_STACK_SIZE\r
+#define                InitTableBiosLessThan1MB                                EfiToLegacy16InitTable\r
+#define                InitTableHiPmmMemory                                    InitTableBiosLessThan1MB + 4\r
+#define                InitTablePmmMemorySizeInBytes                   InitTableHiPmmMemory + 4\r
+#define                InitTableReverseThunkCallSegment                InitTablePmmMemorySizeInBytes + 4\r
+#define                InitTableReverseThunkCallOffset                 InitTableReverseThunkCallSegment + 2\r
+#define                InitTableNumberE820Entries                              InitTableReverseThunkCallOffset + 2\r
+#define                InitTableOsMemoryAbove1Mb                               InitTableNumberE820Entries + 4\r
+#define                InitTableThunkStart                                             InitTableOsMemoryAbove1Mb + 4\r
+#define                InitTableThunkSizeInBytes                               InitTableThunkStart + 4\r
+#define                InitTable16InitTableEnd                                 InitTableThunkSizeInBytes + 4\r
+\r
+#define                EfiToLegacy16BootTable                                  InitTable16InitTableEnd\r
+#define                BootTableBiosLessThan1MB                                EfiToLegacy16BootTable\r
+#define                BootTableHiPmmMemory                                    BootTableBiosLessThan1MB + 4\r
+#define                BootTablePmmMemorySizeInBytes                   BootTableHiPmmMemory + 4\r
+#define                BootTableReverseThunkCallSegment                BootTablePmmMemorySizeInBytes + 4\r
+#define                BootTableReverseThunkCallOffset                 BootTableReverseThunkCallSegment + 2\r
+#define                BootTableNumberE820Entries                              BootTableReverseThunkCallOffset + 2\r
+#define                BootTableOsMemoryAbove1Mb                               BootTableNumberE820Entries + 4\r
+#define                BootTableThunkStart                                             BootTableOsMemoryAbove1Mb + 4\r
+#define                BootTableThunkSizeInBytes                               BootTableThunkStart + 4\r
+#define                EfiToLegacy16BootTableEnd                               BootTableThunkSizeInBytes + 4\r
+\r
+#define                InterruptRedirectionCode                                EfiToLegacy16BootTableEnd\r
+#define                PciHandler                                                              InterruptRedirectionCode + 32\r
+\r
+\r
+//\r
+// Register Sets (16 Bit)\r
+//\r
+\r
+#define                AX              0\r
+#define                BX              2\r
+#define                CX              4\r
+#define                DX              6\r
+#define                SI              8\r
+#define                DI              10\r
+#define                Flags   12\r
+#define                ES              14\r
+#define                CS              16\r
+#define                SS              18\r
+#define                DS              20\r
+#define                BP              22\r
+\r
+\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s
new file mode 100644 (file)
index 0000000..d08f781
--- /dev/null
@@ -0,0 +1,524 @@
+//// @file
+//
+// Copyright (c) 1999 - 2008, 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.
+//
+////
+
+.file  "IpfThunk.s"
+
+#include  "IpfMacro.i"
+#include  "Ipf/IpfThunk.i"
+
+.align 0x10
+//-----------------------------------------------------------------------------
+//++
+// EfiIaEntryPoint
+//
+// Register physical address of Esal Data Area
+//
+// On Entry :
+//  in1 = ptr to legacy bios reg
+//  in2 = ptr to Call Stack
+//  in3 = Call Stack Size
+//
+// Return Value:
+//  r8 = SAL_SUCCESS
+//
+// As per static calling conventions.
+//
+//--
+//---------------------------------------------------------------------------
+PROCEDURE_ENTRY(EfiIaEntryPoint)
+
+               alloc         loc0 = 8,10,8,0;;
+
+               mov             out0 = r0;;
+          mov          out1 = r0;;
+          mov          out2 = r0;;
+          mov          out3 = r0;;
+               mov             out4 = r0;;
+          mov          out5 = r0;;
+          mov          out6 = r0;;
+          mov          out7 = r0;;
+
+               mov             loc1 = b0;;                                                     // save efi (b0)
+               mov             loc2 = psr;;                                            // save efi (PSR)
+               mov             loc3 = gp;;                                                     // save efi (GP)
+               mov             loc4 = pr;;                                                     // save efi (PR)
+               mov             loc5 = sp;;                                                     // save efi (SP)
+               mov             loc6 = r13;;                                            // save efi (TP)
+               mov             loc7 = ar.lc;;                                  // save efi (LC)
+               mov             loc8 = ar.fpsr;;                                // save efi (FPSR)
+
+               mov             r8   = r0;;                                                   // return status
+               mov             r9   = r0;;                                                   // return value
+               mov             r10  = r0;;                                                     // return value
+               mov             r11  = r0;;                                                     // return value
+
+bios_int_func::
+               rsm                   0x4000;;                                              // i(14)=0, disable interrupt
+               srlz.d;;
+               srlz.i;;
+
+//---------------------//
+// save fp registers   //
+//---------------------//
+
+               dep                   sp = 0,sp,0,4;;                                         // align 16
+               add                   sp = -16,sp;;                                                   // post decrement
+
+int_ip_1x::
+               mov                   r2 = ip;;
+               add                   r2 = (int_ip_1y - int_ip_1x),r2;;
+               mov                   b7 = r2;;
+               br                    save_fp_registers;;
+
+int_ip_1y::
+               add                   sp    = 16,sp;;               // adjust (SP)
+               mov                   loc9  = sp;;                                                    // save (SP)
+               adds          sp    = 0x10,in1;;                                    // in1 + 0x10 = SP
+               ld4                   sp    = [sp];;                                                // SP
+               adds          r17   = 0x32,in1;;                              // in1 + 0x32 = SS
+               ld2                   r17   = [r17];;                                         // SS
+               movl          r2    = 0xffffffff;;                          // if no SS:SP, then define new SS:SP
+               cmp.ne      p6,p0 = sp,r2;;
+               movl          r2    = 0xffff;;
+               cmp.ne.or   p6,p0 = r17,r2;;
+     (p6) br.sptk      bif_1;;
+
+               mov                   sp    = in3;;                                                   // 16-bit stack pointer
+               mov                   r2    = psr;;
+               tbit.z      p6,p7 = r2,17;;                               // psr.dt (Physical OR Virtual)
+
+bif_ip1x::
+               mov                   r2    = in2;;                                                   // ia32 callback stack top
+               mov                   r3    = in3;;                                                   // 16-bit stack pointer
+               sub                   r2    = r2,r3;;
+               shr.u         r17   = r2,4;;                                          // 16-bit stack segment
+
+bif_1::
+               extr.u      sp    = sp,0,16;;                           // SP (16-bit sp for legacy code)
+               dep                   sp    = 0,sp,0,3;;                        // align 8
+               cmp.eq      p6,p0 = 0,sp;;                // if SP=0000 then wrap to 0x10000
+    (p6)       dep             sp    = -1,sp,16,1;;
+               shladd      r2    = r17,4,sp;;                        // ESP = SS<<4+SP
+               add                   r2    = -8,r2;;                                         // post decrement 64 bit pointer
+               add                   sp    = -8,sp;;                                         // post decrement SP
+
+sale_ip1x::
+               mov                   r18   = ip;;
+               adds          r18   = (sale_ip1y - sale_ip1x),r18;;
+               sub                   r18   = r18,r2;;                                // return address - CS base
+               add                   r18   = r18,sp;;                                // adjustment for stack
+               shl                   r18   = r18,32;;
+               movl          r19   = 0xb80f66fa;;                    // CLI, JMPE xxxxxxxx
+               or                    r18   = r18,r19;;
+               st8                   [r2]  = r18;;                                             // (FA,66,0F,B8,xx,xx,xx,xx)
+
+               cmp.eq      p6,p0 = 0,sp;;                                // if SP=0000 then wrap to 0x10000
+    (p6)       dep             sp    = -1,sp,16,1;;
+               shladd      r2    = r17,4,sp;;                        // ESP=SS<<4+SP
+               add                   r2    = -2,r2;;                                         // post decrement 64 bit pointer
+               add                   sp    = -2,sp;;                                         // post decrement SP
+
+               movl          r18   = 0x8000000000000100;;      // CALL FAR function
+               cmp.eq      p6,p7 = in0,r18;;
+    (p6)       add             r19   = 0x28,in1;;                            // in1 + 0x28 = CS
+    (p6)       ld2             r18   = [r19],-4;;                            // CS
+    (p6)       st2             [r2]  = r18,-2;;                                      // in1 + 0x24 = EIP
+    (p6)       ld2             r18   = [r19];;                                       // EIP
+    (p6)       st2             [r2]  = r18,-2;;                                      //
+    (p6)       movl          r18   = 0x9a90;;                          // nop, CALLFAR xxxx:yyyy
+
+    (p7)       movl          r18   = 0xcd;;                                    // INT xx
+    (p7)       dep             r18   = in0,r18,8,8;;
+           st2         [r2]  = r18;;                                                       // (CD,xx)
+
+               mov             r18   = r2;;                    // EIP for legacy execution
+
+//------------------------------//
+// flush 32 bytes legacy code    //
+//------------------------------//
+
+               dep                   r2    = 0,r2,0,5;;            // align to 32
+               fc                    r2;;
+               sync.i;;
+               srlz.i;;
+               srlz.d;;
+
+//------------------------------//
+// load legacy registers                   //
+//------------------------------//
+               mov                   r2    = in1;;                                                   // IA32 BIOS register state
+               ld4                   r8    = [r2],4;;                                            // in1 + 0 = EAX
+               ld4                   r9    = [r2],4;;                                            // in1 + 4 = ECX
+               ld4                   r10   = [r2],4;;                                      // in1 + 8 = EDX
+               ld4                   r11   = [r2],4;;                                      // in1 + 12 = EBX
+
+               add                   r2    = 4,r2;;                                                // in1 + 16 = ESP (skip)
+
+               ld4                   r13   = [r2],4;;                                      // in1 + 20 = EBP
+               ld4                   r14   = [r2],4;;                                      // in1 + 24 = ESI
+               ld4                   r15   = [r2],4;;                                      // in1 + 28 = EDI
+               ld4                   r3    = [r2],4;;                                            // in1 + 32 = EFLAGS
+               mov                   ar.eflag = r3;;
+
+               add                   r2    = 4,r2;;                                                // in1 + 36 = EIP (skip)
+               add                   r2    = 2,r2;;                                                // in1 + 40 = CS (skip)
+
+               ld2                   r16   = [r2],2;;                                      // in1 + 42 = DS, (r16 = GS,FS,ES,DS)
+               movl          r27   = 0xc93fffff00000000;;
+               dep                   r27   = r16,r27,4,16;;                            // r27 = DSD
+
+               ld2                   r19   = [r2],2;;                                      // in1 + 44 = ES
+               dep                   r16   = r19,r16,16,16;;
+               movl          r24   = 0xc93fffff00000000;;
+               dep                   r24   = r19,r24,4,16;;                            // r24 = ESD
+
+               ld2                   r19   = [r2],2;;                                      // in1 + 46 = FS
+               dep                   r16   = r19,r16,32,16;;
+               movl          r28   = 0xc93fffff00000000;;
+               dep                   r28   = r19,r28,4,16;;                            // r28 = FSD
+
+               ld2                   r19   = [r2],2;;                                      // in1 + 48 = GS
+               dep                   r16   = r19,r16,48,16;;
+               movl          r29   = 0xc93fffff00000000;;
+               dep                   r29   = r19,r29,4,16;;                            // r29 = GSD
+
+               mov                   r30   = r0;;                                                    // r30 = LDTD, clear NaT
+               mov                   r31   = r0;;                                                    // r31 = GDTD, clear NaT
+
+               dep                   r17   = r17,r17,16,16;;                     // CS = SS, (r17 = TSS,LDT,SS,CS)
+
+               movl          r3    = 0x0930ffff00000000;;
+               dep                   r3    = r17,r3,4,16;;
+               mov                   ar.csd = r3;;                                                   // ar25 = CSD
+               mov                   ar.ssd = r3;;                                                   // ar26 = SSD
+
+//------------------------------//
+// give control to INT function //
+//------------------------------//
+
+               br.call.sptk  b0  = execute_int_function;;
+
+//------------------------------//
+// store legacy registers                  //
+//------------------------------//
+
+               mov                   r2    = in1;;
+               st4                   [r2]  = r8,4;;                                                // EAX
+               st4                   [r2]  = r9,4;;                                                // ECX
+               st4                   [r2]  = r10,4;;                                         // EDX
+               st4                   [r2]  = r11,4;;                                         // EBX
+
+               add                   r2    = 4,r2;;                                                // ESP (skip)
+
+               st4                   [r2]  = r13,4;;                                         // EBP
+               st4                   [r2]  = r14,4;;                                         // ESI
+               st4                   [r2]  = r15,4;;                                         // EDI
+
+               mov                   r3    = ar.eflag;;
+               st4                   [r2]  = r3,4;;                                                // EFLAGS
+
+               add                   r2    = 4,r2;;                                                // EIP (skip)
+               add                   r2    = 2,r2;;                                                // CS (skip)
+
+               st2                   [r2]  = r16,2;;                                         // DS, (r16 = GS,FS,ES,DS)
+
+               extr.u      r3    = r16,16,16;;
+               st2                   [r2]  = r3,2;;                                                // ES
+
+               extr.u      r3    = r16,32,16;;
+               st2                   [r2]  = r3,2;;                                                // FS
+
+               extr.u      r3    = r16,48,16;;
+               st2                   [r2]  = r3,2;;                                                // GS
+
+//------------------------------//
+// restore fp registers                    //
+//------------------------------//
+               mov                   sp    = loc9;;                                                // restore (SP)
+int_ip_2x::
+               mov                   r2    = ip;;
+               add                   r2    = (int_ip_2y - int_ip_2x),r2;;
+               mov                   b7    = r2;;
+               br                    restore_fp_registers;;
+
+int_ip_2y::
+               mov                   r8    = r0;;                                                    // return status
+               mov                   r9    = r0;;                                                    // return value
+               mov                   r10   = r0;;                                                    // return value
+               mov                   r11   = r0;;                                                    // return value
+
+               mov                   ar.fpsr = loc8;;                          // restore efi (FPSR)
+               mov                   ar.lc = loc7;;                                    // restore efi (LC)
+               mov                   r13   = loc6;;                                          // restore efi (TP)
+               mov                   sp    = loc5;;                                                // restore efi (SP)
+               mov                   pr    = loc4;;                                                // restore efi (PR)
+               mov                   gp    = loc3;;                                                // restore efi (GP)
+               mov                   psr.l = loc2;;                                    // restore efi (PSR)
+               srlz.d;;
+               srlz.i;;
+               mov                   b0    = loc1;;                                                // restore efi (b0)
+               mov                   ar.pfs = loc0;;
+       br.ret.sptk     b0;;                                                            // return to efi
+
+PROCEDURE_EXIT (EfiIaEntryPoint)
+
+//==============================//
+//     EXECUTE_INT_FUNCTION                //
+//==============================//
+// switch to virtual address     //
+//------------------------------//
+
+execute_int_function::
+
+               alloc         r2 = 0,0,0,0;;                                    // cfm.sof=0
+               flushrs;;
+
+               rsm                   0x2000;;                                                    // ic(13)=0 for control register programming
+               srlz.d;;
+               srlz.i;;
+
+               mov                   r2  = psr;;
+               dep                   r2  = -1,r2,34,1;;                              // set is(34)
+               dep                   r2  = -1,r2,44,1;;                              // set bn(44)
+               dep                   r2  = -1,r2,36,1;;                              // set it(36)
+               dep                   r2  = -1,r2,27,1;;                              // set rt(27)
+               dep                   r2  = -1,r2,17,1;;                              // set dt(17)
+               dep                   r2  = 0,r2,3,1;;                                // reset ac(3)
+               dep                   r2  = -1,r2,13,1;;                              // set ic(13)
+
+               mov                   cr.ipsr = r2;;
+               mov                   cr.ifs  = r0;;                                          // clear interruption function state register
+               mov                   cr.iip  = r18;;
+
+               rfi;;                                                                                       // go to legacy code execution
+
+//------------------------------//
+// back from legacy code                   //
+//------------------------------//
+// switch to physical address    //
+//------------------------------//
+
+sale_ip1y::
+               rsm                 0x6000;;                                                        // i(14)=0,ic(13)=0 for control reg programming
+               srlz.d;;
+               srlz.i;;
+
+               mov                 r2  = psr;;
+               dep                 r2  = -1,r2,44,1;;                                        // set bn(44)
+               dep                 r2  = 0,r2,36,1;;                                         // reset it(36)
+               dep                 r2  = 0,r2,27,1;;                                         // reset rt(27)
+               dep                 r2  = 0,r2,17,1;;                                         // reset dt(17)
+               dep                 r2  = -1,r2,13,1;;                                        // set ic(13)
+               mov                 cr.ipsr = r2;;
+
+sale_ip2x::
+               mov                 r2  = ip;;
+               add                 r2  = (sale_ip2y - sale_ip2x),r2;;
+               mov                 cr.ifs = r0;;                                                       // clear interruption function state register
+               mov                 cr.iip = r2;;
+               rfi;;
+
+sale_ip2y::
+               br.ret.sptk     b0;;                                              // return to SAL
+
+//------------------------------//
+// store fp registers                  //
+//------------------------------//
+save_fp_registers::
+       stf.spill [sp]=f2,-16;;  stf.spill [sp]=f3,-16;;
+       stf.spill [sp]=f4,-16;;  stf.spill [sp]=f5,-16;;  stf.spill [sp]=f6,-16;;  stf.spill [sp]=f7,-16;;
+       stf.spill [sp]=f8,-16;;  stf.spill [sp]=f9,-16;;  stf.spill [sp]=f10,-16;; stf.spill [sp]=f11,-16;;
+       stf.spill [sp]=f12,-16;; stf.spill [sp]=f13,-16;; stf.spill [sp]=f14,-16;; stf.spill [sp]=f15,-16;;
+       stf.spill [sp]=f16,-16;; stf.spill [sp]=f17,-16;; stf.spill [sp]=f18,-16;; stf.spill [sp]=f19,-16;;
+       stf.spill [sp]=f20,-16;; stf.spill [sp]=f21,-16;; stf.spill [sp]=f22,-16;; stf.spill [sp]=f23,-16;;
+       stf.spill [sp]=f24,-16;; stf.spill [sp]=f25,-16;; stf.spill [sp]=f26,-16;; stf.spill [sp]=f27,-16;;
+       stf.spill [sp]=f28,-16;; stf.spill [sp]=f29,-16;; stf.spill [sp]=f30,-16;; stf.spill [sp]=f31,-16;;
+       stf.spill [sp]=f32,-16;; stf.spill [sp]=f33,-16;; stf.spill [sp]=f34,-16;; stf.spill [sp]=f35,-16;;
+       stf.spill [sp]=f36,-16;; stf.spill [sp]=f37,-16;; stf.spill [sp]=f38,-16;; stf.spill [sp]=f39,-16;;
+       stf.spill [sp]=f40,-16;; stf.spill [sp]=f41,-16;; stf.spill [sp]=f42,-16;; stf.spill [sp]=f43,-16;;
+       stf.spill [sp]=f44,-16;; stf.spill [sp]=f45,-16;; stf.spill [sp]=f46,-16;; stf.spill [sp]=f47,-16;;
+       stf.spill [sp]=f48,-16;; stf.spill [sp]=f49,-16;; stf.spill [sp]=f50,-16;; stf.spill [sp]=f51,-16;;
+       stf.spill [sp]=f52,-16;; stf.spill [sp]=f53,-16;; stf.spill [sp]=f54,-16;; stf.spill [sp]=f55,-16;;
+       stf.spill [sp]=f56,-16;; stf.spill [sp]=f57,-16;; stf.spill [sp]=f58,-16;; stf.spill [sp]=f59,-16;;
+       stf.spill [sp]=f60,-16;; stf.spill [sp]=f61,-16;; stf.spill [sp]=f62,-16;; stf.spill [sp]=f63,-16;;
+       stf.spill [sp]=f64,-16;; stf.spill [sp]=f65,-16;; stf.spill [sp]=f66,-16;; stf.spill [sp]=f67,-16;;
+       stf.spill [sp]=f68,-16;; stf.spill [sp]=f69,-16;; stf.spill [sp]=f70,-16;; stf.spill [sp]=f71,-16;;
+       stf.spill [sp]=f72,-16;; stf.spill [sp]=f73,-16;; stf.spill [sp]=f74,-16;; stf.spill [sp]=f75,-16;;
+       stf.spill [sp]=f76,-16;; stf.spill [sp]=f77,-16;; stf.spill [sp]=f78,-16;; stf.spill [sp]=f79,-16;;
+       stf.spill [sp]=f80,-16;; stf.spill [sp]=f81,-16;; stf.spill [sp]=f82,-16;; stf.spill [sp]=f83,-16;;
+       stf.spill [sp]=f84,-16;; stf.spill [sp]=f85,-16;; stf.spill [sp]=f86,-16;; stf.spill [sp]=f87,-16;;
+       stf.spill [sp]=f88,-16;; stf.spill [sp]=f89,-16;; stf.spill [sp]=f90,-16;; stf.spill [sp]=f91,-16;;
+       stf.spill [sp]=f92,-16;; stf.spill [sp]=f93,-16;; stf.spill [sp]=f94,-16;; stf.spill [sp]=f95,-16;;
+       stf.spill [sp]=f96,-16;; stf.spill [sp]=f97,-16;; stf.spill [sp]=f98,-16;; stf.spill [sp]=f99,-16;;
+       stf.spill [sp]=f100,-16;;stf.spill [sp]=f101,-16;;stf.spill [sp]=f102,-16;;stf.spill [sp]=f103,-16;;
+       stf.spill [sp]=f104,-16;;stf.spill [sp]=f105,-16;;stf.spill [sp]=f106,-16;;stf.spill [sp]=f107,-16;;
+       stf.spill [sp]=f108,-16;;stf.spill [sp]=f109,-16;;stf.spill [sp]=f110,-16;;stf.spill [sp]=f111,-16;;
+       stf.spill [sp]=f112,-16;;stf.spill [sp]=f113,-16;;stf.spill [sp]=f114,-16;;stf.spill [sp]=f115,-16;;
+       stf.spill [sp]=f116,-16;;stf.spill [sp]=f117,-16;;stf.spill [sp]=f118,-16;;stf.spill [sp]=f119,-16;;
+       stf.spill [sp]=f120,-16;;stf.spill [sp]=f121,-16;;stf.spill [sp]=f122,-16;;stf.spill [sp]=f123,-16;;
+       stf.spill [sp]=f124,-16;;stf.spill [sp]=f125,-16;;stf.spill [sp]=f126,-16;;stf.spill [sp]=f127,-16;;
+       invala;;
+       br      b7;;
+
+//------------------------------//
+// restore fp registers                //
+//------------------------------//
+restore_fp_registers::
+       ldf.fill f127=[sp],16;;ldf.fill f126=[sp],16;;ldf.fill f125=[sp],16;;ldf.fill f124=[sp],16;;
+       ldf.fill f123=[sp],16;;ldf.fill f122=[sp],16;;ldf.fill f121=[sp],16;;ldf.fill f120=[sp],16;;
+       ldf.fill f119=[sp],16;;ldf.fill f118=[sp],16;;ldf.fill f117=[sp],16;;ldf.fill f116=[sp],16;;
+       ldf.fill f115=[sp],16;;ldf.fill f114=[sp],16;;ldf.fill f113=[sp],16;;ldf.fill f112=[sp],16;;
+       ldf.fill f111=[sp],16;;ldf.fill f110=[sp],16;;ldf.fill f109=[sp],16;;ldf.fill f108=[sp],16;;
+       ldf.fill f107=[sp],16;;ldf.fill f106=[sp],16;;ldf.fill f105=[sp],16;;ldf.fill f104=[sp],16;;
+       ldf.fill f103=[sp],16;;ldf.fill f102=[sp],16;;ldf.fill f101=[sp],16;;ldf.fill f100=[sp],16;;
+       ldf.fill f99=[sp],16;; ldf.fill f98=[sp],16;; ldf.fill f97=[sp],16;; ldf.fill f96=[sp],16;;
+       ldf.fill f95=[sp],16;; ldf.fill f94=[sp],16;; ldf.fill f93=[sp],16;; ldf.fill f92=[sp],16;;
+       ldf.fill f91=[sp],16;; ldf.fill f90=[sp],16;; ldf.fill f89=[sp],16;; ldf.fill f88=[sp],16;;
+       ldf.fill f87=[sp],16;; ldf.fill f86=[sp],16;; ldf.fill f85=[sp],16;; ldf.fill f84=[sp],16;;
+       ldf.fill f83=[sp],16;; ldf.fill f82=[sp],16;; ldf.fill f81=[sp],16;; ldf.fill f80=[sp],16;;
+       ldf.fill f79=[sp],16;; ldf.fill f78=[sp],16;; ldf.fill f77=[sp],16;; ldf.fill f76=[sp],16;;
+       ldf.fill f75=[sp],16;; ldf.fill f74=[sp],16;; ldf.fill f73=[sp],16;; ldf.fill f72=[sp],16;;
+       ldf.fill f71=[sp],16;; ldf.fill f70=[sp],16;; ldf.fill f69=[sp],16;; ldf.fill f68=[sp],16;;
+       ldf.fill f67=[sp],16;; ldf.fill f66=[sp],16;; ldf.fill f65=[sp],16;; ldf.fill f64=[sp],16;;
+       ldf.fill f63=[sp],16;; ldf.fill f62=[sp],16;; ldf.fill f61=[sp],16;; ldf.fill f60=[sp],16;;
+       ldf.fill f59=[sp],16;; ldf.fill f58=[sp],16;; ldf.fill f57=[sp],16;; ldf.fill f56=[sp],16;;
+       ldf.fill f55=[sp],16;; ldf.fill f54=[sp],16;; ldf.fill f53=[sp],16;; ldf.fill f52=[sp],16;;
+       ldf.fill f51=[sp],16;; ldf.fill f50=[sp],16;; ldf.fill f49=[sp],16;; ldf.fill f48=[sp],16;;
+       ldf.fill f47=[sp],16;; ldf.fill f46=[sp],16;; ldf.fill f45=[sp],16;; ldf.fill f44=[sp],16;;
+       ldf.fill f43=[sp],16;; ldf.fill f42=[sp],16;; ldf.fill f41=[sp],16;; ldf.fill f40=[sp],16;;
+       ldf.fill f39=[sp],16;; ldf.fill f38=[sp],16;; ldf.fill f37=[sp],16;; ldf.fill f36=[sp],16;;
+       ldf.fill f35=[sp],16;; ldf.fill f34=[sp],16;; ldf.fill f33=[sp],16;; ldf.fill f32=[sp],16;;
+       ldf.fill f31=[sp],16;; ldf.fill f30=[sp],16;; ldf.fill f29=[sp],16;; ldf.fill f28=[sp],16;;
+       ldf.fill f27=[sp],16;; ldf.fill f26=[sp],16;; ldf.fill f25=[sp],16;; ldf.fill f24=[sp],16;;
+       ldf.fill f23=[sp],16;; ldf.fill f22=[sp],16;; ldf.fill f21=[sp],16;; ldf.fill f20=[sp],16;;
+       ldf.fill f19=[sp],16;; ldf.fill f18=[sp],16;; ldf.fill f17=[sp],16;; ldf.fill f16=[sp],16;;
+       ldf.fill f15=[sp],16;; ldf.fill f14=[sp],16;; ldf.fill f13=[sp],16;; ldf.fill f12=[sp],16;;
+       ldf.fill f11=[sp],16;; ldf.fill f10=[sp],16;; ldf.fill f9=[sp],16;;  ldf.fill f8=[sp],16;;
+       ldf.fill f7=[sp],16;;  ldf.fill f6=[sp],16;;  ldf.fill f5=[sp],16;;  ldf.fill f4=[sp],16;;
+       ldf.fill f3=[sp],16;;  ldf.fill f2=[sp],16;;
+       invala;;
+       br      b7;;
+
+//-----------------------------------------------------------------------------
+//++
+// EsalSetSalDataArea
+//
+// Register physical address of Esal Data Area
+//
+// On Entry :
+//  in0 = Reverse Thunk Address
+//  in1 = IntThunk Address
+//
+// Return Value:
+//  r8 = SAL_SUCCESS
+//
+// As per static calling conventions.
+//
+//--
+//---------------------------------------------------------------------------
+
+PROCEDURE_ENTRY (EsalSetSalDataArea)
+
+      NESTED_SETUP (4,8,0,0)
+
+EsalCalcStart1_3::
+      mov   r8   = ip;;
+      add   r8   = (ReverseThunkAddress - EsalCalcStart1_3), r8;;
+      st8   [r8] = in0;;
+
+EsalCalcStart1_4::
+      mov   r8   = ip;;
+      add   r8   = (IntThunkAddress - EsalCalcStart1_4), r8;;
+      st8   [r8] = in1;;
+
+      mov   r8   = r0;;
+
+      NESTED_RETURN
+
+PROCEDURE_EXIT (EsalSetSalDataArea)
+
+//-----------------------------------------------------------------------------
+//++
+// EsagGetReverseThunkAddress
+//
+// Register physical address of Esal Data Area
+//
+// On Entry :
+//  out0 = CodeStart
+//  out1 = CodeEnd
+//  out1 = ReverseThunkCode
+//
+// Return Value:
+//  r8 = SAL_SUCCESS
+//
+// As per static calling conventions.
+//
+//--
+//---------------------------------------------------------------------------
+
+PROCEDURE_ENTRY (EsalGetReverseThunkAddress)
+
+          NESTED_SETUP (4,8,0,0)
+
+EsalCalcStart1_31::
+          mov       r8 = ip;;
+          add       r8 = (Ia32CodeStart - EsalCalcStart1_31), r8;;
+          mov       r9 = r8;;
+
+EsalCalcStart1_41::
+          mov       r8  = ip;;
+          add       r8  = (Ia32CodeEnd - EsalCalcStart1_41), r8;;
+          mov       r10 = r8;;
+
+EsalCalcStart1_51::
+          mov       r8  = ip;;
+          add       r8  = (ReverseThunkAddress - EsalCalcStart1_51), r8;;
+          mov       r11 = r8;;
+          mov       r8  = r0;;
+
+          NESTED_RETURN
+
+PROCEDURE_EXIT (EsalGetReverseThunkAddress)
+
+
+.align 16
+PROCEDURE_ENTRY (InterruptRedirectionTemplate)
+          data8            0x90CFCD08
+          data8            0x90CFCD09
+          data8            0x90CFCD0A
+          data8            0x90CFCD0B
+          data8            0x90CFCD0C
+          data8            0x90CFCD0D
+          data8            0x90CFCD0E
+          data8            0x90CFCD0F
+PROCEDURE_EXIT (InterruptRedirectionTemplate)
+
+//------------------------------//
+// Reverse Thunk Code           //
+//------------------------------//
+
+Ia32CodeStart::
+          br.sptk.few Ia32CodeStart;;             // IPF CSM integration -Bug (Write This Code)
+ReverseThunkCode::
+               data8         0xb80f66fa                                    // CLI, JMPE xxxx
+ReverseThunkAddress::
+               data8         0                                                   // Return Address
+IntThunkAddress::
+               data8         0                                                   // IntThunk Address
+Ia32CodeEnd::
+
+
+
+
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c
new file mode 100644 (file)
index 0000000..ca59b97
--- /dev/null
@@ -0,0 +1,550 @@
+/** @file\r
+  Call into 16-bit BIOS code\r
+\r
+  BugBug: Thunker does A20 gate. Can we get rid of this code or\r
+          put it into Legacy16 code.\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+#include "IpfThunk.h"\r
+\r
+/**\r
+  Gets the current flat GDT and IDT descriptors and  store them in\r
+  Private->IntThunk.  These values are used by the Thunk code.\r
+  This method must be called before every thunk in order to assure\r
+  that the correct GDT and IDT are restored after the thunk.\r
+\r
+  @param  Private            Private context for Legacy BIOS\r
+\r
+  @retval EFI_SUCCESS        Should only pass.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosGetFlatDescs (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  )\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  BIOS interrupt call function.\r
+\r
+  @param  BiosInt            Int number of BIOS call\r
+  @param  Segment            Segment number\r
+  @param  Offset             Offset in segment\r
+  @param  Regs               IA32 Register set.\r
+  @param  Stack              Base address of stack\r
+  @param  StackSize          Size of stack\r
+\r
+  @retval EFI_SUCCESS        BIOS interrupt call succeeds.\r
+\r
+**/\r
+EFI_STATUS\r
+BiosIntCall (\r
+  IN  UINT16                            BiosInt,\r
+  IN  UINT16                            Segment,\r
+  IN  UINT16                            Offset,\r
+  IN  EFI_IA32_REGISTER_SET             *Regs,\r
+  IN  VOID                              *Stack,\r
+  IN  UINTN                             StackSize\r
+  )\r
+{\r
+  IPF_DWORD_REGS  DwordRegs;\r
+  UINT64          IntTypeVariable;\r
+\r
+  IntTypeVariable = 0x8000000000000000;\r
+  IntTypeVariable |= BiosInt;\r
+\r
+  DwordRegs.Cs    = Segment;\r
+  DwordRegs.Eip   = Offset;\r
+\r
+  DwordRegs.Ds    = Regs->X.DS;\r
+  DwordRegs.Es    = Regs->X.ES;\r
+  DwordRegs.Fs    = Regs->X.ES;\r
+  DwordRegs.Gs    = Regs->X.ES;\r
+  DwordRegs.Ss    = 0xFFFF;\r
+\r
+  DwordRegs.Eax   = Regs->X.AX;\r
+  DwordRegs.Ebx   = Regs->X.BX;\r
+  //\r
+  // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is\r
+  // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.\r
+  //\r
+  DwordRegs.Ecx   = Regs->E.ECX;\r
+  DwordRegs.Edx   = Regs->X.DX;\r
+\r
+  DwordRegs.Ebp   = Regs->X.BP;\r
+  DwordRegs.Eflag = *((UINT16 *) &Regs->X.Flags);\r
+\r
+  DwordRegs.Edi   = Regs->X.DI;\r
+  DwordRegs.Esi   = Regs->X.SI;\r
+  DwordRegs.Esp   = 0xFFFFFFFF;\r
+\r
+  EfiIaEntryPoint (IntTypeVariable, &DwordRegs, ((UINTN) Stack + StackSize), StackSize);\r
+\r
+  Regs->X.CS  = DwordRegs.Cs;\r
+\r
+  Regs->X.DS  = (UINT16) DwordRegs.Ds;\r
+  Regs->X.SS  = (UINT16) DwordRegs.Ss;\r
+\r
+  Regs->E.EAX  = DwordRegs.Eax;\r
+  Regs->E.EBX  = DwordRegs.Ebx;\r
+  Regs->E.ECX  = DwordRegs.Ecx;\r
+  Regs->E.EDX  = DwordRegs.Edx;\r
+\r
+  Regs->E.EBP  = DwordRegs.Ebp;\r
+  CopyMem (&Regs->X.Flags, &DwordRegs.Eflag, sizeof (EFI_FLAGS_REG));\r
+\r
+  Regs->E.EDI  = DwordRegs.Edi;\r
+  Regs->E.ESI  = DwordRegs.Esi;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Template of real mode code.\r
+\r
+  @param  CodeStart          Start address of code.\r
+  @param  CodeEnd            End address of code\r
+  @param  ReverseThunkStart  Start of reverse thunk.\r
+  @param  IntThunk           Low memory thunk.\r
+\r
+**/\r
+VOID\r
+RealModeTemplate (\r
+  OUT UINTN          *CodeStart,\r
+  OUT UINTN          *CodeEnd,\r
+  OUT UINTN          *ReverseThunkStart,\r
+  LOW_MEMORY_THUNK   *IntThunk\r
+  )\r
+{\r
+  SAL_RETURN_REGS SalStatus;\r
+\r
+  SalStatus           = EsalGetReverseThunkAddress ();\r
+\r
+  *CodeStart          = SalStatus.r9;\r
+  *CodeEnd            = SalStatus.r10;\r
+  *ReverseThunkStart  = SalStatus.r11;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Allocate memory < 1 MB and copy the thunker code into low memory. Se up\r
+  all the descriptors.\r
+\r
+  @param  Private            Private context for Legacy BIOS\r
+\r
+  @retval EFI_SUCCESS        Should only pass.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInitializeThunk (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  )\r
+{\r
+  GDT32               *CodeGdt;\r
+  GDT32               *DataGdt;\r
+  UINTN             CodeStart;\r
+  UINTN             CodeEnd;\r
+  UINTN             ReverseThunkStart;\r
+  UINT32            Base;\r
+  LOW_MEMORY_THUNK  *IntThunk;\r
+  UINTN             TempData;\r
+\r
+  ASSERT (Private);\r
+\r
+  IntThunk = Private->IntThunk;\r
+\r
+  //\r
+  // Clear the reserved descriptor\r
+  //\r
+  ZeroMem (&(IntThunk->RealModeGdt[0]), sizeof (GDT32));\r
+\r
+  //\r
+  // Setup a descriptor for real-mode code\r
+  //\r
+  CodeGdt = &(IntThunk->RealModeGdt[1]);\r
+\r
+  //\r
+  // Fill in the descriptor with our real-mode segment value\r
+  //\r
+  CodeGdt->Type = 0xA;\r
+  //\r
+  // code/read\r
+  //\r
+  CodeGdt->System       = 1;\r
+  CodeGdt->Dpl          = 0;\r
+  CodeGdt->Present      = 1;\r
+  CodeGdt->Software     = 0;\r
+  CodeGdt->Reserved     = 0;\r
+  CodeGdt->DefaultSize  = 0;\r
+  //\r
+  // 16 bit operands\r
+  //\r
+  CodeGdt->Granularity  = 0;\r
+\r
+  CodeGdt->LimitHi      = 0;\r
+  CodeGdt->LimitLo      = 0xffff;\r
+\r
+  Base                  = (*((UINT32 *) &IntThunk->Code));\r
+  CodeGdt->BaseHi       = (Base >> 24) & 0xFF;\r
+  CodeGdt->BaseMid      = (Base >> 16) & 0xFF;\r
+  CodeGdt->BaseLo       = Base & 0xFFFF;\r
+\r
+  //\r
+  // Setup a descriptor for read-mode data\r
+  //\r
+  DataGdt = &(IntThunk->RealModeGdt[2]);\r
+  CopyMem (DataGdt, CodeGdt, sizeof (GDT32));\r
+\r
+  DataGdt->Type = 0x2;\r
+  //\r
+  // read/write data\r
+  //\r
+  DataGdt->BaseHi = 0x0;\r
+  //\r
+  // Base = 0\r
+  //\r
+  DataGdt->BaseMid = 0x0;\r
+  //\r
+  DataGdt->BaseLo = 0x0;\r
+  //\r
+  DataGdt->LimitHi = 0x0F;\r
+  //\r
+  // Limit = 4Gb\r
+  //\r
+  DataGdt->LimitLo = 0xFFFF;\r
+  //\r
+  DataGdt->Granularity = 0x1;\r
+  //\r
+  //\r
+  // Compute selector value\r
+  //\r
+  IntThunk->RealModeGdtDesc.Limit = (UINT16) (sizeof (IntThunk->RealModeGdt) - 1);\r
+  CopyMem (&IntThunk->RealModeGdtDesc.Base, (UINT32 *) &IntThunk->RealModeGdt, sizeof (UINT32));\r
+  //\r
+  //  IntThunk->RealModeGdtDesc.Base = *((UINT32*) &IntThunk->RealModeGdt);\r
+  //\r
+  IntThunk->RealModeIdtDesc.Limit = 0xFFFF;\r
+  IntThunk->RealModeIdtDesc.Base  = 0;\r
+  IntThunk->LowCodeSelector       = (UINT32) ((UINTN) CodeGdt - IntThunk->RealModeGdtDesc.Base);\r
+  IntThunk->LowDataSelector       = (UINT32) ((UINTN) DataGdt - IntThunk->RealModeGdtDesc.Base);\r
+\r
+  //\r
+  // Initialize low real-mode code thunk\r
+  //\r
+  RealModeTemplate (&CodeStart, &CodeEnd, &ReverseThunkStart, IntThunk);\r
+\r
+  TempData                        = (UINTN) &(IntThunk->Code);\r
+  IntThunk->LowReverseThunkStart  = ((UINT32) TempData + (UINT32) (ReverseThunkStart - CodeStart));\r
+\r
+  EsalSetSalDataArea (TempData, (UINTN) IntThunk);\r
+  CopyMem (IntThunk->Code, (VOID *) CodeStart, CodeEnd - CodeStart);\r
+\r
+  IntThunk->EfiToLegacy16InitTable.ReverseThunkCallSegment = EFI_SEGMENT (*((UINT32 *) &IntThunk->LowReverseThunkStart));\r
+  IntThunk->EfiToLegacy16InitTable.ReverseThunkCallOffset = EFI_OFFSET (*((UINT32 *) &IntThunk->LowReverseThunkStart));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Thunk to 16-bit real mode and execute a software interrupt with a vector\r
+  of BiosInt. Regs will contain the 16-bit register context on entry and\r
+  exit.\r
+\r
+  @param  This               Protocol instance pointer.\r
+  @param  BiosInt            Processor interrupt vector to invoke\r
+  @param  Regs               Register contexted passed into (and returned) from\r
+                             thunk to  16-bit mode\r
+\r
+  @retval FALSE              Thunk completed, and there were no BIOS errors in the\r
+                             target code. See Regs for status.\r
+  @retval TRUE               There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LegacyBiosInt86 (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  UINT8                             BiosInt,\r
+  IN  EFI_IA32_REGISTER_SET             *Regs\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  LEGACY_BIOS_INSTANCE  *Private;\r
+  LOW_MEMORY_THUNK      *IntThunk;\r
+  UINT16                *Stack16;\r
+  EFI_TPL               OriginalTpl;\r
+  UINTN                 IaSegment;\r
+  UINTN                 IaOffset;\r
+  UINTN                 *Address;\r
+  UINTN                 TempData;\r
+\r
+  Private   = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  IntThunk  = Private->IntThunk;\r
+\r
+  //\r
+  // Get the current flat GDT, IDT, and SS and store them in Private->IntThunk.\r
+  //\r
+  Status = LegacyBiosGetFlatDescs (Private);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Regs->X.Flags.Reserved1 = 1;\r
+  Regs->X.Flags.Reserved2 = 0;\r
+  Regs->X.Flags.Reserved3 = 0;\r
+  Regs->X.Flags.Reserved4 = 0;\r
+  Regs->X.Flags.IOPL      = 3;\r
+  Regs->X.Flags.NT        = 0;\r
+  Regs->X.Flags.IF        = 1;\r
+  Regs->X.Flags.TF        = 0;\r
+  Regs->X.Flags.CF        = 0;\r
+  //\r
+  // Clear the error flag; thunk code may set it.\r
+  //\r
+  Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);\r
+\r
+  //\r
+  // Copy regs to low memory stack\r
+  //\r
+  Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);\r
+  CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  //\r
+  // Provide low stack esp\r
+  //\r
+  TempData            = ((UINTN) Stack16) - ((UINTN) IntThunk);\r
+  IntThunk->LowStack  = *((UINT32 *) &TempData);\r
+\r
+  //\r
+  // Stack for reverse thunk flat mode.\r
+  //    It must point to top of stack (end of stack space).\r
+  //\r
+  TempData                = ((UINTN) IntThunk->RevThunkStack) + LOW_STACK_SIZE;\r
+  IntThunk->RevFlatStack  = *((UINT32 *) &TempData);\r
+\r
+  //\r
+  // The call to Legacy16 is a critical section to EFI\r
+  //\r
+  OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+  //\r
+  // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.\r
+  //\r
+  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Call the real mode thunk code\r
+  //\r
+  TempData  = BiosInt * 4;\r
+  Address   = (UINTN *) TempData;\r
+  IaOffset  = 0xFFFF & (*Address);\r
+  IaSegment = 0xFFFF & ((*Address) >> 16);\r
+\r
+  Status = BiosIntCall (\r
+            BiosInt,\r
+            (UINT16) IaSegment,\r
+            (UINT16) IaOffset,\r
+            (EFI_IA32_REGISTER_SET *) Stack16,\r
+            IntThunk,\r
+            IntThunk->LowStack\r
+            );\r
+\r
+  //\r
+  // Check for errors with the thunk\r
+  //\r
+  switch (Status) {\r
+  case THUNK_OK:\r
+    break;\r
+\r
+  case THUNK_ERR_A20_UNSUP:\r
+  case THUNK_ERR_A20_FAILED:\r
+  default:\r
+    //\r
+    // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).\r
+    //\r
+    Regs->X.Flags.CF = 1;\r
+    break;\r
+  }\r
+\r
+  Status  = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // End critical section\r
+  //\r
+  gBS->RestoreTPL (OriginalTpl);\r
+\r
+  //\r
+  // Return the resulting registers\r
+  //\r
+  CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  return (BOOLEAN) (Regs->X.Flags.CF != 0);\r
+}\r
+\r
+\r
+/**\r
+  Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the\r
+  16-bit register context on entry and exit. Arguments can be passed on\r
+  the Stack argument\r
+\r
+  @param  This               Protocol instance pointer.\r
+  @param  Segment            Segemnt of 16-bit mode call\r
+  @param  Offset             Offset of 16-bit mdoe call\r
+  @param  Regs               Register contexted passed into (and returned) from\r
+                             thunk to  16-bit mode\r
+  @param  Stack              Caller allocated stack used to pass arguments\r
+  @param  StackSize          Size of Stack in bytes\r
+\r
+  @retval FALSE              Thunk completed, and there were no BIOS errors in the\r
+                             target code. See Regs for status.\r
+  @retval TRUE               There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LegacyBiosFarCall86 (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  UINT16                            Segment,\r
+  IN  UINT16                            Offset,\r
+  IN  EFI_IA32_REGISTER_SET             *Regs,\r
+  IN  VOID                              *Stack,\r
+  IN  UINTN                             StackSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  LEGACY_BIOS_INSTANCE  *Private;\r
+  LOW_MEMORY_THUNK      *IntThunk;\r
+  UINT16                *Stack16;\r
+  EFI_TPL               OriginalTpl;\r
+  UINTN                 IaSegment;\r
+  UINTN                 IaOffset;\r
+  UINTN                 TempData;\r
+\r
+  Private   = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  IntThunk  = Private->IntThunk;\r
+  IaSegment = Segment;\r
+  IaOffset  = Offset;\r
+\r
+  //\r
+  // Get the current flat GDT and IDT and store them in Private->IntThunk.\r
+  //\r
+  Status = LegacyBiosGetFlatDescs (Private);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Regs->X.Flags.Reserved1 = 1;\r
+  Regs->X.Flags.Reserved2 = 0;\r
+  Regs->X.Flags.Reserved3 = 0;\r
+  Regs->X.Flags.Reserved4 = 0;\r
+  Regs->X.Flags.IOPL      = 3;\r
+  Regs->X.Flags.NT        = 0;\r
+  Regs->X.Flags.IF        = 1;\r
+  Regs->X.Flags.TF        = 0;\r
+  Regs->X.Flags.CF        = 0;\r
+  //\r
+  // Clear the error flag; thunk code may set it.\r
+  //\r
+  Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);\r
+  if (Stack != NULL && StackSize != 0) {\r
+    //\r
+    // Copy Stack to low memory stack\r
+    //\r
+    Stack16 -= StackSize / sizeof (UINT16);\r
+    CopyMem (Stack16, Stack, StackSize);\r
+  }\r
+  //\r
+  // Copy regs to low memory stack\r
+  //\r
+  Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);\r
+  CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+  //\r
+  // Provide low stack esp\r
+  //\r
+  TempData            = ((UINTN) Stack16) - ((UINTN) IntThunk);\r
+  IntThunk->LowStack  = *((UINT32 *) &TempData);\r
+\r
+  //\r
+  // The call to Legacy16 is a critical section to EFI\r
+  //\r
+  OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+  //\r
+  // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.\r
+  //\r
+  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Call the real mode thunk code\r
+  //\r
+  Status = BiosIntCall (\r
+            0x100,\r
+            (UINT16) IaSegment,\r
+            (UINT16) IaOffset,\r
+            (EFI_IA32_REGISTER_SET *) Stack16,\r
+            IntThunk,\r
+            IntThunk->LowStack\r
+            );\r
+\r
+  //\r
+  // Check for errors with the thunk\r
+  //\r
+  switch (Status) {\r
+  case THUNK_OK:\r
+    break;\r
+\r
+  case THUNK_ERR_A20_UNSUP:\r
+  case THUNK_ERR_A20_FAILED:\r
+  default:\r
+    //\r
+    // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).\r
+    //\r
+    Regs->X.Flags.CF = 1;\r
+    break;\r
+  }\r
+  //\r
+  // Restore protected mode interrupt state\r
+  //\r
+  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // End critical section\r
+  //\r
+  gBS->RestoreTPL (OriginalTpl);\r
+\r
+  //\r
+  // Return the resulting registers\r
+  //\r
+  CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));\r
+  Stack16 += sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);\r
+\r
+  if (Stack != NULL && StackSize != 0) {\r
+    //\r
+    // Copy low memory stack to Stack\r
+    //\r
+    CopyMem (Stack, Stack16, StackSize);\r
+    Stack16 += StackSize / sizeof (UINT16);\r
+  }\r
+\r
+  return (BOOLEAN) (Regs->X.Flags.CF != 0);\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c
new file mode 100644 (file)
index 0000000..c15e599
--- /dev/null
@@ -0,0 +1,384 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+#include <IndustryStandard/Pci.h>\r
+\r
+// Give floppy 3 states\r
+// FLOPPY_PRESENT_WITH_MEDIA  = Floppy controller present and media is inserted\r
+// FLOPPY_NOT_PRESENT = No floppy controller present\r
+// FLOPPY_PRESENT_NO_MEDIA = Floppy controller present but no media inserted\r
+//\r
+#define FLOPPY_NOT_PRESENT           0\r
+#define FLOPPY_PRESENT_WITH_MEDIA    1\r
+#define FLOPPY_PRESENT_NO_MEDIA      2\r
+\r
+BBS_TABLE           *mBbsTable;\r
+BOOLEAN             mBbsTableDoneFlag   = FALSE;\r
+BOOLEAN             IsHaveMediaInFloppy = TRUE;\r
+\r
+/**\r
+  Checks the state of the floppy and if media is inserted.\r
+  \r
+  This routine checks the state of the floppy and if media is inserted.\r
+  There are 3 cases:\r
+  No floppy present         - Set BBS entry to ignore\r
+  Floppy present & no media - Set BBS entry to lowest priority. We cannot\r
+  set it to ignore since 16-bit CSM will\r
+  indicate no floppy and thus drive A: is\r
+  unusable. CSM-16 will not try floppy since\r
+  lowest priority and thus not incur boot\r
+  time penality.\r
+  Floppy present & media    - Set BBS entry to some priority.\r
+\r
+  @return  State of floppy media\r
+\r
+**/\r
+UINT8\r
+HasMediaInFloppy (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 HandleCount;\r
+  EFI_HANDLE                            *HandleBuffer;\r
+  UINTN                                 Index;\r
+  EFI_ISA_IO_PROTOCOL                   *IsaIo;\r
+  EFI_BLOCK_IO_PROTOCOL                 *BlkIo;\r
+\r
+  HandleBuffer  = NULL;\r
+  HandleCount   = 0;\r
+\r
+  gBS->LocateHandleBuffer (\r
+        ByProtocol,\r
+        &gEfiIsaIoProtocolGuid,\r
+        NULL,\r
+        &HandleCount,\r
+        &HandleBuffer\r
+        );\r
+\r
+  //\r
+  // If don't find any ISA/IO protocol assume no floppy. Need for floppy\r
+  // free system\r
+  //\r
+  if (HandleCount == 0) {\r
+    return FLOPPY_NOT_PRESENT;\r
+  }\r
+\r
+  ASSERT (HandleBuffer != NULL);\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiIsaIoProtocolGuid,\r
+                    (VOID **) &IsaIo\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {\r
+      continue;\r
+    }\r
+    //\r
+    // Update blockio in case the floppy is inserted in during BdsTimeout\r
+    //\r
+    Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlkIo\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if (BlkIo->Media->MediaPresent) {\r
+      FreePool (HandleBuffer);\r
+      return FLOPPY_PRESENT_WITH_MEDIA;\r
+    } else {\r
+      FreePool (HandleBuffer);\r
+      return FLOPPY_PRESENT_NO_MEDIA;\r
+    }\r
+  }\r
+\r
+  FreePool (HandleBuffer);\r
+\r
+  return FLOPPY_NOT_PRESENT;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Complete build of BBS TABLE.\r
+\r
+  @param  Private                 Legacy BIOS Instance data\r
+  @param  BbsTable                BBS Table passed to 16-bit code\r
+\r
+  @retval EFI_SUCCESS             Removable media not present\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildBbs (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private,\r
+  IN  BBS_TABLE                 *BbsTable\r
+  )\r
+{\r
+  UINTN     BbsIndex;\r
+  HDD_INFO  *HddInfo;\r
+  UINTN     HddIndex;\r
+  UINTN     Index;\r
+\r
+  //\r
+  // First entry is floppy.\r
+  // Next 2*MAX_IDE_CONTROLLER entries are for onboard IDE.\r
+  // Next n entries are filled in after each ROM is dispatched.\r
+  //   Entry filled in if follow BBS spec. See LegacyPci.c\r
+  // Next entries are for non-BBS compliant ROMS. They are filled in by\r
+  //   16-bit code during Legacy16UpdateBbs invocation. Final BootPriority\r
+  //   occurs after that invocation.\r
+  //\r
+  // Floppy\r
+  // Set default state.\r
+  //\r
+  IsHaveMediaInFloppy = HasMediaInFloppy ();\r
+  if (IsHaveMediaInFloppy == FLOPPY_PRESENT_WITH_MEDIA) {\r
+    BbsTable[0].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+  } else {\r
+    if (IsHaveMediaInFloppy == FLOPPY_PRESENT_NO_MEDIA) {\r
+      BbsTable[0].BootPriority = BBS_LOWEST_PRIORITY;\r
+    } else {\r
+      BbsTable[0].BootPriority = BBS_IGNORE_ENTRY;\r
+    }\r
+  }\r
+\r
+  BbsTable[0].Bus                       = 0xff;\r
+  BbsTable[0].Device                    = 0xff;\r
+  BbsTable[0].Function                  = 0xff;\r
+  BbsTable[0].DeviceType                = BBS_FLOPPY;\r
+  BbsTable[0].Class                     = 01;\r
+  BbsTable[0].SubClass                  = 02;\r
+  BbsTable[0].StatusFlags.OldPosition   = 0;\r
+  BbsTable[0].StatusFlags.Reserved1     = 0;\r
+  BbsTable[0].StatusFlags.Enabled       = 0;\r
+  BbsTable[0].StatusFlags.Failed        = 0;\r
+  BbsTable[0].StatusFlags.MediaPresent  = 0;\r
+  BbsTable[0].StatusFlags.Reserved2     = 0;\r
+\r
+  //\r
+  // Onboard HDD - Note Each HDD controller controls 2 drives\r
+  //               Master & Slave\r
+  //\r
+  HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];\r
+  //\r
+  // Get IDE Drive Info\r
+  //\r
+  LegacyBiosBuildIdeData (Private, &HddInfo, 0);\r
+\r
+  for (HddIndex = 0; HddIndex < MAX_IDE_CONTROLLER; HddIndex++) {\r
+\r
+    BbsIndex = HddIndex * 2 + 1;\r
+    for (Index = 0; Index < 2; ++Index) {\r
+\r
+      BbsTable[BbsIndex + Index].Bus                      = HddInfo[HddIndex].Bus;\r
+      BbsTable[BbsIndex + Index].Device                   = HddInfo[HddIndex].Device;\r
+      BbsTable[BbsIndex + Index].Function                 = HddInfo[HddIndex].Function;\r
+      BbsTable[BbsIndex + Index].Class                    = 01;\r
+      BbsTable[BbsIndex + Index].SubClass                 = 01;\r
+      BbsTable[BbsIndex + Index].StatusFlags.OldPosition  = 0;\r
+      BbsTable[BbsIndex + Index].StatusFlags.Reserved1    = 0;\r
+      BbsTable[BbsIndex + Index].StatusFlags.Enabled      = 0;\r
+      BbsTable[BbsIndex + Index].StatusFlags.Failed       = 0;\r
+      BbsTable[BbsIndex + Index].StatusFlags.MediaPresent = 0;\r
+      BbsTable[BbsIndex + Index].StatusFlags.Reserved2    = 0;\r
+\r
+      //\r
+      // If no controller found or no device found set to ignore\r
+      // else set to unprioritized and set device type\r
+      //\r
+      if (HddInfo[HddIndex].CommandBaseAddress == 0) {\r
+        BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;\r
+      } else {\r
+        if (Index == 0) {\r
+          if ((HddInfo[HddIndex].Status & (HDD_MASTER_IDE | HDD_MASTER_ATAPI_CDROM | HDD_MASTER_ATAPI_ZIPDISK)) != 0) {\r
+            BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+            if ((HddInfo[HddIndex].Status & HDD_MASTER_IDE) != 0) {\r
+              BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;\r
+            } else if ((HddInfo[HddIndex].Status & HDD_MASTER_ATAPI_CDROM) != 0) {\r
+              BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;\r
+            } else {\r
+              //\r
+              // for ZIPDISK\r
+              //\r
+              BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;\r
+            }\r
+          } else {\r
+            BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;\r
+          }\r
+        } else {\r
+          if ((HddInfo[HddIndex].Status & (HDD_SLAVE_IDE | HDD_SLAVE_ATAPI_CDROM | HDD_SLAVE_ATAPI_ZIPDISK)) != 0) {\r
+            BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+            if ((HddInfo[HddIndex].Status & HDD_SLAVE_IDE) != 0) {\r
+              BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;\r
+            } else if ((HddInfo[HddIndex].Status & HDD_SLAVE_ATAPI_CDROM) != 0) {\r
+              BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;\r
+            } else {\r
+              //\r
+              // for ZIPDISK\r
+              //\r
+              BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;\r
+            }\r
+          } else {\r
+            BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Get all BBS info\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  HddCount                Number of HDD_INFO structures\r
+  @param  HddInfo                 Onboard IDE controller information\r
+  @param  BbsCount                Number of BBS_TABLE structures\r
+  @param  BbsTable                List BBS entries\r
+\r
+  @retval EFI_SUCCESS             Tables returned\r
+  @retval EFI_NOT_FOUND           resource not found\r
+  @retval EFI_DEVICE_ERROR        can not get BBS table\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosGetBbsInfo (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  OUT UINT16                          *HddCount,\r
+  OUT HDD_INFO                        **HddInfo,\r
+  OUT UINT16                          *BbsCount,\r
+  OUT BBS_TABLE                       **BbsTable\r
+  )\r
+{\r
+  LEGACY_BIOS_INSTANCE              *Private;\r
+  EFI_IA32_REGISTER_SET             Regs;\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
+//  HDD_INFO                          *LocalHddInfo;\r
+//  IN BBS_TABLE                      *LocalBbsTable;\r
+  UINTN                             NumHandles;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             Index;\r
+  UINTN                             TempData;\r
+  UINT32                            Granularity;\r
+\r
+  HandleBuffer            = NULL;\r
+\r
+  Private                 = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  EfiToLegacy16BootTable  = &Private->IntThunk->EfiToLegacy16BootTable;\r
+//  LocalHddInfo            = EfiToLegacy16BootTable->HddInfo;\r
+//  LocalBbsTable           = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;\r
+\r
+  if (!mBbsTableDoneFlag) {\r
+    mBbsTable = Private->BbsTablePtr;\r
+\r
+    //\r
+    // Always enable disk controllers so 16-bit CSM code has valid information for all\r
+    // drives.\r
+    //\r
+    //\r
+    // Get PciRootBridgeIO protocol\r
+    //\r
+    gBS->LocateHandleBuffer (\r
+          ByProtocol,\r
+          &gEfiPciRootBridgeIoProtocolGuid,\r
+          NULL,\r
+          &NumHandles,\r
+          &HandleBuffer\r
+          );\r
+\r
+    if (NumHandles == 0) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    mBbsTableDoneFlag = TRUE;\r
+    for (Index = 0; Index < NumHandles; Index++) {\r
+      //\r
+      // Connect PciRootBridgeIO protocol handle with FALSE parameter to let\r
+      // PCI bus driver enumerate all subsequent handles\r
+      //\r
+      gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);\r
+\r
+    }\r
+\r
+    LegacyBiosBuildBbs (Private, mBbsTable);\r
+\r
+    Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);\r
+\r
+    //\r
+    // Call into Legacy16 code to add to BBS table for non BBS compliant OPROMs.\r
+    //\r
+    ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+    Regs.X.AX = Legacy16UpdateBbs;\r
+\r
+    //\r
+    // Pass in handoff data\r
+    //\r
+    TempData  = (UINTN) EfiToLegacy16BootTable;\r
+    Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);\r
+    Regs.X.BX = EFI_OFFSET ((UINT32) TempData);\r
+\r
+    Private->LegacyBios.FarCall86 (\r
+      This,\r
+      Private->Legacy16CallSegment,\r
+      Private->Legacy16CallOffset,\r
+      &Regs,\r
+      NULL,\r
+      0\r
+      );\r
+\r
+    Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
+    Private->LegacyRegion->Lock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);\r
+\r
+    if (Regs.X.AX != 0) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+  }\r
+\r
+  *HddCount = MAX_IDE_CONTROLLER;\r
+  *HddInfo  = EfiToLegacy16BootTable->HddInfo;\r
+  *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;\r
+  *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c
new file mode 100644 (file)
index 0000000..c45d5d4
--- /dev/null
@@ -0,0 +1,66 @@
+/** @file\r
+  This code fills in BDA (0x400) and EBDA (pointed to by 0x4xx)\r
+  information. There is support for doing initializeation before\r
+  Legacy16 is loaded and before a legacy boot is attempted.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+\r
+/**\r
+  Fill in the standard BDA and EBDA stuff before Legacy16 load\r
+\r
+  @param  Private     Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInitBda (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  )\r
+{\r
+  BDA_STRUC *Bda;\r
+  UINT8     *Ebda;\r
+\r
+  Bda   = (BDA_STRUC *) ((UINTN) 0x400);\r
+  Ebda  = (UINT8 *) ((UINTN) 0x9fc00);\r
+\r
+  ZeroMem (Bda, 0x100);\r
+  ZeroMem (Ebda, 0x400);\r
+  //\r
+  // 640k-1k for EBDA\r
+  //\r
+  Bda->MemSize        = 0x27f;\r
+  Bda->KeyHead        = 0x1e;\r
+  Bda->KeyTail        = 0x1e;\r
+  Bda->FloppyData     = 0x00;\r
+  Bda->FloppyTimeout  = 0xff;\r
+\r
+  Bda->KeyStart       = 0x001E;\r
+  Bda->KeyEnd         = 0x003E;\r
+  Bda->KeyboardStatus = 0x10;\r
+  Bda->Ebda           = 0x9fc0;\r
+\r
+  //\r
+  // Move LPT time out here and zero out LPT4 since some SCSI OPROMS\r
+  // use this as scratch pad (LPT4 is Reserved)\r
+  //\r
+  Bda->Lpt1_2Timeout  = 0x1414;\r
+  Bda->Lpt3_4Timeout  = 0x1400;\r
+\r
+  *Ebda               = 0x01;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
new file mode 100644 (file)
index 0000000..75add5e
--- /dev/null
@@ -0,0 +1,1007 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+\r
+#define PHYSICAL_ADDRESS_TO_POINTER(Address)  ((VOID *) ((UINTN) Address))\r
+\r
+//\r
+// define maximum number of HDD system supports\r
+//\r
+#define MAX_HDD_ENTRIES 0x30\r
+\r
+//\r
+// Module Global:\r
+//  Since this driver will only ever produce one instance of the Private Data\r
+//  protocol you are not required to dynamically allocate the PrivateData.\r
+//\r
+LEGACY_BIOS_INSTANCE  mPrivateData;\r
+\r
+//\r
+// The end of OPROM shadow address\r
+//\r
+UINTN                 mEndOpromShadowAddress = 0;\r
+\r
+/**\r
+  Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode\r
+  memory.\r
+\r
+  @param  AllocateType               Allocated Legacy Memory Type\r
+  @param  StartPageAddress           Start address of range\r
+  @param  Pages                      Number of pages to allocate\r
+  @param  Result                     Result of allocation\r
+\r
+  @retval EFI_SUCCESS                Legacy16 code loaded\r
+  @retval Other                      No protocol installed, unload driver.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocateLegacyMemory (\r
+  IN  EFI_ALLOCATE_TYPE         AllocateType,\r
+  IN  EFI_PHYSICAL_ADDRESS      StartPageAddress,\r
+  IN  UINTN                     Pages,\r
+  OUT EFI_PHYSICAL_ADDRESS      *Result\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  MemPage;\r
+\r
+  //\r
+  // Allocate Pages of memory less <= StartPageAddress\r
+  //\r
+  MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;\r
+  Status = gBS->AllocatePages (\r
+                  AllocateType,\r
+                  EfiBootServicesCode,\r
+                  Pages,\r
+                  &MemPage\r
+                  );\r
+  //\r
+  // Do not ASSERT on Status error but let caller decide since some cases\r
+  // memory is already taken but that is ok.\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+    *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;\r
+  }\r
+  //\r
+  // If reach here the status = EFI_SUCCESS\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000\r
+  64 KB blocks.\r
+\r
+  Note: inconsistency with the Framework CSM spec. Per the spec, this function may be\r
+  invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.\r
+\r
+  @param  This                       Protocol instance pointer.\r
+  @param  LegacyMemorySize           Size of required region\r
+  @param  Region                     Region to use. 00 = Either 0xE0000 or 0xF0000\r
+                                     block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000\r
+                                     block\r
+  @param  Alignment                  Address alignment. Bit mapped. First non-zero\r
+                                     bit from right is alignment.\r
+  @param  LegacyMemoryAddress        Region Assigned\r
+\r
+  @retval EFI_SUCCESS                Region assigned\r
+  @retval EFI_ACCESS_DENIED          Procedure previously invoked\r
+  @retval Other                      Region not assigned\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosGetLegacyRegion (\r
+  IN    EFI_LEGACY_BIOS_PROTOCOL *This,\r
+  IN    UINTN                    LegacyMemorySize,\r
+  IN    UINTN                    Region,\r
+  IN    UINTN                    Alignment,\r
+  OUT   VOID                     **LegacyMemoryAddress\r
+  )\r
+{\r
+\r
+  LEGACY_BIOS_INSTANCE  *Private;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+  EFI_STATUS            Status;\r
+  UINT32                Granularity;\r
+\r
+  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
+\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+  Regs.X.AX = Legacy16GetTableAddress;\r
+  Regs.X.BX = (UINT16) Region;\r
+  Regs.X.CX = (UINT16) LegacyMemorySize;\r
+  Regs.X.DX = (UINT16) Alignment;\r
+  Private->LegacyBios.FarCall86 (\r
+     &Private->LegacyBios,\r
+     Private->Legacy16CallSegment,\r
+     Private->Legacy16CallOffset,\r
+     &Regs,\r
+     NULL,\r
+     0\r
+     );\r
+\r
+  if (Regs.X.AX == 0) {\r
+    *LegacyMemoryAddress  = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
+  Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is called when copying data to the region assigned by\r
+  EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().\r
+\r
+  @param  This                       Protocol instance pointer.\r
+  @param  LegacyMemorySize           Size of data to copy\r
+  @param  LegacyMemoryAddress        Legacy Region destination address Note: must\r
+                                     be in region assigned by\r
+                                     LegacyBiosGetLegacyRegion\r
+  @param  LegacyMemorySourceAddress  Source of data\r
+\r
+  @retval EFI_SUCCESS                The data was copied successfully.\r
+  @retval EFI_ACCESS_DENIED          Either the starting or ending address is out of bounds.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosCopyLegacyRegion (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
+  IN    UINTN                 LegacyMemorySize,\r
+  IN    VOID                  *LegacyMemoryAddress,\r
+  IN    VOID                  *LegacyMemorySourceAddress\r
+  )\r
+{\r
+\r
+  LEGACY_BIOS_INSTANCE  *Private;\r
+  UINT32                Granularity;\r
+\r
+  if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||\r
+      ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)\r
+        ) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // There is no protection from writes over lapping if this function is\r
+  // called multiple times.\r
+  //\r
+  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
+  CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);\r
+\r
+  Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
+  Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find\r
+  the $EFI table in the shadow area. Thunk into the Legacy16 code after it had\r
+  been shadowed.\r
+\r
+  @param  Private                    Legacy BIOS context data\r
+\r
+  @retval EFI_SUCCESS                Legacy16 code loaded\r
+  @retval Other                      No protocol installed, unload driver.\r
+\r
+**/\r
+EFI_STATUS\r
+ShadowAndStartLegacy16 (\r
+  IN  LEGACY_BIOS_INSTANCE  *Private\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT8                             *Ptr;\r
+  UINT8                             *PtrEnd;\r
+  BOOLEAN                           Done;\r
+  EFI_COMPATIBILITY16_TABLE         *Table;\r
+  UINT8                             CheckSum;\r
+  EFI_IA32_REGISTER_SET             Regs;\r
+  EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
+  VOID                              *LegacyBiosImage;\r
+  UINTN                             LegacyBiosImageSize;\r
+  UINTN                             E820Size;\r
+  UINT32                            *ClearPtr;\r
+  BBS_TABLE                         *BbsTable;\r
+  LEGACY_EFI_HDD_TABLE              *LegacyEfiHddTable;\r
+  UINTN                             Index;\r
+  UINT32                            TpmPointer;\r
+  VOID                              *TpmBinaryImage;\r
+  UINTN                             TpmBinaryImageSize;\r
+  UINTN                             Location;\r
+  UINTN                             Alignment;\r
+  UINTN                             TempData;\r
+  EFI_PHYSICAL_ADDRESS              Address;\r
+  UINT16                            OldMask;\r
+  UINT16                            NewMask;\r
+  UINT32                            Granularity;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   Descriptor;\r
+\r
+  Location  = 0;\r
+  Alignment = 0;\r
+\r
+  //\r
+  // we allocate the C/D/E/F segment as RT code so no one will use it any more.\r
+  //\r
+  Address = 0xC0000;\r
+  gDS->GetMemorySpaceDescriptor (Address, &Descriptor);\r
+  if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {\r
+    //\r
+    // If it is already reserved, we should be safe, or else we allocate it.\r
+    //\r
+    Status = gBS->AllocatePages (\r
+                    AllocateAddress,\r
+                    EfiRuntimeServicesCode,\r
+                    0x40000/EFI_PAGE_SIZE,\r
+                    &Address\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.\r
+      // \r
+      DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));\r
+    }\r
+  }\r
+\r
+  //\r
+  // start testtest\r
+  //    GetTimerValue (&Ticker);\r
+  //\r
+  //  gRT->SetVariable (L"StartLegacy",\r
+  //                    &gEfiGlobalVariableGuid,\r
+  //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+  //                    sizeof (UINT64),\r
+  //                    (VOID *)&Ticker\r
+  //                    );\r
+  // end testtest\r
+  //\r
+  EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
+  Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformBinarySystemRom,\r
+                                          &LegacyBiosImage,\r
+                                          &LegacyBiosImageSize,\r
+                                          &Location,\r
+                                          &Alignment,\r
+                                          0,\r
+                                          0\r
+                                          );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Private->BiosStart            = (UINT32) (0x100000 - LegacyBiosImageSize);\r
+  Private->OptionRom            = 0xc0000;\r
+  Private->LegacyBiosImageSize  = (UINT32) LegacyBiosImageSize;\r
+\r
+  //\r
+  // Can only shadow into memory allocated for legacy useage.\r
+  //\r
+  ASSERT (Private->BiosStart > Private->OptionRom);\r
+\r
+  //\r
+  // Shadow Legacy BIOS. Turn on memory and copy image\r
+  //\r
+  Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);\r
+\r
+  ClearPtr = (VOID *) ((UINTN) 0xc0000);\r
+\r
+  //\r
+  // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused\r
+  // regions to be used by EMM386 etc.\r
+  //\r
+  SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);\r
+\r
+  TempData = Private->BiosStart;\r
+\r
+  CopyMem (\r
+    (VOID *) TempData,\r
+    LegacyBiosImage,\r
+    (UINTN) LegacyBiosImageSize\r
+    );\r
+\r
+  Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);\r
+\r
+  //\r
+  // Search for Legacy16 table in Shadowed ROM\r
+  //\r
+  Done  = FALSE;\r
+  Table = NULL;\r
+  for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {\r
+    if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {\r
+      Table   = (EFI_COMPATIBILITY16_TABLE *) Ptr;\r
+      PtrEnd  = Ptr + Table->TableLength;\r
+      for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {\r
+        CheckSum = (UINT8) (CheckSum +*Ptr);\r
+      }\r
+\r
+      Done = TRUE;\r
+    }\r
+  }\r
+\r
+  if (Table == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (!Done) {\r
+    //\r
+    // Legacy16 table header checksum error.\r
+    //\r
+    DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));\r
+  }\r
+\r
+  //\r
+  // Remember location of the Legacy16 table\r
+  //\r
+  Private->Legacy16Table            = Table;\r
+  Private->Legacy16CallSegment      = Table->Compatibility16CallSegment;\r
+  Private->Legacy16CallOffset       = Table->Compatibility16CallOffset;\r
+  EfiToLegacy16InitTable            = &Private->IntThunk->EfiToLegacy16InitTable;\r
+  Private->Legacy16InitPtr          = EfiToLegacy16InitTable;\r
+  Private->Legacy16BootPtr          = &Private->IntThunk->EfiToLegacy16BootTable;\r
+  Private->InternalIrqRoutingTable  = NULL;\r
+  Private->NumberIrqRoutingEntries  = 0;\r
+  Private->BbsTablePtr              = NULL;\r
+  Private->LegacyEfiHddTable        = NULL;\r
+  Private->DiskEnd                  = 0;\r
+  Private->Disk4075                 = 0;\r
+  Private->HddTablePtr              = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;\r
+  Private->NumberHddControllers     = MAX_IDE_CONTROLLER;\r
+  Private->Dump[0]                  = 'D';\r
+  Private->Dump[1]                  = 'U';\r
+  Private->Dump[2]                  = 'M';\r
+  Private->Dump[3]                  = 'P';\r
+\r
+  ZeroMem (\r
+    Private->Legacy16BootPtr,\r
+    sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)\r
+    );\r
+\r
+  //\r
+  // Store away a copy of the EFI System Table\r
+  //\r
+  Table->EfiSystemTable = (UINT32) (UINTN) gST;\r
+\r
+  //\r
+  // Get the end of OPROM shadow address\r
+  //\r
+  Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformEndOpromShadowAddr,\r
+                                          NULL,\r
+                                          NULL,\r
+                                          &mEndOpromShadowAddress,\r
+                                          NULL,\r
+                                          0,\r
+                                          0\r
+                                          );\r
+  if (EFI_ERROR (Status)) {\r
+    mEndOpromShadowAddress = 0xDFFFF;\r
+  }\r
+\r
+  //\r
+  // IPF CSM integration -Bug\r
+  //\r
+  // Construct the Legacy16 boot memory map. This sets up number of\r
+  // E820 entries.\r
+  //\r
+  LegacyBiosBuildE820 (Private, &E820Size);\r
+  //\r
+  // Initialize BDA and EBDA standard values needed to load Legacy16 code\r
+  //\r
+  LegacyBiosInitBda (Private);\r
+  LegacyBiosInitCmos (Private);\r
+\r
+  //\r
+  // All legacy interrupt should be masked when do initialization work from legacy 16 code.\r
+  //\r
+  Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r
+  NewMask = 0xFFFF;\r
+  Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);\r
+  \r
+  //\r
+  // Call into Legacy16 code to do an INIT\r
+  //\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+  Regs.X.AX = Legacy16InitializeYourself;\r
+  Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));\r
+  Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));\r
+\r
+  Private->LegacyBios.FarCall86 (\r
+    &Private->LegacyBios,\r
+    Table->Compatibility16CallSegment,\r
+    Table->Compatibility16CallOffset,\r
+    &Regs,\r
+    NULL,\r
+    0\r
+    );\r
+\r
+  //\r
+  // Restore original legacy interrupt mask value\r
+  //\r
+  Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r
+  \r
+  if (Regs.X.AX != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // start testtest\r
+  //  GetTimerValue (&Ticker);\r
+  //\r
+  //  gRT->SetVariable (L"BackFromInitYourself",\r
+  //                    &gEfiGlobalVariableGuid,\r
+  //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+  //                    sizeof (UINT64),\r
+  //                    (VOID *)&Ticker\r
+  //                    );\r
+  // end testtest\r
+  //\r
+  // Copy E820 table after InitializeYourself is completed\r
+  //\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+  Regs.X.AX = Legacy16GetTableAddress;\r
+  Regs.X.CX = (UINT16) E820Size;\r
+  Regs.X.DX = 1;\r
+  Private->LegacyBios.FarCall86 (\r
+    &Private->LegacyBios,\r
+    Table->Compatibility16CallSegment,\r
+    Table->Compatibility16CallOffset,\r
+    &Regs,\r
+    NULL,\r
+    0\r
+    );\r
+\r
+  Table->E820Pointer  = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
+  Table->E820Length   = (UINT32) E820Size;\r
+  if (Regs.X.AX != 0) {\r
+    DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));\r
+  } else {\r
+    TempData = Table->E820Pointer;\r
+    CopyMem ((VOID *) TempData, Private->E820Table, E820Size);\r
+  }\r
+  //\r
+  // Get PnPInstallationCheck Info.\r
+  //\r
+  Private->PnPInstallationCheckSegment  = Table->PnPInstallationCheckSegment;\r
+  Private->PnPInstallationCheckOffset   = Table->PnPInstallationCheckOffset;\r
+\r
+  //\r
+  // Check if PCI Express is supported. If yes, Save base address.\r
+  //\r
+  Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformPciExpressBase,\r
+                                          NULL,\r
+                                          NULL,\r
+                                          &Location,\r
+                                          &Alignment,\r
+                                          0,\r
+                                          0\r
+                                          );\r
+  if (!EFI_ERROR (Status)) {\r
+    Private->Legacy16Table->PciExpressBase  = (UINT32)Location;\r
+    Location = 0;\r
+  }\r
+  //\r
+  // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it\r
+  // into, copy it and update pointer to binary image. This needs to be\r
+  // done prior to any OPROM for security purposes.\r
+  //\r
+  Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformBinaryTpmBinary,\r
+                                          &TpmBinaryImage,\r
+                                          &TpmBinaryImageSize,\r
+                                          &Location,\r
+                                          &Alignment,\r
+                                          0,\r
+                                          0\r
+                                          );\r
+  if (!EFI_ERROR (Status)) {\r
+\r
+    ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+    Regs.X.AX = Legacy16GetTableAddress;\r
+    Regs.X.CX = (UINT16) TpmBinaryImageSize;\r
+    Regs.X.DX = 1;\r
+    Private->LegacyBios.FarCall86 (\r
+      &Private->LegacyBios,\r
+      Table->Compatibility16CallSegment,\r
+      Table->Compatibility16CallOffset,\r
+      &Regs,\r
+      NULL,\r
+      0\r
+      );\r
+\r
+    TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
+    if (Regs.X.AX != 0) {\r
+      DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));\r
+    } else {\r
+      CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);\r
+      Table->TpmSegment = Regs.X.DS;\r
+      Table->TpmOffset  = Regs.X.BX;\r
+\r
+    }\r
+  }\r
+  //\r
+  // Lock the Legacy BIOS region\r
+  //\r
+  Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);\r
+  Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);\r
+\r
+  //\r
+  // Get the BbsTable from LOW_MEMORY_THUNK\r
+  //\r
+  BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;\r
+  ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));\r
+\r
+  EfiToLegacy16BootTable->BbsTable  = (UINT32)(UINTN)BbsTable;\r
+  Private->BbsTablePtr              = (VOID *) BbsTable;\r
+  //\r
+  // Skip Floppy and possible onboard IDE drives\r
+  //\r
+  EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;\r
+\r
+  for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {\r
+    BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;\r
+  }\r
+  //\r
+  // Allocate space for Legacy HDD table\r
+  //\r
+  LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));\r
+  ASSERT (LegacyEfiHddTable);\r
+\r
+  Private->LegacyEfiHddTable      = LegacyEfiHddTable;\r
+  Private->LegacyEfiHddTableIndex = 0x00;\r
+\r
+  //\r
+  // start testtest\r
+  //  GetTimerValue (&Ticker);\r
+  //\r
+  //  gRT->SetVariable (L"EndOfLoadFv",\r
+  //                    &gEfiGlobalVariableGuid,\r
+  //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+  //                    sizeof (UINT64),\r
+  //                    (VOID *)&Ticker\r
+  //                    );\r
+  // end testtest\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Shadow all legacy16 OPROMs that haven't been shadowed.\r
+  Warning: Use this with caution. This routine disconnects all EFI\r
+  drivers. If used externally then caller must re-connect EFI\r
+  drivers.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS             OPROMs shadowed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosShadowAllLegacyOproms (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL *This\r
+  )\r
+{\r
+  LEGACY_BIOS_INSTANCE  *Private;\r
+\r
+  //\r
+  //  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL    *LegacyBiosPlatform;\r
+  //  EFI_LEGACY16_TABLE                   *Legacy16Table;\r
+  //\r
+  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+\r
+  //\r
+  //  LegacyBiosPlatform       = Private->LegacyBiosPlatform;\r
+  //  Legacy16Table            = Private->Legacy16Table;\r
+  //\r
+  // Shadow PCI ROMs. We must do this near the end since this will kick\r
+  // of Native EFI drivers that may be needed to collect info for Legacy16\r
+  //\r
+  //  WARNING: PciIo is gone after this call.\r
+  //\r
+  PciProgramAllInterruptLineRegisters (Private);\r
+\r
+  PciShadowRoms (Private);\r
+\r
+  //\r
+  // Shadow PXE base code, BIS etc.\r
+  //\r
+  //  LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,\r
+  //                       &Private->OptionRom,\r
+  //                       Legacy16Table);\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the PCI BIOS interface version.\r
+\r
+  @param  Private  Driver private data.\r
+\r
+  @return The PCI interface version number in Binary Coded Decimal (BCD) format.\r
+          E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00\r
+\r
+**/\r
+UINT16\r
+GetPciInterfaceVersion (\r
+  IN LEGACY_BIOS_INSTANCE *Private\r
+  )\r
+{\r
+  EFI_IA32_REGISTER_SET Reg;\r
+  BOOLEAN               ThunkFailed;\r
+  UINT16                PciInterfaceVersion;\r
+\r
+  PciInterfaceVersion = 0;\r
+  \r
+  Reg.X.AX = 0xB101;\r
+  Reg.E.EDI = 0;\r
+\r
+  ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);\r
+  if (!ThunkFailed) {\r
+    //\r
+    // From PCI Firmware 3.0 Specification:\r
+    //   If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the\r
+    //   contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the\r
+    //   presence of the PCI function set. [BX] will further indicate the version level, with enough\r
+    //   granularity to allow for incremental changes in the code that don't affect the function interface.\r
+    //   Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10\r
+    //   would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.\r
+    //\r
+    if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {\r
+      PciInterfaceVersion = Reg.X.BX;\r
+    }\r
+  }\r
+  return PciInterfaceVersion;\r
+}\r
+\r
+/**\r
+  Install Driver to produce Legacy BIOS protocol.\r
+\r
+  @param  ImageHandle  Handle of driver image.\r
+  @param  SystemTable  Pointer to system table.\r
+\r
+  @retval EFI_SUCCESS  Legacy BIOS protocol installed\r
+  @retval No protocol installed, unload driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosInstall (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  LEGACY_BIOS_INSTANCE               *Private;\r
+  EFI_TO_COMPATIBILITY16_INIT_TABLE  *EfiToLegacy16InitTable;\r
+  EFI_PHYSICAL_ADDRESS               MemoryAddress;\r
+  VOID                               *MemoryPtr;\r
+  EFI_PHYSICAL_ADDRESS               MemoryAddressUnder1MB;\r
+  UINTN                              Index;\r
+  UINT32                             *BaseVectorMaster;\r
+  EFI_PHYSICAL_ADDRESS               StartAddress;\r
+  UINT32                             *ClearPtr;\r
+  EFI_PHYSICAL_ADDRESS               MemStart;\r
+  UINT32                             IntRedirCode;\r
+  UINT32                             Granularity;\r
+  BOOLEAN                            DecodeOn;\r
+  UINT32                             MemorySize;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR    Descriptor;\r
+  UINT64                             Length;\r
+\r
+  //\r
+  // Load this driver's image to memory\r
+  //\r
+  Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Private = &mPrivateData;\r
+  ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));\r
+\r
+  //\r
+  // Grab a copy of all the protocols we depend on. Any error would\r
+  // be a dispatcher bug!.\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Locate Memory Test Protocol if exists\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiGenericMemTestProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &Private->GenericMemoryTest\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Make sure all memory from 0-640K is tested\r
+  //\r
+  for (StartAddress = 0; StartAddress < 0xa0000; ) {\r
+    gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r
+    if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
+      StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r
+      continue;\r
+    }\r
+    Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);\r
+    Private->GenericMemoryTest->CompatibleRangeTest (\r
+                                  Private->GenericMemoryTest,\r
+                                  StartAddress,\r
+                                  Length\r
+                                  );\r
+    StartAddress = StartAddress + Length;\r
+  }\r
+  //\r
+  // Make sure all memory from 1MB to 16MB is tested and added to memory map\r
+  //\r
+  for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {\r
+    gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r
+    if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
+      StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r
+      continue;\r
+    }\r
+    Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);\r
+    Private->GenericMemoryTest->CompatibleRangeTest (\r
+                                  Private->GenericMemoryTest,\r
+                                  StartAddress,\r
+                                  Length\r
+                                  );\r
+    StartAddress = StartAddress + Length;\r
+  }\r
+\r
+  Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;\r
+\r
+  Private->LegacyBios.Int86 = LegacyBiosInt86;\r
+  Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;\r
+  Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;\r
+  Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;\r
+  Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;\r
+  Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;\r
+  Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;\r
+  Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;\r
+  Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;\r
+  Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;\r
+  Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;\r
+  Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;\r
+\r
+  Private->ImageHandle = ImageHandle;\r
+\r
+  //\r
+  // Enable read attribute of legacy region.\r
+  //\r
+  DecodeOn = TRUE;\r
+  Private->LegacyRegion->Decode (\r
+                           Private->LegacyRegion,\r
+                           0xc0000,\r
+                           0x40000,\r
+                           &Granularity,\r
+                           &DecodeOn\r
+                           );\r
+  //\r
+  // Set Cachebility for legacy region\r
+  // BUGBUG: Comments about this legacy region cacheability setting\r
+  //         This setting will make D865GCHProduction CSM Unhappy\r
+  //\r
+  if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {\r
+    gDS->SetMemorySpaceAttributes (\r
+           0x0,\r
+           0xA0000,\r
+           EFI_MEMORY_WB\r
+           );\r
+    gDS->SetMemorySpaceAttributes (\r
+           0xc0000,\r
+           0x40000,\r
+           EFI_MEMORY_WB\r
+           );\r
+  }\r
+\r
+  gDS->SetMemorySpaceAttributes (\r
+         0xA0000,\r
+         0x20000,\r
+         EFI_MEMORY_UC\r
+         );\r
+\r
+  //\r
+  // Allocate 0 - 4K for real mode interupt vectors and BDA.\r
+  //\r
+  AllocateLegacyMemory (\r
+    AllocateAddress,\r
+    0,\r
+    1,\r
+    &MemoryAddress\r
+    );\r
+  ASSERT (MemoryAddress == 0x000000000);\r
+\r
+  ClearPtr = (VOID *) ((UINTN) 0x0000);\r
+\r
+  //\r
+  // Initialize region from 0x0000 to 4k. This initializes interrupt vector\r
+  // range.\r
+  //\r
+  gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);\r
+  ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);\r
+\r
+  //\r
+  // Allocate pages for OPROM usage\r
+  //\r
+  MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);\r
+  ASSERT ((MemorySize & 0xFFF) == 0);\r
+\r
+  Status = AllocateLegacyMemory (\r
+             AllocateAddress,\r
+             CONVENTIONAL_MEMORY_TOP - MemorySize,\r
+             EFI_SIZE_TO_PAGES (MemorySize),\r
+             &MemoryAddress\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);\r
+\r
+  //\r
+  // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that\r
+  // don't use PMM but look for zeroed memory. Note that various non-BBS\r
+  // SCSIs expect different areas to be free\r
+  //\r
+  for (MemStart = 0x60000; MemStart < 0x88000; MemStart += 0x1000) {\r
+    Status = AllocateLegacyMemory (\r
+               AllocateAddress,\r
+               MemStart,\r
+               1,\r
+               &MemoryAddress\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      MemoryPtr = (VOID *) ((UINTN) MemoryAddress);\r
+      ZeroMem (MemoryPtr, 0x1000);\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate a 64k area (16 4k pages) for 16-bit code for scratch pad and zero it out\r
+  //\r
+  Status = AllocateLegacyMemory (\r
+             AllocateMaxAddress,\r
+             CONVENTIONAL_MEMORY_TOP,\r
+             16,\r
+             &MemoryAddressUnder1MB\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), 0x10000);\r
+\r
+  //\r
+  // Allocate space for thunker and Init Thunker\r
+  //\r
+  Status = AllocateLegacyMemory (\r
+             AllocateMaxAddress,\r
+             CONVENTIONAL_MEMORY_TOP,\r
+             (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,\r
+             &MemoryAddress\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+  Private->IntThunk                   = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;\r
+  EfiToLegacy16InitTable                   = &Private->IntThunk->EfiToLegacy16InitTable;\r
+  EfiToLegacy16InitTable->ThunkStart       = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;\r
+  EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));\r
+\r
+  Status = LegacyBiosInitializeThunk (Private);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Init the legacy memory map in memory < 1 MB.\r
+  //\r
+  EfiToLegacy16InitTable->BiosLessThan1MB         = (UINT32) MemoryAddressUnder1MB;\r
+  EfiToLegacy16InitTable->LowPmmMemory            = (UINT32) MemoryAddressUnder1MB;\r
+  EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = 0x10000;\r
+\r
+  //\r
+  // Allocate 4 MB of PMM Memory under 16 MB\r
+  //\r
+  Status = AllocateLegacyMemory (\r
+             AllocateMaxAddress,\r
+             0x1000000,\r
+             0x400,\r
+             &MemoryAddress\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    EfiToLegacy16InitTable->HiPmmMemory            = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;\r
+    EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = PMM_MEMORY_SIZE;\r
+  }\r
+\r
+  //\r
+  //  ShutdownAPs();\r
+  //\r
+  // Start the Legacy BIOS;\r
+  //\r
+  Status = ShadowAndStartLegacy16 (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Initialize interrupt redirection code and entries;\r
+  // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.\r
+  //\r
+  CopyMem (\r
+         Private->IntThunk->InterruptRedirectionCode,\r
+         (VOID *) (UINTN) InterruptRedirectionTemplate,\r
+         sizeof (Private->IntThunk->InterruptRedirectionCode)\r
+         );\r
+\r
+  //\r
+  // Save Unexpected interrupt vector so can restore it just prior to boot\r
+  //\r
+  BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
+  Private->BiosUnexpectedInt = BaseVectorMaster[0];\r
+  IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;\r
+  for (Index = 0; Index < 8; Index++) {\r
+    BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);\r
+  }\r
+  //\r
+  // Save EFI value\r
+  //\r
+  Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));\r
+\r
+  //\r
+  // Make a new handle and install the protocol\r
+  //\r
+  Private->Handle = NULL;\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Private->Handle,\r
+                  &gEfiLegacyBiosProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &Private->LegacyBios\r
+                  );\r
+  Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);\r
+  \r
+  DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n", \r
+          (UINT8) (Private->Csm16PciInterfaceVersion >> 8), \r
+          (UINT8) Private->Csm16PciInterfaceVersion\r
+        ));\r
+  ASSERT (Private->Csm16PciInterfaceVersion != 0);\r
+  return Status;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
new file mode 100644 (file)
index 0000000..4e310aa
--- /dev/null
@@ -0,0 +1,143 @@
+## @file\r
+# Legacy Bios Module to support CSM.\r
+#\r
+# This driver installs Legacy Bios Protocol to support CSM module work in EFI system.\r
+#\r
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution.  The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = LegacyBiosDxe\r
+  FILE_GUID                      = F122A15C-C10B-4d54-8F48-60F4F06DD1AD\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = LegacyBiosInstall\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF\r
+#\r
+\r
+[Sources]\r
+  LegacyCmos.c\r
+  LegacyIde.c\r
+  LegacyBios.c\r
+  LegacyBda.c\r
+  LegacyBiosInterface.h\r
+  LegacyPci.c\r
+\r
+[Sources.Ia32]\r
+  IA32/InterruptTable.S\r
+  IA32/InterruptTable.asm\r
+  Thunk.c\r
+  LegacyBootSupport.c\r
+  LegacyBbs.c\r
+  LegacySio.c\r
+\r
+[Sources.X64]\r
+  X64/InterruptTable.asm\r
+  X64/InterruptTable.S\r
+  Thunk.c\r
+  LegacyBootSupport.c\r
+  LegacyBbs.c\r
+  LegacySio.c\r
+\r
+[Sources.IPF]\r
+  Ipf/IpfThunk.s\r
+  Ipf/Thunk.c\r
+  Ipf/IpfThunk.i\r
+  Ipf/IpfBootSupport.c\r
+  Ipf/IpfThunk.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  DevicePathLib\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  UefiLib\r
+  DebugLib\r
+  DxeServicesTableLib\r
+  PcdLib\r
+  ReportStatusCodeLib\r
+  PeCoffLib\r
+  CacheMaintenanceLib\r
+  DebugAgentLib\r
+\r
+[LibraryClasses.IA32]\r
+  IoLib\r
+  HobLib\r
+  UefiRuntimeServicesTableLib\r
+  BaseLib\r
+\r
+[LibraryClasses.X64]\r
+  IoLib\r
+  HobLib\r
+  UefiRuntimeServicesTableLib\r
+  BaseLib\r
+\r
+[LibraryClasses.IPF]\r
+  IoLib\r
+  UefiRuntimeServicesTableLib\r
+\r
+\r
+[Guids]\r
+  gEfiDiskInfoIdeInterfaceGuid                  # ALWAYS_CONSUMED\r
+  gEfiLegacyBiosGuid                            # ALWAYS_PRODUCED\r
+\r
+[Guids.IA32]\r
+  gEfiSmbiosTableGuid                           # ALWAYS_CONSUMED\r
+  gEfiAcpi20TableGuid                           # ALWAYS_CONSUMED\r
+  gEfiAcpi10TableGuid                           # ALWAYS_CONSUMED\r
+\r
+[Guids.X64]\r
+  gEfiSmbiosTableGuid                           # ALWAYS_CONSUMED\r
+  gEfiAcpi20TableGuid                           # ALWAYS_CONSUMED\r
+  gEfiAcpi10TableGuid                           # ALWAYS_CONSUMED\r
+\r
+\r
+[Protocols]\r
+  gEfiLoadedImageProtocolGuid                   # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiPciRootBridgeIoProtocolGuid               # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiCpuArchProtocolGuid                       # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiIsaIoProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiBlockIoProtocolGuid                       # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiPciIoProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiGenericMemTestProtocolGuid                # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDiskInfoProtocolGuid                      # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSimpleTextInProtocolGuid                  # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiLegacy8259ProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiLegacyBiosPlatformProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiLegacyInterruptProtocolGuid               # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiLegacyRegion2ProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiLegacyBiosProtocolGuid                    # PROTOCOL ALWAYS_PRODUCED\r
+  gEfiTimerArchProtocolGuid                     # PROTOCOL ALWAYS_PRODUCED\r
+\r
+[Pcd]\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize\r
+\r
+[Depex]\r
+  gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h
new file mode 100644 (file)
index 0000000..c398d1e
--- /dev/null
@@ -0,0 +1,1501 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LEGACY_BIOS_INTERFACE_\r
+#define _LEGACY_BIOS_INTERFACE_\r
+\r
+\r
+#include <FrameworkDxe.h>\r
+\r
+#include <Guid/SmBios.h>\r
+#include <Guid/Acpi.h>\r
+#include <Guid/DxeServices.h>\r
+#include <Guid/LegacyBios.h>\r
+#include <Guid/StatusCodeDataTypeId.h>\r
+\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/Cpu.h>\r
+#include <Protocol/IsaIo.h>\r
+#include <Protocol/LegacyRegion2.h>\r
+#include <Protocol/SimpleTextIn.h>\r
+#include <Protocol/LegacyInterrupt.h>\r
+#include <Protocol/LegacyBios.h>\r
+#include <Protocol/DiskInfo.h>\r
+#include <Protocol/GenericMemoryTest.h>\r
+#include <Protocol/LegacyBiosPlatform.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/Legacy8259.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/Timer.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/DebugAgentLib.h>\r
+\r
+//\r
+// System Tickers\r
+//\r
+#define DEFAULT_LAGACY_TIMER_TICK_DURATION 549254\r
+// BUGBUG: This entry maybe changed to PCD in future and wait for\r
+//         redesign of BDS library\r
+//\r
+#define MAX_BBS_ENTRIES 0x100\r
+\r
+//\r
+// Thunk Status Codes\r
+//   (These apply only to errors with the thunk and not to the code that was\r
+//   thunked to.)\r
+//\r
+#define THUNK_OK              0x00\r
+#define THUNK_ERR_A20_UNSUP   0x01\r
+#define THUNK_ERR_A20_FAILED  0x02\r
+\r
+//\r
+// Vector base definitions\r
+//\r
+//\r
+// 8259 Hardware definitions\r
+//\r
+#define LEGACY_MODE_BASE_VECTOR_MASTER     0x08\r
+#define LEGACY_MODE_BASE_VECTOR_SLAVE      0x70\r
+\r
+//\r
+// The original PC used INT8-F for master PIC. Since these mapped over\r
+// processor exceptions TIANO moved the master PIC to INT68-6F.\r
+//\r
+// The vector base for slave PIC is set as 0x70 for PC-AT compatibility.\r
+//\r
+#define PROTECTED_MODE_BASE_VECTOR_MASTER  0x68\r
+#define PROTECTED_MODE_BASE_VECTOR_SLAVE   0x70\r
+\r
+//\r
+// Trace defines\r
+//\r
+//\r
+#define LEGACY_BDA_TRACE    0x000\r
+#define LEGACY_BIOS_TRACE   0x040\r
+#define LEGACY_BOOT_TRACE   0x080\r
+#define LEGACY_CMOS_TRACE   0x0C0\r
+#define LEGACY_IDE_TRACE    0x100\r
+#define LEGACY_MP_TRACE     0x140\r
+#define LEGACY_PCI_TRACE    0x180\r
+#define LEGACY_SIO_TRACE    0x1C0\r
+\r
+#define LEGACY_PCI_TRACE_000 LEGACY_PCI_TRACE + 0x00\r
+#define LEGACY_PCI_TRACE_001 LEGACY_PCI_TRACE + 0x01\r
+#define LEGACY_PCI_TRACE_002 LEGACY_PCI_TRACE + 0x02\r
+#define LEGACY_PCI_TRACE_003 LEGACY_PCI_TRACE + 0x03\r
+#define LEGACY_PCI_TRACE_004 LEGACY_PCI_TRACE + 0x04\r
+#define LEGACY_PCI_TRACE_005 LEGACY_PCI_TRACE + 0x05\r
+#define LEGACY_PCI_TRACE_006 LEGACY_PCI_TRACE + 0x06\r
+#define LEGACY_PCI_TRACE_007 LEGACY_PCI_TRACE + 0x07\r
+#define LEGACY_PCI_TRACE_008 LEGACY_PCI_TRACE + 0x08\r
+#define LEGACY_PCI_TRACE_009 LEGACY_PCI_TRACE + 0x09\r
+#define LEGACY_PCI_TRACE_00A LEGACY_PCI_TRACE + 0x0A\r
+#define LEGACY_PCI_TRACE_00B LEGACY_PCI_TRACE + 0x0B\r
+#define LEGACY_PCI_TRACE_00C LEGACY_PCI_TRACE + 0x0C\r
+#define LEGACY_PCI_TRACE_00D LEGACY_PCI_TRACE + 0x0D\r
+#define LEGACY_PCI_TRACE_00E LEGACY_PCI_TRACE + 0x0E\r
+#define LEGACY_PCI_TRACE_00F LEGACY_PCI_TRACE + 0x0F\r
+\r
+\r
+typedef struct {\r
+  UINTN   PciSegment;\r
+  UINTN   PciBus;\r
+  UINTN   PciDevice;\r
+  UINTN   PciFunction;\r
+  UINT32  ShadowAddress;\r
+  UINT32  ShadowedSize;\r
+  UINT8   DiskStart;\r
+  UINT8   DiskEnd;\r
+} ROM_INSTANCE_ENTRY;\r
+\r
+//\r
+// Values for RealModeGdt\r
+//\r
+#if defined (MDE_CPU_IA32)\r
+\r
+#define NUM_REAL_GDT_ENTRIES  3\r
+#define CONVENTIONAL_MEMORY_TOP 0xA0000   // 640 KB\r
+#define INITIAL_VALUE_BELOW_1K  0x0\r
+\r
+#elif defined (MDE_CPU_X64)\r
+\r
+#define NUM_REAL_GDT_ENTRIES  8\r
+#define CONVENTIONAL_MEMORY_TOP 0xA0000   // 640 KB\r
+#define INITIAL_VALUE_BELOW_1K  0x0\r
+\r
+#elif defined (MDE_CPU_IPF)\r
+\r
+#define NUM_REAL_GDT_ENTRIES  3\r
+#define CONVENTIONAL_MEMORY_TOP 0x80000   // 512 KB\r
+#define INITIAL_VALUE_BELOW_1K  0xff\r
+\r
+#endif\r
+\r
+//\r
+// Miscellaneous numbers\r
+//\r
+#define PMM_MEMORY_SIZE         0x400000  // 4 MB\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// Define what a processor GDT looks like\r
+//\r
+typedef struct {\r
+  UINT32  LimitLo : 16;\r
+  UINT32  BaseLo : 16;\r
+  UINT32  BaseMid : 8;\r
+  UINT32  Type : 4;\r
+  UINT32  System : 1;\r
+  UINT32  Dpl : 2;\r
+  UINT32  Present : 1;\r
+  UINT32  LimitHi : 4;\r
+  UINT32  Software : 1;\r
+  UINT32  Reserved : 1;\r
+  UINT32  DefaultSize : 1;\r
+  UINT32  Granularity : 1;\r
+  UINT32  BaseHi : 8;\r
+} GDT32;\r
+\r
+typedef struct {\r
+  UINT16  LimitLow;\r
+  UINT16  BaseLow;\r
+  UINT8   BaseMid;\r
+  UINT8   Attribute;\r
+  UINT8   LimitHi;\r
+  UINT8   BaseHi;\r
+} GDT64;\r
+\r
+//\r
+// Define what a processor descriptor looks like\r
+// This data structure must be kept in sync with ASM STRUCT in Thunk.inc\r
+//\r
+typedef struct {\r
+  UINT16  Limit;\r
+  UINT64  Base;\r
+} DESCRIPTOR64;\r
+\r
+typedef struct {\r
+  UINT16  Limit;\r
+  UINT32  Base;\r
+} DESCRIPTOR32;\r
+\r
+//\r
+// Low stub lay out\r
+//\r
+#define LOW_STACK_SIZE      (8 * 1024)  // 8k?\r
+#define EFI_MAX_E820_ENTRY  100\r
+#define FIRST_INSTANCE      1\r
+#define NOT_FIRST_INSTANCE  0\r
+\r
+#if defined (MDE_CPU_IA32)\r
+typedef struct {\r
+  //\r
+  // Space for the code\r
+  //  The address of Code is also the beginning of the relocated Thunk code\r
+  //\r
+  CHAR8                             Code[4096]; // ?\r
+  //\r
+  // The address of the Reverse Thunk code\r
+  //  Note that this member CONTAINS the address of the relocated reverse thunk\r
+  //  code unlike the member variable 'Code', which IS the address of the Thunk\r
+  //  code.\r
+  //\r
+  UINT32                            LowReverseThunkStart;\r
+\r
+  //\r
+  // Data for the code (cs releative)\r
+  //\r
+  DESCRIPTOR32                      GdtDesc;          // Protected mode GDT\r
+  DESCRIPTOR32                      IdtDesc;          // Protected mode IDT\r
+  UINT32                            FlatSs;\r
+  UINT32                            FlatEsp;\r
+\r
+  UINT32                            LowCodeSelector;  // Low code selector in GDT\r
+  UINT32                            LowDataSelector;  // Low data selector in GDT\r
+  UINT32                            LowStack;\r
+  DESCRIPTOR32                      RealModeIdtDesc;\r
+\r
+  //\r
+  // real-mode GDT (temporary GDT with two real mode segment descriptors)\r
+  //\r
+  GDT32                             RealModeGdt[NUM_REAL_GDT_ENTRIES];\r
+  DESCRIPTOR32                      RealModeGdtDesc;\r
+\r
+  //\r
+  // Members specifically for the reverse thunk\r
+  //  The RevReal* members are used to store the current state of real mode\r
+  //  before performing the reverse thunk.  The RevFlat* members must be set\r
+  //  before calling the reverse thunk assembly code.\r
+  //\r
+  UINT16                            RevRealDs;\r
+  UINT16                            RevRealSs;\r
+  UINT32                            RevRealEsp;\r
+  DESCRIPTOR32                      RevRealIdtDesc;\r
+  UINT16                            RevFlatDataSelector;  // Flat data selector in GDT\r
+  UINT32                            RevFlatStack;\r
+\r
+  //\r
+  // A low memory stack\r
+  //\r
+  CHAR8                             Stack[LOW_STACK_SIZE];\r
+\r
+  //\r
+  // Stack for flat mode after reverse thunk\r
+  // @bug    - This may no longer be necessary if the reverse thunk interface\r
+  //           is changed to have the flat stack in a different location.\r
+  //\r
+  CHAR8                             RevThunkStack[LOW_STACK_SIZE];\r
+\r
+  //\r
+  // Legacy16 Init memory map info\r
+  //\r
+  EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;\r
+\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;\r
+\r
+  CHAR8                             InterruptRedirectionCode[32];\r
+  EFI_LEGACY_INSTALL_PCI_HANDLER    PciHandler;\r
+  EFI_DISPATCH_OPROM_TABLE          DispatchOpromTable;\r
+  BBS_TABLE                         BbsTable[MAX_BBS_ENTRIES];\r
+} LOW_MEMORY_THUNK;\r
+\r
+#elif defined (MDE_CPU_X64)\r
+\r
+typedef struct {\r
+  //\r
+  // Space for the code\r
+  //  The address of Code is also the beginning of the relocated Thunk code\r
+  //\r
+  CHAR8                             Code[4096]; // ?\r
+\r
+  //\r
+  // Data for the code (cs releative)\r
+  //\r
+  DESCRIPTOR64                      X64GdtDesc;          // Protected mode GDT\r
+  DESCRIPTOR64                      X64IdtDesc;          // Protected mode IDT\r
+  UINTN                             X64Ss;\r
+  UINTN                             X64Esp;\r
+\r
+  UINTN                             RealStack;\r
+  DESCRIPTOR32                      RealModeIdtDesc;\r
+  DESCRIPTOR32                      RealModeGdtDesc;\r
+\r
+  //\r
+  // real-mode GDT (temporary GDT with two real mode segment descriptors)\r
+  //\r
+  GDT64                             RealModeGdt[NUM_REAL_GDT_ENTRIES];\r
+  UINT64                            PageMapLevel4;\r
+\r
+  //\r
+  // A low memory stack\r
+  //\r
+  CHAR8                             Stack[LOW_STACK_SIZE];\r
+\r
+  //\r
+  // Legacy16 Init memory map info\r
+  //\r
+  EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;\r
+\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;\r
+\r
+  CHAR8                             InterruptRedirectionCode[32];\r
+  EFI_LEGACY_INSTALL_PCI_HANDLER    PciHandler;\r
+  EFI_DISPATCH_OPROM_TABLE          DispatchOpromTable;\r
+  BBS_TABLE                         BbsTable[MAX_BBS_ENTRIES];\r
+} LOW_MEMORY_THUNK;\r
+\r
+#elif defined (MDE_CPU_IPF)\r
+\r
+typedef struct {\r
+  //\r
+  // Space for the code\r
+  //  The address of Code is also the beginning of the relocated Thunk code\r
+  //\r
+  CHAR8                             Code[4096]; // ?\r
+  //\r
+  // The address of the Reverse Thunk code\r
+  //  Note that this member CONTAINS the address of the relocated reverse thunk\r
+  //  code unlike the member variable 'Code', which IS the address of the Thunk\r
+  //  code.\r
+  //\r
+  UINT32                            LowReverseThunkStart;\r
+\r
+  //\r
+  // Data for the code (cs releative)\r
+  //\r
+  DESCRIPTOR32                      GdtDesc;          // Protected mode GDT\r
+  DESCRIPTOR32                      IdtDesc;          // Protected mode IDT\r
+  UINT32                            FlatSs;\r
+  UINT32                            FlatEsp;\r
+\r
+  UINT32                            LowCodeSelector;  // Low code selector in GDT\r
+  UINT32                            LowDataSelector;  // Low data selector in GDT\r
+  UINT32                            LowStack;\r
+  DESCRIPTOR32                      RealModeIdtDesc;\r
+\r
+  //\r
+  // real-mode GDT (temporary GDT with two real mode segment descriptors)\r
+  //\r
+  GDT32                             RealModeGdt[NUM_REAL_GDT_ENTRIES];\r
+  DESCRIPTOR32                      RealModeGdtDesc;\r
+\r
+  //\r
+  // Members specifically for the reverse thunk\r
+  //  The RevReal* members are used to store the current state of real mode\r
+  //  before performing the reverse thunk.  The RevFlat* members must be set\r
+  //  before calling the reverse thunk assembly code.\r
+  //\r
+  UINT16                            RevRealDs;\r
+  UINT16                            RevRealSs;\r
+  UINT32                            RevRealEsp;\r
+  DESCRIPTOR32                      RevRealIdtDesc;\r
+  UINT16                            RevFlatDataSelector;  // Flat data selector in GDT\r
+  UINT32                            RevFlatStack;\r
+\r
+  //\r
+  // A low memory stack\r
+  //\r
+  CHAR8                             Stack[LOW_STACK_SIZE];\r
+\r
+  //\r
+  // Stack for flat mode after reverse thunk\r
+  // @bug - This may no longer be necessary if the reverse thunk interface\r
+  //           is changed to have the flat stack in a different location.\r
+  //\r
+  CHAR8                             RevThunkStack[LOW_STACK_SIZE];\r
+\r
+  //\r
+  // Legacy16 Init memory map info\r
+  //\r
+  EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;\r
+\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;\r
+\r
+  CHAR8                             InterruptRedirectionCode[32];\r
+  EFI_LEGACY_INSTALL_PCI_HANDLER    PciHandler;\r
+  EFI_DISPATCH_OPROM_TABLE          DispatchOpromTable;\r
+  BBS_TABLE                         BbsTable[MAX_BBS_ENTRIES];\r
+} LOW_MEMORY_THUNK;\r
+\r
+#endif\r
+\r
+//\r
+// PnP Expansion Header\r
+//\r
+typedef struct {\r
+  UINT32  PnpSignature;\r
+  UINT8   Revision;\r
+  UINT8   Length;\r
+  UINT16  NextHeader;\r
+  UINT8   Reserved1;\r
+  UINT8   Checksum;\r
+  UINT32  DeviceId;\r
+  UINT16  MfgPointer;\r
+  UINT16  ProductNamePointer;\r
+  UINT8   Class;\r
+  UINT8   SubClass;\r
+  UINT8   Interface;\r
+  UINT8   DeviceIndicators;\r
+  UINT16  Bcv;\r
+  UINT16  DisconnectVector;\r
+  UINT16  Bev;\r
+  UINT16  Reserved2;\r
+  UINT16  StaticResourceVector;\r
+} LEGACY_PNP_EXPANSION_HEADER;\r
+\r
+typedef struct {\r
+  UINT8   PciSegment;\r
+  UINT8   PciBus;\r
+  UINT8   PciDevice;\r
+  UINT8   PciFunction;\r
+  UINT16  Vid;\r
+  UINT16  Did;\r
+  UINT16  SysSid;\r
+  UINT16  SVid;\r
+  UINT8   Class;\r
+  UINT8   SubClass;\r
+  UINT8   Interface;\r
+  UINT8   Reserved;\r
+  UINTN   RomStart;\r
+  UINTN   ManufacturerString;\r
+  UINTN   ProductNameString;\r
+} LEGACY_ROM_AND_BBS_TABLE;\r
+\r
+//\r
+// Structure how EFI has mapped a devices HDD drive numbers.\r
+// Boot to EFI aware OS or shell requires this mapping when\r
+// 16-bit CSM assigns drive numbers.\r
+// This mapping is ignored booting to a legacy OS.\r
+//\r
+typedef struct {\r
+  UINT8 PciSegment;\r
+  UINT8 PciBus;\r
+  UINT8 PciDevice;\r
+  UINT8 PciFunction;\r
+  UINT8 StartDriveNumber;\r
+  UINT8 EndDriveNumber;\r
+} LEGACY_EFI_HDD_TABLE;\r
+\r
+//\r
+// This data is passed to Leacy16Boot\r
+//\r
+typedef enum {\r
+  EfiAcpiAddressRangeMemory   = 1,\r
+  EfiAcpiAddressRangeReserved = 2,\r
+  EfiAcpiAddressRangeACPI     = 3,\r
+  EfiAcpiAddressRangeNVS      = 4\r
+} EFI_ACPI_MEMORY_TYPE;\r
+\r
+typedef struct {\r
+  UINT64                BaseAddr;\r
+  UINT64                Length;\r
+  EFI_ACPI_MEMORY_TYPE  Type;\r
+} EFI_E820_ENTRY64;\r
+\r
+typedef struct {\r
+  UINT32                BassAddrLow;\r
+  UINT32                BaseAddrHigh;\r
+  UINT32                LengthLow;\r
+  UINT32                LengthHigh;\r
+  EFI_ACPI_MEMORY_TYPE  Type;\r
+} EFI_E820_ENTRY;\r
+\r
+#pragma pack()\r
+\r
+extern BBS_TABLE           *mBbsTable;\r
+\r
+extern EFI_GENERIC_MEMORY_TEST_PROTOCOL *gGenMemoryTest;\r
+\r
+extern UINTN               mEndOpromShadowAddress;\r
+\r
+#define PORT_70 0x70\r
+#define PORT_71 0x71\r
+\r
+#define CMOS_0A     0x0a  ///< Status register A\r
+#define CMOS_0D     0x0d  ///< Status register D\r
+#define CMOS_0E     0x0e  ///< Diagnostic Status\r
+#define CMOS_0F     0x0f  ///< Shutdown status\r
+#define CMOS_10     0x10  ///< Floppy type\r
+#define CMOS_12     0x12  ///< IDE type\r
+#define CMOS_14     0x14  ///< Same as BDA 40:10\r
+#define CMOS_15     0x15  ///< Low byte of base memory in 1k increments\r
+#define CMOS_16     0x16  ///< High byte of base memory in 1k increments\r
+#define CMOS_17     0x17  ///< Low byte of 1MB+ memory in 1k increments - max 15 MB\r
+#define CMOS_18     0x18  ///< High byte of 1MB+ memory in 1k increments - max 15 MB\r
+#define CMOS_19     0x19  ///< C: extended drive type\r
+#define CMOS_1A     0x1a  ///< D: extended drive type\r
+#define CMOS_2E     0x2e  ///< Most significient byte of standard checksum\r
+#define CMOS_2F     0x2f  ///< Least significient byte of standard checksum\r
+#define CMOS_30     0x30  ///< CMOS 0x17\r
+#define CMOS_31     0x31  ///< CMOS 0x18\r
+#define CMOS_32     0x32  ///< Century byte\r
+\r
+\r
+#define LEGACY_BIOS_INSTANCE_SIGNATURE  SIGNATURE_32 ('L', 'B', 'I', 'T')\r
+typedef struct {\r
+  UINTN                             Signature;\r
+\r
+  EFI_HANDLE                        Handle;\r
+  EFI_LEGACY_BIOS_PROTOCOL          LegacyBios;\r
+\r
+  EFI_HANDLE                        ImageHandle;\r
+\r
+  //\r
+  // CPU Architectural Protocol \r
+  //\r
+  EFI_CPU_ARCH_PROTOCOL             *Cpu;\r
+\r
+  //\r
+  // Protocol to Lock and Unlock 0xc0000 - 0xfffff\r
+  //\r
+  EFI_LEGACY_REGION2_PROTOCOL       *LegacyRegion;\r
+\r
+  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
+\r
+  //\r
+  // Interrupt control for thunk and PCI IRQ\r
+  //\r
+  EFI_LEGACY_8259_PROTOCOL          *Legacy8259;\r
+\r
+  //\r
+  // PCI Interrupt PIRQ control\r
+  //\r
+  EFI_LEGACY_INTERRUPT_PROTOCOL     *LegacyInterrupt;\r
+\r
+  //\r
+  // Generic Memory Test\r
+  //\r
+  EFI_GENERIC_MEMORY_TEST_PROTOCOL  *GenericMemoryTest;\r
+\r
+  //\r
+  // TRUE if PCI Interupt Line registers have been programmed.\r
+  //\r
+  BOOLEAN                           PciInterruptLine;\r
+\r
+  //\r
+  // Code space below 1MB needed by thunker to transition to real mode.\r
+  // Contains stack and real mode code fragments\r
+  //\r
+  LOW_MEMORY_THUNK                  *IntThunk;\r
+\r
+  //\r
+  // Starting shadow address of the Legacy BIOS\r
+  //\r
+  UINT32                            BiosStart;\r
+  UINT32                            LegacyBiosImageSize;\r
+\r
+  //\r
+  // Start of variables used by CsmItp.mac ITP macro file and/os LegacyBios\r
+  //\r
+  UINT8                             Dump[4];\r
+\r
+  //\r
+  // $EFI Legacy16 code entry info in memory < 1 MB;\r
+  //\r
+  EFI_COMPATIBILITY16_TABLE         *Legacy16Table;\r
+  VOID                              *Legacy16InitPtr;\r
+  VOID                              *Legacy16BootPtr;\r
+  VOID                              *InternalIrqRoutingTable;\r
+  UINT32                            NumberIrqRoutingEntries;\r
+  VOID                              *BbsTablePtr;\r
+  VOID                              *HddTablePtr;\r
+  UINT32                            NumberHddControllers;\r
+\r
+  //\r
+  // Cached copy of Legacy16 entry point\r
+  //\r
+  UINT16                            Legacy16CallSegment;\r
+  UINT16                            Legacy16CallOffset;\r
+\r
+  //\r
+  // Returned from $EFI and passed in to OPROMS\r
+  //\r
+  UINT16                            PnPInstallationCheckSegment;\r
+  UINT16                            PnPInstallationCheckOffset;\r
+\r
+  //\r
+  // E820 table\r
+  //\r
+  EFI_E820_ENTRY                    E820Table[EFI_MAX_E820_ENTRY];\r
+  UINT32                            NumberE820Entries;\r
+\r
+  //\r
+  // True if legacy VGA INT 10h handler installed\r
+  //\r
+  BOOLEAN                           VgaInstalled;\r
+\r
+  //\r
+  // Number of IDE drives\r
+  //\r
+  UINT8                             IdeDriveCount;\r
+\r
+  //\r
+  // Current Free Option ROM space. An option ROM must NOT go past\r
+  // BiosStart.\r
+  //\r
+  UINT32                            OptionRom;\r
+\r
+  //\r
+  // Save Legacy16 unexpected interrupt vector. Reprogram INT 68-6F from\r
+  // EFI values to legacy value just before boot.\r
+  //\r
+  UINT32                            BiosUnexpectedInt;\r
+  UINT32                            ThunkSavedInt[8];\r
+  UINT16                            ThunkSeg;\r
+  LEGACY_EFI_HDD_TABLE              *LegacyEfiHddTable;\r
+  UINT16                            LegacyEfiHddTableIndex;\r
+  UINT8                             DiskEnd;\r
+  UINT8                             Disk4075;\r
+  UINT16                            TraceIndex;\r
+  UINT16                            Trace[0x200];\r
+\r
+  //\r
+  // Indicate that whether GenericLegacyBoot is entered or not\r
+  //\r
+  BOOLEAN                           LegacyBootEntered;                              \r
+\r
+  //\r
+  // CSM16 PCI Interface Version\r
+  //\r
+  UINT16                            Csm16PciInterfaceVersion;\r
+\r
+} LEGACY_BIOS_INSTANCE;\r
+\r
+\r
+#pragma pack(1)\r
+\r
+/*\r
+  40:00-01 Com1\r
+  40:02-03 Com2\r
+  40:04-05 Com3\r
+  40:06-07 Com4\r
+  40:08-09 Lpt1\r
+  40:0A-0B Lpt2\r
+  40:0C-0D Lpt3\r
+  40:0E-0E Ebda segment\r
+  40:10-11 MachineConfig\r
+  40:12    Bda12 - skip\r
+  40:13-14 MemSize below 1MB\r
+  40:15-16 Bda15_16 - skip\r
+  40:17    Keyboard Shift status\r
+  40:18-19 Bda18_19 - skip\r
+  40:1A-1B Key buffer head\r
+  40:1C-1D Key buffer tail\r
+  40:1E-3D Bda1E_3D- key buffer -skip\r
+  40:3E-3F FloppyData 3E = Calibration status 3F = Motor status\r
+  40:40    FloppyTimeout\r
+  40:41-74 Bda41_74 - skip\r
+  40:75    Number of HDD drives\r
+  40:76-77 Bda76_77 - skip\r
+  40:78-79 78 = Lpt1 timeout, 79 = Lpt2 timeout\r
+  40:7A-7B 7A = Lpt3 timeout, 7B = Lpt4 timeout\r
+  40:7C-7D 7C = Com1 timeout, 7D = Com2 timeout\r
+  40:7E-7F 7E = Com3 timeout, 7F = Com4 timeout\r
+  40:80-81 Pointer to start of key buffer\r
+  40:82-83 Pointer to end of key buffer\r
+  40:84-87 Bda84_87 - skip\r
+  40:88    HDD Data Xmit rate\r
+  40:89-8f skip\r
+  40:90    Floppy data rate\r
+  40:91-95 skip\r
+  40:96    Keyboard Status\r
+  40:97    LED Status\r
+  40:98-101 skip\r
+*/\r
+typedef struct {\r
+  UINT16  Com1;\r
+  UINT16  Com2;\r
+  UINT16  Com3;\r
+  UINT16  Com4;\r
+  UINT16  Lpt1;\r
+  UINT16  Lpt2;\r
+  UINT16  Lpt3;\r
+  UINT16  Ebda;\r
+  UINT16  MachineConfig;\r
+  UINT8   Bda12;\r
+  UINT16  MemSize;\r
+  UINT8   Bda15_16[0x02];\r
+  UINT8   ShiftStatus;\r
+  UINT8   Bda18_19[0x02];\r
+  UINT16  KeyHead;\r
+  UINT16  KeyTail;\r
+  UINT16  Bda1E_3D[0x10];\r
+  UINT16  FloppyData;\r
+  UINT8   FloppyTimeout;\r
+  UINT8   Bda41_74[0x34];\r
+  UINT8   NumberOfDrives;\r
+  UINT8   Bda76_77[0x02];\r
+  UINT16  Lpt1_2Timeout;\r
+  UINT16  Lpt3_4Timeout;\r
+  UINT16  Com1_2Timeout;\r
+  UINT16  Com3_4Timeout;\r
+  UINT16  KeyStart;\r
+  UINT16  KeyEnd;\r
+  UINT8   Bda84_87[0x4];\r
+  UINT8   DataXmit;\r
+  UINT8   Bda89_8F[0x07];\r
+  UINT8   FloppyXRate;\r
+  UINT8   Bda91_95[0x05];\r
+  UINT8   KeyboardStatus;\r
+  UINT8   LedStatus;\r
+} BDA_STRUC;\r
+#pragma pack()\r
+\r
+#define LEGACY_BIOS_INSTANCE_FROM_THIS(this)  CR (this, LEGACY_BIOS_INSTANCE, LegacyBios, LEGACY_BIOS_INSTANCE_SIGNATURE)\r
+\r
+/**\r
+  Thunk to 16-bit real mode and execute a software interrupt with a vector\r
+  of BiosInt. Regs will contain the 16-bit register context on entry and\r
+  exit.\r
+\r
+  @param  This    Protocol instance pointer.\r
+  @param  BiosInt Processor interrupt vector to invoke\r
+  @param  Regs    Register contexted passed into (and returned) from thunk to\r
+                  16-bit mode\r
+\r
+  @retval FALSE   Thunk completed, and there were no BIOS errors in the target code.\r
+                  See Regs for status.\r
+  @retval TRUE     There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LegacyBiosInt86 (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,\r
+  IN  UINT8                             BiosInt,\r
+  IN  EFI_IA32_REGISTER_SET             *Regs\r
+  );\r
+\r
+\r
+/**\r
+  Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the\r
+  16-bit register context on entry and exit. Arguments can be passed on\r
+  the Stack argument\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  Segment                Segemnt of 16-bit mode call\r
+  @param  Offset                 Offset of 16-bit mdoe call\r
+  @param  Regs                   Register contexted passed into (and returned) from\r
+                                 thunk to  16-bit mode\r
+  @param  Stack                  Caller allocated stack used to pass arguments\r
+  @param  StackSize              Size of Stack in bytes\r
+\r
+  @retval FALSE                  Thunk completed, and there were no BIOS errors in\r
+                                 the target code. See Regs for status.\r
+  @retval TRUE                   There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LegacyBiosFarCall86 (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,\r
+  IN  UINT16                            Segment,\r
+  IN  UINT16                            Offset,\r
+  IN  EFI_IA32_REGISTER_SET             *Regs,\r
+  IN  VOID                              *Stack,\r
+  IN  UINTN                             StackSize\r
+  );\r
+\r
+\r
+/**\r
+  Test to see if a legacy PCI ROM exists for this device. Optionally return\r
+  the Legacy ROM instance for this PCI device.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will\r
+                                 be loaded\r
+  @param  RomImage               Return the legacy PCI ROM for this device\r
+  @param  RomSize                Size of ROM Image\r
+  @param  Flags                  Indicates if ROM found and if PC-AT.\r
+\r
+  @retval EFI_SUCCESS            Legacy Option ROM availible for this device\r
+  @retval EFI_UNSUPPORTED        Legacy Option ROM not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosCheckPciRom (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,\r
+  IN  EFI_HANDLE                        PciHandle,\r
+  OUT VOID                              **RomImage, OPTIONAL\r
+  OUT UINTN                             *RomSize, OPTIONAL\r
+  OUT UINTN                             *Flags\r
+  );\r
+\r
+\r
+/**\r
+  Assign drive number to legacy HDD drives prior to booting an EFI\r
+  aware OS so the OS can access drives without an EFI driver.\r
+  Note: BBS compliant drives ARE NOT available until this call by\r
+  either shell or EFI.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  BbsCount               Number of BBS_TABLE structures\r
+  @param  BbsTable               List BBS entries\r
+\r
+  @retval EFI_SUCCESS            Drive numbers assigned\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosPrepareToBootEfi (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  OUT UINT16                          *BbsCount,\r
+  OUT BBS_TABLE                       **BbsTable\r
+  );\r
+\r
+\r
+/**\r
+  To boot from an unconventional device like parties and/or execute\r
+  HDD diagnostics.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  Attributes             How to interpret the other input parameters\r
+  @param  BbsEntry               The 0-based index into the BbsTable for the parent\r
+                                  device.\r
+  @param  BeerData               Pointer to the 128 bytes of ram BEER data.\r
+  @param  ServiceAreaData        Pointer to the 64 bytes of raw Service Area data.\r
+                                 The caller must provide a pointer to the specific\r
+                                 Service Area and not the start all Service Areas.\r
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosBootUnconventionalDevice (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  IN UDC_ATTRIBUTES                   Attributes,\r
+  IN UINTN                            BbsEntry,\r
+  IN VOID                             *BeerData,\r
+  IN VOID                             *ServiceAreaData\r
+  );\r
+\r
+\r
+/**\r
+  Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
+  about how many disks were added by the OPROM and the shadow address and\r
+  size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will\r
+                                 be loaded. This value is NULL if RomImage is\r
+                                 non-NULL. This is the normal case.\r
+  @param  RomImage               A PCI PC-AT ROM image. This argument is non-NULL\r
+                                 if there is no hardware associated with the ROM\r
+                                 and thus no PciHandle, otherwise is must be NULL.\r
+                                 Example is PXE base code.\r
+  @param  Flags                  Indicates if ROM found and if PC-AT.\r
+  @param  DiskStart              Disk number of first device hooked by the ROM. If\r
+                                 DiskStart is the same as DiskEnd no disked were\r
+                                 hooked.\r
+  @param  DiskEnd                Disk number of the last device hooked by the ROM.\r
+  @param  RomShadowAddress       Shadow address of PC-AT ROM\r
+  @param  RomShadowedSize        Size of RomShadowAddress in bytes\r
+\r
+  @retval EFI_SUCCESS            Legacy ROM loaded for this device\r
+  @retval EFI_INVALID_PARAMETER  PciHandle not found\r
+  @retval EFI_UNSUPPORTED        There is no PCI ROM in the ROM BAR or no onboard\r
+                                 ROM\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosInstallPciRom (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL          * This,\r
+  IN  EFI_HANDLE                        PciHandle,\r
+  IN  VOID                              **RomImage,\r
+  OUT UINTN                             *Flags,\r
+  OUT UINT8                             *DiskStart, OPTIONAL\r
+  OUT UINT8                             *DiskEnd, OPTIONAL\r
+  OUT VOID                              **RomShadowAddress, OPTIONAL\r
+  OUT UINT32                            *RomShadowedSize OPTIONAL\r
+  );\r
+\r
+\r
+/**\r
+  Fill in the standard BDA for Keyboard LEDs\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  Leds                   Current LED status\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosUpdateKeyboardLedStatus (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN UINT8                              Leds\r
+  );\r
+\r
+\r
+/**\r
+  Get all BBS info\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  HddCount               Number of HDD_INFO structures\r
+  @param  HddInfo                Onboard IDE controller information\r
+  @param  BbsCount               Number of BBS_TABLE structures\r
+  @param  BbsTable               List BBS entries\r
+\r
+  @retval EFI_SUCCESS            Tables returned\r
+  @retval EFI_NOT_FOUND          resource not found\r
+  @retval EFI_DEVICE_ERROR       can not get BBS table\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosGetBbsInfo (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,\r
+  OUT UINT16                            *HddCount,\r
+  OUT HDD_INFO                          **HddInfo,\r
+  OUT UINT16                            *BbsCount,\r
+  OUT BBS_TABLE                         **BbsTable\r
+  );\r
+\r
+\r
+/**\r
+  Shadow all legacy16 OPROMs that haven't been shadowed.\r
+  Warning: Use this with caution. This routine disconnects all EFI\r
+  drivers. If used externally then caller must re-connect EFI\r
+  drivers.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS            OPROMs shadowed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosShadowAllLegacyOproms (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL   *This\r
+  );\r
+\r
+\r
+/**\r
+  Attempt to legacy boot the BootOption. If the EFI contexted has been\r
+  compromised this function will not return.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  BbsDevicePath          EFI Device Path from BootXXXX variable.\r
+  @param  LoadOptionsSize        Size of LoadOption in size.\r
+  @param  LoadOptions            LoadOption from BootXXXX variable\r
+\r
+  @retval EFI_SUCCESS            Removable media not present\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosLegacyBoot (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL          *This,\r
+  IN  BBS_BBS_DEVICE_PATH               *BbsDevicePath,\r
+  IN  UINT32                            LoadOptionsSize,\r
+  IN  VOID                              *LoadOptions\r
+  );\r
+\r
+\r
+/**\r
+  Allocate memory < 1 MB and copy the thunker code into low memory. Se up\r
+  all the descriptors.\r
+\r
+  @param  Private                Private context for Legacy BIOS\r
+\r
+  @retval EFI_SUCCESS            Should only pass.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInitializeThunk (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  );\r
+\r
+\r
+/**\r
+  Fill in the standard BDA and EBDA stuff before Legacy16 load\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInitBda (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  );\r
+\r
+\r
+/**\r
+  Collect IDE Inquiry data from the IDE disks\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+  @param  HddInfo                Hdd Information\r
+  @param  Flag                   Reconnect IdeController or not\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildIdeData (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private,\r
+  IN  HDD_INFO                  **HddInfo,\r
+  IN  UINT16                    Flag\r
+  );\r
+\r
+\r
+/**\r
+  Enable ide controller.  This gets disabled when LegacyBoot.c is about\r
+  to run the Option ROMs.\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+\r
+\r
+**/\r
+VOID\r
+EnableIdeController (\r
+  IN LEGACY_BIOS_INSTANCE       *Private\r
+  );\r
+\r
+\r
+/**\r
+  If the IDE channel is in compatibility (legacy) mode, remove all\r
+  PCI I/O BAR addresses from the controller.\r
+\r
+  @param  IdeController          The handle of target IDE controller\r
+\r
+\r
+**/\r
+VOID\r
+InitLegacyIdeController (\r
+  IN EFI_HANDLE                 IdeController\r
+  );\r
+\r
+\r
+/**\r
+  Program the interrupt routing register in all the PCI devices. On a PC AT system\r
+  this register contains the 8259 IRQ vector that matches it's PCI interrupt.\r
+\r
+  @param  Private                Legacy  BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS            Succeed.\r
+  @retval EFI_ALREADY_STARTED    All PCI devices have been processed.\r
+\r
+**/\r
+EFI_STATUS\r
+PciProgramAllInterruptLineRegisters (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private\r
+  );\r
+\r
+\r
+/**\r
+  Collect EFI Info about legacy devices.\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildSioData (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private\r
+  );\r
+\r
+\r
+/**\r
+  Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol\r
+  to chose the order. Skip any devices that have already have legacy\r
+  BIOS run.\r
+\r
+  @param  Private                Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS            Succeed.\r
+  @retval EFI_UNSUPPORTED        Cannot get VGA device handle.\r
+\r
+**/\r
+EFI_STATUS\r
+PciShadowRoms (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private\r
+  );\r
+\r
+\r
+/**\r
+  Fill in the standard BDA and EBDA stuff prior to legacy Boot\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosCompleteBdaBeforeBoot (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  );\r
+\r
+\r
+/**\r
+  Fill in the standard CMOS stuff before Legacy16 load\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInitCmos (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  );\r
+\r
+\r
+/**\r
+  Fill in the standard CMOS stuff prior to legacy Boot\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosCompleteStandardCmosBeforeBoot (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  );\r
+\r
+\r
+/**\r
+  Contains the code that is copied into low memory (below 640K).\r
+  This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.\r
+  This template must be copied into low memory, and the IDT entries\r
+  0x68-0x6F must be point to the low memory copy of this code.  Each\r
+  entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily\r
+  computed.\r
+\r
+**/\r
+VOID\r
+InterruptRedirectionTemplate (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  Build the E820 table.\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+  @param  Size                   Size of E820 Table\r
+\r
+  @retval EFI_SUCCESS            It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildE820 (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private,\r
+  OUT UINTN                   *Size\r
+  );\r
+\r
+/**\r
+  This function is to put all AP in halt state.\r
+\r
+  @param  Private                Legacy BIOS Instance data\r
+\r
+**/\r
+VOID\r
+ShutdownAPs (\r
+  IN LEGACY_BIOS_INSTANCE              *Private\r
+  );\r
+\r
+/**\r
+  Worker function for LegacyBiosGetFlatDescs, retrieving content of\r
+  specific registers.\r
+\r
+  @param  IntThunk  Pointer to IntThunk of Legacy BIOS context.\r
+\r
+**/\r
+VOID\r
+GetRegisters (\r
+  LOW_MEMORY_THUNK    *IntThunk\r
+  );\r
+\r
+/**\r
+  Routine for calling real thunk code.\r
+\r
+  @param  RealCode    The address of thunk code.\r
+  @param  BiosInt     The Bios interrupt vector number.\r
+  @param  CallAddress The address of 16-bit mode call.\r
+\r
+  @return  Status returned by real thunk code\r
+\r
+**/\r
+UINTN\r
+CallRealThunkCode (\r
+  UINT8               *RealCode,\r
+  UINT8               BiosInt,\r
+  UINT32              CallAddress\r
+  );\r
+\r
+/**\r
+  Routine for generating soft interrupt.\r
+\r
+  @param Vector  The interrupt vector number.\r
+\r
+**/\r
+VOID\r
+GenerateSoftInit (\r
+  UINT8               Vector\r
+  );\r
+\r
+/**\r
+  Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode\r
+  memory.\r
+\r
+  @param  AllocateType               Allocated Legacy Memory Type\r
+  @param  StartPageAddress           Start address of range\r
+  @param  Pages                      Number of pages to allocate\r
+  @param  Result                     Result of allocation\r
+\r
+  @retval EFI_SUCCESS                Legacy16 code loaded\r
+  @retval Other                      No protocol installed, unload driver.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocateLegacyMemory (\r
+  IN  EFI_ALLOCATE_TYPE         AllocateType,\r
+  IN  EFI_PHYSICAL_ADDRESS      StartPageAddress,\r
+  IN  UINTN                     Pages,\r
+  OUT EFI_PHYSICAL_ADDRESS      *Result\r
+  );\r
+\r
+/**\r
+  Get a region from the LegacyBios for Tiano usage. Can only be invoked once.\r
+\r
+  @param  This                       Protocol instance pointer.\r
+  @param  LegacyMemorySize           Size of required region\r
+  @param  Region                     Region to use. 00 = Either 0xE0000 or 0xF0000\r
+                                     block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000\r
+                                     block\r
+  @param  Alignment                  Address alignment. Bit mapped. First non-zero\r
+                                     bit from right is alignment.\r
+  @param  LegacyMemoryAddress        Region Assigned\r
+\r
+  @retval EFI_SUCCESS                Region assigned\r
+  @retval EFI_ACCESS_DENIED          Procedure previously invoked\r
+  @retval Other                      Region not assigned\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosGetLegacyRegion (\r
+  IN    EFI_LEGACY_BIOS_PROTOCOL *This,\r
+  IN    UINTN                    LegacyMemorySize,\r
+  IN    UINTN                    Region,\r
+  IN    UINTN                    Alignment,\r
+  OUT   VOID                     **LegacyMemoryAddress\r
+  );\r
+\r
+/**\r
+  Get a region from the LegacyBios for Tiano usage. Can only be invoked once.\r
+\r
+  @param  This                       Protocol instance pointer.\r
+  @param  LegacyMemorySize           Size of data to copy\r
+  @param  LegacyMemoryAddress        Legacy Region destination address Note: must\r
+                                     be in region assigned by\r
+                                     LegacyBiosGetLegacyRegion\r
+  @param  LegacyMemorySourceAddress  Source of data\r
+\r
+  @retval EFI_SUCCESS                Region assigned\r
+  @retval EFI_ACCESS_DENIED          Destination outside assigned region\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosCopyLegacyRegion (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
+  IN    UINTN                 LegacyMemorySize,\r
+  IN    VOID                  *LegacyMemoryAddress,\r
+  IN    VOID                  *LegacyMemorySourceAddress\r
+  );\r
+\r
+/**\r
+  Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find\r
+  the $EFI table in the shadow area. Thunk into the Legacy16 code after it had\r
+  been shadowed.\r
+\r
+  @param  Private                    Legacy BIOS context data\r
+\r
+  @retval EFI_SUCCESS                Legacy16 code loaded\r
+  @retval Other                      No protocol installed, unload driver.\r
+\r
+**/\r
+EFI_STATUS\r
+ShadowAndStartLegacy16 (\r
+  IN  LEGACY_BIOS_INSTANCE  *Private\r
+  );\r
+\r
+/**\r
+  Checks the state of the floppy and if media is inserted.\r
+  \r
+  This routine checks the state of the floppy and if media is inserted.\r
+  There are 3 cases:\r
+  No floppy present         - Set BBS entry to ignore\r
+  Floppy present & no media - Set BBS entry to lowest priority. We cannot\r
+  set it to ignore since 16-bit CSM will\r
+  indicate no floppy and thus drive A: is\r
+  unusable. CSM-16 will not try floppy since\r
+  lowest priority and thus not incur boot\r
+  time penality.\r
+  Floppy present & media    - Set BBS entry to some priority.\r
+\r
+  @return  State of floppy media\r
+\r
+**/\r
+UINT8\r
+HasMediaInFloppy (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Identify drive data must be updated to actual parameters before boot.\r
+  This requires updating the checksum, if it exists.\r
+\r
+  @param  IdentifyDriveData       ATA Identify Data\r
+  @param  Checksum                checksum of the ATA Identify Data\r
+\r
+  @retval EFI_SUCCESS             checksum calculated\r
+  @retval EFI_SECURITY_VIOLATION  IdentifyData invalid\r
+\r
+**/\r
+EFI_STATUS\r
+CalculateIdentifyDriveChecksum (\r
+  IN  UINT8     *IdentifyDriveData,\r
+  OUT UINT8     *Checksum\r
+  );\r
+\r
+/**\r
+  Identify drive data must be updated to actual parameters before boot.\r
+\r
+  @param  IdentifyDriveData       ATA Identify Data\r
+\r
+**/\r
+VOID\r
+UpdateIdentifyDriveData (\r
+  IN  UINT8     *IdentifyDriveData\r
+  );\r
+\r
+/**\r
+  Complete build of BBS TABLE.\r
+\r
+  @param  Private                 Legacy BIOS Instance data\r
+  @param  BbsTable                BBS Table passed to 16-bit code\r
+\r
+  @retval EFI_SUCCESS             Removable media not present\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildBbs (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private,\r
+  IN  BBS_TABLE                 *BbsTable\r
+  );\r
+\r
+/**\r
+  Read CMOS register through index/data port.\r
+\r
+  @param[in]  Index   The index of the CMOS register to read.\r
+\r
+  @return  The data value from the CMOS register specified by Index.\r
+\r
+**/\r
+UINT8\r
+LegacyReadStandardCmos (\r
+  IN UINT8  Index\r
+  );\r
+\r
+/**\r
+  Write CMOS register through index/data port.\r
+\r
+  @param[in]  Index  The index of the CMOS register to write.\r
+  @param[in]  Value  The value of CMOS register to write.\r
+\r
+  @return  The value written to the CMOS register specified by Index.\r
+\r
+**/\r
+UINT8\r
+LegacyWriteStandardCmos (\r
+  IN UINT8  Index,\r
+  IN UINT8  Value\r
+  );\r
+\r
+/**\r
+  Calculate the new standard CMOS checksum and write it.\r
+\r
+  @param  Private      Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS  Calculate 16-bit checksum successfully\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyCalculateWriteStandardCmosChecksum (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Test to see if a legacy PCI ROM exists for this device. Optionally return\r
+  the Legacy ROM instance for this PCI device.\r
+\r
+  @param[in]  This                   Protocol instance pointer.\r
+  @param[in]  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will be loaded\r
+  @param[out] RomImage               Return the legacy PCI ROM for this device\r
+  @param[out] RomSize                Size of ROM Image\r
+  @param[out] RuntimeImageLength     Runtime size of ROM Image\r
+  @param[out] Flags                  Indicates if ROM found and if PC-AT.\r
+  @param[out] OpromRevision          Revision of the PCI Rom\r
+  @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header\r
+\r
+  @return EFI_SUCCESS            Legacy Option ROM availible for this device\r
+  @return EFI_ALREADY_STARTED    This device is already managed by its Oprom\r
+  @return EFI_UNSUPPORTED        Legacy Option ROM not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosCheckPciRomEx (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  EFI_HANDLE                        PciHandle,\r
+  OUT VOID                              **RomImage, OPTIONAL\r
+  OUT UINTN                             *RomSize, OPTIONAL\r
+  OUT UINTN                             *RuntimeImageLength, OPTIONAL\r
+  OUT UINTN                             *Flags, OPTIONAL\r
+  OUT UINT8                             *OpromRevision, OPTIONAL\r
+  OUT VOID                              **ConfigUtilityCodeHeader OPTIONAL\r
+  );\r
+\r
+/**\r
+  Relocate this image under 4G memory for IPF.\r
+\r
+  @param  ImageHandle  Handle of driver image.\r
+  @param  SystemTable  Pointer to system table.\r
+\r
+  @retval EFI_SUCCESS  Image successfully relocated.\r
+  @retval EFI_ABORTED  Failed to relocate image.\r
+\r
+**/\r
+EFI_STATUS\r
+RelocateImageUnder4GIfNeeded (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  );\r
+\r
+/**\r
+  Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the\r
+  16-bit register context on entry and exit. Arguments can be passed on\r
+  the Stack argument\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  Segment    Segemnt of 16-bit mode call\r
+  @param  Offset     Offset of 16-bit mdoe call\r
+  @param  Regs       Register contexted passed into (and returned) from thunk to\r
+                     16-bit mode\r
+  @param  Stack      Caller allocated stack used to pass arguments\r
+  @param  StackSize  Size of Stack in bytes\r
+\r
+  @retval FALSE      Thunk completed, and there were no BIOS errors in the target code.\r
+                     See Regs for status.\r
+  @retval TRUE       There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+InternalLegacyBiosFarCall (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL        *This,\r
+  IN  UINT16                          Segment,\r
+  IN  UINT16                          Offset,\r
+  IN  EFI_IA32_REGISTER_SET           *Regs,\r
+  IN  VOID                            *Stack,\r
+  IN  UINTN                           StackSize\r
+  );\r
+\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c
new file mode 100644 (file)
index 0000000..40d027a
--- /dev/null
@@ -0,0 +1,2032 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#define BOOT_LEGACY_OS              0\r
+#define BOOT_EFI_OS                 1\r
+#define BOOT_UNCONVENTIONAL_DEVICE  2\r
+\r
+UINT32              mLoadOptionsSize    = 0;\r
+UINTN               mBootMode           = BOOT_LEGACY_OS;\r
+VOID                *mLoadOptions       = NULL;\r
+BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr  = NULL;\r
+BBS_BBS_DEVICE_PATH mBbsDevicePathNode;\r
+UDC_ATTRIBUTES      mAttributes         = { 0, 0, 0, 0 };\r
+UINTN               mBbsEntry           = 0;\r
+VOID                *mBeerData          = NULL;\r
+VOID                *mServiceAreaData   = NULL;\r
+UINT64              mLowWater           = 0xffffffffffffffffULL;\r
+\r
+extern BBS_TABLE           *mBbsTable;\r
+\r
+/**\r
+  Print the BBS Table.\r
+\r
+  @param BbsTable   The BBS table.\r
+\r
+\r
+**/\r
+VOID\r
+PrintBbsTable (\r
+  IN BBS_TABLE *BbsTable\r
+  )\r
+{\r
+  UINT16 Index;\r
+  UINT16 SubIndex;\r
+  CHAR8  *String;\r
+\r
+  DEBUG ((EFI_D_INFO, "\n"));\r
+  DEBUG ((EFI_D_INFO, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));\r
+  DEBUG ((EFI_D_INFO, "=================================================================\n"));\r
+  for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {\r
+    //\r
+    // Filter\r
+    //\r
+    if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
+      continue;\r
+    }\r
+\r
+    DEBUG ((\r
+      EFI_D_INFO,\r
+      " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",\r
+      (UINTN) Index,\r
+      (UINTN) BbsTable[Index].BootPriority,\r
+      (UINTN) BbsTable[Index].Bus,\r
+      (UINTN) BbsTable[Index].Device,\r
+      (UINTN) BbsTable[Index].Function,\r
+      (UINTN) BbsTable[Index].Class,\r
+      (UINTN) BbsTable[Index].SubClass,\r
+      (UINTN) BbsTable[Index].DeviceType,\r
+      (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags\r
+      ));\r
+    DEBUG ((\r
+      EFI_D_INFO,\r
+      " %04x:%04x %04x:%04x %04x:%04x",\r
+      (UINTN) BbsTable[Index].BootHandlerSegment,\r
+      (UINTN) BbsTable[Index].BootHandlerOffset,\r
+      (UINTN) BbsTable[Index].MfgStringSegment,\r
+      (UINTN) BbsTable[Index].MfgStringOffset,\r
+      (UINTN) BbsTable[Index].DescStringSegment,\r
+      (UINTN) BbsTable[Index].DescStringOffset\r
+      ));\r
+\r
+    //\r
+    // Print DescString\r
+    //\r
+    String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);\r
+    if (String != NULL) {\r
+      DEBUG ((EFI_D_INFO," ("));\r
+      for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {\r
+        DEBUG ((EFI_D_INFO, "%c", String[SubIndex]));\r
+      }\r
+      DEBUG ((EFI_D_INFO,")"));\r
+    }\r
+    DEBUG ((EFI_D_INFO,"\n"));\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "\n"));\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Print the BBS Table.\r
+\r
+  @param HddInfo   The HddInfo table.\r
+\r
+\r
+**/\r
+VOID\r
+PrintHddInfo (\r
+  IN HDD_INFO *HddInfo\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  DEBUG ((EFI_D_INFO, "\n"));\r
+  for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {\r
+    DEBUG ((EFI_D_INFO, "Index - %04x\n", Index));\r
+    DEBUG ((EFI_D_INFO, "  Status    - %04x\n", (UINTN)HddInfo[Index].Status));\r
+    DEBUG ((EFI_D_INFO, "  B/D/F     - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));\r
+    DEBUG ((EFI_D_INFO, "  Command   - %04x\n", HddInfo[Index].CommandBaseAddress));\r
+    DEBUG ((EFI_D_INFO, "  Control   - %04x\n", HddInfo[Index].ControlBaseAddress));\r
+    DEBUG ((EFI_D_INFO, "  BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));\r
+    DEBUG ((EFI_D_INFO, "  HddIrq    - %02x\n", HddInfo[Index].HddIrq));\r
+    DEBUG ((EFI_D_INFO, "  IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));\r
+    DEBUG ((EFI_D_INFO, "  IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "\n"));\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Identify drive data must be updated to actual parameters before boot.\r
+\r
+  @param  IdentifyDriveData       ATA Identify Data\r
+\r
+**/\r
+VOID\r
+UpdateIdentifyDriveData (\r
+  IN  UINT8     *IdentifyDriveData\r
+  );\r
+\r
+/**\r
+  Update SIO data.\r
+\r
+  @param  Private                 Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS             Removable media not present\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateSioData (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINTN                               Index;\r
+  UINTN                               Index1;\r
+  UINT8                               LegacyInterrupts[16];\r
+  EFI_LEGACY_IRQ_ROUTING_ENTRY        *RoutingTable;\r
+  UINTN                               RoutingTableEntries;\r
+  EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;\r
+  UINTN                               NumberPriorityEntries;\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE   *EfiToLegacy16BootTable;\r
+  UINT8                               HddIrq;\r
+  UINT16                              LegacyInt;\r
+  UINT16                              LegMask;\r
+  UINT32                              Register;\r
+  UINTN                               HandleCount;\r
+  EFI_HANDLE                          *HandleBuffer;\r
+  EFI_ISA_IO_PROTOCOL                 *IsaIo;\r
+\r
+  LegacyInt               = 0;\r
+  HandleBuffer            = NULL;\r
+\r
+  EfiToLegacy16BootTable  = &Private->IntThunk->EfiToLegacy16BootTable;\r
+  LegacyBiosBuildSioData (Private);\r
+  SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);\r
+\r
+  //\r
+  // Create list of legacy interrupts.\r
+  //\r
+  for (Index = 0; Index < 4; Index++) {\r
+    LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;\r
+  }\r
+\r
+  for (Index = 4; Index < 7; Index++) {\r
+    LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;\r
+  }\r
+\r
+  LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;\r
+\r
+  //\r
+  // Get Legacy Hdd IRQs. If native mode treat as PCI\r
+  //\r
+  for (Index = 0; Index < 2; Index++) {\r
+    HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;\r
+    if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {\r
+      LegacyInterrupts[Index + 8] = HddIrq;\r
+    }\r
+  }\r
+\r
+  Private->LegacyBiosPlatform->GetRoutingTable (\r
+                                Private->LegacyBiosPlatform,\r
+                                (VOID *) &RoutingTable,\r
+                                &RoutingTableEntries,\r
+                                NULL,\r
+                                NULL,\r
+                                (VOID **) &IrqPriorityTable,\r
+                                &NumberPriorityEntries\r
+                                );\r
+  //\r
+  // Remove legacy interrupts from the list of PCI interrupts available.\r
+  //\r
+  for (Index = 0; Index <= 0x0b; Index++) {\r
+    for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {\r
+      if (LegacyInterrupts[Index] != 0) {\r
+        LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index]));\r
+        if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {\r
+          IrqPriorityTable[Index1].Used = LEGACY_USED;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  Private->Legacy8259->GetMask (\r
+                        Private->Legacy8259,\r
+                        &LegMask,\r
+                        NULL,\r
+                        NULL,\r
+                        NULL\r
+                        );\r
+\r
+  //\r
+  // Set SIO interrupts and disable mouse. Let mouse driver\r
+  // re-enable it.\r
+  //\r
+  LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000);\r
+  Private->Legacy8259->SetMask (\r
+                        Private->Legacy8259,\r
+                        &LegMask,\r
+                        NULL,\r
+                        NULL,\r
+                        NULL\r
+                        );\r
+\r
+  //\r
+  // Disable mouse in keyboard controller\r
+  //\r
+  Register = 0xA7;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiIsaIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiIsaIoProtocolGuid,\r
+                    (VOID **) &IsaIo\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);\r
+\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  Identify drive data must be updated to actual parameters before boot.\r
+  This requires updating the checksum, if it exists.\r
+\r
+  @param  IdentifyDriveData       ATA Identify Data\r
+  @param  Checksum                checksum of the ATA Identify Data\r
+\r
+  @retval EFI_SUCCESS             checksum calculated\r
+  @retval EFI_SECURITY_VIOLATION  IdentifyData invalid\r
+\r
+**/\r
+EFI_STATUS\r
+CalculateIdentifyDriveChecksum (\r
+  IN  UINT8     *IdentifyDriveData,\r
+  OUT UINT8     *Checksum\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINT8 LocalChecksum;\r
+  LocalChecksum = 0;\r
+  *Checksum     = 0;\r
+  if (IdentifyDriveData[510] != 0xA5) {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  for (Index = 0; Index < 512; Index++) {\r
+    LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]);\r
+  }\r
+\r
+  *Checksum = LocalChecksum;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Identify drive data must be updated to actual parameters before boot.\r
+\r
+  @param  IdentifyDriveData       ATA Identify Data\r
+\r
+\r
+**/\r
+VOID\r
+UpdateIdentifyDriveData (\r
+  IN  UINT8     *IdentifyDriveData\r
+  )\r
+{\r
+  UINT16          NumberCylinders;\r
+  UINT16          NumberHeads;\r
+  UINT16          NumberSectorsTrack;\r
+  UINT32          CapacityInSectors;\r
+  UINT8           OriginalChecksum;\r
+  UINT8           FinalChecksum;\r
+  EFI_STATUS      Status;\r
+  ATAPI_IDENTIFY  *ReadInfo;\r
+\r
+  //\r
+  // Status indicates if Integrity byte is correct. Checksum should be\r
+  // 0 if valid.\r
+  //\r
+  ReadInfo  = (ATAPI_IDENTIFY *) IdentifyDriveData;\r
+  Status    = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);\r
+  if (OriginalChecksum != 0) {\r
+    Status = EFI_SECURITY_VIOLATION;\r
+  }\r
+  //\r
+  // If NumberCylinders = 0 then do data(Controller present but don drive attached).\r
+  //\r
+  NumberCylinders = ReadInfo->Raw[1];\r
+  if (NumberCylinders != 0) {\r
+    ReadInfo->Raw[54]   = NumberCylinders;\r
+\r
+    NumberHeads         = ReadInfo->Raw[3];\r
+    ReadInfo->Raw[55]   = NumberHeads;\r
+\r
+    NumberSectorsTrack  = ReadInfo->Raw[6];\r
+    ReadInfo->Raw[56]   = NumberSectorsTrack;\r
+\r
+    //\r
+    // Copy Multisector info and set valid bit.\r
+    //\r
+    ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100);\r
+    CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack));\r
+    ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16);\r
+    ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff);\r
+    if (Status == EFI_SUCCESS) {\r
+      //\r
+      // Forece checksum byte to 0 and get new checksum.\r
+      //\r
+      ReadInfo->Raw[255] &= 0xff;\r
+      CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);\r
+\r
+      //\r
+      // Force new checksum such that sum is 0.\r
+      //\r
+      FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum);\r
+      ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8));\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Identify drive data must be updated to actual parameters before boot.\r
+  Do for all drives.\r
+\r
+  @param  Private                 Legacy BIOS Instance data\r
+\r
+\r
+**/\r
+VOID\r
+UpdateAllIdentifyDriveData (\r
+  IN LEGACY_BIOS_INSTANCE                 *Private\r
+  )\r
+{\r
+  UINTN     Index;\r
+  HDD_INFO  *HddInfo;\r
+\r
+  HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];\r
+\r
+  for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {\r
+    //\r
+    // Each controller can have 2 devices. Update for each device\r
+    //\r
+    if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {\r
+      UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0]));\r
+    }\r
+\r
+    if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {\r
+      UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0]));\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Enable ide controller.  This gets disabled when LegacyBoot.c is about\r
+  to run the Option ROMs.\r
+\r
+  @param  Private        Legacy BIOS Instance data\r
+\r
+\r
+**/\r
+VOID\r
+EnableIdeController (\r
+  IN LEGACY_BIOS_INSTANCE              *Private\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  EFI_STATUS          Status;\r
+  EFI_HANDLE          IdeController;\r
+  UINT8               ByteBuffer;\r
+  UINTN               HandleCount;\r
+  EFI_HANDLE          *HandleBuffer;\r
+\r
+  Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformIdeHandle,\r
+                                          0,\r
+                                          &HandleBuffer,\r
+                                          &HandleCount,\r
+                                          NULL\r
+                                          );\r
+  if (!EFI_ERROR (Status)) {\r
+    IdeController = HandleBuffer[0];\r
+    Status = gBS->HandleProtocol (\r
+                    IdeController,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+    ByteBuffer = 0x1f;\r
+    if (!EFI_ERROR (Status)) {\r
+      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Enable ide controller.  This gets disabled when LegacyBoot.c is about\r
+  to run the Option ROMs.\r
+\r
+  @param  Private                 Legacy BIOS Instance data\r
+\r
+\r
+**/\r
+VOID\r
+EnableAllControllers (\r
+  IN LEGACY_BIOS_INSTANCE              *Private\r
+  )\r
+{\r
+  UINTN               HandleCount;\r
+  EFI_HANDLE          *HandleBuffer;\r
+  UINTN               Index;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  PCI_TYPE01          PciConfigHeader;\r
+  EFI_STATUS          Status;\r
+\r
+  //\r
+  //\r
+  //\r
+  EnableIdeController (Private);\r
+\r
+  //\r
+  // Assumption is table is built from low bus to high bus numbers.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    PciIo->Pci.Read (\r
+                PciIo,\r
+                EfiPciIoWidthUint32,\r
+                0,\r
+                sizeof (PciConfigHeader) / sizeof (UINT32),\r
+                &PciConfigHeader\r
+                );\r
+\r
+    //\r
+    // We do not enable PPB here. This is for HotPlug Consideration.\r
+    // The Platform HotPlug Driver is responsible for Padding enough hot plug\r
+    // resources. It is also responsible for enable this bridge. If it\r
+    // does not pad it. It will cause some early Windows fail to installation.\r
+    // If the platform driver does not pad resource for PPB, PPB should be in\r
+    // un-enabled state to let Windows know that this PPB is not configured by\r
+    // BIOS. So Windows will allocate default resource for PPB.\r
+    //\r
+    // The reason for why we enable the command register is:\r
+    // The CSM will use the IO bar to detect some IRQ status, if the command\r
+    // is disabled, the IO resource will be out of scope.\r
+    // For example:\r
+    // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ\r
+    // comes up, the handle will check the IO space to identify is the\r
+    // controller generated the IRQ source.\r
+    // If the IO command is not enabled, the IRQ handler will has wrong\r
+    // information. It will cause IRQ storm when the correctly IRQ handler fails\r
+    // to run.\r
+    //\r
+    if (!(IS_PCI_VGA (&PciConfigHeader)     ||\r
+          IS_PCI_OLD_VGA (&PciConfigHeader) ||\r
+          IS_PCI_IDE (&PciConfigHeader)     ||\r
+          IS_PCI_P2P (&PciConfigHeader)     ||\r
+          IS_PCI_P2P_SUB (&PciConfigHeader) ||\r
+          IS_PCI_LPC (&PciConfigHeader)     )) {\r
+\r
+      PciConfigHeader.Hdr.Command |= 0x1f;\r
+\r
+      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  The following routines are identical in operation, so combine\r
+  for code compaction:\r
+  EfiGetPlatformBinaryGetMpTable\r
+  EfiGetPlatformBinaryGetOemIntData\r
+  EfiGetPlatformBinaryGetOem32Data\r
+  EfiGetPlatformBinaryGetOem16Data\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  Id                      Table/Data identifier\r
+\r
+  @retval EFI_SUCCESS             Success\r
+  @retval EFI_INVALID_PARAMETER   Invalid ID\r
+  @retval EFI_OUT_OF_RESOURCES    no resource to get data or table\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyGetDataOrTable (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  IN EFI_GET_PLATFORM_INFO_MODE       Id\r
+  )\r
+{\r
+  VOID                              *Table;\r
+  UINT32                            TablePtr;\r
+  UINTN                             TableSize;\r
+  UINTN                             Alignment;\r
+  UINTN                             Location;\r
+  EFI_STATUS                        Status;\r
+  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
+  EFI_COMPATIBILITY16_TABLE         *Legacy16Table;\r
+  EFI_IA32_REGISTER_SET             Regs;\r
+  LEGACY_BIOS_INSTANCE              *Private;\r
+\r
+  Private             = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+\r
+  LegacyBiosPlatform  = Private->LegacyBiosPlatform;\r
+  Legacy16Table       = Private->Legacy16Table;\r
+\r
+  //\r
+  // Phase 1 - get an address allocated in 16-bit code\r
+  //\r
+  while (TRUE) {\r
+    switch (Id) {\r
+    case EfiGetPlatformBinaryMpTable:\r
+    case EfiGetPlatformBinaryOemIntData:\r
+    case EfiGetPlatformBinaryOem32Data:\r
+    case EfiGetPlatformBinaryOem16Data:\r
+      {\r
+        Status = LegacyBiosPlatform->GetPlatformInfo (\r
+                                      LegacyBiosPlatform,\r
+                                      Id,\r
+                                      (VOID *) &Table,\r
+                                      &TableSize,\r
+                                      &Location,\r
+                                      &Alignment,\r
+                                      0,\r
+                                      0\r
+                                      );\r
+        DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));\r
+        DEBUG ((EFI_D_INFO, "  Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));\r
+        break;\r
+      }\r
+\r
+    default:\r
+      {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+    Regs.X.AX = Legacy16GetTableAddress;\r
+    Regs.X.CX = (UINT16) TableSize;\r
+    Regs.X.BX = (UINT16) Location;\r
+    Regs.X.DX = (UINT16) Alignment;\r
+    Private->LegacyBios.FarCall86 (\r
+      This,\r
+      Private->Legacy16CallSegment,\r
+      Private->Legacy16CallOffset,\r
+      &Regs,\r
+      NULL,\r
+      0\r
+      );\r
+\r
+    if (Regs.X.AX != 0) {\r
+      DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id));\r
+      return EFI_OUT_OF_RESOURCES;\r
+    } else {\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // Phase 2 Call routine second time with address to allow address adjustment\r
+  //\r
+  Status = LegacyBiosPlatform->GetPlatformInfo (\r
+                                LegacyBiosPlatform,\r
+                                Id,\r
+                                (VOID *) &Table,\r
+                                &TableSize,\r
+                                &Location,\r
+                                &Alignment,\r
+                                Regs.X.DS,\r
+                                Regs.X.BX\r
+                                );\r
+  switch (Id) {\r
+  case EfiGetPlatformBinaryMpTable:\r
+    {\r
+      Legacy16Table->MpTablePtr     = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
+      Legacy16Table->MpTableLength  = (UINT32)TableSize;\r
+      DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));\r
+      break;\r
+    }\r
+\r
+  case EfiGetPlatformBinaryOemIntData:\r
+    {\r
+\r
+      Legacy16Table->OemIntSegment  = Regs.X.DS;\r
+      Legacy16Table->OemIntOffset   = Regs.X.BX;\r
+      DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));\r
+      break;\r
+    }\r
+\r
+  case EfiGetPlatformBinaryOem32Data:\r
+    {\r
+      Legacy16Table->Oem32Segment = Regs.X.DS;\r
+      Legacy16Table->Oem32Offset  = Regs.X.BX;\r
+      DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));\r
+      break;\r
+    }\r
+\r
+  case EfiGetPlatformBinaryOem16Data:\r
+    {\r
+      //\r
+      //          Legacy16Table->Oem16Segment = Regs.X.DS;\r
+      //          Legacy16Table->Oem16Offset  = Regs.X.BX;\r
+      DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));\r
+      break;\r
+    }\r
+\r
+  default:\r
+    {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Phase 3 Copy table to final location\r
+  //\r
+  TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
+\r
+  CopyMem (\r
+    (VOID *) (UINTN)TablePtr,\r
+    Table,\r
+    TableSize\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Assign drive number to legacy HDD drives prior to booting an EFI\r
+  aware OS so the OS can access drives without an EFI driver.\r
+  Note: BBS compliant drives ARE NOT available until this call by\r
+  either shell or EFI.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS             Drive numbers assigned\r
+\r
+**/\r
+EFI_STATUS\r
+GenericLegacyBoot (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  LEGACY_BIOS_INSTANCE              *Private;\r
+  EFI_IA32_REGISTER_SET             Regs;\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
+  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
+  UINTN                             CopySize;\r
+  VOID                              *AcpiPtr;\r
+  HDD_INFO                          *HddInfo;\r
+  HDD_INFO                          *LocalHddInfo;\r
+  UINTN                             Index;\r
+  EFI_COMPATIBILITY16_TABLE         *Legacy16Table;\r
+  UINT32                            *BdaPtr;\r
+  UINT16                            HddCount;\r
+  UINT16                            BbsCount;\r
+  BBS_TABLE                         *LocalBbsTable;\r
+  UINT32                            *BaseVectorMaster;\r
+  EFI_TIME                          BootTime;\r
+  UINT32                            LocalTime;\r
+  EFI_HANDLE                        IdeController;\r
+  UINTN                             HandleCount;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  VOID                              *SmbiosTable;\r
+  VOID                              *AcpiTable;\r
+  UINTN                             ShadowAddress;\r
+  UINT32                            Granularity;\r
+  EFI_TIMER_ARCH_PROTOCOL           *Timer;\r
+  UINT64                            TimerPeriod;\r
+\r
+  LocalHddInfo  = NULL;\r
+  HddCount      = 0;\r
+  BbsCount      = 0;\r
+  LocalBbsTable = NULL;\r
+  TimerPeriod   = 0;\r
+\r
+  Private       = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  DEBUG_CODE (\r
+    DEBUG ((EFI_D_ERROR, "Start of legacy boot\n"));\r
+  );\r
+\r
+  Legacy16Table                         = Private->Legacy16Table;\r
+  EfiToLegacy16BootTable                = &Private->IntThunk->EfiToLegacy16BootTable;\r
+  HddInfo = &EfiToLegacy16BootTable->HddInfo[0];\r
+\r
+  LegacyBiosPlatform = Private->LegacyBiosPlatform;\r
+\r
+  EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;\r
+  EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;\r
+\r
+  //\r
+  // Before starting the Legacy boot check the system ticker.\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiTimerArchProtocolGuid, \r
+                  NULL,\r
+                  (VOID **) &Timer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = Timer->GetTimerPeriod (\r
+                    Timer,\r
+                    &TimerPeriod\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (TimerPeriod != DEFAULT_LAGACY_TIMER_TICK_DURATION) {\r
+    Status = Timer->SetTimerPeriod (\r
+                      Timer, \r
+                      DEFAULT_LAGACY_TIMER_TICK_DURATION\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // If booting to a legacy OS then force HDD drives to the appropriate\r
+  // boot mode by calling GetIdeHandle.\r
+  // A reconnect -r can force all HDDs back to native mode.\r
+  //\r
+  IdeController = NULL;\r
+  if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
+    Status = LegacyBiosPlatform->GetPlatformHandle (\r
+                                  Private->LegacyBiosPlatform,\r
+                                  EfiGetPlatformIdeHandle,\r
+                                  0,\r
+                                  &HandleBuffer,\r
+                                  &HandleCount,\r
+                                  NULL\r
+                                  );\r
+    if (!EFI_ERROR (Status)) {\r
+      IdeController = HandleBuffer[0];\r
+    }   \r
+  }\r
+  //\r
+  // Unlock the Legacy BIOS region\r
+  //\r
+  Private->LegacyRegion->UnLock (\r
+                           Private->LegacyRegion,\r
+                           0xE0000,\r
+                           0x20000,\r
+                           &Granularity\r
+                           );\r
+\r
+  //\r
+  // Reconstruct the Legacy16 boot memory map\r
+  //\r
+  LegacyBiosBuildE820 (Private, &CopySize);\r
+  if (CopySize > Private->Legacy16Table->E820Length) {\r
+    ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+    Regs.X.AX = Legacy16GetTableAddress;\r
+    Regs.X.CX = (UINT16) CopySize;\r
+    Private->LegacyBios.FarCall86 (\r
+      &Private->LegacyBios,\r
+      Private->Legacy16Table->Compatibility16CallSegment,\r
+      Private->Legacy16Table->Compatibility16CallOffset,\r
+      &Regs,\r
+      NULL,\r
+      0\r
+      );\r
+\r
+    Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
+    Private->Legacy16Table->E820Length  = (UINT32) CopySize;\r
+    if (Regs.X.AX != 0) {\r
+      DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));\r
+    } else {\r
+      CopyMem (\r
+        (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,\r
+        Private->E820Table,\r
+        CopySize\r
+        );\r
+    }\r
+  } else {\r
+    CopyMem (\r
+      (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,\r
+      Private->E820Table,\r
+      CopySize\r
+      );\r
+    Private->Legacy16Table->E820Length = (UINT32) CopySize;\r
+  }\r
+  //\r
+  // Get SMBIOS and ACPI table pointers\r
+  //\r
+  SmbiosTable = NULL;\r
+  EfiGetSystemConfigurationTable (\r
+    &gEfiSmbiosTableGuid,\r
+    &SmbiosTable\r
+    );\r
+  //\r
+  // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.\r
+  //\r
+  if (SmbiosTable == NULL) {\r
+    DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));\r
+  }\r
+  EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)SmbiosTable;\r
+\r
+  AcpiTable = NULL;\r
+  Status = EfiGetSystemConfigurationTable (\r
+             &gEfiAcpi20TableGuid,\r
+             &AcpiTable\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EfiGetSystemConfigurationTable (\r
+               &gEfiAcpi10TableGuid,\r
+               &AcpiTable\r
+               );\r
+  }\r
+  //\r
+  // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.\r
+  //\r
+  if (AcpiTable == NULL) {\r
+    DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));\r
+  }\r
+  EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;\r
+\r
+  //\r
+  // Get RSD Ptr table rev at offset 15 decimal\r
+  // Rev = 0 Length is 20 decimal\r
+  // Rev != 0 Length is UINT32 at offset 20 decimal\r
+  //\r
+  if (AcpiTable != NULL) {\r
+\r
+    AcpiPtr = AcpiTable;\r
+    if (*((UINT8 *) AcpiPtr + 15) == 0) {\r
+      CopySize = 20;\r
+    } else {\r
+      AcpiPtr   = ((UINT8 *) AcpiPtr + 20);\r
+      CopySize  = (*(UINT32 *) AcpiPtr);\r
+    }\r
+\r
+    CopyMem (\r
+      (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,\r
+      AcpiTable,\r
+      CopySize\r
+      );\r
+  }\r
+  //\r
+  // Make sure all PCI Interrupt Line register are programmed to match 8259\r
+  //\r
+  PciProgramAllInterruptLineRegisters (Private);\r
+\r
+  //\r
+  // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters\r
+  // can lock it.\r
+  //\r
+  Private->LegacyRegion->UnLock (\r
+                           Private->LegacyRegion,\r
+                           Private->BiosStart,\r
+                           Private->LegacyBiosImageSize,\r
+                           &Granularity\r
+                           );\r
+\r
+  //\r
+  // Configure Legacy Device Magic\r
+  //\r
+  // Only do this code if booting legacy OS\r
+  //\r
+  if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
+    UpdateSioData (Private);\r
+  }\r
+  //\r
+  // Setup BDA and EBDA standard areas before Legacy Boot\r
+  //\r
+  LegacyBiosCompleteBdaBeforeBoot (Private);\r
+  LegacyBiosCompleteStandardCmosBeforeBoot (Private);\r
+\r
+  //\r
+  // We must build IDE data, if it hasn't been done, before PciShadowRoms\r
+  // to insure EFI drivers are connected.\r
+  //\r
+  LegacyBiosBuildIdeData (Private, &HddInfo, 1);\r
+  UpdateAllIdentifyDriveData (Private);\r
+\r
+  //\r
+  // Clear IO BAR, if IDE controller in legacy mode.\r
+  //\r
+  InitLegacyIdeController (IdeController);\r
+\r
+  //\r
+  // Generate number of ticks since midnight for BDA. DOS requires this\r
+  // for its time. We have to make assumptions as to how long following\r
+  // code takes since after PciShadowRoms PciIo is gone. Place result in\r
+  // 40:6C-6F\r
+  //\r
+  // Adjust value by 1 second.\r
+  //\r
+  gRT->GetTime (&BootTime, NULL);\r
+  LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;\r
+  LocalTime += 1;\r
+\r
+  //\r
+  // Multiply result by 18.2 for number of ticks since midnight.\r
+  // Use 182/10 to avoid floating point math.\r
+  //\r
+  LocalTime = (LocalTime * 182) / 10;\r
+  BdaPtr    = (UINT32 *) (UINTN)0x46C;\r
+  *BdaPtr   = LocalTime;\r
+\r
+  //\r
+  // Shadow PCI ROMs. We must do this near the end since this will kick\r
+  // of Native EFI drivers that may be needed to collect info for Legacy16\r
+  //\r
+  //  WARNING: PciIo is gone after this call.\r
+  //\r
+  PciShadowRoms (Private);\r
+\r
+  //\r
+  // Shadow PXE base code, BIS etc.\r
+  //\r
+  Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);\r
+  ShadowAddress = Private->OptionRom;\r
+  Private->LegacyBiosPlatform->PlatformHooks (\r
+                                 Private->LegacyBiosPlatform,\r
+                                 EfiPlatformHookShadowServiceRoms,\r
+                                 0,\r
+                                 0,\r
+                                 &ShadowAddress,\r
+                                 Legacy16Table,\r
+                                 NULL\r
+                                 );\r
+  Private->OptionRom = (UINT32)ShadowAddress;\r
+  //\r
+  // Register Legacy SMI Handler\r
+  //\r
+  LegacyBiosPlatform->SmmInit (\r
+                        LegacyBiosPlatform,\r
+                        EfiToLegacy16BootTable\r
+                        );\r
+\r
+  //\r
+  // Let platform code know the boot options\r
+  //\r
+  LegacyBiosGetBbsInfo (\r
+    This,\r
+    &HddCount,\r
+    &LocalHddInfo,\r
+    &BbsCount,\r
+    &LocalBbsTable\r
+    );\r
+\r
+  PrintBbsTable (LocalBbsTable);\r
+  PrintHddInfo (LocalHddInfo);\r
+\r
+  //\r
+  // If drive wasn't spun up then BuildIdeData may have found new drives.\r
+  // Need to update BBS boot priority.\r
+  //\r
+  for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {\r
+    if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&\r
+        (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)\r
+        ) {\r
+      LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+    }\r
+\r
+    if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&\r
+        (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)\r
+        ) {\r
+      LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+    }\r
+  }\r
+\r
+  Private->LegacyRegion->UnLock (\r
+                           Private->LegacyRegion,\r
+                           0xc0000,\r
+                           0x40000,\r
+                           &Granularity\r
+                           );\r
+\r
+  LegacyBiosPlatform->PrepareToBoot (\r
+                        LegacyBiosPlatform,\r
+                        mBbsDevicePathPtr,\r
+                        mBbsTable,\r
+                        mLoadOptionsSize,\r
+                        mLoadOptions,\r
+                        (VOID *) &Private->IntThunk->EfiToLegacy16BootTable\r
+                        );\r
+\r
+  //\r
+  // If no boot device return to BDS\r
+  //\r
+  if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
+    for (Index = 0; Index < BbsCount; Index++){\r
+      if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&\r
+          (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&\r
+          (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {\r
+        break;\r
+      }\r
+    }\r
+    if (Index == BbsCount) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+  //\r
+  // Let the Legacy16 code know the device path type for legacy boot\r
+  //\r
+  EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;\r
+\r
+  //\r
+  // Copy MP table, if it exists.\r
+  //\r
+  LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);\r
+\r
+  if (!Private->LegacyBootEntered) {\r
+    //\r
+    // Copy OEM INT Data, if it exists. Note: This code treats any data\r
+    // as a bag of bits and knows nothing of the contents nor cares.\r
+    // Contents are IBV specific.\r
+    //\r
+    LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);\r
+\r
+    //\r
+    // Copy OEM16 Data, if it exists.Note: This code treats any data\r
+    // as a bag of bits and knows nothing of the contents nor cares.\r
+    // Contents are IBV specific.\r
+    //\r
+    LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);\r
+\r
+    //\r
+    // Copy OEM32 Data, if it exists.Note: This code treats any data\r
+    // as a bag of bits and knows nothing of the contents nor cares.\r
+    // Contents are IBV specific.\r
+    //\r
+    LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);\r
+  }\r
+\r
+  //\r
+  // Call into Legacy16 code to prepare for INT 19h\r
+  //\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+  Regs.X.AX = Legacy16PrepareToBoot;\r
+\r
+  //\r
+  // Pass in handoff data\r
+  //\r
+  Regs.X.ES = EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);\r
+  Regs.X.BX = EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);\r
+\r
+  Private->LegacyBios.FarCall86 (\r
+    This,\r
+    Private->Legacy16CallSegment,\r
+    Private->Legacy16CallOffset,\r
+    &Regs,\r
+    NULL,\r
+    0\r
+    );\r
+\r
+  if (Regs.X.AX != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Lock the Legacy BIOS region\r
+  //\r
+  Private->LegacyRegion->Lock (\r
+                           Private->LegacyRegion,\r
+                           0xc0000,\r
+                           0x40000,\r
+                           &Granularity\r
+                           );\r
+  //\r
+  // Lock attributes of the Legacy Region if chipset supports\r
+  //\r
+  Private->LegacyRegion->BootLock (\r
+                           Private->LegacyRegion,\r
+                           0xc0000,\r
+                           0x40000,\r
+                           &Granularity\r
+                           );\r
+\r
+  //\r
+  // Call into Legacy16 code to do the INT 19h\r
+  //\r
+  EnableAllControllers (Private);\r
+  if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
+    //\r
+    // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT\r
+    //\r
+    EfiSignalEventLegacyBoot ();\r
+    DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));\r
+    //\r
+    // Raise TPL to high level to disable CPU interrupts\r
+    //\r
+    gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+    //\r
+    // Put the 8259 into its legacy mode by reprogramming the vector bases\r
+    //\r
+    Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);\r
+    //\r
+    // PC History\r
+    //   The original PC used INT8-F for master PIC. Since these mapped over\r
+    //   processor exceptions TIANO moved the master PIC to INT68-6F.\r
+    // We need to set these back to the Legacy16 unexpected interrupt(saved\r
+    // in LegacyBios.c) since some OS see that these have values different from\r
+    // what is expected and invoke them. Since the legacy OS corrupts EFI\r
+    // memory, there is no handler for these interrupts and OS blows up.\r
+    //\r
+    // We need to save the TIANO values for the rare case that the Legacy16\r
+    // code cannot boot but knows memory hasn't been destroyed.\r
+    //\r
+    // To compound the problem, video takes over one of these INTS and must be\r
+    // be left.\r
+    // @bug - determine if video hooks INT(in which case we must find new\r
+    //          set of TIANO vectors) or takes it over.\r
+    //\r
+    //\r
+    BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
+    for (Index = 0; Index < 8; Index++) {\r
+      Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];\r
+      if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {\r
+        BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);\r
+      }\r
+    }\r
+\r
+    ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+    Regs.X.AX = Legacy16Boot;\r
+\r
+    Private->LegacyBios.FarCall86 (\r
+      This,\r
+      Private->Legacy16CallSegment,\r
+      Private->Legacy16CallOffset,\r
+      &Regs,\r
+      NULL,\r
+      0\r
+      );\r
+\r
+    BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
+    for (Index = 0; Index < 8; Index++) {\r
+      BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];\r
+    }\r
+  }\r
+  Private->LegacyBootEntered = TRUE;\r
+  if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
+    //\r
+    // Should never return unless never passed control to 0:7c00(first stage\r
+    // OS loader) and only then if no bootable device found.\r
+    //\r
+    return EFI_DEVICE_ERROR;\r
+  } else {\r
+    //\r
+    // If boot to EFI then expect to return to caller\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Assign drive number to legacy HDD drives prior to booting an EFI\r
+  aware OS so the OS can access drives without an EFI driver.\r
+  Note: BBS compliant drives ARE NOT available until this call by\r
+  either shell or EFI.\r
+\r
+  @param  This                    Protocol instance pointer.\r
+  @param  BbsCount                Number of BBS_TABLE structures\r
+  @param  BbsTable                List BBS entries\r
+\r
+  @retval EFI_SUCCESS             Drive numbers assigned\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosPrepareToBootEfi (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  OUT UINT16                          *BbsCount,\r
+  OUT BBS_TABLE                       **BbsTable\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
+  LEGACY_BIOS_INSTANCE              *Private;\r
+\r
+  Private                 = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  EfiToLegacy16BootTable  = &Private->IntThunk->EfiToLegacy16BootTable;\r
+  mBootMode               = BOOT_EFI_OS;\r
+  mBbsDevicePathPtr       = NULL;\r
+  Status                  = GenericLegacyBoot (This);\r
+  *BbsTable               = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;\r
+  *BbsCount               = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  To boot from an unconventional device like parties and/or execute HDD diagnostics.\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  Attributes      How to interpret the other input parameters\r
+  @param  BbsEntry        The 0-based index into the BbsTable for the parent\r
+                          device.\r
+  @param  BeerData        Pointer to the 128 bytes of ram BEER data.\r
+  @param  ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The\r
+                          caller must provide a pointer to the specific Service\r
+                          Area and not the start all Service Areas.\r
+\r
+  @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.\r
+\r
+***/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosBootUnconventionalDevice (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL         *This,\r
+  IN UDC_ATTRIBUTES                   Attributes,\r
+  IN UINTN                            BbsEntry,\r
+  IN VOID                             *BeerData,\r
+  IN VOID                             *ServiceAreaData\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
+  LEGACY_BIOS_INSTANCE              *Private;\r
+  UD_TABLE                          *UcdTable;\r
+  UINTN                             Index;\r
+  UINT16                            BootPriority;\r
+  BBS_TABLE                         *BbsTable;\r
+\r
+  BootPriority = 0;\r
+  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  mBootMode = BOOT_UNCONVENTIONAL_DEVICE;\r
+  mBbsDevicePathPtr = &mBbsDevicePathNode;\r
+  mAttributes = Attributes;\r
+  mBbsEntry = BbsEntry;\r
+  mBeerData = BeerData, mServiceAreaData = ServiceAreaData;\r
+\r
+  EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
+\r
+  //\r
+  // Do input parameter checking\r
+  //\r
+  if ((Attributes.DirectoryServiceValidity == 0) &&\r
+      (Attributes.RabcaUsedFlag == 0) &&\r
+      (Attributes.ExecuteHddDiagnosticsFlag == 0)\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||\r
+      (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UcdTable = (UD_TABLE *) AllocatePool (\r
+                                                                                                               sizeof (UD_TABLE)\r
+                                                                                                               );\r
+  if (NULL == UcdTable) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;\r
+  UcdTable->Attributes = Attributes;\r
+  UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;\r
+  //\r
+  // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM\r
+  // to assign drive numbers but bot boot from. Only newly created entries\r
+  // will be valid.\r
+  //\r
+  BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;\r
+  for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {\r
+    BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;\r
+  }\r
+  //\r
+  // If parent is onboard IDE then assign controller & device number\r
+  // else they are 0.\r
+  //\r
+  if (BbsEntry < MAX_IDE_CONTROLLER * 2) {\r
+    UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);\r
+  }\r
+\r
+  if (BeerData != NULL) {\r
+    CopyMem (\r
+      (VOID *) UcdTable->BeerData,\r
+      BeerData,\r
+      (UINTN) 128\r
+      );\r
+  }\r
+\r
+  if (ServiceAreaData != NULL) {\r
+    CopyMem (\r
+      (VOID *) UcdTable->ServiceAreaData,\r
+      ServiceAreaData,\r
+      (UINTN) 64\r
+      );\r
+  }\r
+  //\r
+  // For each new entry do the following:\r
+  //   1. Increment current number of BBS entries\r
+  //   2. Copy parent entry to new entry.\r
+  //   3. Zero out BootHandler Offset & segment\r
+  //   4. Set appropriate device type. BEV(0x80) for HDD diagnostics\r
+  //      and Floppy(0x01) for PARTIES boot.\r
+  //   5. Assign new priority.\r
+  //\r
+  if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {\r
+    EfiToLegacy16BootTable->NumberBbsEntries += 1;\r
+\r
+    CopyMem (\r
+      (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,\r
+      (VOID *) &BbsTable[BbsEntry].BootPriority,\r
+      sizeof (BBS_TABLE)\r
+      );\r
+\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset  = 0;\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType         = 0x80;\r
+\r
+    UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);\r
+\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;\r
+    BootPriority += 1;\r
+\r
+    //\r
+    // Set device type as BBS_TYPE_DEV for PARTIES diagnostic\r
+    //\r
+    mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;\r
+  }\r
+\r
+  if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {\r
+    EfiToLegacy16BootTable->NumberBbsEntries += 1;\r
+    CopyMem (\r
+      (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,\r
+      (VOID *) &BbsTable[BbsEntry].BootPriority,\r
+      sizeof (BBS_TABLE)\r
+      );\r
+\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset  = 0;\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType         = 0x01;\r
+    UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);\r
+    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;\r
+\r
+    //\r
+    // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy\r
+    //\r
+    mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;\r
+  }\r
+  //\r
+  // Build the BBS Device Path for this boot selection\r
+  //\r
+  mBbsDevicePathNode.Header.Type    = BBS_DEVICE_PATH;\r
+  mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;\r
+  SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));\r
+  mBbsDevicePathNode.StatusFlag = 0;\r
+  mBbsDevicePathNode.String[0]  = 0;\r
+\r
+  Status                        = GenericLegacyBoot (This);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Attempt to legacy boot the BootOption. If the EFI contexted has been\r
+  compromised this function will not return.\r
+\r
+  @param  This             Protocol instance pointer.\r
+  @param  BbsDevicePath    EFI Device Path from BootXXXX variable.\r
+  @param  LoadOptionsSize  Size of LoadOption in size.\r
+  @param  LoadOptions      LoadOption from BootXXXX variable\r
+\r
+  @retval EFI_SUCCESS      Removable media not present\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosLegacyBoot (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  BBS_BBS_DEVICE_PATH               *BbsDevicePath,\r
+  IN  UINT32                            LoadOptionsSize,\r
+  IN  VOID                              *LoadOptions\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  mBbsDevicePathPtr = BbsDevicePath;\r
+  mLoadOptionsSize  = LoadOptionsSize;\r
+  mLoadOptions      = LoadOptions;\r
+  mBootMode         = BOOT_LEGACY_OS;\r
+  Status            = GenericLegacyBoot (This);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Convert EFI Memory Type to E820 Memory Type.\r
+\r
+  @param  Type  EFI Memory Type\r
+\r
+  @return ACPI Memory Type for EFI Memory Type\r
+\r
+**/\r
+EFI_ACPI_MEMORY_TYPE\r
+EfiMemoryTypeToE820Type (\r
+  IN  UINT32    Type\r
+  )\r
+{\r
+  switch (Type) {\r
+  case EfiLoaderCode:\r
+  case EfiLoaderData:\r
+  case EfiBootServicesCode:\r
+  case EfiBootServicesData:\r
+  case EfiConventionalMemory:\r
+  case EfiRuntimeServicesCode:\r
+  case EfiRuntimeServicesData:\r
+    return EfiAcpiAddressRangeMemory;\r
+\r
+  case EfiACPIReclaimMemory:\r
+    return EfiAcpiAddressRangeACPI;\r
+\r
+  case EfiACPIMemoryNVS:\r
+    return EfiAcpiAddressRangeNVS;\r
+\r
+  //\r
+  // All other types map to reserved.\r
+  // Adding the code just waists FLASH space.\r
+  //\r
+  //  case  EfiReservedMemoryType:\r
+  //  case  EfiUnusableMemory:\r
+  //  case  EfiMemoryMappedIO:\r
+  //  case  EfiMemoryMappedIOPortSpace:\r
+  //  case  EfiPalCode:\r
+  //\r
+  default:\r
+    return EfiAcpiAddressRangeReserved;\r
+  }\r
+}\r
+\r
+/**\r
+  Build the E820 table.\r
+\r
+  @param  Private  Legacy BIOS Instance data\r
+  @param  Size     Size of E820 Table\r
+\r
+  @retval EFI_SUCCESS  It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildE820 (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private,\r
+  OUT UINTN                   *Size\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_E820_ENTRY64            *E820Table;\r
+  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMap;\r
+  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMapEnd;\r
+  EFI_MEMORY_DESCRIPTOR       *EfiEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *NextEfiEntry;\r
+  EFI_MEMORY_DESCRIPTOR       TempEfiEntry;\r
+  UINTN                       EfiMemoryMapSize;\r
+  UINTN                       EfiMapKey;\r
+  UINTN                       EfiDescriptorSize;\r
+  UINT32                      EfiDescriptorVersion;\r
+  UINTN                       Index;\r
+  EFI_PEI_HOB_POINTERS        Hob;\r
+  EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
+  UINTN                       TempIndex;\r
+  UINTN                       IndexSort;\r
+  UINTN                       TempNextIndex;\r
+  EFI_E820_ENTRY64            TempE820;\r
+  EFI_ACPI_MEMORY_TYPE        TempType;\r
+  BOOLEAN                     ChangedFlag;\r
+  UINTN                       Above1MIndex;\r
+  UINT64                      MemoryBlockLength;\r
+\r
+  E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;\r
+\r
+  //\r
+  // Get the EFI memory map.\r
+  //\r
+  EfiMemoryMapSize  = 0;\r
+  EfiMemoryMap      = NULL;\r
+  Status = gBS->GetMemoryMap (\r
+                  &EfiMemoryMapSize,\r
+                  EfiMemoryMap,\r
+                  &EfiMapKey,\r
+                  &EfiDescriptorSize,\r
+                  &EfiDescriptorVersion\r
+                  );\r
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+  do {\r
+    //\r
+    // Use size returned back plus 1 descriptor for the AllocatePool.\r
+    // We don't just multiply by 2 since the "for" loop below terminates on\r
+    // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize\r
+    // we process bogus entries and create bogus E820 entries.\r
+    //\r
+    EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);\r
+    ASSERT (EfiMemoryMap != NULL);\r
+    Status = gBS->GetMemoryMap (\r
+                    &EfiMemoryMapSize,\r
+                    EfiMemoryMap,\r
+                    &EfiMapKey,\r
+                    &EfiDescriptorSize,\r
+                    &EfiDescriptorVersion\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (EfiMemoryMap);\r
+    }\r
+  } while (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Punch in the E820 table for memory less than 1 MB.\r
+  // Assume ZeroMem () has been done on data structure.\r
+  //\r
+  //\r
+  // First entry is 0 to (640k - EBDA)\r
+  //\r
+  E820Table[0].BaseAddr  = 0;\r
+  E820Table[0].Length    = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);\r
+  E820Table[0].Type      = EfiAcpiAddressRangeMemory;\r
+\r
+  //\r
+  // Second entry is (640k - EBDA) to 640k\r
+  //\r
+  E820Table[1].BaseAddr  = E820Table[0].Length;\r
+  E820Table[1].Length    = (UINT64) ((640 * 1024) - E820Table[0].Length);\r
+  E820Table[1].Type      = EfiAcpiAddressRangeReserved;\r
+\r
+  //\r
+  // Third Entry is legacy BIOS\r
+  // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas\r
+  // to page in memory under 1MB.\r
+  // Omit region from 0xE0000 to start of BIOS, if any. This can be\r
+  // used for a multiple reasons including OPROMS.\r
+  //\r
+\r
+  //\r
+  // The CSM binary image size is not the actually size that CSM binary used,\r
+  // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.\r
+  //\r
+  E820Table[2].BaseAddr  = 0xE0000;\r
+  E820Table[2].Length    = 0x20000;\r
+  E820Table[2].Type      = EfiAcpiAddressRangeReserved;\r
+\r
+  Above1MIndex = 2;\r
+\r
+  //\r
+  // Process the EFI map to produce E820 map;\r
+  //\r
+\r
+  //\r
+  // Sort memory map from low to high\r
+  //\r
+  EfiEntry        = EfiMemoryMap;\r
+  NextEfiEntry    = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
+  while (EfiEntry < EfiMemoryMapEnd) {\r
+    while (NextEfiEntry < EfiMemoryMapEnd) {\r
+      if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {\r
+        CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
+        CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
+        CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
+      }\r
+\r
+      NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);\r
+    }\r
+\r
+    EfiEntry      = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+    NextEfiEntry  = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+  }\r
+\r
+  EfiEntry        = EfiMemoryMap;\r
+  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
+  for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {\r
+    MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));\r
+    if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {\r
+      //\r
+      // Skip the memory block is under 1MB\r
+      //\r
+    } else {\r
+      if (EfiEntry->PhysicalStart < 0x100000) {\r
+        //\r
+        // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB\r
+        //\r
+        MemoryBlockLength       -= 0x100000 - EfiEntry->PhysicalStart;\r
+        EfiEntry->PhysicalStart =  0x100000;\r
+      }\r
+\r
+      //\r
+      // Convert memory type to E820 type\r
+      //\r
+      TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);\r
+\r
+      if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {\r
+        //\r
+        // Grow an existing entry\r
+        //\r
+        E820Table[Index].Length += MemoryBlockLength;\r
+      } else {\r
+        //\r
+        // Make a new entry\r
+        //\r
+        ++Index;\r
+        E820Table[Index].BaseAddr  = EfiEntry->PhysicalStart;\r
+        E820Table[Index].Length    = MemoryBlockLength;\r
+        E820Table[Index].Type      = TempType;\r
+      }\r
+    }\r
+    EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
+  }\r
+\r
+  FreePool (EfiMemoryMap);\r
+\r
+  //\r
+  // Process the reserved memory map to produce E820 map ;\r
+  //\r
+  for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+    if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+      ResourceHob = Hob.ResourceDescriptor;\r
+      if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||\r
+          (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE)  ||\r
+          (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED)    ) &&\r
+          (ResourceHob->PhysicalStart > 0x100000) &&\r
+          (Index < EFI_MAX_E820_ENTRY - 1)) {\r
+        ++Index;\r
+        E820Table[Index].BaseAddr  = ResourceHob->PhysicalStart;\r
+        E820Table[Index].Length    = ResourceHob->ResourceLength;\r
+        E820Table[Index].Type      = EfiAcpiAddressRangeReserved;\r
+      }\r
+    }\r
+  }\r
+\r
+  Index ++;\r
+  Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;\r
+  Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;\r
+  Private->NumberE820Entries = (UINT32)Index;\r
+  *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));\r
+\r
+  //\r
+  // Sort E820Table from low to high\r
+  //\r
+  for (TempIndex = 0; TempIndex < Index; TempIndex++) {\r
+    ChangedFlag = FALSE;\r
+    for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {\r
+      if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {\r
+        ChangedFlag                       = TRUE;\r
+        TempE820.BaseAddr                 = E820Table[TempNextIndex - 1].BaseAddr;\r
+        TempE820.Length                   = E820Table[TempNextIndex - 1].Length;\r
+        TempE820.Type                     = E820Table[TempNextIndex - 1].Type;\r
+\r
+        E820Table[TempNextIndex - 1].BaseAddr  = E820Table[TempNextIndex].BaseAddr;\r
+        E820Table[TempNextIndex - 1].Length    = E820Table[TempNextIndex].Length;\r
+        E820Table[TempNextIndex - 1].Type      = E820Table[TempNextIndex].Type;\r
+\r
+        E820Table[TempNextIndex].BaseAddr      = TempE820.BaseAddr;\r
+        E820Table[TempNextIndex].Length        = TempE820.Length;\r
+        E820Table[TempNextIndex].Type          = TempE820.Type;\r
+      }\r
+    }\r
+\r
+    if (!ChangedFlag) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Remove the overlap range\r
+  //\r
+  for (TempIndex = 1; TempIndex < Index; TempIndex++) {\r
+    if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&\r
+        ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=\r
+         (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {\r
+        //\r
+        //Overlap range is found\r
+        //\r
+        ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);\r
+\r
+        if (TempIndex == Index - 1) {\r
+          E820Table[TempIndex].BaseAddr = 0;\r
+          E820Table[TempIndex].Length   = 0;\r
+          E820Table[TempIndex].Type     = (EFI_ACPI_MEMORY_TYPE) 0;\r
+          Index--;\r
+          break;\r
+        } else {\r
+          for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {\r
+            E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;\r
+            E820Table[IndexSort].Length   = E820Table[IndexSort + 1].Length;\r
+            E820Table[IndexSort].Type     = E820Table[IndexSort + 1].Type;\r
+          }\r
+          Index--;\r
+       }\r
+    }\r
+  }\r
+\r
+\r
+\r
+  Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;\r
+  Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;\r
+  Private->NumberE820Entries = (UINT32)Index;\r
+  *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));\r
+\r
+  //\r
+  // Determine OS usable memory above 1Mb\r
+  //\r
+  Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;\r
+  for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {\r
+    if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory\r
+      //\r
+      // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.\r
+      //\r
+      if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {\r
+        Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);\r
+      } else {\r
+        break; // break at first not normal memory, because SMM may use reserved memory.\r
+      }\r
+    }\r
+  }\r
+\r
+  Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;\r
+\r
+  //\r
+  // Print DEBUG information\r
+  //\r
+  for (TempIndex = 0; TempIndex < Index; TempIndex++) {\r
+    DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",\r
+      TempIndex,\r
+      E820Table[TempIndex].BaseAddr,\r
+      (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),\r
+      E820Table[TempIndex].Type\r
+      ));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Fill in the standard BDA and EBDA stuff prior to legacy Boot\r
+\r
+  @param  Private      Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS  It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosCompleteBdaBeforeBoot (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  )\r
+{\r
+  BDA_STRUC                   *Bda;\r
+  UINT16                      MachineConfig;\r
+  DEVICE_PRODUCER_DATA_HEADER *SioPtr;\r
+\r
+  Bda           = (BDA_STRUC *) ((UINTN) 0x400);\r
+  MachineConfig = 0;\r
+\r
+  SioPtr        = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);\r
+  Bda->Com1     = SioPtr->Serial[0].Address;\r
+  Bda->Com2     = SioPtr->Serial[1].Address;\r
+  Bda->Com3     = SioPtr->Serial[2].Address;\r
+  Bda->Com4     = SioPtr->Serial[3].Address;\r
+\r
+  if (SioPtr->Serial[0].Address != 0x00) {\r
+    MachineConfig += 0x200;\r
+  }\r
+\r
+  if (SioPtr->Serial[1].Address != 0x00) {\r
+    MachineConfig += 0x200;\r
+  }\r
+\r
+  if (SioPtr->Serial[2].Address != 0x00) {\r
+    MachineConfig += 0x200;\r
+  }\r
+\r
+  if (SioPtr->Serial[3].Address != 0x00) {\r
+    MachineConfig += 0x200;\r
+  }\r
+\r
+  Bda->Lpt1 = SioPtr->Parallel[0].Address;\r
+  Bda->Lpt2 = SioPtr->Parallel[1].Address;\r
+  Bda->Lpt3 = SioPtr->Parallel[2].Address;\r
+\r
+  if (SioPtr->Parallel[0].Address != 0x00) {\r
+    MachineConfig += 0x4000;\r
+  }\r
+\r
+  if (SioPtr->Parallel[1].Address != 0x00) {\r
+    MachineConfig += 0x4000;\r
+  }\r
+\r
+  if (SioPtr->Parallel[2].Address != 0x00) {\r
+    MachineConfig += 0x4000;\r
+  }\r
+\r
+  Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);\r
+  if (SioPtr->Floppy.NumberOfFloppy != 0x00) {\r
+    MachineConfig     = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);\r
+    Bda->FloppyXRate  = 0x07;\r
+  }\r
+\r
+  Bda->Lpt1_2Timeout  = 0x1414;\r
+  Bda->Lpt3_4Timeout  = 0x1414;\r
+  Bda->Com1_2Timeout  = 0x0101;\r
+  Bda->Com3_4Timeout  = 0x0101;\r
+\r
+  //\r
+  // Force VGA and Coprocessor, indicate 101/102 keyboard\r
+  //\r
+  MachineConfig       = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));\r
+  Bda->MachineConfig  = MachineConfig;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Fill in the standard BDA for Keyboard LEDs\r
+\r
+  @param  This         Protocol instance pointer.\r
+  @param  Leds         Current LED status\r
+\r
+  @retval EFI_SUCCESS  It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosUpdateKeyboardLedStatus (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  UINT8                             Leds\r
+  )\r
+{\r
+  LEGACY_BIOS_INSTANCE  *Private;\r
+  BDA_STRUC             *Bda;\r
+  UINT8                 LocalLeds;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+\r
+  Bda                 = (BDA_STRUC *) ((UINTN) 0x400);\r
+\r
+  Private             = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  LocalLeds           = Leds;\r
+  Bda->LedStatus      = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);\r
+  LocalLeds           = (UINT8) (LocalLeds << 4);\r
+  Bda->ShiftStatus    = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);\r
+  LocalLeds           = (UINT8) (Leds & 0x20);\r
+  Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);\r
+  //\r
+  // Call into Legacy16 code to allow it to do any processing\r
+  //\r
+  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+  Regs.X.AX = Legacy16SetKeyboardLeds;\r
+  Regs.H.CL = Leds;\r
+\r
+  Private->LegacyBios.FarCall86 (\r
+    &Private->LegacyBios,\r
+    Private->Legacy16Table->Compatibility16CallSegment,\r
+    Private->Legacy16Table->Compatibility16CallOffset,\r
+    &Regs,\r
+    NULL,\r
+    0\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Fill in the standard CMOS stuff prior to legacy Boot\r
+\r
+  @param  Private      Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS  It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosCompleteStandardCmosBeforeBoot (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  )\r
+{\r
+  UINT8   Bda;\r
+  UINT8   Floppy;\r
+  UINT32  Size;\r
+\r
+  //\r
+  // Update CMOS locations\r
+  // 10 floppy\r
+  // 12,19,1A - ignore as OS don't use them and there is no standard due\r
+  //            to large capacity drives\r
+  // CMOS 14 = BDA 40:10 plus bit 3(display enabled)\r
+  //\r
+  Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);\r
+\r
+  //\r
+  // Force display enabled\r
+  //\r
+  Floppy = 0x00;\r
+  if ((Bda & BIT0) != 0) {\r
+    Floppy = BIT6;\r
+  }\r
+\r
+  //\r
+  // Check if 2.88MB floppy set\r
+  //\r
+  if ((Bda & (BIT7 | BIT6)) != 0) {\r
+    Floppy = (UINT8)(Floppy | BIT1);\r
+  }\r
+\r
+  LegacyWriteStandardCmos (CMOS_10, Floppy);\r
+  LegacyWriteStandardCmos (CMOS_14, Bda);\r
+\r
+  //\r
+  // Force Status Register A to set rate selection bits and divider\r
+  //\r
+  LegacyWriteStandardCmos (CMOS_0A, 0x26);\r
+\r
+  //\r
+  // redo memory size since it can change\r
+  //\r
+  Size = 15 * SIZE_1MB;\r
+  if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {\r
+    Size  = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;\r
+  }\r
+\r
+  LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));\r
+  LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));\r
+  LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));\r
+  LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));\r
+\r
+  LegacyCalculateWriteStandardCmosChecksum ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Relocate this image under 4G memory for IPF.\r
+\r
+  @param  ImageHandle  Handle of driver image.\r
+  @param  SystemTable  Pointer to system table.\r
+\r
+  @retval EFI_SUCCESS  Image successfully relocated.\r
+  @retval EFI_ABORTED  Failed to relocate image.\r
+\r
+**/\r
+EFI_STATUS\r
+RelocateImageUnder4GIfNeeded (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c
new file mode 100644 (file)
index 0000000..0fbf902
--- /dev/null
@@ -0,0 +1,124 @@
+/** @file\r
+  This code fills in standard CMOS values and updates the standard CMOS\r
+  checksum. The Legacy16 code or LegacyBiosPlatform.c is responsible for\r
+  non-standard CMOS locations and non-standard checksums.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+\r
+/**\r
+  Read CMOS register through index/data port.\r
+\r
+  @param[in]  Index   The index of the CMOS register to read.\r
+\r
+  @return  The data value from the CMOS register specified by Index.\r
+\r
+**/\r
+UINT8\r
+LegacyReadStandardCmos (\r
+  IN UINT8  Index\r
+  )\r
+{\r
+  IoWrite8 (PORT_70, Index);\r
+  return IoRead8 (PORT_71);\r
+}\r
+\r
+/**\r
+  Write CMOS register through index/data port.\r
+\r
+  @param[in]  Index  The index of the CMOS register to write.\r
+  @param[in]  Value  The value of CMOS register to write.\r
+\r
+  @return  The value written to the CMOS register specified by Index.\r
+\r
+**/\r
+UINT8\r
+LegacyWriteStandardCmos (\r
+  IN UINT8  Index,\r
+  IN UINT8  Value\r
+  )\r
+{\r
+  IoWrite8 (PORT_70, Index);\r
+  return IoWrite8 (PORT_71, Value);\r
+}\r
+\r
+/**\r
+  Calculate the new standard CMOS checksum and write it.\r
+\r
+  @param  Private      Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS  Calculate 16-bit checksum successfully\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyCalculateWriteStandardCmosChecksum (\r
+  VOID\r
+  )\r
+{\r
+  UINT8   Register;\r
+  UINT16  Checksum;\r
+\r
+  for (Checksum = 0, Register = 0x10; Register < 0x2e; Register++) {\r
+    Checksum = (UINT16)(Checksum + LegacyReadStandardCmos (Register));\r
+  }\r
+  LegacyWriteStandardCmos (CMOS_2E, (UINT8)(Checksum >> 8));\r
+  LegacyWriteStandardCmos (CMOS_2F, (UINT8)(Checksum & 0xff));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Fill in the standard CMOS stuff before Legacy16 load\r
+\r
+  @param  Private      Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS  It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInitCmos (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  )\r
+{\r
+  UINT32  Size;\r
+\r
+  //\r
+  //  Clear all errors except RTC lost power\r
+  //\r
+  LegacyWriteStandardCmos (CMOS_0E, (UINT8)(LegacyReadStandardCmos (CMOS_0E) & BIT7));\r
+\r
+  //\r
+  // Update CMOS locations 15,16,17,18,30,31 and 32\r
+  // CMOS 16,15 = 640Kb = 0x280\r
+  // CMOS 18,17 = 31,30 = 15Mb max in 1Kb increments =0x3C00 max\r
+  // CMOS 32 = 0x20\r
+  //\r
+  LegacyWriteStandardCmos (CMOS_15, 0x80);\r
+  LegacyWriteStandardCmos (CMOS_16, 0x02);\r
+\r
+  Size = 15 * SIZE_1MB;\r
+  if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {\r
+    Size  = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;\r
+  }\r
+\r
+  LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));\r
+  LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));\r
+  LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));\r
+  LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));\r
+\r
+  LegacyCalculateWriteStandardCmosChecksum ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c
new file mode 100644 (file)
index 0000000..4e52fe9
--- /dev/null
@@ -0,0 +1,300 @@
+/** @file\r
+  Collect IDE information from Native EFI Driver\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+\r
+BOOLEAN mIdeDataBuiltFlag = FALSE;\r
+\r
+/**\r
+  Collect IDE Inquiry data from the IDE disks\r
+\r
+  @param  Private        Legacy BIOS Instance data\r
+  @param  HddInfo        Hdd Information\r
+  @param  Flag           Reconnect IdeController or not\r
+\r
+  @retval EFI_SUCCESS    It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildIdeData (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private,\r
+  IN  HDD_INFO                  **HddInfo,\r
+  IN  UINT16                    Flag\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                IdeController;\r
+  UINTN                     HandleCount;\r
+  EFI_HANDLE                *HandleBuffer;\r
+  UINTN                     Index;\r
+  EFI_DISK_INFO_PROTOCOL    *DiskInfo;\r
+  UINT32                    IdeChannel;\r
+  UINT32                    IdeDevice;\r
+  UINT32                    Size;\r
+  UINT8                     *InquiryData;\r
+  UINT32                    InquiryDataSize;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  UINT32                    PciIndex;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePathNode;\r
+  PCI_DEVICE_PATH           *PciDevicePath;\r
+\r
+  //\r
+  // Only build data once\r
+  // We have a problem with GetBbsInfo in that it can be invoked two\r
+  // places. Once in BDS, when all EFI drivers are connected and once in\r
+  // LegacyBoot after all EFI drivers are disconnected causing this routine\r
+  // to hang. In LegacyBoot this function is also called before EFI drivers\r
+  // are disconnected.\r
+  // Cases covered\r
+  //    GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.\r
+  //    GetBbsInfo not invoked in BDS. First invocation of this function\r
+  //       proceeds normally and second via GetBbsInfo ignored.\r
+  //\r
+  PciDevicePath = NULL;\r
+  LocalHddInfo  = *HddInfo;\r
+  Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformIdeHandle,\r
+                                          0,\r
+                                          &HandleBuffer,\r
+                                          &HandleCount,\r
+                                          (VOID *) &LocalHddInfo\r
+                                          );\r
+  if (!EFI_ERROR (Status)) {\r
+    IdeController = HandleBuffer[0];    \r
+    //\r
+    // Force IDE drive spin up!\r
+    //\r
+    if (Flag != 0) {\r
+      gBS->DisconnectController (\r
+            IdeController,\r
+            NULL,\r
+            NULL\r
+            );\r
+    }\r
+\r
+    gBS->ConnectController (IdeController, NULL, NULL, FALSE);\r
+\r
+    //\r
+    // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode\r
+    // And GetIdeHandle will switch to Legacy mode, if required.\r
+    //\r
+    Private->LegacyBiosPlatform->GetPlatformHandle (\r
+                                  Private->LegacyBiosPlatform,\r
+                                  EfiGetPlatformIdeHandle,\r
+                                  0,\r
+                                  &HandleBuffer,\r
+                                  &HandleCount,\r
+                                  (VOID *) &LocalHddInfo\r
+                                  );\r
+  }\r
+\r
+  mIdeDataBuiltFlag = TRUE;\r
+\r
+  //\r
+  // Get Identity command from all drives\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+        ByProtocol,\r
+        &gEfiDiskInfoProtocolGuid,\r
+        NULL,\r
+        &HandleCount,\r
+        &HandleBuffer\r
+        );\r
+\r
+  Private->IdeDriveCount = (UINT8) HandleCount;\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiDiskInfoProtocolGuid,\r
+                    (VOID **) &DiskInfo\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {\r
+      //\r
+      //  Locate which PCI device\r
+      //\r
+      Status = gBS->HandleProtocol (\r
+                      HandleBuffer[Index],\r
+                      &gEfiDevicePathProtocolGuid,\r
+                      (VOID *) &DevicePath\r
+                      );\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      DevicePathNode = DevicePath;\r
+      while (!IsDevicePathEnd (DevicePathNode)) {\r
+        TempDevicePathNode = NextDevicePathNode (DevicePathNode);\r
+        if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&\r
+              ( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&\r
+              ( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&\r
+              ( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {\r
+          PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;\r
+          break;\r
+        }\r
+        DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+      }\r
+\r
+      if (PciDevicePath == NULL) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Find start of PCI device in HddInfo. The assumption of the data\r
+      // structure is 2 controllers(channels) per PCI device and each\r
+      // controller can have 2 drives(devices).\r
+      // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master\r
+      // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave\r
+      // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master\r
+      // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave\r
+      // @bug eventually need to pass in max number of entries\r
+      // for end of for loop\r
+      //\r
+      for (PciIndex = 0; PciIndex < 8; PciIndex++) {\r
+        if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&\r
+            (PciDevicePath->Function == LocalHddInfo[PciIndex].Function)\r
+            ) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (PciIndex == 8) {\r
+        continue;\r
+      }\r
+\r
+      Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);\r
+      if (!EFI_ERROR (Status)) {\r
+        Size = sizeof (ATAPI_IDENTIFY);\r
+        DiskInfo->Identify (\r
+                    DiskInfo,\r
+                    &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],\r
+                    &Size\r
+                    );\r
+        if (IdeChannel == 0) {\r
+          LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;\r
+        } else if (IdeChannel == 1) {\r
+          LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;\r
+        }\r
+\r
+        InquiryData     = NULL;\r
+        InquiryDataSize = 0;\r
+        Status = DiskInfo->Inquiry (\r
+                             DiskInfo,\r
+                             NULL,\r
+                             &InquiryDataSize\r
+                             );\r
+        if (Status == EFI_BUFFER_TOO_SMALL) {\r
+          InquiryData = (UINT8 *) AllocatePool (\r
+                                  InquiryDataSize\r
+                                  );\r
+          if (InquiryData != NULL) {\r
+            Status = DiskInfo->Inquiry (\r
+                                 DiskInfo,\r
+                                 InquiryData,\r
+                                 &InquiryDataSize\r
+                                 );\r
+          }\r
+        } else {\r
+          Status = EFI_DEVICE_ERROR;\r
+        }\r
+\r
+        //\r
+        // If ATAPI device then Inquiry will pass and ATA fail.\r
+        //\r
+        if (!EFI_ERROR (Status)) {\r
+          ASSERT (InquiryData != NULL);\r
+          //\r
+          // If IdeDevice = 0 then set master bit, else slave bit\r
+          //\r
+          if (IdeDevice == 0) {\r
+            if ((InquiryData[0] & 0x1f) == 0x05) {\r
+              LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;\r
+            } else if ((InquiryData[0] & 0x1f) == 0x00) {\r
+              LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;\r
+            }\r
+          } else {\r
+            if ((InquiryData[0] & 0x1f) == 0x05) {\r
+              LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;\r
+            } else if ((InquiryData[0] & 0x1f) == 0x00) {\r
+              LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;\r
+            }\r
+          }\r
+          FreePool (InquiryData);\r
+        } else {\r
+          if (IdeDevice == 0) {\r
+            LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;\r
+          } else {\r
+            LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  If the IDE channel is in compatibility (legacy) mode, remove all\r
+  PCI I/O BAR addresses from the controller.\r
+\r
+  @param  IdeController  The handle of target IDE controller\r
+\r
+\r
+**/\r
+VOID\r
+InitLegacyIdeController (\r
+  IN EFI_HANDLE                        IdeController\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  UINT8                             Pi;\r
+  UINT32                            IOBarClear;\r
+  EFI_STATUS                        Status;\r
+\r
+  //\r
+  // If the IDE channel is in compatibility (legacy) mode, remove all\r
+  // PCI I/O BAR addresses from the controller.  Some software gets\r
+  // confused if an IDE controller is in compatibility (legacy) mode\r
+  // and has PCI I/O resources allocated\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  IdeController,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    IOBarClear = 0x00;\r
+    PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 1, &Pi);\r
+    if ((Pi & 0x01) == 0) {\r
+      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);\r
+      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);\r
+    }\r
+    if ((Pi & 0x04) == 0) {\r
+      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);\r
+      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);\r
+    }\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c
new file mode 100644 (file)
index 0000000..a53b57a
--- /dev/null
@@ -0,0 +1,2901 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+#include <IndustryStandard/Pci30.h>\r
+\r
+#define PCI_START_ADDRESS(x)   (((x) + 0x7ff) & ~0x7ff)\r
+\r
+#define MAX_BRIDGE_INDEX  0x20\r
+typedef struct {\r
+  UINTN PciSegment;\r
+  UINTN PciBus;\r
+  UINTN PciDevice;\r
+  UINTN PciFunction;\r
+  UINT8 PrimaryBus;\r
+  UINT8 SecondaryBus;\r
+  UINT8 SubordinateBus;\r
+} BRIDGE_TABLE;\r
+\r
+#define ROM_MAX_ENTRIES 24\r
+BRIDGE_TABLE                        Bridges[MAX_BRIDGE_INDEX];\r
+UINTN                               SortedBridgeIndex[MAX_BRIDGE_INDEX];\r
+UINTN                               NumberOfBridges;\r
+LEGACY_PNP_EXPANSION_HEADER  *mBasePnpPtr;\r
+UINT16                              mBbsRomSegment;\r
+UINTN                               mHandleCount;\r
+EFI_HANDLE                          mVgaHandle;\r
+BOOLEAN                             mIgnoreBbsUpdateFlag;\r
+BOOLEAN                             mVgaInstallationInProgress  = FALSE;\r
+UINT32                              mRomCount                   = 0x00;\r
+ROM_INSTANCE_ENTRY                  mRomEntry[ROM_MAX_ENTRIES];\r
+\r
+\r
+/**\r
+  Query shadowed legacy ROM parameters registered by RomShadow() previously.\r
+\r
+  @param  PciHandle        PCI device whos ROM has been shadowed\r
+  @param  DiskStart        DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
+  @param  DiskEnd          DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
+  @param  RomShadowAddress Address where ROM was shadowed\r
+  @param  ShadowedSize     Runtime size of ROM\r
+\r
+  @retval EFI_SUCCESS      Query Logging successful.\r
+  @retval EFI_NOT_FOUND    No logged data found about PciHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+GetShadowedRomParameters (\r
+  IN EFI_HANDLE                         PciHandle,\r
+  OUT UINT8                             *DiskStart,         OPTIONAL\r
+  OUT UINT8                             *DiskEnd,           OPTIONAL\r
+  OUT VOID                              **RomShadowAddress, OPTIONAL\r
+  OUT UINTN                             *ShadowedSize       OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  UINTN               Index;\r
+  UINTN               PciSegment;\r
+  UINTN               PciBus;\r
+  UINTN               PciDevice;\r
+  UINTN               PciFunction;\r
+\r
+  //\r
+  // Get the PCI I/O Protocol on PciHandle\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  PciHandle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get the location of the PCI device\r
+  //\r
+  PciIo->GetLocation (\r
+           PciIo,\r
+           &PciSegment,\r
+           &PciBus,\r
+           &PciDevice,\r
+           &PciFunction\r
+           );\r
+\r
+  for(Index = 0; Index < mRomCount; Index++) {\r
+    if ((mRomEntry[Index].PciSegment == PciSegment) &&\r
+        (mRomEntry[Index].PciBus == PciBus)         &&\r
+        (mRomEntry[Index].PciDevice == PciDevice)   &&\r
+        (mRomEntry[Index].PciFunction == PciFunction)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == mRomCount) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (DiskStart != NULL) {\r
+    *DiskStart = mRomEntry[Index].DiskStart;\r
+  }\r
+\r
+  if (DiskEnd != NULL) {\r
+    *DiskEnd = mRomEntry[Index].DiskEnd;\r
+  }\r
+\r
+  if (RomShadowAddress != NULL) {\r
+    *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;\r
+  }\r
+\r
+  if (ShadowedSize != NULL) {\r
+    *ShadowedSize = mRomEntry[Index].ShadowedSize;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Every legacy ROM that is shadowed by the Legacy BIOS driver will be\r
+  registered into this API so that the policy code can know what has\r
+  happend\r
+\r
+  @param  PciHandle              PCI device whos ROM is being shadowed\r
+  @param  ShadowAddress          Address that ROM was shadowed\r
+  @param  ShadowedSize           Runtime size of ROM\r
+  @param  DiskStart              DiskStart value from\r
+                                 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
+  @param  DiskEnd                DiskEnd value from\r
+                                 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
+\r
+  @retval EFI_SUCCESS            Logging successful.\r
+  @retval EFI_OUT_OF_RESOURCES   No remaining room for registering another option\r
+                                 ROM.\r
+\r
+**/\r
+EFI_STATUS\r
+RomShadow (\r
+  IN  EFI_HANDLE                                  PciHandle,\r
+  IN  UINT32                                      ShadowAddress,\r
+  IN  UINT32                                      ShadowedSize,  \r
+  IN  UINT8                                       DiskStart,\r
+  IN  UINT8                                       DiskEnd\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+  //\r
+  // See if there is room to register another option ROM\r
+  //\r
+  if (mRomCount >= ROM_MAX_ENTRIES) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Get the PCI I/O Protocol on PciHandle\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  PciHandle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get the location of the PCI device\r
+  //\r
+  PciIo->GetLocation (\r
+           PciIo,\r
+           &mRomEntry[mRomCount].PciSegment,\r
+           &mRomEntry[mRomCount].PciBus,\r
+           &mRomEntry[mRomCount].PciDevice,\r
+           &mRomEntry[mRomCount].PciFunction\r
+           );\r
+  mRomEntry[mRomCount].ShadowAddress = ShadowAddress;\r
+  mRomEntry[mRomCount].ShadowedSize  = ShadowedSize;\r
+  mRomEntry[mRomCount].DiskStart     = DiskStart;\r
+  mRomEntry[mRomCount].DiskEnd       = DiskEnd;\r
+\r
+  mRomCount++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This\r
+  information represents every call to RomShadow ()\r
+\r
+  @param  PciHandle              PCI device to get status for\r
+\r
+  @retval EFI_SUCCESS            Legacy ROM loaded for this device\r
+  @retval EFI_NOT_FOUND          No Legacy ROM loaded for this device\r
+\r
+**/\r
+EFI_STATUS\r
+IsLegacyRom (\r
+  IN  EFI_HANDLE                PciHandle\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  UINTN               Index;\r
+  UINTN               Segment;\r
+  UINTN               Bus;\r
+  UINTN               Device;\r
+  UINTN               Function;\r
+\r
+  //\r
+  // Get the PCI I/O Protocol on PciHandle\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  PciHandle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get the location of the PCI device\r
+  //\r
+  PciIo->GetLocation (\r
+           PciIo,\r
+           &Segment,\r
+           &Bus,\r
+           &Device,\r
+           &Function\r
+           );\r
+\r
+  //\r
+  // See if the option ROM from PciHandle has been previously posted\r
+  //\r
+  for (Index = 0; Index < mRomCount; Index++) {\r
+    if (mRomEntry[Index].PciSegment == Segment &&\r
+        mRomEntry[Index].PciBus == Bus &&\r
+        mRomEntry[Index].PciDevice == Device &&\r
+        mRomEntry[Index].PciFunction == Function\r
+        ) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the \r
+  related information from the header.\r
+\r
+  @param  Csm16Revision           The PCI interface version of underlying CSM16\r
+  @param  VendorId                Vendor ID of the PCI device\r
+  @param  DeviceId                Device ID of the PCI device\r
+  @param  Rom                     On input pointing to beginning of the raw PCI OpROM\r
+                                  On output pointing to the first legacy PCI OpROM\r
+  @param  ImageSize               On input is the size of Raw PCI Rom\r
+                                  On output is the size of the first legacy PCI ROM\r
+  @param  MaxRuntimeImageLength   The max runtime image length only valid if OpRomRevision >= 3\r
+  @param  OpRomRevision           Revision of the PCI Rom\r
+  @param  ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header\r
+\r
+  @retval EFI_SUCCESS             Successfully find the legacy PCI ROM\r
+  @retval EFI_NOT_FOUND           Failed to find the legacy PCI ROM\r
+\r
+**/\r
+EFI_STATUS\r
+GetPciLegacyRom (\r
+  IN     UINT16 Csm16Revision,\r
+  IN     UINT16 VendorId,\r
+  IN     UINT16 DeviceId,\r
+  IN OUT VOID   **Rom,\r
+  IN OUT UINTN  *ImageSize,\r
+  OUT    UINTN  *MaxRuntimeImageLength,   OPTIONAL\r
+  OUT    UINT8  *OpRomRevision,           OPTIONAL\r
+  OUT    VOID   **ConfigUtilityCodeHeader OPTIONAL\r
+  )\r
+{\r
+  BOOLEAN                 Match;\r
+  UINT16                  *DeviceIdList;\r
+  EFI_PCI_ROM_HEADER      RomHeader;\r
+  PCI_3_0_DATA_STRUCTURE  *Pcir;\r
+  VOID                    *BackupImage;\r
+  VOID                    *BestImage;\r
+\r
+\r
+  if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  BestImage     = NULL;\r
+  BackupImage   = NULL;\r
+  RomHeader.Raw = *Rom;\r
+  while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
+    if (*ImageSize < \r
+        RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)\r
+        ) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);\r
+\r
+    if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
+      Match = FALSE;\r
+      if (Pcir->VendorId == VendorId) {\r
+        if (Pcir->DeviceId == DeviceId) {\r
+          Match = TRUE;\r
+        } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {\r
+          DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);\r
+          //\r
+          // Checking the device list\r
+          //\r
+          while (*DeviceIdList != 0) {\r
+            if (*DeviceIdList == DeviceId) {\r
+              Match = TRUE;\r
+              break;\r
+            }\r
+            DeviceIdList ++;\r
+          }\r
+        }\r
+      }\r
+\r
+      if (Match) {\r
+        if (Csm16Revision >= 0x0300) {\r
+          //\r
+          // Case 1: CSM16 3.0\r
+          //\r
+          if (Pcir->Revision >= 3) {\r
+            //\r
+            // case 1.1: meets OpRom 3.0\r
+            //           Perfect!!!\r
+            //\r
+            BestImage  = RomHeader.Raw;\r
+            break;\r
+          } else {\r
+            //\r
+            // case 1.2: meets OpRom 2.x\r
+            //           Store it and try to find the OpRom 3.0\r
+            //\r
+            BackupImage = RomHeader.Raw;\r
+          }\r
+        } else {\r
+          //\r
+          // Case 2: CSM16 2.x\r
+          //\r
+          if (Pcir->Revision >= 3) {\r
+            //\r
+            // case 2.1: meets OpRom 3.0\r
+            //           Store it and try to find the OpRom 2.x\r
+            //\r
+            BackupImage = RomHeader.Raw;\r
+          } else {\r
+            //\r
+            // case 2.2: meets OpRom 2.x\r
+            //           Perfect!!!\r
+            //\r
+            BestImage   = RomHeader.Raw;\r
+            break;\r
+          }\r
+        }\r
+      } else {\r
+        DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));\r
+      }\r
+    }\r
+    \r
+    if ((Pcir->Indicator & 0x80) == 0x80) {\r
+      break;\r
+    } else {\r
+      RomHeader.Raw += 512 * Pcir->ImageLength;\r
+    }\r
+  }\r
+\r
+  if (BestImage == NULL) {\r
+    if (BackupImage == NULL) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    //\r
+    // The versions of CSM16 and OpRom don't match exactly\r
+    //\r
+    BestImage = BackupImage;\r
+  }\r
+  RomHeader.Raw = BestImage;\r
+  Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);\r
+  *Rom       = BestImage;\r
+  *ImageSize = Pcir->ImageLength * 512;\r
+\r
+  if (MaxRuntimeImageLength != NULL) {\r
+    if (Pcir->Revision < 3) {\r
+      *MaxRuntimeImageLength = 0;\r
+    } else {\r
+      *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;\r
+    }\r
+  }\r
+\r
+  if (OpRomRevision != NULL) {\r
+    // \r
+    // Optional return PCI Data Structure revision\r
+    //\r
+    if (Pcir->Length >= 0x1C) {\r
+      *OpRomRevision = Pcir->Revision;\r
+    } else {\r
+      *OpRomRevision = 0;\r
+    }\r
+  }\r
+\r
+  if (ConfigUtilityCodeHeader != NULL) {\r
+    //\r
+    // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM\r
+    //\r
+    if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {\r
+      *ConfigUtilityCodeHeader = NULL;\r
+    } else {\r
+      *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Build a table of bridge info for PIRQ translation.\r
+\r
+  @param  RoutingTable         RoutingTable obtained from Platform.\r
+  @param  RoutingTableEntries  Number of RoutingTable entries.\r
+\r
+  @retval EFI_SUCCESS          New Subordinate bus.\r
+  @retval EFI_NOT_FOUND        No more Subordinate busses.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateBridgeTable (\r
+  IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,\r
+  IN UINTN                                RoutingTableEntries\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINTN               HandleCount;\r
+  EFI_HANDLE          *HandleBuffer;\r
+  UINTN               BridgeIndex;\r
+  UINTN               Index;\r
+  UINTN               Index1;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  PCI_TYPE01          PciConfigHeader;\r
+  BRIDGE_TABLE        SlotBridges[MAX_BRIDGE_INDEX];\r
+  UINTN               SlotBridgeIndex;\r
+\r
+  BridgeIndex = 0x00;\r
+  SlotBridgeIndex = 0x00;\r
+\r
+  //\r
+  // Assumption is table is built from low bus to high bus numbers.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    PciIo->Pci.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint32,\r
+                 0,\r
+                 sizeof (PciConfigHeader) / sizeof (UINT32),\r
+                 &PciConfigHeader\r
+                 );\r
+\r
+    if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {\r
+      PciIo->GetLocation (\r
+               PciIo,\r
+               &Bridges[BridgeIndex].PciSegment,\r
+               &Bridges[BridgeIndex].PciBus,\r
+               &Bridges[BridgeIndex].PciDevice,\r
+               &Bridges[BridgeIndex].PciFunction\r
+               );\r
+\r
+      Bridges[BridgeIndex].PrimaryBus     = PciConfigHeader.Bridge.PrimaryBus;\r
+\r
+      Bridges[BridgeIndex].SecondaryBus   = PciConfigHeader.Bridge.SecondaryBus;\r
+\r
+      Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;\r
+\r
+      for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){\r
+        //\r
+        // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board\r
+        // Once we find one, store it in the SlotBridges[]\r
+        //\r
+        if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)\r
+           && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {\r
+          CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));\r
+          SlotBridgeIndex++;\r
+\r
+          break;\r
+        }\r
+      }\r
+\r
+      ++BridgeIndex;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Pack up Bridges by removing those useless ones\r
+  //\r
+  for (Index = 0; Index < BridgeIndex;){\r
+    for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {\r
+      if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||\r
+        ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {\r
+        //\r
+        // We have found one that meets our criteria\r
+        //\r
+        Index++;\r
+        break;\r
+      }\r
+    }\r
+\r
+    //\r
+    // This one doesn't meet criteria, pack it\r
+    //\r
+    if (Index1 >= SlotBridgeIndex) {\r
+      for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {\r
+        CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));\r
+      }\r
+\r
+      BridgeIndex--;\r
+    }\r
+  }\r
+\r
+  NumberOfBridges = BridgeIndex;\r
+\r
+  //\r
+  // Sort bridges low to high by Secondary bus followed by subordinate bus\r
+  //\r
+  if (NumberOfBridges > 1) {\r
+    Index = 0;\r
+    do {\r
+      SortedBridgeIndex[Index] = Index;\r
+      ++Index;\r
+    } while (Index < NumberOfBridges);\r
+\r
+    for (Index = 0; Index < NumberOfBridges - 1; Index++) {\r
+      for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {\r
+        if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {\r
+          SortedBridgeIndex[Index]  = Index1;\r
+          SortedBridgeIndex[Index1] = Index;\r
+        }\r
+\r
+        if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&\r
+            (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)\r
+            ) {\r
+          SortedBridgeIndex[Index]  = Index1;\r
+          SortedBridgeIndex[Index1] = Index;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  FreePool (HandleBuffer);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Find base Bridge for device.\r
+\r
+  @param  Private                Legacy  BIOS Instance data\r
+  @param  PciBus                 Input = Bus of device.\r
+  @param  PciDevice              Input = Device.\r
+  @param  RoutingTable           The platform specific routing table\r
+  @param  RoutingTableEntries    Number of entries in table\r
+\r
+  @retval EFI_SUCCESS            At base bus.\r
+  @retval EFI_NOT_FOUND          Behind a bridge.\r
+\r
+**/\r
+EFI_STATUS\r
+GetBaseBus (\r
+  IN  LEGACY_BIOS_INSTANCE        *Private,\r
+  IN UINTN                        PciBus,\r
+  IN UINTN                        PciDevice,\r
+  IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,\r
+  IN UINTN                        RoutingTableEntries\r
+  )\r
+{\r
+  UINTN Index;\r
+  for (Index = 0; Index < RoutingTableEntries; Index++) {\r
+    if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Translate PIRQ through busses\r
+\r
+  @param  Private              Legacy  BIOS Instance data\r
+  @param  PciBus               Input = Bus of device. Output = Translated Bus\r
+  @param  PciDevice            Input = Device. Output = Translated Device\r
+  @param  PciFunction          Input = Function. Output = Translated Function\r
+  @param  PirqIndex            Input = Original PIRQ index. If single function\r
+                                  device then 0, otherwise 0-3.\r
+                               Output = Translated Index\r
+\r
+  @retval EFI_SUCCESS          Pirq successfully translated.\r
+  @retval EFI_NOT_FOUND        The device is not behind any known bridge.\r
+\r
+**/\r
+EFI_STATUS\r
+TranslateBusPirq (\r
+  IN  LEGACY_BIOS_INSTANCE            *Private,\r
+  IN OUT UINTN                        *PciBus,\r
+  IN OUT UINTN                        *PciDevice,\r
+  IN OUT UINTN                        *PciFunction,\r
+  IN OUT UINT8                        *PirqIndex\r
+  )\r
+{\r
+  /*\r
+  This routine traverses the PCI busses from base slot\r
+  and translates the PIRQ register to the appropriate one.\r
+\r
+  Example:\r
+\r
+  Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.\r
+    Primary bus# = 0\r
+    Secondary bus # = 1\r
+    Subordinate bus # is highest bus # behind this bus\r
+       Bus 1, Device 0 is Slot 0 and is not a bridge.\r
+       Bus 1, Device 1 is Slot 1 and is a bridge.\r
+         Slot PIRQ routing is A,B,C,D.\r
+         Primary bus # = 1\r
+         Secondary bus # = 2\r
+         Subordinate bus # = 5\r
+            Bus 2, Device 6 is a bridge. It has no bridges behind it.\r
+              Primary bus # = 2\r
+              Secondary bus # = 3\r
+              Subordinate bus # = 3\r
+              Bridge PIRQ routing is C,D,A,B\r
+            Bus 2, Device 7 is a bridge. It has 1 bridge behind it.\r
+              Primary bus # = 2\r
+              Secondary bus = 4   Device 6 takes bus 2.\r
+              Subordinate bus = 5.\r
+              Bridge PIRQ routing is D,A,B,C\r
+                 Bus 4, Device 2 is a bridge. It has no bridges behind it.\r
+                   Primary bus # = 4\r
+                   Secondary bus # = 5\r
+                   Subordinate bus = 5\r
+                   Bridge PIRQ routing is B,C,D,A\r
+                      Bus 5, Device 1 is to be programmed.\r
+                         Device PIRQ routing is C,D,A,B\r
+\r
+\r
+Search busses starting from slot bus for final bus >= Secondary bus and\r
+final bus <= Suborninate bus. Assumption is bus entries increase in bus\r
+number.\r
+Starting PIRQ is A,B,C,D.\r
+Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device\r
+  7 modulo 4 giving (D,A,B,C).\r
+Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving\r
+  (B,C,D,A).\r
+No other busses match criteria. Device to be programmed is Bus 5, Device 1.\r
+Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.\r
+\r
+*/\r
+  UINTN LocalBus;\r
+  UINTN LocalDevice;\r
+  UINTN BaseBus;\r
+  UINTN BaseDevice;\r
+  UINTN BaseFunction;\r
+  UINT8 LocalPirqIndex;\r
+  BOOLEAN BaseIndexFlag;\r
+  UINTN BridgeIndex;\r
+  UINTN SBridgeIndex;\r
+  BaseIndexFlag   = FALSE;\r
+  BridgeIndex     = 0x00;\r
+\r
+  LocalPirqIndex  = *PirqIndex;\r
+  LocalBus        = *PciBus;\r
+  LocalDevice     = *PciDevice;\r
+  BaseBus         = *PciBus;\r
+  BaseDevice      = *PciDevice;\r
+  BaseFunction    = *PciFunction;\r
+\r
+  //\r
+  // LocalPirqIndex list PIRQs in rotated fashion\r
+  // = 0  A,B,C,D\r
+  // = 1  B,C,D,A\r
+  // = 2  C,D,A,B\r
+  // = 3  D,A,B,C\r
+  //\r
+\r
+  for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {\r
+    SBridgeIndex = SortedBridgeIndex[BridgeIndex];\r
+    //\r
+    // Check if device behind this bridge\r
+    //\r
+    if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {\r
+      //\r
+      // If BaseIndexFlag = FALSE then have found base bridge, i.e\r
+      // bridge in slot. Save info for use by IRQ routing table.\r
+      //\r
+      if (!BaseIndexFlag) {\r
+        BaseBus       = Bridges[SBridgeIndex].PciBus;\r
+        BaseDevice    = Bridges[SBridgeIndex].PciDevice;\r
+        BaseFunction  = Bridges[SBridgeIndex].PciFunction;\r
+        BaseIndexFlag = TRUE;\r
+      } else {\r
+        LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);\r
+      }\r
+\r
+      //\r
+      // Check if at device. If not get new PCI location & PIRQ\r
+      //\r
+      if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {\r
+        //\r
+        // Translate PIRQ\r
+        //\r
+        LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user\r
+  //\r
+  if(BridgeIndex >= NumberOfBridges){\r
+    DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));\r
+  }\r
+\r
+  *PirqIndex    = LocalPirqIndex;\r
+  *PciBus       = BaseBus;\r
+  *PciDevice    = BaseDevice;\r
+  *PciFunction  = BaseFunction;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Copy the $PIR table as required.\r
+\r
+  @param  Private                Legacy  BIOS Instance data\r
+  @param  RoutingTable           Pointer to IRQ routing table\r
+  @param  RoutingTableEntries    IRQ routing table entries\r
+  @param  PirqTable              Pointer to $PIR table\r
+  @param  PirqTableSize          Length of table\r
+\r
+**/\r
+VOID\r
+CopyPirqTable (\r
+  IN  LEGACY_BIOS_INSTANCE                *Private,\r
+  IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,\r
+  IN UINTN                                RoutingTableEntries,\r
+  IN EFI_LEGACY_PIRQ_TABLE_HEADER         *PirqTable,\r
+  IN UINTN                                PirqTableSize\r
+  )\r
+{\r
+  EFI_IA32_REGISTER_SET Regs;\r
+  UINT32                Granularity;\r
+\r
+  //\r
+  // Copy $PIR table, if it exists.\r
+  //\r
+  if (PirqTable != NULL) {\r
+    Private->LegacyRegion->UnLock (\r
+                            Private->LegacyRegion,\r
+                            0xE0000,\r
+                            0x20000,\r
+                            &Granularity\r
+                            );\r
+\r
+    Private->InternalIrqRoutingTable  = RoutingTable;\r
+    Private->NumberIrqRoutingEntries  = (UINT16) (RoutingTableEntries);\r
+    ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
+\r
+    Regs.X.AX = Legacy16GetTableAddress;\r
+    Regs.X.CX = (UINT16) PirqTableSize;\r
+    //\r
+    // Allocate at F segment according to PCI IRQ Routing Table Specification\r
+    //\r
+    Regs.X.BX = (UINT16) 0x1;\r
+    //\r
+    // 16-byte boundary alignment requirement according to \r
+    // PCI IRQ Routing Table Specification\r
+    //\r
+    Regs.X.DX = 0x10;\r
+    Private->LegacyBios.FarCall86 (\r
+      &Private->LegacyBios,\r
+      Private->Legacy16CallSegment,\r
+      Private->Legacy16CallOffset,\r
+      &Regs,\r
+      NULL,\r
+      0\r
+      );\r
+\r
+    Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
+    if (Regs.X.AX != 0) {\r
+      DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));\r
+    } else {\r
+      DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));   \r
+      Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;\r
+      CopyMem (\r
+        (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,\r
+        PirqTable,\r
+        PirqTableSize\r
+        );\r
+    }\r
+\r
+    Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
+    Private->LegacyRegion->Lock (\r
+                             Private->LegacyRegion,\r
+                             0xE0000,\r
+                             0x20000,\r
+                             &Granularity\r
+                             );\r
+  }\r
+\r
+  Private->PciInterruptLine = TRUE;\r
+  mHandleCount              = 0;\r
+}\r
+\r
+/**\r
+  Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.\r
+\r
+  @param  PciHandle               The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure\r
+\r
+**/\r
+VOID\r
+DumpPciHandle (\r
+  IN EFI_LEGACY_INSTALL_PCI_HANDLER  *PciHandle\r
+  )\r
+{\r
+  DEBUG ((EFI_D_INFO, "PciBus             - %02x\n", (UINTN)PciHandle->PciBus));\r
+  DEBUG ((EFI_D_INFO, "PciDeviceFun       - %02x\n", (UINTN)PciHandle->PciDeviceFun));\r
+  DEBUG ((EFI_D_INFO, "PciSegment         - %02x\n", (UINTN)PciHandle->PciSegment));\r
+  DEBUG ((EFI_D_INFO, "PciClass           - %02x\n", (UINTN)PciHandle->PciClass));\r
+  DEBUG ((EFI_D_INFO, "PciSubclass        - %02x\n", (UINTN)PciHandle->PciSubclass));\r
+  DEBUG ((EFI_D_INFO, "PciInterface       - %02x\n", (UINTN)PciHandle->PciInterface));\r
+\r
+  DEBUG ((EFI_D_INFO, "PrimaryIrq         - %02x\n", (UINTN)PciHandle->PrimaryIrq));\r
+  DEBUG ((EFI_D_INFO, "PrimaryReserved    - %02x\n", (UINTN)PciHandle->PrimaryReserved));\r
+  DEBUG ((EFI_D_INFO, "PrimaryControl     - %04x\n", (UINTN)PciHandle->PrimaryControl));\r
+  DEBUG ((EFI_D_INFO, "PrimaryBase        - %04x\n", (UINTN)PciHandle->PrimaryBase));\r
+  DEBUG ((EFI_D_INFO, "PrimaryBusMaster   - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));\r
+\r
+  DEBUG ((EFI_D_INFO, "SecondaryIrq       - %02x\n", (UINTN)PciHandle->SecondaryIrq));\r
+  DEBUG ((EFI_D_INFO, "SecondaryReserved  - %02x\n", (UINTN)PciHandle->SecondaryReserved));\r
+  DEBUG ((EFI_D_INFO, "SecondaryControl   - %04x\n", (UINTN)PciHandle->SecondaryControl));\r
+  DEBUG ((EFI_D_INFO, "SecondaryBase      - %04x\n", (UINTN)PciHandle->SecondaryBase));\r
+  DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));\r
+  return;\r
+}\r
+\r
+/**\r
+  Copy the $PIR table as required.\r
+\r
+  @param  Private                Legacy  BIOS Instance data\r
+  @param  PciIo                  Pointer to PCI_IO protocol\r
+  @param  PciIrq                 Pci IRQ number\r
+  @param  PciConfigHeader        Type00 Pci configuration header\r
+\r
+**/\r
+VOID\r
+InstallLegacyIrqHandler (\r
+  IN LEGACY_BIOS_INSTANCE       *Private,\r
+  IN EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN UINT8                      PciIrq,\r
+  IN PCI_TYPE00                 *PciConfigHeader\r
+  )\r
+{\r
+  EFI_IA32_REGISTER_SET     Regs;\r
+  UINT16                    LegMask;\r
+  UINTN                     PciSegment;\r
+  UINTN                     PciBus;\r
+  UINTN                     PciDevice;\r
+  UINTN                     PciFunction;\r
+  EFI_LEGACY_8259_PROTOCOL  *Legacy8259;\r
+  UINT16                    PrimaryMaster;\r
+  UINT16                    SecondaryMaster;\r
+  UINTN                     TempData;\r
+  UINTN                     RegisterAddress;\r
+  UINT32                    Granularity;\r
+\r
+  PrimaryMaster   = 0;\r
+  SecondaryMaster = 0;\r
+  Legacy8259      = Private->Legacy8259;\r
+  //\r
+  // Disable interrupt in PIC, in case shared, to prevent an\r
+  // interrupt from occuring.\r
+  //\r
+  Legacy8259->GetMask (\r
+                Legacy8259,\r
+                &LegMask,\r
+                NULL,\r
+                NULL,\r
+                NULL\r
+                );\r
+\r
+  LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));\r
+\r
+  Legacy8259->SetMask (\r
+                Legacy8259,\r
+                &LegMask,\r
+                NULL,\r
+                NULL,\r
+                NULL\r
+                );\r
+\r
+  PciIo->GetLocation (\r
+          PciIo,\r
+          &PciSegment,\r
+          &PciBus,\r
+          &PciDevice,\r
+          &PciFunction\r
+          );\r
+  Private->IntThunk->PciHandler.PciBus              = (UINT8) PciBus;\r
+  Private->IntThunk->PciHandler.PciDeviceFun        = (UINT8) ((PciDevice << 3) + PciFunction);\r
+  Private->IntThunk->PciHandler.PciSegment          = (UINT8) PciSegment;\r
+  Private->IntThunk->PciHandler.PciClass            = PciConfigHeader->Hdr.ClassCode[2];\r
+  Private->IntThunk->PciHandler.PciSubclass         = PciConfigHeader->Hdr.ClassCode[1];\r
+  Private->IntThunk->PciHandler.PciInterface        = PciConfigHeader->Hdr.ClassCode[0];\r
+\r
+  //\r
+  // Use native mode base address registers in two cases:\r
+  // 1. Programming Interface (PI) register indicates Primary Controller is\r
+  // in native mode OR\r
+  // 2. PCI device Sub Class Code is not IDE\r
+  //\r
+  Private->IntThunk->PciHandler.PrimaryBusMaster  = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);\r
+  if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {\r
+    Private->IntThunk->PciHandler.PrimaryIrq      = PciIrq;\r
+    Private->IntThunk->PciHandler.PrimaryBase     = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);\r
+    Private->IntThunk->PciHandler.PrimaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);\r
+  } else {\r
+    Private->IntThunk->PciHandler.PrimaryIrq      = 14;\r
+    Private->IntThunk->PciHandler.PrimaryBase     = 0x1f0;\r
+    Private->IntThunk->PciHandler.PrimaryControl  = 0x3f6;\r
+  }\r
+  //\r
+  // Secondary controller data\r
+  //\r
+  if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {\r
+    Private->IntThunk->PciHandler.SecondaryBusMaster  = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);\r
+    PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);\r
+    SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);\r
+\r
+    //\r
+    // Clear pending interrupts in Bus Master registers\r
+    //\r
+    IoWrite16 (PrimaryMaster, 0x04);\r
+    IoWrite16 (SecondaryMaster, 0x04);\r
+\r
+  }\r
+\r
+  //\r
+  // Use native mode base address registers in two cases:\r
+  // 1. Programming Interface (PI) register indicates Secondary Controller is\r
+  // in native mode OR\r
+  // 2. PCI device Sub Class Code is not IDE\r
+  //\r
+  if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {\r
+    Private->IntThunk->PciHandler.SecondaryIrq      = PciIrq;\r
+    Private->IntThunk->PciHandler.SecondaryBase     = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);\r
+    Private->IntThunk->PciHandler.SecondaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);\r
+  } else {\r
+\r
+    Private->IntThunk->PciHandler.SecondaryIrq      = 15;\r
+    Private->IntThunk->PciHandler.SecondaryBase     = 0x170;\r
+    Private->IntThunk->PciHandler.SecondaryControl  = 0x376;\r
+  }\r
+\r
+  //\r
+  // Clear pending interrupts in IDE Command Block Status reg before we\r
+  // Thunk to CSM16 below.  Don't want a pending Interrupt before we\r
+  // install the handlers as wierd corruption would occur and hang system.\r
+  //\r
+  //\r
+  // Read IDE CMD blk status reg to clear out any pending interrupts.\r
+  // Do here for Primary and Secondary IDE channels\r
+  //\r
+  RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;\r
+  IoRead8 (RegisterAddress);\r
+  RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;\r
+  IoRead8 (RegisterAddress);\r
+\r
+  Private->IntThunk->PciHandler.PrimaryReserved   = 0;\r
+  Private->IntThunk->PciHandler.SecondaryReserved = 0;\r
+  Private->LegacyRegion->UnLock (\r
+                           Private->LegacyRegion,\r
+                           0xE0000,\r
+                           0x20000,\r
+                           &Granularity\r
+                           );\r
+\r
+  Regs.X.AX = Legacy16InstallPciHandler;\r
+  TempData  = (UINTN) &Private->IntThunk->PciHandler;\r
+  Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);\r
+  Regs.X.BX = EFI_OFFSET ((UINT32) TempData);\r
+\r
+  DumpPciHandle (&Private->IntThunk->PciHandler);\r
+\r
+  Private->LegacyBios.FarCall86 (\r
+    &Private->LegacyBios,\r
+    Private->Legacy16CallSegment,\r
+    Private->Legacy16CallOffset,\r
+    &Regs,\r
+    NULL,\r
+    0\r
+    );\r
+\r
+  Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
+  Private->LegacyRegion->Lock (\r
+                           Private->LegacyRegion,\r
+                           0xE0000,\r
+                           0x20000,\r
+                           &Granularity\r
+                           );\r
+\r
+}\r
+\r
+\r
+/**\r
+  Program the interrupt routing register in all the PCI devices. On a PC AT system\r
+  this register contains the 8259 IRQ vector that matches it's PCI interrupt.\r
+\r
+  @param  Private                Legacy  BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS            Succeed.\r
+  @retval EFI_ALREADY_STARTED    All PCI devices have been processed.\r
+\r
+**/\r
+EFI_STATUS\r
+PciProgramAllInterruptLineRegisters (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_LEGACY_8259_PROTOCOL          *Legacy8259;\r
+  EFI_LEGACY_INTERRUPT_PROTOCOL     *LegacyInterrupt;\r
+  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
+  UINT8                             InterruptPin;\r
+  UINTN                             Index;\r
+  UINTN                             HandleCount;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             MassStorageHandleCount;\r
+  EFI_HANDLE                        *MassStorageHandleBuffer;\r
+  UINTN                             MassStorageHandleIndex;\r
+  UINT8                             PciIrq;\r
+  UINT16                            Command;\r
+  UINTN                             PciSegment;\r
+  UINTN                             PciBus;\r
+  UINTN                             PciDevice;\r
+  UINTN                             PciFunction;\r
+  EFI_LEGACY_IRQ_ROUTING_ENTRY      *RoutingTable;\r
+  UINTN                             RoutingTableEntries;\r
+  UINT16                            LegMask;\r
+  UINT16                            LegEdgeLevel;\r
+  PCI_TYPE00                        PciConfigHeader;\r
+  EFI_LEGACY_PIRQ_TABLE_HEADER      *PirqTable;\r
+  UINTN                             PirqTableSize;\r
+  UINTN                             Flags;\r
+  HDD_INFO                          *HddInfo;\r
+  UINT64                            Supports;\r
+\r
+  //\r
+  // Note - This routine use to return immediately if Private->PciInterruptLine\r
+  //        was true. Routine changed since resets etc can cause not all\r
+  //        PciIo protocols to be registered the first time through.\r
+  // New algorithm is to do the copy $PIR table on first pass and save\r
+  // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives\r
+  // a larger handle count then proceed with body of function else return\r
+  // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.\r
+  // If zero then function unprogrammed else skip function.\r
+  //\r
+  Legacy8259          = Private->Legacy8259;\r
+  LegacyInterrupt     = Private->LegacyInterrupt;\r
+  LegacyBiosPlatform  = Private->LegacyBiosPlatform;\r
+\r
+  LegacyBiosPlatform->GetRoutingTable (\r
+                        Private->LegacyBiosPlatform,\r
+                        (VOID *) &RoutingTable,\r
+                        &RoutingTableEntries,\r
+                        (VOID *) &PirqTable,\r
+                        &PirqTableSize,\r
+                        NULL,\r
+                        NULL\r
+                        );\r
+  CreateBridgeTable (RoutingTable, RoutingTableEntries);\r
+\r
+  if (!Private->PciInterruptLine) {\r
+    CopyPirqTable (\r
+      Private,\r
+      RoutingTable,\r
+      RoutingTableEntries,\r
+      PirqTable,\r
+      PirqTableSize\r
+      );\r
+  }\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  if (HandleCount == mHandleCount) {\r
+    FreePool (HandleBuffer);\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  if (mHandleCount == 0x00) {\r
+    mHandleCount = HandleCount;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    //\r
+    // If VGA then only do VGA to allow drives fore time to spin up\r
+    // otherwise assign PCI IRQs to all potential devices.\r
+    //\r
+    if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {\r
+      continue;\r
+    } else {\r
+      //\r
+      // Force code to go through all handles next time called if video.\r
+      // This will catch case where HandleCount doesn't change but want\r
+      //  to get drive info etc.\r
+      //\r
+      mHandleCount = 0x00;\r
+    }\r
+\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Test whether the device can be enabled or not.\r
+    // If it can't be enabled, then just skip it to avoid further operation.\r
+    //\r
+    PciIo->Pci.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint32,\r
+                 0,\r
+                 sizeof (PciConfigHeader) / sizeof (UINT32),\r
+                 &PciConfigHeader\r
+                 );\r
+    Command = PciConfigHeader.Hdr.Command;\r
+\r
+    //\r
+    // Note PciIo->Attributes does not program the PCI command register\r
+    //\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationSupported,\r
+                      0,\r
+                      &Supports\r
+                      );\r
+    if (!EFI_ERROR (Status)) {\r
+      Supports &= EFI_PCI_DEVICE_ENABLE;\r
+      Status = PciIo->Attributes (\r
+                        PciIo,\r
+                        EfiPciIoAttributeOperationEnable,\r
+                        Supports,\r
+                        NULL\r
+                        );\r
+    }\r
+    PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    InterruptPin = PciConfigHeader.Device.InterruptPin;\r
+\r
+    if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {\r
+      PciIo->GetLocation (\r
+               PciIo,\r
+               &PciSegment,\r
+               &PciBus,\r
+               &PciDevice,\r
+               &PciFunction\r
+               );\r
+      //\r
+      // Translate PIRQ index back thru busses to slot bus with InterruptPin\r
+      // zero based\r
+      //\r
+      InterruptPin -= 1;\r
+\r
+      Status = GetBaseBus (\r
+                 Private,\r
+                 PciBus,\r
+                 PciDevice,\r
+                 RoutingTable,\r
+                 RoutingTableEntries\r
+                 );\r
+\r
+      if (Status == EFI_NOT_FOUND) {\r
+        TranslateBusPirq (\r
+          Private,\r
+          &PciBus,\r
+          &PciDevice,\r
+          &PciFunction,\r
+          &InterruptPin\r
+          );\r
+      }\r
+      //\r
+      // Translate InterruptPin(0-3) into PIRQ\r
+      //\r
+      Status = LegacyBiosPlatform->TranslatePirq (\r
+                                     LegacyBiosPlatform,\r
+                                     PciBus,\r
+                                     (PciDevice << 3),\r
+                                     PciFunction,\r
+                                     &InterruptPin,\r
+                                     &PciIrq\r
+                                     );\r
+      //\r
+      // TranslatePirq() should never fail or we are in trouble\r
+      // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));\r
+        continue;\r
+      }\r
+\r
+      LegacyInterrupt->WritePirq (\r
+                         LegacyInterrupt,\r
+                         InterruptPin,\r
+                         PciIrq\r
+                         );\r
+\r
+      //\r
+      // Check if device has an OPROM associated with it.\r
+      // If not invoke special 16-bit function, to allow 16-bit\r
+      // code to install an interrupt handler.\r
+      //\r
+      Status = LegacyBiosCheckPciRom (\r
+                 &Private->LegacyBios,\r
+                 HandleBuffer[Index],\r
+                 NULL,\r
+                 NULL,\r
+                 &Flags\r
+                 );\r
+      if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {\r
+        //\r
+        // Device has no OPROM associated with it and is a mass storage\r
+        // device. It needs to have an PCI IRQ handler installed. To\r
+        // correctly install the handler we need to insure device is\r
+        // connected. The device may just have register itself but not\r
+        // been connected. Re-read PCI config space after as it can\r
+        // change\r
+        //\r
+        //\r
+        // Get IDE Handle. If matches handle then skip ConnectController\r
+        // since ConnectController may force native mode and we don't\r
+        // want that for primary IDE controller\r
+        //\r
+        MassStorageHandleCount = 0;\r
+        MassStorageHandleBuffer = NULL;\r
+        LegacyBiosPlatform->GetPlatformHandle (\r
+                              Private->LegacyBiosPlatform,\r
+                              EfiGetPlatformIdeHandle,\r
+                              0,\r
+                              &MassStorageHandleBuffer,\r
+                              &MassStorageHandleCount,\r
+                              NULL\r
+                              );\r
+\r
+        HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];\r
+\r
+        LegacyBiosBuildIdeData (Private, &HddInfo, 0);\r
+        PciIo->Pci.Read (\r
+                     PciIo,\r
+                     EfiPciIoWidthUint32,\r
+                     0,\r
+                     sizeof (PciConfigHeader) / sizeof (UINT32),\r
+                     &PciConfigHeader\r
+                     );\r
+\r
+        for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {\r
+          if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {\r
+            //\r
+            // InstallLegacyIrqHandler according to Platform requirement\r
+            //\r
+            InstallLegacyIrqHandler (\r
+              Private,\r
+              PciIo,\r
+              PciIrq,\r
+              &PciConfigHeader\r
+              );\r
+            break;\r
+          }\r
+        }\r
+      }\r
+      //\r
+      // Write InterruptPin and enable 8259.\r
+      //\r
+      PciIo->Pci.Write (\r
+                   PciIo,\r
+                   EfiPciIoWidthUint8,\r
+                   0x3c,\r
+                   1,\r
+                   &PciIrq\r
+                   );\r
+      Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));\r
+\r
+      Legacy8259->GetMask (\r
+                    Legacy8259,\r
+                    &LegMask,\r
+                    &LegEdgeLevel,\r
+                    NULL,\r
+                    NULL\r
+                    );\r
+\r
+      LegMask       = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));\r
+      LegEdgeLevel  = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));\r
+      Legacy8259->SetMask (\r
+                    Legacy8259,\r
+                    &LegMask,\r
+                    &LegEdgeLevel,\r
+                    NULL,\r
+                    NULL\r
+                    );\r
+    }\r
+  }\r
+  FreePool (HandleBuffer);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Find & verify PnP Expansion header in ROM image\r
+\r
+  @param  Private                Protocol instance pointer.\r
+  @param  FirstHeader            1 = Find first header, 0 = Find successive headers\r
+  @param  PnpPtr                 Input Rom start if FirstHeader =1, Current Header\r
+                                 otherwise Output Next header, if it exists\r
+\r
+  @retval EFI_SUCCESS            Next Header found at BasePnpPtr\r
+  @retval EFI_NOT_FOUND          No more headers\r
+\r
+**/\r
+EFI_STATUS\r
+FindNextPnpExpansionHeader (\r
+  IN  LEGACY_BIOS_INSTANCE             *Private,\r
+  IN BOOLEAN                           FirstHeader,\r
+  IN OUT LEGACY_PNP_EXPANSION_HEADER   **PnpPtr\r
+\r
+  )\r
+{\r
+  UINTN                       TempData;\r
+  LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;\r
+  LocalPnpPtr = *PnpPtr;\r
+  if (FirstHeader == FIRST_INSTANCE) {\r
+    mBasePnpPtr     = LocalPnpPtr;\r
+    mBbsRomSegment  = (UINT16) ((UINTN) mBasePnpPtr >> 4);\r
+    //\r
+    // Offset 0x1a gives offset to PnP expansion header for the first\r
+    // instance, there after the structure gives the offset to the next\r
+    // structure\r
+    //\r
+    LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);\r
+    TempData    = (*((UINT16 *) LocalPnpPtr));\r
+  } else {\r
+    TempData = (UINT16) LocalPnpPtr->NextHeader;\r
+  }\r
+\r
+  LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));\r
+\r
+  //\r
+  // Search for PnP table in Shadowed ROM\r
+  //\r
+  *PnpPtr = LocalPnpPtr;\r
+  if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Update list of Bev or BCV table entries.\r
+\r
+  @param  Private                Protocol instance pointer.\r
+  @param  RomStart               Table of ROM start address in RAM/ROM. PciIo  _\r
+                                 Handle to PCI IO for this device\r
+  @param  PciIo                  Instance of PCI I/O Protocol\r
+\r
+  @retval EFI_SUCCESS            Always should succeed.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateBevBcvTable (\r
+  IN  LEGACY_BIOS_INSTANCE             *Private,\r
+  IN  EFI_LEGACY_EXPANSION_ROM_HEADER  *RomStart,\r
+  IN  EFI_PCI_IO_PROTOCOL              *PciIo\r
+  )\r
+{\r
+  VOID                            *RomEnd;\r
+  BBS_TABLE                       *BbsTable;\r
+  UINTN                           BbsIndex;\r
+  EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;\r
+  LEGACY_PNP_EXPANSION_HEADER     *PnpPtr;\r
+  BOOLEAN                         Instance;\r
+  EFI_STATUS                      Status;\r
+  UINTN                           Segment;\r
+  UINTN                           Bus;\r
+  UINTN                           Device;\r
+  UINTN                           Function;\r
+  UINT8                           Class;\r
+  UINT16                          DeviceType;\r
+  Segment     = 0;\r
+  Bus         = 0;\r
+  Device      = 0;\r
+  Function    = 0;\r
+  Class       = 0;\r
+  DeviceType  = BBS_UNKNOWN;\r
+\r
+  //\r
+  // Skip floppy and 2*onboard IDE controller entries(Master/Slave per\r
+  // controller).\r
+  //\r
+  BbsIndex  = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
+\r
+  BbsTable  = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;\r
+  PnpPtr    = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;\r
+  PciPtr    = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;\r
+\r
+  RomEnd    = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);\r
+  Instance  = FIRST_INSTANCE;\r
+  //\r
+  // OPROMs like PXE may not be tied to a piece of hardware and thus\r
+  // don't have a PciIo associated with them\r
+  //\r
+  if (PciIo != NULL) {\r
+    PciIo->GetLocation (\r
+             PciIo,\r
+             &Segment,\r
+             &Bus,\r
+             &Device,\r
+             &Function\r
+             );\r
+    PciIo->Pci.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint8,\r
+                 0x0b,\r
+                 1,\r
+                 &Class\r
+                 );\r
+\r
+    if (Class == PCI_CLASS_MASS_STORAGE) {\r
+      DeviceType = BBS_HARDDISK;\r
+    } else {\r
+      if (Class == PCI_CLASS_NETWORK) {\r
+        DeviceType = BBS_EMBED_NETWORK;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (PciPtr >= (EFI_LEGACY_EXPANSION_ROM_HEADER *) ((UINTN) 0xc8000)) {\r
+    while (TRUE) {\r
+      Status    = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);\r
+      Instance  = NOT_FIRST_INSTANCE;\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+      //\r
+      // There can be additional $PnP headers within the OPROM.\r
+      // Example: SCSI can have one per drive.\r
+      //\r
+      BbsTable[BbsIndex].BootPriority             = BBS_UNPRIORITIZED_ENTRY;\r
+      BbsTable[BbsIndex].DeviceType               = DeviceType;\r
+      BbsTable[BbsIndex].Bus                      = (UINT32) Bus;\r
+      BbsTable[BbsIndex].Device                   = (UINT32) Device;\r
+      BbsTable[BbsIndex].Function                 = (UINT32) Function;\r
+      BbsTable[BbsIndex].StatusFlags.OldPosition  = 0;\r
+      BbsTable[BbsIndex].StatusFlags.Reserved1    = 0;\r
+      BbsTable[BbsIndex].StatusFlags.Enabled      = 0;\r
+      BbsTable[BbsIndex].StatusFlags.Failed       = 0;\r
+      BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;\r
+      BbsTable[BbsIndex].StatusFlags.Reserved2    = 0;\r
+      BbsTable[BbsIndex].Class                    = PnpPtr->Class;\r
+      BbsTable[BbsIndex].SubClass                 = PnpPtr->SubClass;\r
+      BbsTable[BbsIndex].DescStringOffset         = PnpPtr->ProductNamePointer;\r
+      BbsTable[BbsIndex].DescStringSegment        = mBbsRomSegment;\r
+      BbsTable[BbsIndex].MfgStringOffset          = PnpPtr->MfgPointer;\r
+      BbsTable[BbsIndex].MfgStringSegment         = mBbsRomSegment;\r
+      BbsTable[BbsIndex].BootHandlerSegment       = mBbsRomSegment;\r
+\r
+      //\r
+      // Have seen case where PXE base code have PnP expansion ROM\r
+      // header but no Bcv or Bev vectors.\r
+      //\r
+      if (PnpPtr->Bcv != 0) {\r
+        BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;\r
+        ++BbsIndex;\r
+      }\r
+\r
+      if (PnpPtr->Bev != 0) {\r
+        BbsTable[BbsIndex].BootHandlerOffset  = PnpPtr->Bev;\r
+        BbsTable[BbsIndex].DeviceType         = BBS_BEV_DEVICE;\r
+        ++BbsIndex;\r
+      }\r
+\r
+      if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;\r
+  Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol\r
+  to chose the order. Skip any devices that have already have legacy\r
+  BIOS run.\r
+\r
+  @param  Private                Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS            Succeed.\r
+  @retval EFI_UNSUPPORTED        Cannot get VGA device handle.\r
+\r
+**/\r
+EFI_STATUS\r
+PciShadowRoms (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  PCI_TYPE00                        Pci;\r
+  UINTN                             Index;\r
+  UINTN                             HandleCount;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  EFI_HANDLE                        VgaHandle;\r
+  EFI_HANDLE                        FirstHandle;\r
+  VOID                              **RomStart;\r
+  UINTN                             Flags;\r
+  PCI_TYPE00                        PciConfigHeader;\r
+  UINT16                            *Command;\r
+  UINT64                            Supports;\r
+\r
+  //\r
+  // Make the VGA device first\r
+  //\r
+  Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformVgaHandle,\r
+                                          0,\r
+                                          &HandleBuffer,\r
+                                          &HandleCount,\r
+                                          NULL\r
+                                          ); \r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  VgaHandle = HandleBuffer[0];\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Place the VGA handle as first.\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    if (HandleBuffer[Index] == VgaHandle) {\r
+      FirstHandle         = HandleBuffer[0];\r
+      HandleBuffer[0]     = HandleBuffer[Index];\r
+      HandleBuffer[Index] = FirstHandle;\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // Allocate memory to save Command WORD from each device. We do this\r
+  // to restore devices to same state as EFI after switching to legacy.\r
+  //\r
+  Command = (UINT16 *) AllocatePool (\r
+                         sizeof (UINT16) * (HandleCount + 1)\r
+                         );\r
+  if (NULL == Command) {\r
+    FreePool (HandleBuffer);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Disconnect all EFI devices first. This covers cases where alegacy BIOS\r
+  // may control multiple PCI devices.\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Save command register for "connect" loop\r
+    //\r
+    PciIo->Pci.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint32,\r
+                 0,\r
+                 sizeof (PciConfigHeader) / sizeof (UINT32),\r
+                 &PciConfigHeader\r
+                 );\r
+    Command[Index] = PciConfigHeader.Hdr.Command;\r
+    //\r
+    // Skip any device that already has a legacy ROM run\r
+    //\r
+    Status = IsLegacyRom (HandleBuffer[Index]);\r
+    if (!EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    //\r
+    // Stop EFI Drivers with oprom.\r
+    //\r
+    gBS->DisconnectController (\r
+           HandleBuffer[Index],\r
+           NULL,\r
+           NULL\r
+           );\r
+  }\r
+  //\r
+  // For every device that has not had a legacy ROM started. Start a legacy ROM.\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Here make sure if one VGA have been shadowed,\r
+    // then wil not shadowed another one.\r
+    //\r
+    PciIo->Pci.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint32,\r
+                 0,\r
+                 sizeof (Pci) / sizeof (UINT32),\r
+                 &Pci\r
+                 );\r
+    \r
+    //\r
+    // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices, \r
+    // one will work in legacy mode (OPROM will be given control) and \r
+    // other Video devices will work in native mode (OS driver will handle these devices).\r
+    // \r
+    if (IS_PCI_DISPLAY (&Pci) && Index != 0) {    \r
+      continue;\r
+    }\r
+    //\r
+    // Skip any device that already has a legacy ROM run\r
+    //\r
+    Status = IsLegacyRom (HandleBuffer[Index]);\r
+    if (!EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    //\r
+    // Install legacy ROM\r
+    //\r
+    Status = LegacyBiosInstallPciRom (\r
+               &Private->LegacyBios,\r
+               HandleBuffer[Index],\r
+               NULL,\r
+               &Flags,\r
+               NULL,\r
+               NULL,\r
+               (VOID **) &RomStart,\r
+               NULL\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {\r
+        continue;\r
+      }\r
+    }\r
+    //\r
+    // Restore Command register so legacy has same devices enabled or disabled\r
+    // as EFI.\r
+    // If Flags = NO_ROM use command register as is. This covers the\r
+    //            following cases:\r
+    //              Device has no ROMs associated with it.\r
+    //              Device has ROM associated with it but was already\r
+    //              installed.\r
+    //          = ROM_FOUND but not VALID_LEGACY_ROM, disable it.\r
+    //          = ROM_FOUND and VALID_LEGACY_ROM, enable it.\r
+    //\r
+    if ((Flags & ROM_FOUND) == ROM_FOUND) {\r
+      if ((Flags & VALID_LEGACY_ROM) == 0) {\r
+        Command[Index] = 0;\r
+      } else {\r
+        //\r
+        // For several VGAs, only one of them can be enabled.\r
+        //\r
+        Status = PciIo->Attributes (\r
+                          PciIo,\r
+                          EfiPciIoAttributeOperationSupported,\r
+                          0,\r
+                          &Supports\r
+                          );\r
+        if (!EFI_ERROR (Status)) {\r
+          Supports &= EFI_PCI_DEVICE_ENABLE;\r
+          Status = PciIo->Attributes (\r
+                            PciIo,\r
+                            EfiPciIoAttributeOperationEnable,\r
+                            Supports,\r
+                            NULL\r
+                            );\r
+        }\r
+        if (!EFI_ERROR (Status)) {\r
+          Command[Index] = 0x1f;\r
+        }\r
+      }\r
+    }\r
+\r
+    PciIo->Pci.Write (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint16,\r
+                 0x04,\r
+                 1,\r
+                 &Command[Index]\r
+                 );\r
+  }\r
+\r
+  FreePool (Command);\r
+  FreePool (HandleBuffer);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Test to see if a legacy PCI ROM exists for this device. Optionally return\r
+  the Legacy ROM instance for this PCI device.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will\r
+                                 be loaded\r
+  @param  RomImage               Return the legacy PCI ROM for this device\r
+  @param  RomSize                Size of ROM Image\r
+  @param  Flags                  Indicates if ROM found and if PC-AT.\r
+\r
+  @retval EFI_SUCCESS            Legacy Option ROM availible for this device\r
+  @retval EFI_UNSUPPORTED        Legacy Option ROM not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosCheckPciRom (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  EFI_HANDLE                        PciHandle,\r
+  OUT VOID                              **RomImage, OPTIONAL\r
+  OUT UINTN                             *RomSize, OPTIONAL\r
+  OUT UINTN                             *Flags\r
+  )\r
+{\r
+  return LegacyBiosCheckPciRomEx (\r
+           This,\r
+           PciHandle,\r
+           RomImage,\r
+           RomSize,\r
+           NULL,\r
+           Flags,\r
+           NULL,\r
+           NULL\r
+           );\r
+\r
+}\r
+\r
+/**\r
+\r
+  Routine Description:\r
+    Test to see if a legacy PCI ROM exists for this device. Optionally return\r
+    the Legacy ROM instance for this PCI device.\r
+\r
+    @param[in] This          Protocol instance pointer.\r
+    @param[in] PciHandle               The PCI PC-AT OPROM from this devices ROM BAR will be loaded\r
+    @param[out] RomImage               Return the legacy PCI ROM for this device\r
+    @param[out] RomSize                Size of ROM Image\r
+    @param[out] RuntimeImageLength     Runtime size of ROM Image\r
+    @param[out] Flags                  Indicates if ROM found and if PC-AT.\r
+    @param[out] OpromRevision          Revision of the PCI Rom\r
+    @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header\r
+\r
+    @return EFI_SUCCESS            Legacy Option ROM availible for this device\r
+    @return EFI_ALREADY_STARTED    This device is already managed by its Oprom\r
+    @return EFI_UNSUPPORTED        Legacy Option ROM not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosCheckPciRomEx (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN  EFI_HANDLE                        PciHandle,\r
+  OUT VOID                              **RomImage, OPTIONAL\r
+  OUT UINTN                             *RomSize, OPTIONAL\r
+  OUT UINTN                             *RuntimeImageLength, OPTIONAL\r
+  OUT UINTN                             *Flags, OPTIONAL\r
+  OUT UINT8                             *OpromRevision, OPTIONAL\r
+  OUT VOID                              **ConfigUtilityCodeHeader OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  LEGACY_BIOS_INSTANCE            *Private;\r
+  EFI_PCI_IO_PROTOCOL             *PciIo;\r
+  UINTN                           LocalRomSize;\r
+  VOID                            *LocalRomImage;\r
+  PCI_TYPE00                      PciConfigHeader;\r
+  VOID                            *LocalConfigUtilityCodeHeader;\r
+\r
+  *Flags = NO_ROM;\r
+  Status = gBS->HandleProtocol (\r
+                  PciHandle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // See if the option ROM for PciHandle has already been executed\r
+  //\r
+  Status = IsLegacyRom (PciHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    *Flags |= (ROM_FOUND | VALID_LEGACY_ROM);\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Check for PCI ROM Bar\r
+  //\r
+  LocalRomSize  = (UINTN) PciIo->RomSize;\r
+  LocalRomImage = PciIo->RomImage;\r
+  if (LocalRomSize != 0) {\r
+    *Flags |= ROM_FOUND;\r
+  }\r
+\r
+  //\r
+  // PCI specification states you should check VendorId and Device Id.\r
+  //\r
+  PciIo->Pci.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               0,\r
+               sizeof (PciConfigHeader) / sizeof (UINT32),\r
+               &PciConfigHeader\r
+               );\r
+\r
+  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  Status = GetPciLegacyRom (\r
+             Private->Csm16PciInterfaceVersion,\r
+             PciConfigHeader.Hdr.VendorId,\r
+             PciConfigHeader.Hdr.DeviceId,\r
+             &LocalRomImage,\r
+             &LocalRomSize,\r
+             RuntimeImageLength,\r
+             OpromRevision,\r
+             &LocalConfigUtilityCodeHeader\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  *Flags |= VALID_LEGACY_ROM;\r
+\r
+  //\r
+  // See if Configuration Utility Code Header valid\r
+  //\r
+  if (LocalConfigUtilityCodeHeader != NULL) {\r
+    *Flags |= ROM_WITH_CONFIG;\r
+  }\r
+\r
+  if (ConfigUtilityCodeHeader != NULL) {\r
+    *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;\r
+  }\r
+\r
+  if (RomImage != NULL) {\r
+    *RomImage = LocalRomImage;\r
+  }\r
+\r
+  if (RomSize != NULL) {\r
+    *RomSize = LocalRomSize;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
+  about how many disks were added by the OPROM and the shadow address and\r
+  size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
+\r
+  @retval EFI_SUCCESS   Legacy ROM loaded for this device\r
+  @retval EFI_NOT_FOUND No PS2 Keyboard found\r
+\r
+**/\r
+EFI_STATUS\r
+EnablePs2Keyboard (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          *HandleBuffer;\r
+  UINTN                               HandleCount;\r
+  EFI_ISA_IO_PROTOCOL                 *IsaIo;\r
+  UINTN                               Index;\r
+\r
+  //\r
+  // Get SimpleTextIn and find PS2 controller\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiSimpleTextInProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    //\r
+    // Open the IO Abstraction(s) needed to perform the supported test\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiIsaIoProtocolGuid,\r
+                    (VOID **) &IsaIo,\r
+                    NULL,\r
+                    HandleBuffer[Index],\r
+                    EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL\r
+                    );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Use the ISA I/O Protocol to see if Controller is the Keyboard\r
+      // controller\r
+      //\r
+      if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+\r
+      gBS->CloseProtocol (\r
+             HandleBuffer[Index],\r
+             &gEfiIsaIoProtocolGuid,\r
+             NULL,\r
+             HandleBuffer[Index]\r
+             );\r
+    }\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);\r
+    }\r
+  }\r
+  FreePool (HandleBuffer);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Load a legacy PC-AT OpROM for VGA controller.\r
+\r
+  @param  Private                Driver private data.\r
+\r
+  @retval EFI_SUCCESS            Legacy ROM successfully installed for this device.\r
+  @retval EFI_DEVICE_ERROR       No VGA device handle found, or native EFI video\r
+                                 driver cannot be successfully disconnected, or VGA\r
+                                 thunk driver cannot be successfully connected.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInstallVgaRom (\r
+  IN  LEGACY_BIOS_INSTANCE            *Private\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_HANDLE                           VgaHandle;\r
+  UINTN                                HandleCount;\r
+  EFI_HANDLE                           *HandleBuffer;\r
+  EFI_HANDLE                           *ConnectHandleBuffer;\r
+  EFI_PCI_IO_PROTOCOL                  *PciIo;\r
+  PCI_TYPE00                           PciConfigHeader;\r
+  UINT64                               Supports;\r
+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;\r
+  UINTN                                EntryCount;\r
+  UINTN                                Index;\r
+  VOID                                 *Interface;\r
+\r
+  //\r
+  // EfiLegacyBiosGuild attached to a device implies that there is a legacy\r
+  // BIOS associated with that device.\r
+  //\r
+  // There are 3 cases to consider.\r
+  //   Case 1: No EFI driver is controlling the video.\r
+  //     Action: Return EFI_SUCCESS from DisconnectController, search\r
+  //             video thunk driver, and connect it.\r
+  //   Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is\r
+  //           not on the image handle.\r
+  //     Action: Disconnect EFI driver.\r
+  //             ConnectController for video thunk\r
+  //   Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is\r
+  //           on the image handle.\r
+  //     Action: Do nothing and set Private->VgaInstalled = TRUE.\r
+  //             Then this routine is not called any more.\r
+  //\r
+  //\r
+  // Get the VGA device.\r
+  //\r
+  Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformVgaHandle,\r
+                                          0,\r
+                                          &HandleBuffer,\r
+                                          &HandleCount,\r
+                                          NULL\r
+                                          );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  VgaHandle = HandleBuffer[0];\r
+\r
+  //\r
+  // Check whether video thunk driver already starts.\r
+  //\r
+  Status = gBS->OpenProtocolInformation (\r
+                  VgaHandle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  &OpenInfoBuffer,\r
+                  &EntryCount\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  for (Index = 0; Index < EntryCount; Index++) {\r
+    if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
+      Status = gBS->HandleProtocol (\r
+                      OpenInfoBuffer[Index].AgentHandle,\r
+                      &gEfiLegacyBiosGuid,\r
+                      (VOID **) &Interface\r
+                      );\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // This should be video thunk driver which is managing video device\r
+        // So it need not start again\r
+        //\r
+        DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));\r
+        Private->VgaInstalled = TRUE;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Kick off the native EFI driver\r
+  //\r
+  Status = gBS->DisconnectController (\r
+                  VgaHandle,\r
+                  NULL,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status != EFI_NOT_FOUND) {\r
+      return EFI_DEVICE_ERROR;\r
+    } else {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // Find all the Thunk Driver\r
+  //\r
+  HandleBuffer = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiLegacyBiosGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));\r
+  ASSERT (ConnectHandleBuffer != NULL);\r
+\r
+  CopyMem (\r
+    ConnectHandleBuffer,\r
+    HandleBuffer,\r
+    sizeof (EFI_HANDLE) * HandleCount\r
+    );\r
+  ConnectHandleBuffer[HandleCount] = NULL;\r
+\r
+  FreePool (HandleBuffer);\r
+\r
+  //\r
+  // Enable the device and make sure VGA cycles are being forwarded to this VGA device\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  VgaHandle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  PciIo->Pci.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               0,\r
+               sizeof (PciConfigHeader) / sizeof (UINT32),\r
+               &PciConfigHeader\r
+               );\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \\r
+                EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+  }\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+    Private->VgaInstalled = TRUE;\r
+\r
+    //\r
+    // Attach the VGA thunk driver.\r
+    // Assume the video is installed. This prevents potential of infinite recursion.\r
+    //\r
+    Status = gBS->ConnectController (\r
+                    VgaHandle,\r
+                    ConnectHandleBuffer,\r
+                    NULL,\r
+                    TRUE\r
+                    );\r
+  }\r
+\r
+  FreePool (ConnectHandleBuffer);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    Private->VgaInstalled = FALSE;\r
+\r
+    //\r
+    // Reconnect the EFI VGA driver.\r
+    //\r
+    gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Load a legacy PC-AT OpROM.\r
+\r
+  @param  This                              Protocol instance pointer.\r
+  @param  Private                          Driver's private data.\r
+  @param  PciHandle                      The EFI handle for the PCI device. It could be\r
+                                                    NULL if the  OpROM image is not associated with\r
+                                                    any device.\r
+  @param  OpromRevision              The revision of PCI PC-AT ROM image.\r
+  @param  RomImage                    Pointer to PCI PC-AT ROM image header. It must not\r
+                                                    be NULL.\r
+  @param  ImageSize                     Size of the PCI PC-AT ROM image.\r
+  @param  RuntimeImageLength      On input is the max runtime image length indicated by the PCIR structure\r
+                                                    On output is the actual runtime image length\r
+  @param  DiskStart                       Disk number of first device hooked by the ROM. If\r
+                                                    DiskStart is the same as DiskEnd no disked were\r
+                                                    hooked.\r
+  @param  DiskEnd                         Disk number of the last device hooked by the ROM.\r
+  @param  RomShadowAddress       Shadow address of PC-AT ROM\r
+\r
+  @retval EFI_SUCCESS            Legacy ROM loaded for this device\r
+  @retval EFI_OUT_OF_RESOURCES   No more space for this ROM\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosInstallRom (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           *This,\r
+  IN LEGACY_BIOS_INSTANCE               *Private,\r
+  IN EFI_HANDLE                         PciHandle,\r
+  IN UINT8                              OpromRevision,\r
+  IN VOID                               *RomImage,\r
+  IN UINTN                              ImageSize,\r
+  IN OUT UINTN                          *RuntimeImageLength,\r
+  OUT UINT8                             *DiskStart, OPTIONAL\r
+  OUT UINT8                             *DiskEnd, OPTIONAL\r
+  OUT VOID                              **RomShadowAddress OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_STATUS            PciEnableStatus;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  UINT8                 LocalDiskStart;\r
+  UINT8                 LocalDiskEnd;\r
+  UINTN                 Segment;\r
+  UINTN                 Bus;\r
+  UINTN                 Device;\r
+  UINTN                 Function;\r
+  EFI_IA32_REGISTER_SET Regs;\r
+  UINT8                 VideoMode;\r
+  EFI_TIME              BootTime;\r
+  UINT32                *BdaPtr;\r
+  UINT32                LocalTime;\r
+  UINT32                StartBbsIndex;\r
+  UINT32                EndBbsIndex;\r
+  UINTN                 TempData;\r
+  UINTN                 InitAddress;\r
+  UINTN                 RuntimeAddress;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;\r
+  UINT32                Granularity;\r
+\r
+  PciIo           = NULL;\r
+  LocalDiskStart  = 0;\r
+  LocalDiskEnd    = 0;\r
+  Segment         = 0;\r
+  Bus             = 0;\r
+  Device          = 0;\r
+  Function        = 0;\r
+  VideoMode       = 0;\r
+  PhysicalAddress = 0;\r
+\r
+  PciProgramAllInterruptLineRegisters (Private);\r
+\r
+  if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {\r
+    //\r
+    // CSM16 3.0 meets PCI 3.0 OpROM\r
+    //   first test if there is enough space for its INIT code\r
+    //\r
+    PhysicalAddress = CONVENTIONAL_MEMORY_TOP;\r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiBootServicesCode,\r
+                    EFI_SIZE_TO_PAGES (ImageSize),\r
+                    &PhysicalAddress\r
+                    );\r
+        \r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    InitAddress = (UINTN) PhysicalAddress;\r
+    //\r
+    //   then test if there is enough space for its RT code\r
+    //\r
+    RuntimeAddress = Private->OptionRom;\r
+    if (RuntimeAddress + *RuntimeImageLength > mEndOpromShadowAddress) {\r
+      DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
+      gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+    // CSM16 3.0 meets PCI 2.x OpROM\r
+    // CSM16 2.x meets PCI 2.x/3.0 OpROM\r
+    //   test if there is enough space for its INIT code\r
+    //\r
+    InitAddress    = PCI_START_ADDRESS (Private->OptionRom);\r
+    if (InitAddress + ImageSize > mEndOpromShadowAddress) {\r
+      DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    RuntimeAddress = InitAddress;\r
+  }\r
+\r
+  Private->LegacyRegion->UnLock (\r
+                           Private->LegacyRegion,\r
+                           0xE0000,\r
+                           0x20000,\r
+                           &Granularity\r
+                           );\r
+\r
+  Private->LegacyRegion->UnLock (\r
+                           Private->LegacyRegion,\r
+                           (UINT32) RuntimeAddress,\r
+                           (UINT32) ImageSize,\r
+                           &Granularity\r
+                           );\r
+    \r
+  DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));\r
+\r
+  CopyMem ((VOID *) InitAddress, RomImage, ImageSize);\r
+\r
+  //\r
+  // Read the highest disk number "installed: and assume a new disk will\r
+  // show up on the first drive past the current value.\r
+  // There are several considerations here:\r
+  // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo\r
+  //    the change until boot selection time frame.\r
+  // 2. BBS compliants drives will not change 40:75 until boot time.\r
+  // 3. Onboard IDE controllers will change 40:75\r
+  //\r
+  LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);\r
+  if ((Private->Disk4075 + 0x80) < LocalDiskStart) {\r
+    //\r
+    // Update table since onboard IDE drives found\r
+    //\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = 0xff;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = 0xff;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = 0xff;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = 0xff;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = (UINT8) (Private->Disk4075 + 0x80);\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber    = LocalDiskStart;\r
+    Private->LegacyEfiHddTableIndex ++;\r
+    Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);\r
+    Private->DiskEnd  = LocalDiskStart;\r
+  }\r
+\r
+  if (PciHandle != mVgaHandle) {\r
+\r
+    EnablePs2Keyboard ();\r
+\r
+    //\r
+    // Store current mode settings since PrepareToScanRom may change mode.\r
+    //\r
+    VideoMode = *(UINT8 *) ((UINTN) 0x449);\r
+  }\r
+  //\r
+  // Notify the platform that we are about to scan the ROM\r
+  //\r
+  Status = Private->LegacyBiosPlatform->PlatformHooks (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiPlatformHookPrepareToScanRom,\r
+                                          0,\r
+                                          PciHandle,\r
+                                          &InitAddress,\r
+                                          NULL,\r
+                                          NULL\r
+                                          );\r
+\r
+  //\r
+  // If Status returned is EFI_UNSUPPORTED then abort due to platform\r
+  // policy.\r
+  //\r
+  if (Status == EFI_UNSUPPORTED) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Report corresponding status code\r
+  //\r
+  REPORT_STATUS_CODE (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)\r
+    );\r
+\r
+  //\r
+  // Generate number of ticks since midnight for BDA. Some OPROMs require\r
+  // this. Place result in 40:6C-6F\r
+  //\r
+  gRT->GetTime (&BootTime, NULL);\r
+  LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;\r
+  \r
+  //\r
+  // Multiply result by 18.2 for number of ticks since midnight.\r
+  // Use 182/10 to avoid floating point math.\r
+  //\r
+  LocalTime = (LocalTime * 182) / 10;\r
+  BdaPtr    = (UINT32 *) ((UINTN) 0x46C);\r
+  *BdaPtr   = LocalTime;\r
+  \r
+  //\r
+  // Pass in handoff data\r
+  //\r
+  PciEnableStatus = EFI_UNSUPPORTED;\r
+  ZeroMem (&Regs, sizeof (Regs));\r
+  if (PciHandle != NULL) {\r
+  \r
+    Status = gBS->HandleProtocol (\r
+                    PciHandle,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  \r
+    //\r
+    // Enable command register.\r
+    //\r
+    PciEnableStatus = PciIo->Attributes (\r
+                               PciIo,\r
+                               EfiPciIoAttributeOperationEnable,\r
+                               EFI_PCI_DEVICE_ENABLE,\r
+                               NULL\r
+                               );\r
+  \r
+    PciIo->GetLocation (\r
+             PciIo,\r
+             &Segment,\r
+             &Bus,\r
+             &Device,\r
+             &Function\r
+             );\r
+    DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));\r
+  }\r
+  \r
+  mIgnoreBbsUpdateFlag  = FALSE;\r
+  Regs.X.AX             = Legacy16DispatchOprom;\r
+  \r
+  //\r
+  // Generate DispatchOpRomTable data\r
+  //\r
+  Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;\r
+  Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset  = Private->Legacy16Table->PnPInstallationCheckOffset;\r
+  Private->IntThunk->DispatchOpromTable.OpromSegment                = (UINT16) (InitAddress >> 4);\r
+  Private->IntThunk->DispatchOpromTable.PciBus                      = (UINT8) Bus;\r
+  Private->IntThunk->DispatchOpromTable.PciDeviceFunction           = (UINT8) ((Device << 3) | Function);\r
+  Private->IntThunk->DispatchOpromTable.NumberBbsEntries            = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
+  Private->IntThunk->DispatchOpromTable.BbsTablePointer             = (UINT32) (UINTN) Private->BbsTablePtr;\r
+  Private->IntThunk->DispatchOpromTable.RuntimeSegment              = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));\r
+  TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;\r
+  Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);\r
+  Regs.X.BX = EFI_OFFSET ((UINT32) TempData);\r
+  //\r
+  // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes\r
+  // Otherwise, it may cause the system to hang in some cases\r
+  //\r
+  if (!EFI_ERROR (PciEnableStatus)) {\r
+    DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));\r
+    Private->LegacyBios.FarCall86 (\r
+      &Private->LegacyBios,\r
+      Private->Legacy16CallSegment,\r
+      Private->Legacy16CallOffset,\r
+      &Regs,\r
+      NULL,\r
+      0\r
+      );\r
+  } else {\r
+    Regs.X.BX = 0;\r
+  }\r
+  \r
+  if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {\r
+    Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries  = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;\r
+    mIgnoreBbsUpdateFlag = TRUE;\r
+  }\r
+  //\r
+  // Check if non-BBS compliant drives found\r
+  //\r
+  if (Regs.X.BX != 0) {\r
+    LocalDiskEnd  = (UINT8) (LocalDiskStart + Regs.H.BL);\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;\r
+    Private->DiskEnd = LocalDiskEnd;\r
+    Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;\r
+    Private->LegacyEfiHddTableIndex += 1;\r
+  }\r
+  //\r
+  // Skip video mode set, if installing VGA\r
+  //\r
+  if (PciHandle != mVgaHandle) {\r
+    //\r
+    // Set mode settings since PrepareToScanRom may change mode\r
+    //\r
+    Regs.H.AH = 0x00;\r
+    Regs.H.AL = VideoMode;\r
+    Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);\r
+  }\r
+  //\r
+  // Regs.X.AX from the adapter initializion is ignored since some adapters\r
+  // do not follow the standard of setting AX = 0 on success.\r
+  //\r
+  //\r
+  // The ROM could have updated it's size so we need to read again.\r
+  //\r
+  *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) (RuntimeAddress))->Size512 * 512;\r
+  DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));\r
+\r
+  //\r
+  // If OpROM runs in 2.0 mode\r
+  //\r
+  if (PhysicalAddress == 0) {\r
+    if (*RuntimeImageLength < ImageSize) {\r
+      //\r
+      // Make area from end of shadowed rom to end of original rom all ffs\r
+      //\r
+      gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);\r
+    }\r
+  }\r
+\r
+  LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);\r
+  \r
+  //\r
+  // Allow platform to perform any required actions after the\r
+  // OPROM has been initialized.\r
+  //\r
+  Status = Private->LegacyBiosPlatform->PlatformHooks (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiPlatformHookAfterRomInit,\r
+                                          0,\r
+                                          PciHandle,\r
+                                          &RuntimeAddress,\r
+                                          NULL,\r
+                                          NULL\r
+                                          );\r
+  if (PciHandle != NULL) {\r
+    //\r
+    // If no PCI Handle then no header or Bevs.\r
+    //\r
+    if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {\r
+      StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
+      TempData      = RuntimeAddress;\r
+      UpdateBevBcvTable (\r
+        Private,\r
+        (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,\r
+        PciIo\r
+        );\r
+      EndBbsIndex   = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
+      LocalDiskEnd  = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));\r
+      if (LocalDiskEnd != LocalDiskStart) {\r
+        Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;\r
+        Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;\r
+        Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;\r
+        Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;\r
+        Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;\r
+        Private->DiskEnd = LocalDiskEnd;\r
+        Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;\r
+        Private->LegacyEfiHddTableIndex += 1;\r
+      }\r
+    }\r
+    //\r
+    // Mark PCI device as having a legacy BIOS ROM loaded.\r
+    //\r
+    RomShadow (\r
+      PciHandle,\r
+      (UINT32) RuntimeAddress,\r
+      (UINT32) *RuntimeImageLength,\r
+      LocalDiskStart,\r
+      LocalDiskEnd\r
+      );\r
+  }\r
+\r
+  //\r
+  // Stuff caller's OPTIONAL return parameters.\r
+  //\r
+  if (RomShadowAddress != NULL) {\r
+    *RomShadowAddress = (VOID *) RuntimeAddress;\r
+  }\r
+\r
+  if (DiskStart != NULL) {\r
+    *DiskStart = LocalDiskStart;\r
+  }\r
+\r
+  if (DiskEnd != NULL) {\r
+    *DiskEnd = LocalDiskEnd;\r
+  }\r
+\r
+  Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);\r
+\r
+  Status = EFI_SUCCESS;\r
+   \r
+Done:\r
+  if (PhysicalAddress != 0) {\r
+    //\r
+    // Free pages when OpROM is 3.0\r
+    //\r
+    gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));\r
+  }\r
+\r
+  //\r
+  // Insure all shadowed  areas are locked\r
+  //\r
+  Private->LegacyRegion->Lock (\r
+                           Private->LegacyRegion,\r
+                           0xC0000,\r
+                           0x40000,\r
+                           &Granularity\r
+                           );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
+  about how many disks were added by the OPROM and the shadow address and\r
+  size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will\r
+                                 be loaded. This value is NULL if RomImage is\r
+                                 non-NULL. This is the normal case.\r
+  @param  RomImage               A PCI PC-AT ROM image. This argument is non-NULL\r
+                                 if there is no hardware associated with the ROM\r
+                                 and thus no PciHandle, otherwise is must be NULL.\r
+                                 Example is PXE base code.\r
+  @param  Flags                  Indicates if ROM found and if PC-AT.\r
+  @param  DiskStart              Disk number of first device hooked by the ROM. If\r
+                                 DiskStart is the same as DiskEnd no disked were\r
+                                 hooked.\r
+  @param  DiskEnd                Disk number of the last device hooked by the ROM.\r
+  @param  RomShadowAddress       Shadow address of PC-AT ROM\r
+  @param  RomShadowedSize        Size of RomShadowAddress in bytes\r
+\r
+  @retval EFI_SUCCESS            Legacy ROM loaded for this device\r
+  @retval EFI_INVALID_PARAMETER  PciHandle not found\r
+  @retval EFI_UNSUPPORTED        There is no PCI ROM in the ROM BAR or no onboard\r
+                                 ROM\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBiosInstallPciRom (\r
+  IN EFI_LEGACY_BIOS_PROTOCOL           * This,\r
+  IN  EFI_HANDLE                        PciHandle,\r
+  IN  VOID                              **RomImage,\r
+  OUT UINTN                             *Flags,\r
+  OUT UINT8                             *DiskStart, OPTIONAL\r
+  OUT UINT8                             *DiskEnd, OPTIONAL\r
+  OUT VOID                              **RomShadowAddress, OPTIONAL\r
+  OUT UINT32                            *RomShadowedSize OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  LEGACY_BIOS_INSTANCE            *Private;\r
+  VOID                            *LocalRomImage;\r
+  UINTN                           ImageSize;\r
+  UINTN                           RuntimeImageLength;\r
+  EFI_PCI_IO_PROTOCOL             *PciIo;\r
+  PCI_TYPE01                      PciConfigHeader;\r
+  UINTN                           HandleCount;\r
+  EFI_HANDLE                      *HandleBuffer;\r
+  UINTN                           PciSegment;\r
+  UINTN                           PciBus;\r
+  UINTN                           PciDevice;\r
+  UINTN                           PciFunction;\r
+  UINTN                           LastBus;\r
+  UINTN                           Index;\r
+  UINT8                           OpromRevision;\r
+  UINT32                          Granularity;\r
+  PCI_3_0_DATA_STRUCTURE          *Pcir;\r
+\r
+  OpromRevision = 0;\r
+\r
+  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+  if (Private->Legacy16Table->LastPciBus == 0) {\r
+    //\r
+    // Get last bus number if not already found\r
+    //\r
+    Status = gBS->LocateHandleBuffer (\r
+                    ByProtocol,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    NULL,\r
+                    &HandleCount,\r
+                    &HandleBuffer\r
+                    );\r
+\r
+    LastBus = 0;\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      HandleBuffer[Index],\r
+                      &gEfiPciIoProtocolGuid,\r
+                      (VOID **) &PciIo\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      Status = PciIo->GetLocation (\r
+                        PciIo,\r
+                        &PciSegment,\r
+                        &PciBus,\r
+                        &PciDevice,\r
+                        &PciFunction\r
+                        );\r
+      if (PciBus > LastBus) {\r
+        LastBus = PciBus;\r
+      }\r
+    }\r
+\r
+    Private->LegacyRegion->UnLock (\r
+                             Private->LegacyRegion,\r
+                             0xE0000,\r
+                             0x20000,\r
+                             &Granularity\r
+                             );\r
+    Private->Legacy16Table->LastPciBus = (UINT8) LastBus;\r
+    Private->LegacyRegion->Lock (\r
+                             Private->LegacyRegion,\r
+                             0xE0000,\r
+                             0x20000,\r
+                             &Granularity\r
+                             );\r
+  }\r
+\r
+  *Flags = 0;\r
+  if ((PciHandle != NULL) && (RomImage == NULL)) {\r
+    //\r
+    // If PciHandle has OpRom to Execute \r
+    // and OpRom are all associated with Hardware\r
+    //\r
+    Status = gBS->HandleProtocol (\r
+                    PciHandle,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **) &PciIo\r
+                    );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      PciIo->Pci.Read (\r
+                   PciIo,\r
+                   EfiPciIoWidthUint32,\r
+                   0,\r
+                   sizeof (PciConfigHeader) / sizeof (UINT32),\r
+                   &PciConfigHeader\r
+                   );\r
+\r
+      //\r
+      // if video installed & OPROM is video return\r
+      //\r
+      if (\r
+          (\r
+           ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&\r
+            (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))\r
+           ||\r
+           ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&\r
+            (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))\r
+          )\r
+          &&\r
+          (!Private->VgaInstalled)\r
+         ) {\r
+        mVgaInstallationInProgress = TRUE;\r
+\r
+        //\r
+        //      return EFI_UNSUPPORTED;\r
+        //\r
+      }\r
+    }\r
+    //\r
+    // To run any legacy image, the VGA needs to be installed first.\r
+    // if installing the video, then don't need the thunk as already installed.\r
+    //\r
+    Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
+                                            Private->LegacyBiosPlatform,\r
+                                            EfiGetPlatformVgaHandle,\r
+                                            0,\r
+                                            &HandleBuffer,\r
+                                            &HandleCount,\r
+                                            NULL\r
+                                            );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      mVgaHandle = HandleBuffer[0];\r
+      if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {\r
+        //\r
+        // A return status of EFI_NOT_FOUND is considered valid (No EFI\r
+        // driver is controlling video.\r
+        //\r
+        mVgaInstallationInProgress  = TRUE;\r
+        Status                      = LegacyBiosInstallVgaRom (Private);\r
+        if (EFI_ERROR (Status)) {\r
+          if (Status != EFI_NOT_FOUND) {\r
+            mVgaInstallationInProgress = FALSE;\r
+            return Status;\r
+          }\r
+        } else {\r
+          mVgaInstallationInProgress = FALSE;\r
+        }\r
+      }\r
+    }\r
+    //\r
+    // See if the option ROM for PciHandle has already been executed\r
+    //\r
+    Status = IsLegacyRom (PciHandle);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      mVgaInstallationInProgress = FALSE;\r
+      GetShadowedRomParameters (\r
+        PciHandle,\r
+        DiskStart,\r
+        DiskEnd,\r
+        RomShadowAddress,\r
+        (UINTN *) RomShadowedSize\r
+        );\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Status = LegacyBiosCheckPciRomEx (\r
+               &Private->LegacyBios,\r
+               PciHandle,\r
+               &LocalRomImage,\r
+               &ImageSize,\r
+               &RuntimeImageLength,\r
+               Flags,\r
+               &OpromRevision,\r
+               NULL\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // There is no PCI ROM in the ROM BAR or no onboard ROM\r
+      //\r
+      mVgaInstallationInProgress = FALSE;\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  } else {\r
+    if (*RomImage == NULL) {\r
+      //\r
+      // If PciHandle is NULL, and no OpRom is to be associated\r
+      //\r
+      mVgaInstallationInProgress = FALSE;\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    LocalRomImage = *RomImage;\r
+    Pcir = (PCI_3_0_DATA_STRUCTURE *)\r
+           ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);\r
+    ImageSize = Pcir->ImageLength * 512;\r
+    if (Pcir->Length >= 0x1C) {\r
+      OpromRevision = Pcir->Revision;\r
+    } else {\r
+      OpromRevision = 0;\r
+    }\r
+    if (Pcir->Revision < 3) {\r
+      RuntimeImageLength = 0;\r
+    } else {\r
+      RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;\r
+    }\r
+  }\r
+  //\r
+  // Shadow and initialize the OpROM.\r
+  //\r
+  ASSERT (Private->TraceIndex < 0x200);\r
+  Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;\r
+  Private->TraceIndex ++;\r
+  Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);\r
+  Status = LegacyBiosInstallRom (\r
+             This,\r
+             Private,\r
+             PciHandle,\r
+             OpromRevision,\r
+             LocalRomImage,\r
+             ImageSize,\r
+             &RuntimeImageLength,\r
+             DiskStart,\r
+             DiskEnd,\r
+             RomShadowAddress\r
+             );\r
+  if (RomShadowedSize != NULL) {\r
+    *RomShadowedSize = (UINT32) RuntimeImageLength;\r
+  }\r
+\r
+  mVgaInstallationInProgress = FALSE;\r
+  return Status;\r
+}\r
+\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c
new file mode 100644 (file)
index 0000000..f82121c
--- /dev/null
@@ -0,0 +1,234 @@
+/** @file\r
+  Collect Sio information from Native EFI Drivers.\r
+  Sio is floppy, parallel, serial, ... hardware\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+\r
+\r
+/**\r
+  Collect EFI Info about legacy devices.\r
+\r
+  @param  Private      Legacy BIOS Instance data\r
+\r
+  @retval EFI_SUCCESS  It should always work.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosBuildSioData (\r
+  IN  LEGACY_BIOS_INSTANCE      *Private\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  DEVICE_PRODUCER_DATA_HEADER         *SioPtr;\r
+  DEVICE_PRODUCER_SERIAL              *Sio1Ptr;\r
+  DEVICE_PRODUCER_PARALLEL            *Sio2Ptr;\r
+  DEVICE_PRODUCER_FLOPPY              *Sio3Ptr;\r
+  EFI_HANDLE                          IsaBusController;\r
+  UINTN                               HandleCount;\r
+  EFI_HANDLE                          *HandleBuffer;\r
+  UINTN                               Index;\r
+  UINTN                               ResourceIndex;\r
+  UINTN                               ChildIndex;\r
+  EFI_ISA_IO_PROTOCOL                 *IsaIo;\r
+  EFI_ISA_ACPI_RESOURCE_LIST          *ResourceList;\r
+  EFI_ISA_ACPI_RESOURCE               *IoResource;\r
+  EFI_ISA_ACPI_RESOURCE               *DmaResource;\r
+  EFI_ISA_ACPI_RESOURCE               *InterruptResource;\r
+  UINTN                               EntryCount;\r
+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+  EFI_BLOCK_IO_PROTOCOL               *BlockIo;\r
+\r
+  //\r
+  // Get the pointer to the SIO data structure\r
+  //\r
+  SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData;\r
+\r
+  //\r
+  // Zero the data in the SIO data structure\r
+  //\r
+  gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0);\r
+\r
+  //\r
+  // Find the ISA Bus Controller used for legacy\r
+  //\r
+  Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
+                                          Private->LegacyBiosPlatform,\r
+                                          EfiGetPlatformIsaBusHandle,\r
+                                          0,\r
+                                          &HandleBuffer,\r
+                                          &HandleCount,\r
+                                          NULL\r
+                                          );\r
+  IsaBusController = HandleBuffer[0];\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Force ISA Bus Controller to produce all ISA devices\r
+    //\r
+    gBS->ConnectController (IsaBusController, NULL, NULL, TRUE);\r
+  }\r
+  //\r
+  // Get the list of ISA controllers in the system\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiIsaIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Collect legacy information from each of the ISA controllers in the system\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+\r
+    Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    ResourceList = IsaIo->ResourceList;\r
+\r
+    if (ResourceList == NULL) {\r
+      continue;\r
+    }\r
+    //\r
+    // Collect the resource types neededto fill in the SIO data structure\r
+    //\r
+    IoResource        = NULL;\r
+    DmaResource       = NULL;\r
+    InterruptResource = NULL;\r
+    for (ResourceIndex = 0;\r
+         ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList;\r
+         ResourceIndex++\r
+        ) {\r
+      switch (ResourceList->ResourceItem[ResourceIndex].Type) {\r
+      case EfiIsaAcpiResourceIo:\r
+        IoResource = &ResourceList->ResourceItem[ResourceIndex];\r
+        break;\r
+\r
+      case EfiIsaAcpiResourceMemory:\r
+        break;\r
+\r
+      case EfiIsaAcpiResourceDma:\r
+        DmaResource = &ResourceList->ResourceItem[ResourceIndex];\r
+        break;\r
+\r
+      case EfiIsaAcpiResourceInterrupt:\r
+        InterruptResource = &ResourceList->ResourceItem[ResourceIndex];\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+    }\r
+    //\r
+    // See if this is an ISA serial port\r
+    //\r
+    // Ignore DMA resource since it is always returned NULL\r
+    //\r
+    if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) {\r
+\r
+      if (ResourceList->Device.UID <= 3 &&\r
+          IoResource != NULL &&\r
+          InterruptResource != NULL\r
+          ) {\r
+        //\r
+        // Get the handle of the child device that has opened the ISA I/O Protocol\r
+        //\r
+        Status = gBS->OpenProtocolInformation (\r
+                        HandleBuffer[Index],\r
+                        &gEfiIsaIoProtocolGuid,\r
+                        &OpenInfoBuffer,\r
+                        &EntryCount\r
+                        );\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\r
+        }\r
+        //\r
+        // We want resource for legacy even if no 32-bit driver installed\r
+        //\r
+        for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {\r
+          Sio1Ptr           = &SioPtr->Serial[ResourceList->Device.UID];\r
+          Sio1Ptr->Address  = (UINT16) IoResource->StartRange;\r
+          Sio1Ptr->Irq      = (UINT8) InterruptResource->StartRange;\r
+          Sio1Ptr->Mode     = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;\r
+        }\r
+\r
+        FreePool (OpenInfoBuffer);\r
+      }\r
+    }\r
+    //\r
+    // See if this is an ISA parallel port\r
+    //\r
+    // Ignore DMA resource since it is always returned NULL, port\r
+    // only used in output mode.\r
+    //\r
+    if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) {\r
+      if (ResourceList->Device.UID <= 2 &&\r
+          IoResource != NULL &&\r
+          InterruptResource != NULL &&\r
+          DmaResource != NULL\r
+          ) {\r
+        Sio2Ptr           = &SioPtr->Parallel[ResourceList->Device.UID];\r
+        Sio2Ptr->Address  = (UINT16) IoResource->StartRange;\r
+        Sio2Ptr->Irq      = (UINT8) InterruptResource->StartRange;\r
+        Sio2Ptr->Dma      = (UINT8) DmaResource->StartRange;\r
+        Sio2Ptr->Mode     = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;\r
+      }\r
+    }\r
+    //\r
+    // See if this is an ISA floppy controller\r
+    //\r
+    if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) {\r
+      if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) {\r
+        Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+        if (!EFI_ERROR (Status)) {\r
+          Sio3Ptr           = &SioPtr->Floppy;\r
+          Sio3Ptr->Address  = (UINT16) IoResource->StartRange;\r
+          Sio3Ptr->Irq      = (UINT8) InterruptResource->StartRange;\r
+          Sio3Ptr->Dma      = (UINT8) DmaResource->StartRange;\r
+          Sio3Ptr->NumberOfFloppy++;\r
+        }\r
+      }\r
+    }\r
+    //\r
+    // See if this is a mouse\r
+    // Always set mouse found so USB hot plug will work\r
+    //\r
+    // Ignore lower byte of HID. Pnp0fxx is any type of mouse.\r
+    //\r
+    //    Hid = ResourceList->Device.HID & 0xff00ffff;\r
+    //    PnpId = EISA_PNP_ID(0x0f00);\r
+    //    if (Hid == PnpId) {\r
+    //      if (ResourceList->Device.UID == 1) {\r
+    //        Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);\r
+    //      if (!EFI_ERROR (Status)) {\r
+    //\r
+    SioPtr->MousePresent = 0x01;\r
+    //\r
+    //        }\r
+    //      }\r
+    //    }\r
+    //\r
+  }\r
+\r
+  FreePool (HandleBuffer);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c
new file mode 100644 (file)
index 0000000..c33288a
--- /dev/null
@@ -0,0 +1,284 @@
+/** @file\r
+  Call into 16-bit BIOS code, Use AsmThunk16 function of BaseLib.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "LegacyBiosInterface.h"\r
+\r
+THUNK_CONTEXT      mThunkContext;\r
+\r
+/**\r
+  Thunk to 16-bit real mode and execute a software interrupt with a vector\r
+  of BiosInt. Regs will contain the 16-bit register context on entry and\r
+  exit.\r
+\r
+  @param  This    Protocol instance pointer.\r
+  @param  BiosInt Processor interrupt vector to invoke\r
+  @param  Regs    Register contexted passed into (and returned) from thunk to\r
+                  16-bit mode\r
+\r
+  @retval FALSE   Thunk completed, and there were no BIOS errors in the target code.\r
+                  See Regs for status.\r
+  @retval TRUE    There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LegacyBiosInt86 (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL      *This,\r
+  IN  UINT8                         BiosInt,\r
+  IN  EFI_IA32_REGISTER_SET         *Regs\r
+  )\r
+{\r
+  Regs->X.Flags.Reserved1 = 1;\r
+  Regs->X.Flags.Reserved2 = 0;\r
+  Regs->X.Flags.Reserved3 = 0;\r
+  Regs->X.Flags.Reserved4 = 0;\r
+  Regs->X.Flags.IOPL      = 3;\r
+  Regs->X.Flags.NT        = 0;\r
+  Regs->X.Flags.IF        = 0;\r
+  Regs->X.Flags.TF        = 0;\r
+  Regs->X.Flags.CF        = 0;\r
+\r
+  return InternalLegacyBiosFarCall (\r
+           This,\r
+           (UINT16) (((UINT32 *)NULL)[BiosInt] >> 16),\r
+           (UINT16) ((UINT32 *)NULL)[BiosInt],\r
+           Regs,\r
+           &Regs->X.Flags,\r
+           sizeof (Regs->X.Flags)\r
+           );\r
+}\r
+\r
+/**\r
+  Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the\r
+  16-bit register context on entry and exit. Arguments can be passed on\r
+  the Stack argument\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  Segment                Segemnt of 16-bit mode call\r
+  @param  Offset                 Offset of 16-bit mdoe call\r
+  @param  Regs                   Register contexted passed into (and returned) from\r
+                                 thunk to  16-bit mode\r
+  @param  Stack                  Caller allocated stack used to pass arguments\r
+  @param  StackSize              Size of Stack in bytes\r
+\r
+  @retval FALSE                  Thunk completed, and there were no BIOS errors in\r
+                                 the target code. See Regs for status.\r
+  @retval TRUE                   There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LegacyBiosFarCall86 (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL        *This,\r
+  IN  UINT16                          Segment,\r
+  IN  UINT16                          Offset,\r
+  IN  EFI_IA32_REGISTER_SET           *Regs,\r
+  IN  VOID                            *Stack,\r
+  IN  UINTN                           StackSize\r
+  )\r
+{\r
+  Regs->X.Flags.Reserved1 = 1;\r
+  Regs->X.Flags.Reserved2 = 0;\r
+  Regs->X.Flags.Reserved3 = 0;\r
+  Regs->X.Flags.Reserved4 = 0;\r
+  Regs->X.Flags.IOPL      = 3;\r
+  Regs->X.Flags.NT        = 0;\r
+  Regs->X.Flags.IF        = 1;\r
+  Regs->X.Flags.TF        = 0;\r
+  Regs->X.Flags.CF        = 0;\r
+\r
+  return InternalLegacyBiosFarCall (This, Segment, Offset, Regs, Stack, StackSize);\r
+}\r
+\r
+/**\r
+  Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the\r
+  16-bit register context on entry and exit. Arguments can be passed on\r
+  the Stack argument\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  Segment    Segemnt of 16-bit mode call\r
+  @param  Offset     Offset of 16-bit mdoe call\r
+  @param  Regs       Register contexted passed into (and returned) from thunk to\r
+                     16-bit mode\r
+  @param  Stack      Caller allocated stack used to pass arguments\r
+  @param  StackSize  Size of Stack in bytes\r
+\r
+  @retval FALSE      Thunk completed, and there were no BIOS errors in the target code.\r
+                     See Regs for status.\r
+  @retval TRUE       There was a BIOS erro in the target code.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+InternalLegacyBiosFarCall (\r
+  IN  EFI_LEGACY_BIOS_PROTOCOL        *This,\r
+  IN  UINT16                          Segment,\r
+  IN  UINT16                          Offset,\r
+  IN  EFI_IA32_REGISTER_SET           *Regs,\r
+  IN  VOID                            *Stack,\r
+  IN  UINTN                           StackSize\r
+  )\r
+{\r
+  UINTN                 Status;\r
+  LEGACY_BIOS_INSTANCE  *Private;\r
+  UINT16                *Stack16;\r
+  EFI_TPL               OriginalTpl;\r
+  IA32_REGISTER_SET     ThunkRegSet;\r
+  BOOLEAN               InterruptState;\r
+\r
+  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
+\r
+  ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));\r
+  ThunkRegSet.X.DI   = Regs->X.DI;\r
+  ThunkRegSet.X.SI   = Regs->X.SI;\r
+  ThunkRegSet.X.BP   = Regs->X.BP;\r
+  ThunkRegSet.X.BX   = Regs->X.BX;\r
+  ThunkRegSet.X.DX   = Regs->X.DX;\r
+  //\r
+  // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is\r
+  // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.\r
+  //\r
+  ThunkRegSet.E.ECX   = Regs->E.ECX;\r
+  ThunkRegSet.X.AX   = Regs->X.AX;\r
+  ThunkRegSet.E.DS   = Regs->X.DS;\r
+  ThunkRegSet.E.ES   = Regs->X.ES;\r
+\r
+  CopyMem (&(ThunkRegSet.E.EFLAGS.UintN), &(Regs->X.Flags), sizeof (Regs->X.Flags));\r
+\r
+  //\r
+  // Clear the error flag; thunk code may set it. Stack16 should be the high address\r
+  // Make Statk16 address the low 16 bit must be not zero.\r
+  //\r
+  Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));\r
+\r
+  //\r
+  // Save and disable interrutp of debug timer\r
+  //\r
+  InterruptState = SaveAndSetDebugTimerInterrupt (FALSE);\r
+\r
+  //\r
+  // The call to Legacy16 is a critical section to EFI\r
+  //\r
+  OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+  if (Stack != NULL && StackSize != 0) {\r
+    //\r
+    // Copy Stack to low memory stack\r
+    //\r
+    Stack16 -= StackSize / sizeof (UINT16);\r
+    CopyMem (Stack16, Stack, StackSize);\r
+  }\r
+\r
+  ThunkRegSet.E.SS   = (UINT16) (((UINTN) Stack16 >> 16) << 12);\r
+  ThunkRegSet.E.ESP  = (UINT16) (UINTN) Stack16;\r
+  ThunkRegSet.E.CS   = Segment;\r
+  ThunkRegSet.E.Eip  = Offset;\r
+\r
+  mThunkContext.RealModeState      = &ThunkRegSet;\r
+\r
+  //\r
+  // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.\r
+  //\r
+  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  AsmThunk16 (&mThunkContext);\r
+\r
+  //\r
+  // OPROM may allocate EBDA range by itself and change EBDA base and EBDA size.\r
+  // Get the current EBDA base address, and compared with pre-allocate minimum\r
+  // EBDA base address, if the current EBDA base address is smaller, it indicates\r
+  // PcdEbdaReservedMemorySize should be adjusted to larger for more OPROMs.\r
+  //\r
+  DEBUG_CODE (\r
+    {\r
+      UINTN                 EbdaBaseAddress;\r
+      UINTN                 ReservedEbdaBaseAddress;\r
+\r
+      EbdaBaseAddress = (*(UINT16 *) (UINTN) 0x40E) << 4;\r
+      ReservedEbdaBaseAddress = CONVENTIONAL_MEMORY_TOP - PcdGet32 (PcdEbdaReservedMemorySize);\r
+      ASSERT (ReservedEbdaBaseAddress <= EbdaBaseAddress);\r
+    }\r
+  );\r
+\r
+  if (Stack != NULL && StackSize != 0) {\r
+    //\r
+    // Copy low memory stack to Stack\r
+    //\r
+    CopyMem (Stack, Stack16, StackSize);\r
+  }\r
+\r
+  //\r
+  // Restore protected mode interrupt state\r
+  //\r
+  Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  mThunkContext.RealModeState = NULL;\r
+\r
+  //\r
+  // End critical section\r
+  //\r
+  gBS->RestoreTPL (OriginalTpl);\r
+\r
+  //\r
+  // Restore interrutp of debug timer\r
+  //\r
+  SaveAndSetDebugTimerInterrupt (InterruptState);\r
+\r
+  Regs->E.EDI      = ThunkRegSet.E.EDI;\r
+  Regs->E.ESI      = ThunkRegSet.E.ESI;\r
+  Regs->E.EBP      = ThunkRegSet.E.EBP;\r
+  Regs->E.EBX      = ThunkRegSet.E.EBX;\r
+  Regs->E.EDX      = ThunkRegSet.E.EDX;\r
+  Regs->E.ECX      = ThunkRegSet.E.ECX;\r
+  Regs->E.EAX      = ThunkRegSet.E.EAX;\r
+  Regs->X.SS       = ThunkRegSet.E.SS;\r
+  Regs->X.CS       = ThunkRegSet.E.CS;\r
+  Regs->X.DS       = ThunkRegSet.E.DS;\r
+  Regs->X.ES       = ThunkRegSet.E.ES;\r
+\r
+  CopyMem (&(Regs->X.Flags), &(ThunkRegSet.E.EFLAGS.UintN), sizeof (Regs->X.Flags));\r
+\r
+  return (BOOLEAN) (Regs->X.Flags.CF == 1);\r
+}\r
+\r
+/**\r
+  Allocate memory < 1 MB and copy the thunker code into low memory. Se up\r
+  all the descriptors.\r
+\r
+  @param  Private                Private context for Legacy BIOS\r
+\r
+  @retval EFI_SUCCESS            Should only pass.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBiosInitializeThunk (\r
+  IN  LEGACY_BIOS_INSTANCE    *Private\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS    MemoryAddress;\r
+\r
+  MemoryAddress   = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->IntThunk;\r
+\r
+  mThunkContext.RealModeBuffer     = (VOID *) (UINTN) (MemoryAddress + ((sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE);\r
+  mThunkContext.RealModeBufferSize = EFI_PAGE_SIZE;\r
+  mThunkContext.ThunkAttributes    = THUNK_ATTRIBUTE_BIG_REAL_MODE | THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15;\r
+\r
+  AsmPrepareThunk16 (&mThunkContext);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S
new file mode 100644 (file)
index 0000000..95a0888
--- /dev/null
@@ -0,0 +1,72 @@
+## @file
+#  Interrupt Redirection Template
+#
+# Copyright (c) 2006, 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.
+#
+##
+
+#text SEGMENT
+
+
+#----------------------------------------------------------------------------
+# Procedure:    InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+#
+# Input:        None
+#
+# Output:       None
+#
+# Prototype:    VOID
+#               InterruptRedirectionTemplate (
+#                                VOID
+#                                );
+#
+# Saves:        None
+#
+# Modified:     None
+#
+# Description:  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.
+#
+#----------------------------------------------------------------------------
+
+ASM_GLOBAL ASM_PFX(InterruptRedirectionTemplate)
+ASM_PFX(InterruptRedirectionTemplate):
+  int     $0x08
+  .byte      0x0cf          # IRET
+  nop
+  int     $0x09
+  .byte      0x0cf          # IRET
+  nop
+  int     $0x0a
+  .byte      0x0cf          # IRET
+  nop
+  int     $0x0b
+  .byte      0x0cf          # IRET
+  nop
+  int     $0x0c
+  .byte      0x0cf          # IRET
+  nop
+  int     $0x0d
+  .byte      0x0cf          # IRET
+  nop
+  int     $0x0e
+  .byte      0x0cf          # IRET
+  nop
+  int     $0x0f
+  .byte      0x0cf          # IRET
+  nop
+
+#END
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm
new file mode 100644 (file)
index 0000000..750423e
--- /dev/null
@@ -0,0 +1,71 @@
+;; @file\r
+;  Interrupt Redirection Template\r
+;\r
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+;\r
+; This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions\r
+; of the BSD License which accompanies this distribution.  The\r
+; full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;;\r
+\r
+text SEGMENT\r
+\r
+;----------------------------------------------------------------------------\r
+; Procedure:    InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F \r
+;\r
+; Input:        None\r
+;\r
+; Output:       None\r
+;\r
+; Prototype:    VOID\r
+;               InterruptRedirectionTemplate (  \r
+;                                VOID\r
+;                                );\r
+;\r
+; Saves:        None\r
+;\r
+; Modified:     None\r
+;\r
+; Description:  Contains the code that is copied into low memory (below 640K).\r
+;               This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.\r
+;               This template must be copied into low memory, and the IDT entries\r
+;               0x68-0x6F must be point to the low memory copy of this code.  Each\r
+;               entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily \r
+;               computed.\r
+;\r
+;----------------------------------------------------------------------------\r
+\r
+InterruptRedirectionTemplate PROC\r
+  int     08h\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     09h\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0ah\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0bh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0ch\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0dh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0eh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+  int     0fh\r
+  DB      0cfh          ; IRET\r
+  nop\r
+InterruptRedirectionTemplate ENDP\r
+\r
+END
\ No newline at end of file
diff --git a/IntelFrameworkModulePkg/Include/Guid/LegacyBios.h b/IntelFrameworkModulePkg/Include/Guid/LegacyBios.h
new file mode 100644 (file)
index 0000000..1fcea9c
--- /dev/null
@@ -0,0 +1,36 @@
+/** @file\r
+  Defines a Tag GUID used to mark a UEFI legacy BIOS thunk driver based\r
+  on legacy BIOS services and legacy option ROM. This Tag GUID must be installed on \r
+  the ImageHandle of any module that follows the EFI Driver Model and uses \r
+  the Int86() or FarCall() services of the Legacy Bios Protocol to produce\r
+  a standard UEFI I/O Protocol.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LEGACY_BIOS_H_\r
+#define _LEGACY_BIOS_H_\r
+\r
+///\r
+/// The Global ID for the Legacy BIOS GUID that must be installed onto the ImageHandle \r
+/// of any module follows the EFI Driver Model and uses the Int86() or FarCall() \r
+/// services of the Legacy BIOS Protocol to produce a standard UEFI I/O Protocol.\r
+///\r
+#define EFI_LEGACY_BIOS_GUID \\r
+  { \\r
+    0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \\r
+  }\r
+\r
+extern EFI_GUID gEfiLegacyBiosGuid;\r
+\r
+#endif\r
index 6661eaf9053c0bf732ded1eb866d28b7d6bd39d1..15434893a3b9aa04d8761503cd165a5bb7060ec1 100644 (file)
@@ -56,6 +56,9 @@
   ## Include/Guid/AcpiVariable.h\r
   gEfiAcpiVariableCompatiblityGuid   = { 0xc020489e, 0x6db2, 0x4ef2, { 0x9a, 0xa5, 0xca, 0x6,  0xfc, 0x11, 0xd3, 0x6a }}\r
 \r
+  ## Include/Guid/LegacyBios.h\r
+  gEfiLegacyBiosGuid                 = { 0x2E3044AC, 0x879F, 0x490F, { 0x97, 0x60, 0xBB, 0xDF, 0xAF, 0x69, 0x5F, 0x50 }}\r
+\r
 [Protocols]\r
   ## Vga Mini port binding for a VGA controller\r
   #  Include/Protocol/VgaMiniPort.h\r
   ## This PCD specifies whether Serial device use half hand shake.\r
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010043\r
 \r
+  ## Indicates if CSM support is needed for ACPI S3 Save.\r
+  #  If TRUE, CSM support is enclosed for ACPI S3 Save.\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformCsmSupport|TRUE|BOOLEAN|0x00010044\r
+\r
 [PcdsFixedAtBuild]\r
   ## FFS filename to find the default BMP Logo file.\r
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile |{ 0x99, 0x8b, 0xB2, 0x7B, 0xBB, 0x61, 0xD5, 0x11, 0x9A, 0x5D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }|VOID*|0x40000003\r
   #  This PCD should be set as HII type PCD by platform integrator mapped to variable L"HwErrRecSupport"\r
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|0|UINT16|0x40000002\r
 \r
-\r
 [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx, PcdsPatchableInModule]\r
   ## I/O Base address of floppy device controller.\r
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdFdcBaseAddress|0x3f0|UINT16|0x30000000\r
 \r
+  ## If TRUE, BiosVideo will switch to 80x25 Text VGA Mode when exiting boot service.\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoSetTextVgaModeEnable|FALSE|BOOLEAN|0x30000001\r
+\r
+  ## If TRUE, BiosVideo will check for VESA BIOS Extension service support.\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVbeEnable|TRUE|BOOLEAN|0x30000002\r
+\r
+  ## If TRUE, BiosVideo will check for VGA service support.\r
+  #  NOTE: If both PcdBiosVideoCheckVbeEnable and PcdBiosVideoCheckVgaEnable are set to FALSE,\r
+  #  that means Graphics Output protocol will not be installed, the VGA miniport protocol will be installed instead.\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVgaEnable|TRUE|BOOLEAN|0x30000003\r
+\r
+  ## If TRUE, memory space for legacy region will be set as cacheable.\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion|TRUE|BOOLEAN|0x00000004\r
+\r
+  ## The PCD is used to specify memory size with bytes to reserve EBDA for OPROM.\r
+  ## The value should be a multiple of 4KB.\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize|0x8000|UINT32|0x30000005\r
+\r
index fd2898e25935891546041b8e841fedba62f1fedd..f986b4880b75af20d29f90aaef159c58439608fa 100644 (file)
   0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.\r
 \r
 [LibraryClasses]\r
+  CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf\r
+  DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf\r
   DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf\r
   DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf  \r
   BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
   SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf\r
   BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf\r
+  IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf\r
   PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf\r
   PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf\r
   TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r
@@ -55,6 +58,8 @@
   HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf\r
   PlatformBdsLib|IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf\r
   CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf\r
+  PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf\r
+  PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf\r
   PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf\r
   DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf\r
   ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf\r
   IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.inf\r
   IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortDxe.inf\r
 \r
+  IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf\r
+  IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf\r
+  IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf\r
+  IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf\r
+\r
   IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf\r
   IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf\r
   IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.inf\r
   IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf\r
   IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf\r
   IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf\r
+\r
+[Components.IA32,Components.X64,Components.IPF]\r
+  IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf\r
   \r
 [Components.IA32]\r
   IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf\r