summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-27 23:32:56 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-27 23:32:56 +0000
commitbcecde140a561c64e297225904afebebd62336ce (patch)
tree5f6333ccb04d851d151970e5dee6c9d8ac7ade71
parenta7a0f78bd6fa1fe4684bf6de2b3e5ed5d9b5bf1c (diff)
downloadedk2-bcecde140a561c64e297225904afebebd62336ce.zip
edk2-bcecde140a561c64e297225904afebebd62336ce.tar.gz
edk2-bcecde140a561c64e297225904afebebd62336ce.tar.bz2
IntelFrameworkModulePkg: Add Compatibility Support Module (CSM) drivers
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
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c782
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h439
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c1485
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf58
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c309
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h209
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c2365
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h744
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c183
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h153
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf68
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c3507
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h1655
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c309
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c956
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h613
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c1254
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf67
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c3164
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h532
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c313
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h451
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf80
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S67
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm73
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c277
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h102
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i89
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s524
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c550
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c384
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c66
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c1007
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf143
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h1501
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c2032
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c124
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c300
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c2901
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c234
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c284
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S72
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm71
-rw-r--r--IntelFrameworkModulePkg/Include/Guid/LegacyBios.h36
-rw-r--r--IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec26
-rw-r--r--IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc13
46 files changed, 30571 insertions, 1 deletions
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
new file mode 100644
index 0000000..309cf1a
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
@@ -0,0 +1,782 @@
+/** @file
+ EFI glue for BIOS INT 13h block devices.
+
+ This file is coded to EDD 3.0 as defined by T13 D1386 Revision 4
+ Availible on http://www.t13.org/#Project drafts
+ Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r4.pdf
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosBlkIo.h"
+
+//
+// Global data declaration
+//
+//
+// EFI Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding = {
+ BiosBlockIoDriverBindingSupported,
+ BiosBlockIoDriverBindingStart,
+ BiosBlockIoDriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+//
+// Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb
+//
+EFI_LOCK mGlobalDataLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION);
+
+//
+// Number of active instances of this protocol. This is used to allocate/free
+// the shared buffer. You must acquire the semaphore to modify.
+//
+UINTN mActiveInstances = 0;
+
+//
+// Pointer to the beginning of the buffer used for real mode thunk
+// You must acquire the semaphore to modify.
+//
+EFI_PHYSICAL_ADDRESS mBufferUnder1Mb = 0;
+
+//
+// Address packet is a buffer under 1 MB for all version EDD calls
+//
+EDD_DEVICE_ADDRESS_PACKET *mEddBufferUnder1Mb;
+
+//
+// This is a buffer for INT 13h func 48 information
+//
+BIOS_LEGACY_DRIVE *mLegacyDriverUnder1Mb;
+
+//
+// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
+// 0xFE00 bytes is the max transfer size supported.
+//
+VOID *mEdd11Buffer;
+
+EFI_GUID mUnknownDevGuid = UNKNOWN_DEVICE_GUID;
+
+/**
+ Driver entry point.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Entrypoint successfully executed.
+ @retval Others Fail to execute entrypoint.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install protocols
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosBlockIoDriverBinding,
+ ImageHandle,
+ &gBiosBlockIoComponentName,
+ &gBiosBlockIoComponentName2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
+ //
+ return gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ NULL
+ );
+}
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ PCI_TYPE00 Pci;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // See if this is a PCI VGA Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE ||
+ (Pci.Hdr.ClassCode[2] == PCI_BASE_CLASS_INTELLIGENT && Pci.Hdr.ClassCode[1] == PCI_SUB_CLASS_INTELLIGENT)
+ ) {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 DiskStart;
+ UINT8 DiskEnd;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate;
+ EFI_DEVICE_PATH_PROTOCOL *PciDevPath;
+ UINTN Index;
+ UINTN Flags;
+ UINTN TmpAddress;
+ BOOLEAN DeviceEnable;
+
+ //
+ // Initialize variables
+ //
+ PciIo = NULL;
+ PciDevPath = NULL;
+
+ DeviceEnable = FALSE;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &PciDevPath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ DeviceEnable = TRUE;
+
+ //
+ // Check to see if there is a legacy option ROM image associated with this PCI device
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Post the legacy option ROM if it is available.
+ //
+ Status = LegacyBios->InstallPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ &Flags,
+ &DiskStart,
+ &DiskEnd,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // All instances share a buffer under 1MB to put real mode thunk code in
+ // If it has not been allocated, then we allocate it.
+ //
+ if (mBufferUnder1Mb == 0) {
+ //
+ // Should only be here if there are no active instances
+ //
+ ASSERT (mActiveInstances == 0);
+
+ //
+ // Acquire the lock
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+
+ //
+ // Allocate below 1MB
+ //
+ mBufferUnder1Mb = 0x00000000000FFFFF;
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, BLOCK_IO_BUFFER_PAGE_SIZE, &mBufferUnder1Mb);
+
+ //
+ // Release the lock
+ //
+ EfiReleaseLock (&mGlobalDataLock);
+
+ //
+ // Check memory allocation success
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // In checked builds we want to assert if the allocate failed.
+ //
+ ASSERT_EFI_ERROR (Status);
+ Status = EFI_OUT_OF_RESOURCES;
+ mBufferUnder1Mb = 0;
+ goto Error;
+ }
+
+ TmpAddress = (UINTN) mBufferUnder1Mb;
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mEdd11Buffer = (VOID *) ALIGN_VARIABLE (TmpAddress);
+
+ TmpAddress = (UINTN) mEdd11Buffer + MAX_EDD11_XFER;
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mLegacyDriverUnder1Mb = (BIOS_LEGACY_DRIVE *) ALIGN_VARIABLE (TmpAddress);
+
+ TmpAddress = (UINTN) mLegacyDriverUnder1Mb + sizeof (BIOS_LEGACY_DRIVE);
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mEddBufferUnder1Mb = (EDD_DEVICE_ADDRESS_PACKET *) ALIGN_VARIABLE (TmpAddress);
+ }
+ //
+ // Allocate the private device structure for each disk
+ //
+ for (Index = DiskStart; Index < DiskEnd; Index++) {
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (BIOS_BLOCK_IO_DEV),
+ (VOID **) &BiosBlockIoPrivate
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Zero the private device structure
+ //
+ ZeroMem (BiosBlockIoPrivate, sizeof (BIOS_BLOCK_IO_DEV));
+
+ //
+ // Initialize the private device structure
+ //
+ BiosBlockIoPrivate->Signature = BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE;
+ BiosBlockIoPrivate->ControllerHandle = Controller;
+ BiosBlockIoPrivate->LegacyBios = LegacyBios;
+ BiosBlockIoPrivate->PciIo = PciIo;
+
+ BiosBlockIoPrivate->Bios.Floppy = FALSE;
+ BiosBlockIoPrivate->Bios.Number = (UINT8) Index;
+ BiosBlockIoPrivate->Bios.Letter = (UINT8) (Index - 0x80 + 'C');
+ BiosBlockIoPrivate->BlockMedia.RemovableMedia = FALSE;
+
+ if (BiosInitBlockIo (BiosBlockIoPrivate)) {
+ SetBiosInitBlockIoDevicePath (PciDevPath, &BiosBlockIoPrivate->Bios, &BiosBlockIoPrivate->DevicePath);
+
+ //
+ // Install the Block Io Protocol onto a new child handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BiosBlockIoPrivate->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &BiosBlockIoPrivate->BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ BiosBlockIoPrivate->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &BiosBlockIoPrivate->PciIo,
+ This->DriverBindingHandle,
+ BiosBlockIoPrivate->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ } else {
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+ }
+
+Error:
+ if (EFI_ERROR (Status)) {
+ if (PciIo != NULL) {
+ if (DeviceEnable) {
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (PciDevPath != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ if (mBufferUnder1Mb != 0 && mActiveInstances == 0) {
+ gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
+
+ //
+ // Clear the buffer back to 0
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mBufferUnder1Mb = 0;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+ }
+ } else {
+ //
+ // Successfully installed, so increment the number of active instances
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mActiveInstances++;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ return Status;
+}
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate;
+ UINTN Index;
+
+ //
+ // Decrement the number of active instances
+ //
+ if (mActiveInstances != 0) {
+ //
+ // Add a check since the stop function will be called 2 times for each handle
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mActiveInstances--;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ if ((mActiveInstances == 0) && (mBufferUnder1Mb != 0)) {
+ //
+ // Free our global buffer
+ //
+ Status = gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
+ ASSERT_EFI_ERROR (Status);
+
+ EfiAcquireLock (&mGlobalDataLock);
+ mBufferUnder1Mb = 0;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BiosBlockIoPrivate = BIOS_BLOCK_IO_FROM_THIS (BlockIo);
+
+ //
+ // Release PCI I/O and Block IO Protocols on the clild handle.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ &BiosBlockIoPrivate->BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ BiosBlockIoPrivate->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ //
+ // Shutdown the hardware
+ //
+ BiosBlockIoPrivate->PciIo->Attributes (
+ BiosBlockIoPrivate->PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build device path for device.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+**/
+VOID
+SetBiosInitBlockIoDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UNKNOWN_DEVICE_VENDOR_DEVICE_PATH VendorNode;
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // BugBug: Check for memory leaks!
+ //
+ if (Drive->EddVersion == EDD_VERSION_30) {
+ //
+ // EDD 3.0 case.
+ //
+ Status = BuildEdd30DevicePath (BaseDevicePath, Drive, DevicePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // EDD 1.1 device case or it is unrecognized EDD 3.0 device
+ //
+ ZeroMem (&VendorNode, sizeof (VendorNode));
+ VendorNode.DevicePath.Header.Type = HARDWARE_DEVICE_PATH;
+ VendorNode.DevicePath.Header.SubType = HW_VENDOR_DP;
+ SetDevicePathNodeLength (&VendorNode.DevicePath.Header, sizeof (VendorNode));
+ CopyMem (&VendorNode.DevicePath.Guid, &mUnknownDevGuid, sizeof (EFI_GUID));
+ VendorNode.LegacyDriveLetter = Drive->Number;
+ *DevicePath = AppendDevicePathNode (BaseDevicePath, &VendorNode.DevicePath.Header);
+ }
+}
+
+/**
+ Build device path for EDD 3.0.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+ @retval EFI_SUCCESS The device path is built successfully.
+ @retval EFI_UNSUPPORTED It is failed to built device path.
+
+**/
+EFI_STATUS
+BuildEdd30DevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ //
+ // AVL UINT64 Address;
+ // AVL EFI_HANDLE Handle;
+ //
+ EFI_DEV_PATH Node;
+ UINT32 Controller;
+
+ Controller = (UINT32) Drive->Parameters.InterfacePath.Pci.Controller;
+
+ ZeroMem (&Node, sizeof (Node));
+ if ((AsciiStrnCmp ("ATAPI", Drive->Parameters.InterfaceType, 5) == 0) ||
+ (AsciiStrnCmp ("ATA", Drive->Parameters.InterfaceType, 3) == 0)
+ ) {
+ //
+ // ATA or ATAPI drive found
+ //
+ Node.Atapi.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Atapi.Header.SubType = MSG_ATAPI_DP;
+ SetDevicePathNodeLength (&Node.Atapi.Header, sizeof (ATAPI_DEVICE_PATH));
+ Node.Atapi.SlaveMaster = Drive->Parameters.DevicePath.Atapi.Master;
+ Node.Atapi.Lun = Drive->Parameters.DevicePath.Atapi.Lun;
+ Node.Atapi.PrimarySecondary = (UINT8) Controller;
+ } else {
+ //
+ // Not an ATA/ATAPI drive
+ //
+ if (Controller != 0) {
+ ZeroMem (&Node, sizeof (Node));
+ Node.Controller.Header.Type = HARDWARE_DEVICE_PATH;
+ Node.Controller.Header.SubType = HW_CONTROLLER_DP;
+ SetDevicePathNodeLength (&Node.Controller.Header, sizeof (CONTROLLER_DEVICE_PATH));
+ Node.Controller.ControllerNumber = Controller;
+ *DevicePath = AppendDevicePathNode (*DevicePath, &Node.DevPath);
+ }
+
+ ZeroMem (&Node, sizeof (Node));
+
+ if (AsciiStrnCmp ("SCSI", Drive->Parameters.InterfaceType, 4) == 0) {
+ //
+ // SCSI drive
+ //
+ Node.Scsi.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Scsi.Header.SubType = MSG_SCSI_DP;
+ SetDevicePathNodeLength (&Node.Scsi.Header, sizeof (SCSI_DEVICE_PATH));
+
+ //
+ // Lun is miss aligned in both EDD and Device Path data structures.
+ // thus we do a byte copy, to prevent alignment traps on IA-64.
+ //
+ CopyMem (&Node.Scsi.Lun, &Drive->Parameters.DevicePath.Scsi.Lun, sizeof (UINT16));
+ Node.Scsi.Pun = Drive->Parameters.DevicePath.Scsi.Pun;
+
+ } else if (AsciiStrnCmp ("USB", Drive->Parameters.InterfaceType, 3) == 0) {
+ //
+ // USB drive
+ //
+ Node.Usb.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Usb.Header.SubType = MSG_USB_DP;
+ SetDevicePathNodeLength (&Node.Usb.Header, sizeof (USB_DEVICE_PATH));
+ Node.Usb.ParentPortNumber = (UINT8) Drive->Parameters.DevicePath.Usb.Reserved;
+
+ } else if (AsciiStrnCmp ("1394", Drive->Parameters.InterfaceType, 4) == 0) {
+ //
+ // 1394 drive
+ //
+ Node.F1394.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.F1394.Header.SubType = MSG_1394_DP;
+ SetDevicePathNodeLength (&Node.F1394.Header, sizeof (F1394_DEVICE_PATH));
+ Node.F1394.Guid = Drive->Parameters.DevicePath.FireWire.Guid;
+
+ } else if (AsciiStrnCmp ("FIBRE", Drive->Parameters.InterfaceType, 5) == 0) {
+ //
+ // Fibre drive
+ //
+ Node.FibreChannel.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.FibreChannel.Header.SubType = MSG_FIBRECHANNEL_DP;
+ SetDevicePathNodeLength (&Node.FibreChannel.Header, sizeof (FIBRECHANNEL_DEVICE_PATH));
+ Node.FibreChannel.WWN = Drive->Parameters.DevicePath.FibreChannel.Wwn;
+ Node.FibreChannel.Lun = Drive->Parameters.DevicePath.FibreChannel.Lun;
+
+ } else {
+ DEBUG (
+ (
+ DEBUG_BLKIO, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n",
+ Drive->Number,
+ Drive->Parameters.InterfaceType
+ )
+ );
+ }
+ }
+
+ if (Node.DevPath.Type == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *DevicePath = AppendDevicePathNode (BaseDevicePath, &Node.DevPath);
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h
new file mode 100644
index 0000000..de3c8d3
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h
@@ -0,0 +1,439 @@
+/** @file
+
+Copyright (c) 1999 - 2010, 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.
+
+**/
+
+#ifndef _BIOS_BLOCK_IO_H_
+#define _BIOS_BLOCK_IO_H_
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/DevicePath.h>
+#include <Guid/LegacyBios.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include "Edd.h"
+
+#define UNKNOWN_DEVICE_GUID \
+ { 0xcf31fac5, 0xc24e, 0x11d2, {0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} }
+
+typedef struct {
+ VENDOR_DEVICE_PATH DevicePath;
+ UINT8 LegacyDriveLetter;
+} UNKNOWN_DEVICE_VENDOR_DEVICE_PATH;
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosBlockIoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosBlockIoComponentName2;
+
+
+//
+// Define the I2O class code
+//
+#define PCI_BASE_CLASS_INTELLIGENT 0x0e
+#define PCI_SUB_CLASS_INTELLIGENT 0x00
+
+//
+// Number of pages needed for our buffer under 1MB
+//
+#define BLOCK_IO_BUFFER_PAGE_SIZE (((sizeof (EDD_DEVICE_ADDRESS_PACKET) + sizeof (BIOS_LEGACY_DRIVE) + MAX_EDD11_XFER) / EFI_PAGE_SIZE) + 1 \
+ )
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Other internal functions
+//
+
+/**
+ Build device path for EDD 3.0.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+ @retval EFI_SUCCESS The device path is built successfully.
+ @retval EFI_UNSUPPORTED It is failed to built device path.
+
+**/
+EFI_STATUS
+BuildEdd30DevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Initialize block I/O device instance
+
+ @param Dev Instance of block I/O device instance
+
+ @retval TRUE Initialization succeeds.
+ @retval FALSE Initialization fails.
+
+**/
+BOOLEAN
+BiosInitBlockIo (
+ IN BIOS_BLOCK_IO_DEV *Dev
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosReadLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosWriteLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Gets parameters of block I/O device.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of device parameter retrieval.
+
+**/
+UINTN
+Int13GetDeviceParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ );
+
+/**
+ Extension of INT13 call.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of this extension.
+
+**/
+UINTN
+Int13Extensions (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ );
+
+/**
+ Gets parameters of legacy drive.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of drive parameter retrieval.
+
+**/
+UINTN
+GetDriveParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ );
+
+/**
+ Build device path for device.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+**/
+VOID
+SetBiosInitBlockIoDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c
new file mode 100644
index 0000000..c53490b
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c
@@ -0,0 +1,1485 @@
+/** @file
+ Routines that use BIOS to support INT 13 devices.
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosBlkIo.h"
+
+//
+// Module global variables
+//
+//
+// Address packet is a buffer under 1 MB for all version EDD calls
+//
+extern EDD_DEVICE_ADDRESS_PACKET *mEddBufferUnder1Mb;
+
+//
+// This is a buffer for INT 13h func 48 information
+//
+extern BIOS_LEGACY_DRIVE *mLegacyDriverUnder1Mb;
+
+//
+// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
+// 0xFE00 bytes is the max transfer size supported.
+//
+extern VOID *mEdd11Buffer;
+
+
+/**
+ Initialize block I/O device instance
+
+ @param Dev Instance of block I/O device instance
+
+ @retval TRUE Initialization succeeds.
+ @retval FALSE Initialization fails.
+
+**/
+BOOLEAN
+BiosInitBlockIo (
+ IN BIOS_BLOCK_IO_DEV *Dev
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO_MEDIA *BlockMedia;
+ BIOS_LEGACY_DRIVE *Bios;
+
+ BlockIo = &Dev->BlockIo;
+ BlockIo->Media = &Dev->BlockMedia;
+ BlockMedia = BlockIo->Media;
+ Bios = &Dev->Bios;
+
+ if (Int13GetDeviceParameters (Dev, Bios) != 0) {
+ if (Int13Extensions (Dev, Bios) != 0) {
+ BlockMedia->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ BlockMedia->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+
+ if ((Bios->Parameters.Flags & EDD_DEVICE_REMOVABLE) == EDD_DEVICE_REMOVABLE) {
+ BlockMedia->RemovableMedia = TRUE;
+ }
+
+ } else {
+ //
+ // Legacy Interfaces
+ //
+ BlockMedia->BlockSize = 512;
+ BlockMedia->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
+ }
+
+ DEBUG ((DEBUG_INIT, "BlockSize = %d LastBlock = %d\n", BlockMedia->BlockSize, BlockMedia->LastBlock));
+
+ BlockMedia->LogicalPartition = FALSE;
+ BlockMedia->WriteCaching = FALSE;
+
+ //
+ // BugBug: Need to set this for removable media devices if they do not
+ // have media present
+ //
+ BlockMedia->ReadOnly = FALSE;
+ BlockMedia->MediaPresent = TRUE;
+
+ BlockIo->Reset = BiosBlockIoReset;
+ BlockIo->FlushBlocks = BiosBlockIoFlushBlocks;
+
+ if (!Bios->ExtendedInt13) {
+ //
+ // Legacy interfaces
+ //
+ BlockIo->ReadBlocks = BiosReadLegacyDrive;
+ BlockIo->WriteBlocks = BiosWriteLegacyDrive;
+ } else if ((Bios->EddVersion == EDD_VERSION_30) && (Bios->Extensions64Bit)) {
+ //
+ // EDD 3.0 Required for Device path, but extended reads are not required.
+ //
+ BlockIo->ReadBlocks = Edd30BiosReadBlocks;
+ BlockIo->WriteBlocks = Edd30BiosWriteBlocks;
+ } else {
+ //
+ // Assume EDD 1.1 - Read and Write functions.
+ // This could be EDD 3.0 without Extensions64Bit being set.
+ // If it's EDD 1.1 this will work, but the device path will not
+ // be correct. This will cause confusion to EFI OS installation.
+ //
+ BlockIo->ReadBlocks = Edd11BiosReadBlocks;
+ BlockIo->WriteBlocks = Edd11BiosWriteBlocks;
+ }
+
+ BlockMedia->LogicalPartition = FALSE;
+ BlockMedia->WriteCaching = FALSE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Gets parameters of block I/O device.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of device parameter retrieval.
+
+**/
+UINTN
+Int13GetDeviceParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ )
+{
+ UINTN CarryFlag;
+ UINT16 Cylinder;
+ EFI_IA32_REGISTER_SET Regs;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x08;
+ Regs.H.DL = Drive->Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "Int13GetDeviceParameters: INT 13 08 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
+ if (CarryFlag != 0 || Regs.H.AH != 0x00) {
+ Drive->ErrorCode = Regs.H.AH;
+ return FALSE;
+ }
+
+ if (Drive->Floppy) {
+ if (Regs.H.BL == 0x10) {
+ Drive->AtapiFloppy = TRUE;
+ } else {
+ Drive->MaxHead = Regs.H.DH;
+ Drive->MaxSector = Regs.H.CL;
+ Drive->MaxCylinder = Regs.H.CH;
+ if (Drive->MaxSector == 0) {
+ //
+ // BugBug: You can not trust the Carry flag.
+ //
+ return FALSE;
+ }
+ }
+ } else {
+ Drive->MaxHead = (UINT8) (Regs.H.DH & 0x3f);
+ Cylinder = (UINT16) (((UINT16) Regs.H.DH & 0xc0) << 4);
+ Cylinder = (UINT16) (Cylinder | ((UINT16) Regs.H.CL & 0xc0) << 2);
+ Drive->MaxCylinder = (UINT16) (Cylinder + Regs.H.CH);
+ Drive->MaxSector = (UINT8) (Regs.H.CL & 0x3f);
+ }
+
+ return TRUE;
+}
+
+/**
+ Extension of INT13 call.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of this extension.
+
+**/
+UINTN
+Int13Extensions (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ )
+{
+ INTN CarryFlag;
+ EFI_IA32_REGISTER_SET Regs;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x41;
+ Regs.X.BX = 0x55aa;
+ Regs.H.DL = Drive->Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "Int13Extensions: INT 13 41 DL=%02x : CF=%d BX=%04x\n", Drive->Number, CarryFlag, Regs.X.BX));
+ if (CarryFlag != 0 || Regs.X.BX != 0xaa55) {
+ Drive->ExtendedInt13 = FALSE;
+ Drive->DriveLockingAndEjecting = FALSE;
+ Drive->Edd = FALSE;
+ return FALSE;
+ }
+
+ Drive->EddVersion = Regs.H.AH;
+ Drive->ExtendedInt13 = (BOOLEAN) ((Regs.X.CX & 0x01) == 0x01);
+ Drive->DriveLockingAndEjecting = (BOOLEAN) ((Regs.X.CX & 0x02) == 0x02);
+ Drive->Edd = (BOOLEAN) ((Regs.X.CX & 0x04) == 0x04);
+ Drive->Extensions64Bit = (BOOLEAN) (Regs.X.CX & 0x08);
+
+ Drive->ParametersValid = (UINT8) GetDriveParameters (BiosBlockIoDev, Drive);
+ return TRUE;
+}
+
+/**
+ Gets parameters of legacy drive.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of drive parameter retrieval.
+
+**/
+UINTN
+GetDriveParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ )
+{
+ INTN CarryFlag;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN PointerMath;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x48;
+ Regs.H.DL = Drive->Number;
+
+ //
+ // EDD Buffer must be passed in with max buffer size as first entry in the buffer
+ //
+ mLegacyDriverUnder1Mb->Parameters.StructureSize = (UINT16) sizeof (EDD_DRIVE_PARAMETERS);
+ Regs.X.DS = EFI_SEGMENT ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
+ Regs.X.SI = EFI_OFFSET ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
+ if (CarryFlag != 0 || Regs.H.AH != 0x00) {
+ Drive->ErrorCode = Regs.H.AH;
+ SetMem (&Drive->Parameters, sizeof (Drive->Parameters), 0xaf);
+ return FALSE;
+ }
+ //
+ // We only have one buffer < 1MB, so copy into our instance data
+ //
+ CopyMem (
+ &Drive->Parameters,
+ &mLegacyDriverUnder1Mb->Parameters,
+ sizeof (Drive->Parameters)
+ );
+
+ if (Drive->AtapiFloppy) {
+ //
+ // Sense Media Type
+ //
+ Regs.H.AH = 0x20;
+ Regs.H.DL = Drive->Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n", Drive->Number, CarryFlag, Regs.H.AL));
+ if (CarryFlag != 0) {
+ //
+ // Media not present or unknown media present
+ //
+ if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
+ Drive->MaxHead = (UINT8) (Drive->Parameters.MaxHeads - 1);
+ Drive->MaxSector = (UINT8) Drive->Parameters.SectorsPerTrack;
+ ASSERT (Drive->MaxSector != 0);
+ Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
+ } else {
+ Drive->MaxHead = 0;
+ Drive->MaxSector = 1;
+ Drive->MaxCylinder = 0;
+ }
+
+ } else {
+ //
+ // Media Present
+ //
+ switch (Regs.H.AL) {
+ case 0x03:
+ //
+ // 720 KB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 9;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x04:
+ //
+ // 1.44MB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 18;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x06:
+ //
+ // 2.88MB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 36;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x0C:
+ //
+ // 360 KB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 9;
+ Drive->MaxCylinder = 39;
+ break;
+
+ case 0x0D:
+ //
+ // 1.2 MB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 15;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x0E:
+ //
+ // Toshiba 3 mode
+ //
+ case 0x0F:
+ //
+ // NEC 3 mode
+ //
+ case 0x10:
+ //
+ // Default Media
+ //
+ if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
+ Drive->MaxHead = (UINT8) (Drive->Parameters.MaxHeads - 1);
+ Drive->MaxSector = (UINT8) Drive->Parameters.SectorsPerTrack;
+ ASSERT (Drive->MaxSector != 0);
+ Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
+ } else {
+ Drive->MaxHead = 0;
+ Drive->MaxSector = 1;
+ Drive->MaxCylinder = 0;
+ }
+ break;
+
+ default:
+ //
+ // Unknown media type.
+ //
+ Drive->MaxHead = 0;
+ Drive->MaxSector = 1;
+ Drive->MaxCylinder = 0;
+ break;
+ }
+ }
+
+ Drive->Parameters.PhysicalSectors = (Drive->MaxHead + 1) * Drive->MaxSector * (Drive->MaxCylinder + 1);
+ Drive->Parameters.BytesPerSector = 512;
+ }
+ //
+ // This data comes from the BIOS so it may not allways be valid
+ // since the BIOS may reuse this buffer for future accesses
+ //
+ PointerMath = EFI_SEGMENT (Drive->Parameters.Fdpt) << 4;
+ PointerMath += EFI_OFFSET (Drive->Parameters.Fdpt);
+ Drive->FdptPointer = (VOID *) PointerMath;
+
+ return TRUE;
+}
+//
+// Block IO Routines
+//
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ AddressPacket->SegOffset = 0xffffffff;
+ AddressPacket->Lba = (UINT64) Lba;
+ AddressPacket->TransferBuffer = TransferBuffer;
+
+ Regs.H.AH = 0x42;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ BufferSize = BufferSize - TransferByteSize;
+ TransferBuffer += TransferByteSize;
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ AddressPacket->SegOffset = 0xffffffff;
+ AddressPacket->Lba = (UINT64) Lba;
+ AddressPacket->TransferBuffer = TransferBuffer;
+
+ Regs.H.AH = 0x43;
+ Regs.H.AL = 0x00;
+ //
+ // Write Verify Off
+ //
+ Regs.H.DL = (UINT8) (BiosBlockIoDev->Bios.Number);
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
+ Media->ReadOnly = TRUE;
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Media->ReadOnly = FALSE;
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ BufferSize = BufferSize - TransferByteSize;
+ TransferBuffer += TransferByteSize;
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN CarryFlag;
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x00;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
+ Regs.H.AH
+ )
+ );
+ if (CarryFlag != 0) {
+ if (Regs.H.AL == BIOS_RESET_FAILED) {
+ Regs.H.AH = 0x00;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
+ Regs.H.AH
+ )
+ );
+ if (CarryFlag != 0) {
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+//
+//
+// These functions need to double buffer all data under 1MB!
+//
+//
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) mEdd11Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ AddressPacket->SegOffset = EFI_SEGMENT (TransferBuffer) << 16;
+ AddressPacket->SegOffset |= EFI_OFFSET (TransferBuffer);
+ AddressPacket->Lba = (UINT64) Lba;
+
+ Regs.H.AH = 0x42;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx Block(s) %0d \n",
+ BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
+ )
+ );
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem (Buffer, (VOID *) (UINTN) TransferBuffer, TransferByteSize);
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) mEdd11Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ AddressPacket->SegOffset = EFI_SEGMENT (TransferBuffer) << 16;
+ AddressPacket->SegOffset |= EFI_OFFSET (TransferBuffer);
+ AddressPacket->Lba = (UINT64) Lba;
+
+ Regs.H.AH = 0x43;
+ Regs.H.AL = 0x00;
+ //
+ // Write Verify disable
+ //
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem ((VOID *) (UINTN) TransferBuffer, Buffer, TransferByteSize);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx Block(s) %0d \n",
+ BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
+ )
+ );
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
+ Media->ReadOnly = TRUE;
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Media->ReadOnly = FALSE;
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosReadLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN UpperCylinder;
+ UINTN Temp;
+ UINTN Cylinder;
+ UINTN Head;
+ UINTN Sector;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN ShortLba;
+ UINTN CheckLba;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN Retry;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ ShortLba = (UINTN) Lba;
+
+ while (BufferSize != 0) {
+ //
+ // Compute I/O location in Sector, Head, Cylinder format
+ //
+ Sector = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
+ Temp = ShortLba / BiosBlockIoDev->Bios.MaxSector;
+ Head = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
+ Cylinder = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
+
+ //
+ // Limit transfer to this Head & Cylinder
+ //
+ NumberOfBlocks = BufferSize / BlockSize;
+ Temp = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
+ NumberOfBlocks = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
+
+ Retry = 3;
+ do {
+ //
+ // Perform the IO
+ //
+ Regs.H.AH = 2;
+ Regs.H.AL = (UINT8) NumberOfBlocks;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+
+ UpperCylinder = (Cylinder & 0x0f00) >> 2;
+
+ CheckLba = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
+ CheckLba = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
+ ShortLba,
+ CheckLba,
+ Sector,
+ BiosBlockIoDev->Bios.MaxSector,
+ Head,
+ BiosBlockIoDev->Bios.MaxHead,
+ Cylinder,
+ UpperCylinder)
+ );
+ ASSERT (CheckLba == ShortLba);
+
+ Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
+ Regs.H.DH = (UINT8) (Head & 0x3f);
+ Regs.H.CH = (UINT8) (Cylinder & 0xff);
+
+ Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
+ Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
+ Regs.H.AL,
+ (UINT8) (Head & 0x3f),
+ Regs.H.DL,
+ (UINT8) (Cylinder & 0xff),
+ (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
+ EFI_OFFSET (mEdd11Buffer),
+ EFI_SEGMENT (mEdd11Buffer))
+ );
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+ Retry--;
+ } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ //
+ // If the size of the media changed we need to reset the disk geometry
+ //
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ //
+ // Legacy Interfaces
+ //
+ Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
+ Media->BlockSize = 512;
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem (Buffer, mEdd11Buffer, TransferByteSize);
+
+ ShortLba = ShortLba + NumberOfBlocks;
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosWriteLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN UpperCylinder;
+ UINTN Temp;
+ UINTN Cylinder;
+ UINTN Head;
+ UINTN Sector;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN ShortLba;
+ UINTN CheckLba;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN Retry;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ ShortLba = (UINTN) Lba;
+
+ while (BufferSize != 0) {
+ //
+ // Compute I/O location in Sector, Head, Cylinder format
+ //
+ Sector = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
+ Temp = ShortLba / BiosBlockIoDev->Bios.MaxSector;
+ Head = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
+ Cylinder = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
+
+ //
+ // Limit transfer to this Head & Cylinder
+ //
+ NumberOfBlocks = BufferSize / BlockSize;
+ Temp = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
+ NumberOfBlocks = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
+
+ Retry = 3;
+ do {
+ //
+ // Perform the IO
+ //
+ Regs.H.AH = 3;
+ Regs.H.AL = (UINT8) NumberOfBlocks;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+
+ UpperCylinder = (Cylinder & 0x0f00) >> 2;
+
+ CheckLba = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
+ CheckLba = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
+ ShortLba,
+ CheckLba,
+ Sector,
+ BiosBlockIoDev->Bios.MaxSector,
+ Head,
+ BiosBlockIoDev->Bios.MaxHead,
+ Cylinder,
+ UpperCylinder)
+ );
+ ASSERT (CheckLba == ShortLba);
+
+ Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
+ Regs.H.DH = (UINT8) (Head & 0x3f);
+ Regs.H.CH = (UINT8) (Cylinder & 0xff);
+
+ Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
+ Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem (mEdd11Buffer, Buffer, TransferByteSize);
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
+ Regs.H.AL,
+ (UINT8) (Head & 0x3f),
+ Regs.H.DL,
+ (UINT8) (Cylinder & 0xff),
+ (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
+ EFI_OFFSET (mEdd11Buffer),
+ EFI_SEGMENT (mEdd11Buffer))
+ );
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+ Retry--;
+ } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ //
+ // Legacy Interfaces
+ //
+ Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
+ Media->BlockSize = 512;
+ }
+ //
+ // If the size of the media changed we need to reset the disk geometry
+ //
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
+ Media->ReadOnly = TRUE;
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Media->ReadOnly = FALSE;
+ ShortLba = ShortLba + NumberOfBlocks;
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf
new file mode 100644
index 0000000..3fcaa27
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf
@@ -0,0 +1,58 @@
+## @file
+# Component description file for BIOS Block IO module.
+#
+# Copyright (c) 1999 - 2010, 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BlockIoDxe
+ FILE_GUID = 4495E47E-42A9-4007-8c17-B6664F909D04
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BiosBlockIoDriverEntryPoint
+
+[Sources]
+ BiosBlkIo.h
+ Edd.h
+ BiosBlkIo.c
+ BiosInt13.c
+ ComponentName.c
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiLib
+ DevicePathLib
+ MemoryAllocationLib
+
+
+[Protocols]
+ gEfiBlockIoProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiPciIoProtocolGuid
+ gEfiLegacyBiosProtocolGuid
+
+
+[Guids]
+ gEfiLegacyBiosGuid
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c
new file mode 100644
index 0000000..88bca13
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c
@@ -0,0 +1,309 @@
+/** @file
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosBlkIo.h"
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosBlockIoComponentName = {
+ BiosBlockIoComponentNameGetDriverName,
+ BiosBlockIoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosBlockIoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosBlockIoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosBlockIoComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosBlockIoDriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[INT13] Block Io Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosBlockIoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosBlockIoComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h
new file mode 100644
index 0000000..be4d830
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h
@@ -0,0 +1,209 @@
+/** @file
+ Include file to suport EDD 3.0.
+ This file is coded to T13 D1386 Revision 3
+ Availible on http://www.t13.org/#Project drafts
+ Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r3.pdf
+
+Copyright (c) 1999 - 2010, 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.
+
+**/
+
+#ifndef _EDD_H_
+#define _EDD_H_
+
+//
+// packing with no compiler padding, so that the fields
+// of the following architected structures can be
+// properly accessed from C code.
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 Controller;
+ UINT32 Reserved;
+} EDD_PCI;
+
+typedef struct {
+ UINT16 Base;
+ UINT16 Reserved;
+ UINT32 Reserved2;
+} EDD_LEGACY;
+
+typedef union {
+ EDD_PCI Pci;
+ EDD_LEGACY Legacy;
+} EDD_INTERFACE_PATH;
+
+typedef struct {
+ UINT8 Master;
+ UINT8 Reserved[15];
+} EDD_ATA;
+
+typedef struct {
+ UINT8 Master;
+ UINT8 Lun;
+ UINT8 Reserved[14];
+} EDD_ATAPI;
+
+typedef struct {
+ UINT16 Pun;
+ UINT64 Lun;
+ UINT8 Reserved[6];
+} EDD_SCSI;
+
+typedef struct {
+ UINT64 SerialNumber;
+ UINT64 Reserved;
+} EDD_USB;
+
+typedef struct {
+ UINT64 Guid;
+ UINT64 Reserved;
+} EDD_1394;
+
+typedef struct {
+ UINT64 Wwn;
+ UINT64 Lun;
+} EDD_FIBRE;
+
+typedef union {
+ EDD_ATA Ata;
+ EDD_ATAPI Atapi;
+ EDD_SCSI Scsi;
+ EDD_USB Usb;
+ EDD_1394 FireWire;
+ EDD_FIBRE FibreChannel;
+} EDD_DEVICE_PATH;
+
+typedef struct {
+ UINT16 StructureSize;
+ UINT16 Flags;
+ UINT32 MaxCylinders;
+ UINT32 MaxHeads;
+ UINT32 SectorsPerTrack;
+ UINT64 PhysicalSectors;
+ UINT16 BytesPerSector;
+ UINT32 Fdpt;
+ UINT16 Key;
+ UINT8 DevicePathLength;
+ UINT8 Reserved1;
+ UINT16 Reserved2;
+ CHAR8 HostBusType[4];
+ CHAR8 InterfaceType[8];
+ EDD_INTERFACE_PATH InterfacePath;
+ EDD_DEVICE_PATH DevicePath;
+ UINT8 Reserved3;
+ UINT8 Checksum;
+} EDD_DRIVE_PARAMETERS;
+
+//
+// EDD_DRIVE_PARAMETERS.Flags defines
+//
+#define EDD_GEOMETRY_VALID 0x02
+#define EDD_DEVICE_REMOVABLE 0x04
+#define EDD_WRITE_VERIFY_SUPPORTED 0x08
+#define EDD_DEVICE_CHANGE 0x10
+#define EDD_DEVICE_LOCKABLE 0x20
+
+//
+// BUGBUG: This bit does not follow the spec. It tends to be always set
+// to work properly with Win98.
+//
+#define EDD_DEVICE_GEOMETRY_MAX 0x40
+
+typedef struct {
+ UINT8 PacketSizeInBytes; // 0x18
+ UINT8 Zero;
+ UINT8 NumberOfBlocks; // Max 0x7f
+ UINT8 Zero2;
+ UINT32 SegOffset;
+ UINT64 Lba;
+ UINT64 TransferBuffer;
+ UINT32 ExtendedBlockCount; // Max 0xffffffff
+ UINT32 Zero3;
+} EDD_DEVICE_ADDRESS_PACKET;
+
+#define EDD_VERSION_30 0x30
+
+//
+// Int 13 BIOS Errors
+//
+#define BIOS_PASS 0x00
+#define BIOS_WRITE_PROTECTED 0x03
+#define BIOS_SECTOR_NOT_FOUND 0x04
+#define BIOS_RESET_FAILED 0x05
+#define BIOS_DISK_CHANGED 0x06
+#define BIOS_DRIVE_DOES_NOT_EXIST 0x07
+#define BIOS_DMA_ERROR 0x08
+#define BIOS_DATA_BOUNDRY_ERROR 0x09
+#define BIOS_BAD_SECTOR 0x0a
+#define BIOS_BAD_TRACK 0x0b
+#define BIOS_MEADIA_TYPE_NOT_FOUND 0x0c
+#define BIOS_INVALED_FORMAT 0x0d
+#define BIOS_ECC_ERROR 0x10
+#define BIOS_ECC_CORRECTED_ERROR 0x11
+#define BIOS_HARD_DRIVE_FAILURE 0x20
+#define BIOS_SEEK_FAILED 0x40
+#define BIOS_DRIVE_TIMEOUT 0x80
+#define BIOS_DRIVE_NOT_READY 0xaa
+#define BIOS_UNDEFINED_ERROR 0xbb
+#define BIOS_WRITE_FAULT 0xcc
+#define BIOS_SENSE_FAILED 0xff
+
+#define MAX_EDD11_XFER 0xfe00
+
+#pragma pack()
+//
+// Internal Data Structures
+//
+typedef struct {
+ CHAR8 Letter;
+ UINT8 Number;
+ UINT8 EddVersion;
+ BOOLEAN ExtendedInt13;
+ BOOLEAN DriveLockingAndEjecting;
+ BOOLEAN Edd;
+ BOOLEAN Extensions64Bit;
+ BOOLEAN ParametersValid;
+ UINT8 ErrorCode;
+ VOID *FdptPointer;
+ BOOLEAN Floppy;
+ BOOLEAN AtapiFloppy;
+ UINT8 MaxHead;
+ UINT8 MaxSector;
+ UINT16 MaxCylinder;
+ UINT16 Pad;
+ EDD_DRIVE_PARAMETERS Parameters;
+} BIOS_LEGACY_DRIVE;
+
+#define BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE SIGNATURE_32 ('b', 'b', 'i', 'o')
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_HANDLE ControllerHandle;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO_MEDIA BlockMedia;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ BIOS_LEGACY_DRIVE Bios;
+
+} BIOS_BLOCK_IO_DEV;
+
+#define BIOS_BLOCK_IO_FROM_THIS(a) CR (a, BIOS_BLOCK_IO_DEV, BlockIo, BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE)
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
new file mode 100644
index 0000000..06ef9d3
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
@@ -0,0 +1,2365 @@
+/** @file
+ ConsoleOut Routines that speak VGA.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosKeyboard.h"
+
+//
+// EFI Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = {
+ BiosKeyboardDriverBindingSupported,
+ BiosKeyboardDriverBindingStart,
+ BiosKeyboardDriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+
+/**
+ Enqueue the key.
+
+ @param Queue The queue to be enqueued.
+ @param KeyData The key data to be enqueued.
+
+ @retval EFI_NOT_READY The queue is full.
+ @retval EFI_SUCCESS Successfully enqueued the key data.
+
+**/
+EFI_STATUS
+Enqueue (
+ IN SIMPLE_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
+ Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Dequeue the key.
+
+ @param Queue The queue to be dequeued.
+ @param KeyData The key data to be dequeued.
+
+ @retval EFI_NOT_READY The queue is empty.
+ @retval EFI_SUCCESS Successfully dequeued the key data.
+
+**/
+EFI_STATUS
+Dequeue (
+ IN SIMPLE_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
+ Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether the queue is empty.
+
+ @param Queue The queue to be checked.
+
+ @retval EFI_NOT_READY The queue is empty.
+ @retval EFI_SUCCESS The queue is not empty.
+
+**/
+EFI_STATUS
+CheckQueue (
+ IN SIMPLE_QUEUE *Queue
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// EFI Driver Binding Protocol Functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
+ //
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+ BOOLEAN CarryFlag;
+ EFI_PS2_POLICY_PROTOCOL *Ps2Policy;
+ UINT8 Command;
+ EFI_STATUS_CODE_VALUE StatusCode;
+
+ BiosKeyboardPrivate = NULL;
+ IsaIo = NULL;
+ StatusCode = 0;
+
+ //
+ // Get Ps2 policy to set. Will be use if present.
+ //
+ gBS->LocateProtocol (
+ &gEfiPs2PolicyProtocolGuid,
+ NULL,
+ (VOID **) &Ps2Policy
+ );
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate the private device structure
+ //
+ BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV));
+ if (NULL == BiosKeyboardPrivate) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize the private device structure
+ //
+ BiosKeyboardPrivate->Signature = BIOS_KEYBOARD_DEV_SIGNATURE;
+ BiosKeyboardPrivate->Handle = Controller;
+ BiosKeyboardPrivate->LegacyBios = LegacyBios;
+ BiosKeyboardPrivate->IsaIo = IsaIo;
+
+ BiosKeyboardPrivate->SimpleTextIn.Reset = BiosKeyboardReset;
+ BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke;
+
+ BiosKeyboardPrivate->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;
+ BiosKeyboardPrivate->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;
+ BiosKeyboardPrivate->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
+ BiosKeyboardPrivate->ExtendedKeyboard = TRUE;
+
+ BiosKeyboardPrivate->Queue.Front = 0;
+ BiosKeyboardPrivate->Queue.Rear = 0;
+ BiosKeyboardPrivate->SimpleTextInputEx.Reset = BiosKeyboardResetEx;
+ BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = BiosKeyboardReadKeyStrokeEx;
+ BiosKeyboardPrivate->SimpleTextInputEx.SetState = BiosKeyboardSetState;
+ BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = BiosKeyboardRegisterKeyNotify;
+ BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify;
+ InitializeListHead (&BiosKeyboardPrivate->NotifyList);
+
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &BiosKeyboardPrivate->DevicePath
+ );
+
+ //
+ // Report that the keyboard is being enabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,
+ BiosKeyboardPrivate->DevicePath
+ );
+
+ //
+ // Setup the WaitForKey event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ BiosKeyboardWaitForKey,
+ &(BiosKeyboardPrivate->SimpleTextIn),
+ &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey)
+ );
+ if (EFI_ERROR (Status)) {
+ (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
+ goto Done;
+ }
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ BiosKeyboardWaitForKeyEx,
+ &(BiosKeyboardPrivate->SimpleTextInputEx),
+ &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
+ );
+ if (EFI_ERROR (Status)) {
+ BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
+ goto Done;
+ }
+
+ //
+ // Setup a periodic timer, used for reading keystrokes at a fixed interval
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ BiosKeyboardTimerHandler,
+ BiosKeyboardPrivate,
+ &BiosKeyboardPrivate->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (
+ BiosKeyboardPrivate->TimerEvent,
+ TimerPeriodic,
+ KEYBOARD_TIMER_INTERVAL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto Done;
+ }
+
+ //
+ // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,
+ BiosKeyboardPrivate->DevicePath
+ );
+
+ //
+ // Reset the keyboard device
+ //
+ Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset (
+ &BiosKeyboardPrivate->SimpleTextInputEx,
+ FALSE
+ );
+
+ if (EFI_ERROR (Status)) {
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
+ goto Done;
+ }
+ //
+ // Do platform specific policy like port swapping and keyboard light default
+ //
+ if (Ps2Policy != NULL) {
+
+ Ps2Policy->Ps2InitHardware (Controller);
+
+ Command = 0;
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {
+ Command |= 4;
+ }
+
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {
+ Command |= 2;
+ }
+
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {
+ Command |= 1;
+ }
+
+ KeyboardWrite (BiosKeyboardPrivate, 0xed);
+ KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
+ KeyboardWrite (BiosKeyboardPrivate, Command);
+ //
+ // Call Legacy BIOS Protocol to set whatever is necessary
+ //
+ LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
+ }
+ //
+ // Get Configuration
+ //
+ Regs.H.AH = 0xc0;
+ CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x15,
+ &Regs
+ );
+
+ if (!CarryFlag) {
+ //
+ // Check bit 6 of Feature Byte 2.
+ // If it is set, then Int 16 Func 09 is supported
+ //
+ if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {
+ //
+ // Get Keyboard Functionality
+ //
+ Regs.H.AH = 0x09;
+ CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x16,
+ &Regs
+ );
+
+ if (!CarryFlag) {
+ //
+ // Check bit 5 of AH.
+ // If it is set, then INT 16 Finc 10-12 are supported.
+ //
+ if ((Regs.H.AL & 0x40) != 0) {
+ //
+ // Set the flag to use INT 16 Func 10-12
+ //
+ BiosKeyboardPrivate->ExtendedKeyboard = TRUE;
+ }
+ }
+ }
+ }
+ //
+ // Install protocol interfaces for the keyboard device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextInputEx,
+ NULL
+ );
+
+Done:
+ if (StatusCode != 0) {
+ //
+ // Report an Error Code for failing to start the keyboard device
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ StatusCode,
+ BiosKeyboardPrivate->DevicePath
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+
+ if (BiosKeyboardPrivate != NULL) {
+ if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
+ gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
+ }
+
+ if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
+ gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);
+ }
+ BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
+
+ if (BiosKeyboardPrivate->TimerEvent != NULL) {
+ gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
+ }
+
+ FreePool (BiosKeyboardPrivate);
+ }
+
+ if (IsaIo != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ //
+ // Disable Keyboard
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &SimpleTextIn,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextInputEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Release the IsaIo protocol on the controller handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free other resources
+ //
+ gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
+ gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
+ gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);
+ BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
+
+ FreePool (BiosKeyboardPrivate);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+
+ @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.
+
+**/
+UINT8
+KeyReadDataRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ )
+{
+ UINT8 Data;
+
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Read (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->DataRegisterAddress,
+ 1,
+ &Data
+ );
+
+ return Data;
+}
+
+/**
+ Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+
+ @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.
+
+**/
+UINT8
+KeyReadStatusRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ )
+{
+ UINT8 Data;
+
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Read (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->StatusRegisterAddress,
+ 1,
+ &Data
+ );
+
+ return Data;
+}
+
+/**
+ Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+**/
+VOID
+KeyWriteCommandRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Write (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->CommandRegisterAddress,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+**/
+VOID
+KeyWriteDataRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Write (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->DataRegisterAddress,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data The pointer for data that being read out.
+
+ @retval EFI_SUCCESS The data byte read out successfully.
+ @retval EFI_TIMEOUT Timeout occurred during reading out data byte.
+
+**/
+EFI_STATUS
+KeyboardRead (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ OUT UINT8 *Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegFilled;
+
+ TimeOut = 0;
+ RegFilled = 0;
+
+ //
+ // wait till output buffer full then perform the read
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
+ RegFilled = 1;
+ *Data = KeyReadDataRegister (BiosKeyboardPrivate);
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegFilled == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+ @retval EFI_SUCCESS The data byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWrite (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegEmptied;
+
+ TimeOut = 0;
+ RegEmptied = 0;
+
+ //
+ // wait for input buffer empty
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // Write it
+ //
+ KeyWriteDataRegister (BiosKeyboardPrivate, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Command byte to write.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardCommand (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegEmptied;
+
+ TimeOut = 0;
+ RegEmptied = 0;
+
+ //
+ // Wait For Input Buffer Empty
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // issue the command
+ //
+ KeyWriteCommandRegister (BiosKeyboardPrivate, Data);
+
+ //
+ // Wait For Input Buffer Empty again
+ //
+ RegEmptied = 0;
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait for a specific value to be presented in
+ Data register of Keyboard Controller by keyboard and then read it,
+ used in keyboard commands ack
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Value The value to be waited for
+ @param WaitForValueTimeOut The limit of microseconds for timeout
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWaitForValue (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Value,
+ IN UINTN WaitForValueTimeOut
+ )
+{
+ UINT8 Data;
+ UINT32 TimeOut;
+ UINT32 SumTimeOut;
+ UINT32 GotIt;
+
+ GotIt = 0;
+ TimeOut = 0;
+ SumTimeOut = 0;
+
+ //
+ // Make sure the initial value of 'Data' is different from 'Value'
+ //
+ Data = 0;
+ if (Data == Value) {
+ Data = 1;
+ }
+ //
+ // Read from 8042 (multiple times if needed)
+ // until the expected value appears
+ // use SumTimeOut to control the iteration
+ //
+ while (1) {
+ //
+ // Perform a read
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
+ Data = KeyReadDataRegister (BiosKeyboardPrivate);
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ SumTimeOut += TimeOut;
+
+ if (Data == Value) {
+ GotIt = 1;
+ break;
+ }
+
+ if (SumTimeOut >= WaitForValueTimeOut) {
+ break;
+ }
+ }
+ //
+ // Check results
+ //
+ if (GotIt != 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_TIMEOUT;
+ }
+
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param BiosKeyboardPrivate Bioskeyboard driver private structure.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+KeyboardReadKeyStrokeWorker (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Use TimerEvent callback funciton to check whether there's any key pressed
+ //
+
+ //
+ // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
+ // Csm will be used to check whether there is a key pending, but the csm will disable all
+ // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
+ // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
+ // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
+ // e.g. usb keyboard driver.
+ // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
+ // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
+ //
+ gBS->Stall (1000);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate);
+ //
+ // If there's no key, just return
+ //
+ Status = CheckQueue (&BiosKeyboardPrivate->Queue);
+ if (EFI_ERROR (Status)) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_NOT_READY;
+ }
+
+ Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+//
+// EFI Simple Text In Protocol Functions
+//
+/**
+ Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
+
+ @param This Pointer of simple text Protocol.
+ @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ UINT8 CommandByte;
+ BOOLEAN MouseEnable;
+ EFI_INPUT_KEY Key;
+
+ MouseEnable = FALSE;
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // 1
+ // Report reset progress code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,
+ BiosKeyboardPrivate->DevicePath
+ );
+
+ //
+ // Report a Progress Code for clearing the keyboard buffer
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,
+ BiosKeyboardPrivate->DevicePath
+ );
+
+ //
+ // 2
+ // Raise TPL to avoid mouse operation impact
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ //
+ // Exhaust output buffer data
+ //
+ do {
+ Status = BiosKeyboardReadKeyStroke (
+ This,
+ &Key
+ );
+ } while (!EFI_ERROR (Status));
+ //
+ // 3
+ // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H
+ // if not skip step 4&5 and jump to step 6 to selftest KBC and report this
+ // else go step 4
+ //
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {
+ //
+ // 4
+ // CheckMouseStatus to decide enable it later or not
+ //
+ //
+ // Read the command byte of KBC
+ //
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_CMDBYTE_R
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardRead (
+ BiosKeyboardPrivate,
+ &CommandByte
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // Check mouse enabled or not before
+ //
+ if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {
+ MouseEnable = FALSE;
+ } else {
+ MouseEnable = TRUE;
+ }
+ //
+ // 5
+ // disable mouse (via KBC) and Keyborad device
+ //
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_AUX_DISABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KB_DISABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ } else {
+ //
+ // 6
+ // KBC Self Test
+ //
+ //
+ // Report a Progress Code for performing a self test on the keyboard controller
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,
+ BiosKeyboardPrivate->DevicePath
+ );
+
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KBC_SLFTEST
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_KBCSLFTEST_OK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+ //
+ // 7
+ // Disable Mouse interface, enable Keyboard interface and declare selftest success
+ //
+ // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.
+ //
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_CMDBYTE_W
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // Write 8042 Command Byte, set System Flag
+ // While at the same time:
+ // 1. disable mouse interface,
+ // 2. enable kbd interface,
+ // 3. enable PC/XT kbd translation mode
+ // 4. enable mouse and kbd interrupts
+ //
+ //Command Byte bits:
+ // 7: Reserved
+ // 6: PC/XT translation mode
+ // 5: Disable Auxiliary device interface
+ // 4: Disable keyboard interface
+ // 3: Reserved
+ // 2: System Flag
+ // 1: Enable Auxiliary device interrupt
+ // 0: Enable Keyboard interrupt
+ //
+ CommandByte = 0;
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ (UINT8) ((CommandByte &
+ (~KB_CMMBYTE_DISABLE_KB)) |
+ KB_CMMBYTE_KSCAN2UNI_COV |
+ KB_CMMBYTE_ENABLE_AUXINT |
+ KB_CMMBYTE_ENABLE_KBINT |
+ KB_CMMBYTE_SLFTEST_SUCC |
+ KB_CMMBYTE_DISABLE_AUX)
+ );
+
+ //
+ // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
+ // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.
+ // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,
+ // Real reset will not do.
+ //
+ if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) {
+ //
+ // 8
+ // Send keyboard reset command then read ACK
+ //
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBRESET
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 9
+ // Wait for keyboard return test OK.
+ //
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_BATTEST_OK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 10
+ // set keyboard scan code set = 02 (standard configuration)
+ //
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBSCODE
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_SCODESET2
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 11
+ // enable keyboard itself (not via KBC) by writing CMD F4 via 60H
+ //
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBEN
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 12
+ // Additional validation, do it as follow:
+ // 1). check for status register of PARE && TIM via 64H
+ // 2). perform KB checking by writing ABh via 64H
+ //
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KB_CKECK
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_KBCHECK_OK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+ //
+ // 13
+ // Done for validating keyboard. Enable keyboard (via KBC)
+ // and recover the command byte to proper value
+ //
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KB_ENABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // 14
+ // conditionally enable mouse (via KBC)
+ //
+ if (MouseEnable) {
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_AUX_ENABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+
+ }
+ }
+
+Exit:
+ //
+ // 15
+ // resume priority of task level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+}
+
+/**
+ Read out the scan code of the key that has just been stroked.
+
+ @param This Pointer of simple text Protocol.
+ @param Key Pointer for store the key that read out.
+
+ @retval EFI_SUCCESS The key is read out successfully.
+ @retval other The key reading failed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_KEY_DATA KeyData;
+
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
+ // Csm will be used to check whether there is a key pending, but the csm will disable all
+ // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
+ // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
+ // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
+ // e.g. usb keyboard driver.
+ // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
+ // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
+ //
+ gBS->Stall (1000);
+ //
+ // Use TimerEvent callback funciton to check whether there's any key pressed
+ //
+ BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));
+
+ if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Check key buffer to get the key stroke status.
+
+ @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
+
+ @retval EFI_SUCCESS A key is being pressed now.
+ @retval Other No key is now pressed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardCheckForKey (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ return CheckQueue (&BiosKeyboardPrivate->Queue);
+}
+//
+// Private worker functions
+//
+#define TABLE_END 0x0
+
+typedef struct _CONVERT_TABLE_ENTRY {
+ UINT16 ScanCode;
+ UINT16 EfiScanCode;
+} CONVERT_TABLE_ENTRY;
+
+CONVERT_TABLE_ENTRY mConvertTable[] = {
+ {
+ 0x47,
+ SCAN_HOME
+ },
+ {
+ 0x48,
+ SCAN_UP
+ },
+ {
+ 0x49,
+ SCAN_PAGE_UP
+ },
+ {
+ 0x4b,
+ SCAN_LEFT
+ },
+ {
+ 0x4d,
+ SCAN_RIGHT
+ },
+ {
+ 0x4f,
+ SCAN_END
+ },
+ {
+ 0x50,
+ SCAN_DOWN
+ },
+ {
+ 0x51,
+ SCAN_PAGE_DOWN
+ },
+ {
+ 0x52,
+ SCAN_INSERT
+ },
+ {
+ 0x53,
+ SCAN_DELETE
+ },
+ //
+ // Function Keys are only valid if KeyChar == 0x00
+ // This function does not require KeyChar to be 0x00
+ //
+ {
+ 0x3b,
+ SCAN_F1
+ },
+ {
+ 0x3c,
+ SCAN_F2
+ },
+ {
+ 0x3d,
+ SCAN_F3
+ },
+ {
+ 0x3e,
+ SCAN_F4
+ },
+ {
+ 0x3f,
+ SCAN_F5
+ },
+ {
+ 0x40,
+ SCAN_F6
+ },
+ {
+ 0x41,
+ SCAN_F7
+ },
+ {
+ 0x42,
+ SCAN_F8
+ },
+ {
+ 0x43,
+ SCAN_F9
+ },
+ {
+ 0x44,
+ SCAN_F10
+ },
+ {
+ 0x85,
+ SCAN_F11
+ },
+ {
+ 0x86,
+ SCAN_F12
+ },
+ //
+ // Convert ALT + Fn keys
+ //
+ {
+ 0x68,
+ SCAN_F1
+ },
+ {
+ 0x69,
+ SCAN_F2
+ },
+ {
+ 0x6a,
+ SCAN_F3
+ },
+ {
+ 0x6b,
+ SCAN_F4
+ },
+ {
+ 0x6c,
+ SCAN_F5
+ },
+ {
+ 0x6d,
+ SCAN_F6
+ },
+ {
+ 0x6e,
+ SCAN_F7
+ },
+ {
+ 0x6f,
+ SCAN_F8
+ },
+ {
+ 0x70,
+ SCAN_F9
+ },
+ {
+ 0x71,
+ SCAN_F10
+ },
+ {
+ TABLE_END,
+ SCAN_NULL
+ },
+};
+
+/**
+ Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
+
+ @param KeyChar Unicode of key.
+ @param ScanCode Scan code of key.
+
+ @return The value of EFI Scancode for the key.
+ @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
+
+**/
+UINT16
+ConvertToEFIScanCode (
+ IN CHAR16 KeyChar,
+ IN UINT16 ScanCode
+ )
+{
+ UINT16 EfiScanCode;
+ UINT16 Index;
+
+ if (KeyChar == CHAR_ESC) {
+ EfiScanCode = SCAN_ESC;
+ } else if (KeyChar == 0x00 || KeyChar == 0xe0) {
+ //
+ // Movement & Function Keys
+ //
+ for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) {
+ if (ScanCode == mConvertTable[Index].ScanCode) {
+ return mConvertTable[Index].EfiScanCode;
+ }
+ }
+ //
+ // Reach Table end, return default value
+ //
+ return SCAN_NULL;
+ } else {
+ return SCAN_NULL;
+ }
+
+ return EfiScanCode;
+}
+
+/**
+ Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
+ If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
+ should not be in system.
+
+ @param BiosKeyboardPrivate Keyboard Private Data Struture
+
+ @retval TRUE Keyboard in System.
+ @retval FALSE Keyboard not in System.
+
+**/
+BOOLEAN
+CheckKeyboardConnect (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ //
+ // enable keyboard itself and wait for its ack
+ // If can't receive ack, Keyboard should not be connected.
+ //
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBEN
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Timer event handler: read a series of key stroke from 8042
+ and put them into memory key buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event The timer event
+ @param Context A BIOS_KEYBOARD_DEV pointer
+
+**/
+VOID
+EFIAPI
+BiosKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_TPL OldTpl;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT8 KbFlag1; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1
+ UINT8 KbFlag2; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2
+ EFI_KEY_DATA KeyData;
+ LIST_ENTRY *Link;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ BiosKeyboardPrivate = Context;
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // if there is no key present, just return
+ //
+ if (BiosKeyboardPrivate->ExtendedKeyboard) {
+ Regs.H.AH = 0x11;
+ } else {
+ Regs.H.AH = 0x01;
+ }
+
+ BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x16,
+ &Regs
+ );
+ if (Regs.X.Flags.ZF != 0) {
+ gBS->RestoreTPL (OldTpl);
+ return;
+ }
+
+ //
+ // Read the key
+ //
+ if (BiosKeyboardPrivate->ExtendedKeyboard) {
+ Regs.H.AH = 0x10;
+ } else {
+ Regs.H.AH = 0x00;
+ }
+
+ BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x16,
+ &Regs
+ );
+
+ KeyData.Key.ScanCode = (UINT16) Regs.H.AH;
+ KeyData.Key.UnicodeChar = (UINT16) Regs.H.AL;
+ KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
+ KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
+ //
+ // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then
+ // 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
+ // 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
+ // 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
+ // 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
+ // 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
+ // 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
+ // performance, like USB.
+ //
+ // 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
+ // 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
+ // 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
+ // CTRL and ALT.
+ //
+ // 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
+ // 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,
+ // which will let persist to press SHIFT has same effection as only press one time.
+ //
+ //0040h:0017h - KEYBOARD - STATUS FLAGS 1
+ // 7 INSert active
+ // 6 Caps Lock active
+ // 5 Num Lock active
+ // 4 Scroll Lock active
+ // 3 either Alt pressed
+ // 2 either Ctrl pressed
+ // 1 Left Shift pressed
+ // 0 Right Shift pressed
+
+
+ //
+ // Clear the CTRL and ALT BDA flag
+ //
+ KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1
+ KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2
+
+ //
+ // Record toggle state
+ //
+ if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {
+ KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
+ }
+ if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {
+ KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
+ }
+ if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {
+ KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
+ }
+ //
+ // Record shift state
+ // BUGBUG: Need add Menu key and Left/Right Logo key state in the future
+ //
+ if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED;
+ }
+ if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED;
+ }
+ if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
+ }
+ if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
+ }
+
+ //
+ // Clear left alt and left ctrl BDA flag
+ //
+ KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);
+ *((UINT8 *) (UINTN) 0x418) = KbFlag2;
+ KbFlag1 &= ~0x0C;
+ *((UINT8 *) (UINTN) 0x417) = KbFlag1;
+
+
+ //
+ // Output EFI input key and shift/toggle state
+ //
+ if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) {
+ KeyData.Key.ScanCode = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode);
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ } else {
+ KeyData.Key.ScanCode = SCAN_NULL;
+ }
+
+ //
+ // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.
+ //
+ if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
+ if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) {
+ if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ==
+ ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)
+ ) {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1);
+ } else {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1);
+ }
+ }
+ }
+
+ //
+ // Need not return associated shift state if a class of printable characters that
+ // are normally adjusted by shift modifiers.
+ // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.
+ //
+ if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') ||
+ (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z')
+ ) {
+ KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
+ }
+
+ //
+ // Invoke notification functions if exist
+ //
+ for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ CurrentNotify->KeyNotificationFn (&KeyData);
+ }
+ }
+
+ //
+ // Convert the Ctrl+[a-z] to Ctrl+[1-26]
+ //
+ if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
+ if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'a' + 1);
+ } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'A' + 1);
+ }
+ }
+ Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return ;
+}
+
+/**
+ Free keyboard notify list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully
+ @retval EFI_INVALID_PARAMETER ListHead is invalid.
+
+**/
+EFI_STATUS
+BiosKeyboardFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+ if (ListHead == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (ListHead)) {
+ NotifyNode = CR (
+ ListHead->ForwardLink,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ RemoveEntryList (ListHead->ForwardLink);
+ gBS->FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if key is registered.
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was registered.
+ @param InputData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FLASE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ )
+{
+ ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+ if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
+ (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
+ return FALSE;
+ }
+
+ //
+ // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
+ //
+ if (RegsiteredData->KeyState.KeyShiftState != 0 &&
+ RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
+ return FALSE;
+ }
+ if (RegsiteredData->KeyState.KeyToggleState != 0 &&
+ RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context);
+ BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn);
+
+}
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ Status = BiosKeyboardPrivate->SimpleTextIn.Reset (
+ &BiosKeyboardPrivate->SimpleTextIn,
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData);
+
+}
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ EFI_STATUS Status;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_TPL OldTpl;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT8 Command;
+
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
+ return EFI_UNSUPPORTED;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Command = 0;
+ if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
+ Command |= 4;
+ }
+ if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
+ Command |= 2;
+ }
+ if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
+ Command |= 1;
+ }
+
+ Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ Status = KeyboardWrite (BiosKeyboardPrivate, Command);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call Legacy BIOS Protocol to set whatever is necessary
+ //
+ LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+}
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the registered notification.
+
+
+ @retval EFI_SUCCESS The notification function was registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT EFI_HANDLE *NotifyHandle
+ )
+{
+ EFI_STATUS Status;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_TPL OldTpl;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
+ LIST_ENTRY *Link;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+ //
+ for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify->NotifyHandle;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+
+ NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ NewNotify->Signature = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify->NotifyHandle;
+ Status = EFI_SUCCESS;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_HANDLE NotificationHandle
+ )
+{
+ EFI_STATUS Status;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ //
+ // Check incoming notification handle
+ //
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (CurrentNotify->NotifyHandle == NotificationHandle) {
+ //
+ // Remove the notification function from NotifyList and free resources
+ //
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Can not find the specified Notification Handle
+ //
+ Status = EFI_INVALID_PARAMETER;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ The user Entry Point for module BiosKeyboard. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeBiosKeyboard(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosKeyboardDriverBinding,
+ ImageHandle,
+ &gBiosKeyboardComponentName,
+ &gBiosKeyboardComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h
new file mode 100644
index 0000000..c9f86a1
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h
@@ -0,0 +1,744 @@
+/** @file
+
+Copyright (c) 2006 - 2011, 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.
+
+**/
+
+#ifndef _BIOS_KEYBOARD_H_
+#define _BIOS_KEYBOARD_H_
+
+
+#include <FrameworkDxe.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Ps2Policy.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2;
+
+
+#include <IndustryStandard/Pci.h>
+
+//
+// BISO Keyboard Defines
+//
+#define CHAR_SCANCODE 0xe0
+#define CHAR_ESC 0x1b
+
+#define KEYBOARD_8042_DATA_REGISTER 0x60
+#define KEYBOARD_8042_STATUS_REGISTER 0x64
+#define KEYBOARD_8042_COMMAND_REGISTER 0x64
+
+#define KEYBOARD_TIMEOUT 65536 // 0.07s
+#define KEYBOARD_WAITFORVALUE_TIMEOUT 1000000 // 1s
+#define KEYBOARD_BAT_TIMEOUT 4000000 // 4s
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+// KEYBOARD COMMAND BYTE -- read by writing command KBC_CMDREG_VIA64_CMDBYTE_R to 64H, then read from 60H
+// write by wrting command KBC_CMDREG_VIA64_CMDBYTE_W to 64H, then write to 60H
+// 7: Reserved
+// 6: PC/XT translation mode convert
+// 5: Disable Auxiliary device interface
+// 4: Disable keyboard interface
+// 3: Reserved
+// 2: System Flag: selftest successful
+// 1: Enable Auxiliary device interrupt
+// 0: Enable Keyboard interrupt )
+//
+#define KB_CMMBYTE_KSCAN2UNI_COV (0x1 << 6)
+#define KB_CMMBYTE_DISABLE_AUX (0x1 << 5)
+#define KB_CMMBYTE_DISABLE_KB (0x1 << 4)
+#define KB_CMMBYTE_SLFTEST_SUCC (0x1 << 2)
+#define KB_CMMBYTE_ENABLE_AUXINT (0x1 << 1)
+#define KB_CMMBYTE_ENABLE_KBINT (0x1 << 0)
+
+//
+// KEYBOARD CONTROLLER STATUS REGISTER - read from 64h
+// 7: Parity error
+// 6: General time out
+// 5: Output buffer holds data for AUX
+// 4: Keyboard is not locked
+// 3: Command written via 64h / Data written via 60h
+// 2: KBC self-test successful / Power-on reset
+// 1: Input buffer holds CPU data / empty
+// 0: Output buffer holds keyboard data / empty
+//
+#define KBC_STSREG_VIA64_PARE (0x1 << 7)
+#define KBC_STSREG_VIA64_TIM (0x1 << 6)
+#define KBC_STSREG_VIA64_AUXB (0x1 << 5)
+#define KBC_STSREG_VIA64_KEYL (0x1 << 4)
+#define KBC_STSREG_VIA64_C_D (0x1 << 3)
+#define KBC_STSREG_VIA64_SYSF (0x1 << 2)
+#define KBC_STSREG_VIA64_INPB (0x1 << 1)
+#define KBC_STSREG_VIA64_OUTB (0x1 << 0)
+
+//
+// COMMANDs of KEYBOARD CONTROLLER COMMAND REGISTER - write to 64h
+//
+#define KBC_CMDREG_VIA64_CMDBYTE_R 0x20
+#define KBC_CMDREG_VIA64_CMDBYTE_W 0x60
+#define KBC_CMDREG_VIA64_AUX_DISABLE 0xA7
+#define KBC_CMDREG_VIA64_AUX_ENABLE 0xA8
+#define KBC_CMDREG_VIA64_KBC_SLFTEST 0xAA
+#define KBC_CMDREG_VIA64_KB_CKECK 0xAB
+#define KBC_CMDREG_VIA64_KB_DISABLE 0xAD
+#define KBC_CMDREG_VIA64_KB_ENABLE 0xAE
+#define KBC_CMDREG_VIA64_INTP_LOW_R 0xC0
+#define KBC_CMDREG_VIA64_INTP_HIGH_R 0xC2
+#define KBC_CMDREG_VIA64_OUTP_R 0xD0
+#define KBC_CMDREG_VIA64_OUTP_W 0xD1
+#define KBC_CMDREG_VIA64_OUTB_KB_W 0xD2
+#define KBC_CMDREG_VIA64_OUTB_AUX_W 0xD3
+#define KBC_CMDREG_VIA64_AUX_W 0xD4
+
+//
+// echos of KEYBOARD CONTROLLER COMMAND - read from 60h
+//
+#define KBC_CMDECHO_KBCSLFTEST_OK 0x55
+#define KBC_CMDECHO_KBCHECK_OK 0x00
+#define KBC_CMDECHO_ACK 0xFA
+#define KBC_CMDECHO_BATTEST_OK 0xAA
+#define KBC_CMDECHO_BATTEST_FAILE 0xFC
+
+//
+// OUTPUT PORT COMMANDs - write port by writing KBC_CMDREG_VIA64_OUTP_W via 64H, then write the command to 60H
+// drive data and clock of KB to high for at least 500us for BAT needs
+//
+#define KBC_OUTPORT_DCHIGH_BAT 0xC0
+//
+// scan code set type
+//
+#define KBC_INPBUF_VIA60_SCODESET1 0x01
+#define KBC_INPBUF_VIA60_SCODESET2 0x02
+#define KBC_INPBUF_VIA60_SCODESET3 0x03
+
+//
+// COMMANDs written to INPUT BUFFER - write to 60h
+//
+#define KBC_INPBUF_VIA60_KBECHO 0xEE
+#define KBC_INPBUF_VIA60_KBSCODE 0xF0
+#define KBC_INPBUF_VIA60_KBTYPE 0xF2
+#define KBC_INPBUF_VIA60_KBDELAY 0xF3
+#define KBC_INPBUF_VIA60_KBEN 0xF4
+#define KBC_INPBUF_VIA60_KBSTDDIS 0xF5
+#define KBC_INPBUF_VIA60_KBSTDEN 0xF6
+#define KBC_INPBUF_VIA60_KBRESEND 0xFE
+#define KBC_INPBUF_VIA60_KBRESET 0xFF
+
+//
+// 0040h:0017h - KEYBOARD - STATUS FLAGS 1
+// 7 INSert active
+// 6 Caps Lock active
+// 5 Num Lock active
+// 4 Scroll Lock active
+// 3 either Alt pressed
+// 2 either Ctrl pressed
+// 1 Left Shift pressed
+// 0 Right Shift pressed
+//
+// 0040h:0018h - KEYBOARD - STATUS FLAGS 2
+// 7: insert key is depressed
+// 6: caps-lock key is depressed (does not work well)
+// 5: num-lock key is depressed (does not work well)
+// 4: scroll lock key is depressed (does not work well)
+// 3: suspend key has been toggled (does not work well)
+// 2: system key is pressed and held (does not work well)
+// 1: left ALT key is pressed
+// 0: left CTRL key is pressed
+//
+#define KB_INSERT_BIT (0x1 << 7)
+#define KB_CAPS_LOCK_BIT (0x1 << 6)
+#define KB_NUM_LOCK_BIT (0x1 << 5)
+#define KB_SCROLL_LOCK_BIT (0x1 << 4)
+#define KB_ALT_PRESSED (0x1 << 3)
+#define KB_CTRL_PRESSED (0x1 << 2)
+#define KB_LEFT_SHIFT_PRESSED (0x1 << 1)
+#define KB_RIGHT_SHIFT_PRESSED (0x1 << 0)
+
+#define KB_SUSPEND_PRESSED (0x1 << 3)
+#define KB_SYSREQ_PRESSED (0x1 << 2)
+#define KB_LEFT_ALT_PRESSED (0x1 << 1)
+#define KB_LEFT_CTRL_PRESSED (0x1 << 0)
+
+//
+// BIOS Keyboard Device Structure
+//
+#define BIOS_KEYBOARD_DEV_SIGNATURE SIGNATURE_32 ('B', 'K', 'B', 'D')
+#define BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('c', 'b', 'k', 'h')
+
+typedef struct _BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY {
+ UINTN Signature;
+ EFI_HANDLE NotifyHandle;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY;
+
+#define QUEUE_MAX_COUNT 32
+typedef struct {
+ UINTN Front;
+ UINTN Rear;
+ EFI_KEY_DATA Buffer[QUEUE_MAX_COUNT];
+} SIMPLE_QUEUE;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleTextIn;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleTextInputEx;
+ UINT16 DataRegisterAddress;
+ UINT16 StatusRegisterAddress;
+ UINT16 CommandRegisterAddress;
+ BOOLEAN ExtendedKeyboard;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // Buffer storing EFI_KEY_DATA
+ //
+ SIMPLE_QUEUE Queue;
+
+ //
+ // Notification Function List
+ //
+ LIST_ENTRY NotifyList;
+ EFI_EVENT TimerEvent;
+
+} BIOS_KEYBOARD_DEV;
+
+#define BIOS_KEYBOARD_DEV_FROM_THIS(a) CR (a, BIOS_KEYBOARD_DEV, SimpleTextIn, BIOS_KEYBOARD_DEV_SIGNATURE)
+#define TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS(a) \
+ CR (a, \
+ BIOS_KEYBOARD_DEV, \
+ SimpleTextInputEx, \
+ BIOS_KEYBOARD_DEV_SIGNATURE \
+ )
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding;
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// Simple Text Input Protocol functions
+//
+/**
+ Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
+
+ @param This Pointer of simple text Protocol.
+ @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read out the scan code of the key that has just been stroked.
+
+ @param This Pointer of simple text Protocol.
+ @param Key Pointer for store the key that read out.
+
+ @retval EFI_SUCCESS The key is read out successfully.
+ @retval other The key reading failed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+//
+// Private worker functions
+//
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Check key buffer to get the key stroke status.
+
+ @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
+
+ @retval EFI_SUCCESS A key is being pressed now.
+ @retval Other No key is now pressed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardCheckForKey (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
+ );
+
+/**
+ Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
+
+ @param KeyChar Unicode of key.
+ @param ScanCode Scan code of key.
+
+ @return The value of EFI Scancode for the key.
+ @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
+
+**/
+UINT16
+ConvertToEFIScanCode (
+ IN CHAR16 KeyChar,
+ IN UINT16 ScanCode
+ );
+
+/**
+ Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
+ If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
+ should not be in system.
+
+ @param BiosKeyboardPrivate Keyboard Private Data Struture
+
+ @retval TRUE Keyboard in System.
+ @retval FALSE Keyboard not in System.
+
+**/
+BOOLEAN
+CheckKeyboardConnect (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ );
+
+/**
+ Timer event handler: read a series of key stroke from 8042
+ and put them into memory key buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event The timer event
+ @param Context A BIOS_KEYBOARD_DEV pointer
+
+**/
+VOID
+EFIAPI
+BiosKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ );
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the registered notification.
+
+
+ @retval EFI_SUCCESS The notification function was registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT EFI_HANDLE *NotifyHandle
+ );
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_HANDLE NotificationHandle
+ );
+
+/**
+ Wait for a specific value to be presented in
+ Data register of Keyboard Controller by keyboard and then read it,
+ used in keyboard commands ack
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Value The value to be waited for
+ @param WaitForValueTimeOut The limit of microseconds for timeout
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWaitForValue (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Value,
+ IN UINTN WaitForValueTimeOut
+ );
+
+/**
+ Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+ @retval EFI_SUCCESS The data byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWrite (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ );
+
+/**
+ Free keyboard notify list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully
+ @retval EFI_INVALID_PARAMETER ListHead is invalid.
+
+**/
+EFI_STATUS
+BiosKeyboardFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Check if key is registered.
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was registered.
+ @param InputData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FLASE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
+
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c
new file mode 100644
index 0000000..caeecf7
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c
@@ -0,0 +1,183 @@
+/** @file
+
+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.
+
+**/
+
+#include "BiosKeyboard.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosKeyboardComponentName = {
+ BiosKeyboardComponentNameGetDriverName,
+ BiosKeyboardComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosKeyboardComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosKeyboardComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosKeyboardDriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[INT16] Keyboard Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosKeyboardDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosKeyboardComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h
new file mode 100644
index 0000000..a20061b
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h
@@ -0,0 +1,153 @@
+/** @file
+
+Copyright (c) 2006 - 2010, 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.
+
+**/
+
+#ifndef _BIOS_KEYBOARD_COMPONENT_NAME_H_
+#define _BIOS_KEYBOARD_COMPONENT_NAME_H_
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2;
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf
new file mode 100644
index 0000000..6166ba3
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf
@@ -0,0 +1,68 @@
+## @file
+# Component description file for BiosKeyboard module.
+#
+# Ps2 Keyboard driver by using Legacy Bios protocol service and IsaIo protocol service.
+# This dirver uses legacy INT16 to get the key stroke status.
+#
+# Copyright (c) 2006 - 2010, 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = KeyboardDxe
+ FILE_GUID = 5479662B-6AE4-49e8-A6BD-6DE4B625811F
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeBiosKeyboard
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gBiosKeyboardDriverBinding
+# COMPONENT_NAME = gBiosKeyboardComponentName
+#
+
+[Sources]
+ ComponentName.c
+ ComponentName.h
+ BiosKeyboard.c
+ BiosKeyboard.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ ReportStatusCodeLib
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ BaseLib
+
+[Protocols]
+ gEfiIsaIoProtocolGuid # PROTOCOL TO_START
+ gEfiSimpleTextInProtocolGuid # PROTOCOL BY_START
+ gEfiSimpleTextInputExProtocolGuid # PROTOCOL BY_START
+ gEfiLegacyBiosProtocolGuid # PROTOCOL TO_START
+ gEfiPs2PolicyProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c
new file mode 100644
index 0000000..2ae8dac
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c
@@ -0,0 +1,3507 @@
+/** @file
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+
+///
+/// EFI Driver Binding Protocol Instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gBiosSnp16DriverBinding = {
+ BiosSnp16DriverBindingSupported,
+ BiosSnp16DriverBindingStart,
+ BiosSnp16DriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+///
+/// This boolean is used to determine if we should release the cached vector during an error condition.
+///
+BOOLEAN mCachedInt1A = FALSE;
+
+//
+// Private worker functions;
+//
+
+/**
+ Start the UNDI interface.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+ @param Ax PCI address of Undi device.
+
+ @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
+ @retval Others Status of start 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStartUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINT16 Ax
+ );
+
+/**
+ Start the UNDI interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
+ @retval Others Status of start 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStopUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Stop the UNDI interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM.
+ @retval Others Status of stop 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCleanupUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Get runtime information for Undi network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get runtime information for Undi network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetInformation (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Get NIC type
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NIC type.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNicType (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Get NDIS information
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NDIS information.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Signal handlers for ExitBootServices event.
+
+ Clean up any Real-mode UNDI residue from the system
+
+ @param Event ExitBootServices event
+ @param Context
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Loads the undi driver.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_SUCCESS - Successfully loads undi driver.
+ @retval EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.
+**/
+EFI_STATUS
+Undi16SimpleNetworkLoadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Unload 16 bit UNDI Option ROM from memory
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+Undi16SimpleNetworkUnloadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @return EFI_STATUS Return status from EfiLibInstallAllDriverProtocols.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosSnp16DriverBinding,
+ ImageHandle,
+ &gBiosSnp16ComponentName,
+ &gBiosSnp16ComponentName2
+ );
+}
+
+//
+// EFI Driver Binding Protocol Functions
+//
+/**
+ Tests to see if this driver supports a given controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The driver supports given controller.
+ @retval EFI_UNSUPPORT The driver doesn't support given controller.
+ @retval Other Other errors prevent driver finishing to test
+ if the driver supports given controller.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // See if this is a PCI Network Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.ClassCode[2] == PCI_CLASS_NETWORK) {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the Snp device controller
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS - The device was started.
+ @retval EFI_DEVICE_ERROR - The device could not be started due to a device error.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ EFI_DEV_PATH Node;
+ UINTN Index;
+ UINTN Index2;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINTN Flags;
+ UINT64 Supports;
+
+ SimpleNetworkDevice = NULL;
+ PciIo = NULL;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check to see if there is a legacy option ROM image associated with this PCI device
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Post the legacy option ROM if it is available.
+ //
+ Status = LegacyBios->InstallPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ &Flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Allocate memory for this SimpleNetwork device instance
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_SIMPLE_NETWORK_DEV),
+ (VOID **) &SimpleNetworkDevice
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ZeroMem (SimpleNetworkDevice, sizeof (EFI_SIMPLE_NETWORK_DEV));
+
+ //
+ // Initialize the SimpleNetwork device instance
+ //
+ SimpleNetworkDevice->Signature = EFI_SIMPLE_NETWORK_DEV_SIGNATURE;
+ SimpleNetworkDevice->LegacyBios = LegacyBios;
+ SimpleNetworkDevice->BaseDevicePath = DevicePath;
+ SimpleNetworkDevice->PciIo = PciIo;
+
+ //
+ // Initialize the Nii Protocol
+ //
+ SimpleNetworkDevice->Nii.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
+ SimpleNetworkDevice->Nii.Type = EfiNetworkInterfaceUndi;
+
+ CopyMem (&SimpleNetworkDevice->Nii.StringId, "UNDI", 4);
+
+ //
+ // Load 16 bit UNDI Option ROM into Memory
+ //
+ Status = Undi16SimpleNetworkLoadUndi (SimpleNetworkDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_NET, "ERROR : Could not load UNDI. Status = %r\n", Status));
+ goto Done;
+ }
+
+ SimpleNetworkDevice->UndiLoaded = TRUE;
+
+ //
+ // Call PXENV_START_UNDI - Initilizes the UNID interface for use.
+ //
+ PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
+ Status = Undi16SimpleNetworkStartUndi (
+ SimpleNetworkDevice,
+ (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function))
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_NET, "ERROR : Could not StartUndi. Status = %r\n", Status));
+ goto Done;
+ }
+ //
+ // Initialize the Simple Network Protocol
+ //
+ DEBUG ((DEBUG_NET, "Initialize SimpleNetworkDevice instance\n"));
+
+ SimpleNetworkDevice->SimpleNetwork.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+ SimpleNetworkDevice->SimpleNetwork.Start = Undi16SimpleNetworkStart;
+ SimpleNetworkDevice->SimpleNetwork.Stop = Undi16SimpleNetworkStop;
+ SimpleNetworkDevice->SimpleNetwork.Initialize = Undi16SimpleNetworkInitialize;
+ SimpleNetworkDevice->SimpleNetwork.Reset = Undi16SimpleNetworkReset;
+ SimpleNetworkDevice->SimpleNetwork.Shutdown = Undi16SimpleNetworkShutdown;
+ SimpleNetworkDevice->SimpleNetwork.ReceiveFilters = Undi16SimpleNetworkReceiveFilters;
+ SimpleNetworkDevice->SimpleNetwork.StationAddress = Undi16SimpleNetworkStationAddress;
+ SimpleNetworkDevice->SimpleNetwork.Statistics = Undi16SimpleNetworkStatistics;
+ SimpleNetworkDevice->SimpleNetwork.MCastIpToMac = Undi16SimpleNetworkMCastIpToMac;
+ SimpleNetworkDevice->SimpleNetwork.NvData = Undi16SimpleNetworkNvData;
+ SimpleNetworkDevice->SimpleNetwork.GetStatus = Undi16SimpleNetworkGetStatus;
+ SimpleNetworkDevice->SimpleNetwork.Transmit = Undi16SimpleNetworkTransmit;
+ SimpleNetworkDevice->SimpleNetwork.Receive = Undi16SimpleNetworkReceive;
+ SimpleNetworkDevice->SimpleNetwork.Mode = &(SimpleNetworkDevice->SimpleNetworkMode);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ Undi16SimpleNetworkWaitForPacket,
+ &SimpleNetworkDevice->SimpleNetwork,
+ &SimpleNetworkDevice->SimpleNetwork.WaitForPacket
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : Could not create event. Status = %r\n", Status));
+ goto Done;
+ }
+ //
+ // Create an event to be signalled when ExitBootServices occurs in order
+ // to clean up nicely
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ Undi16SimpleNetworkEvent,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &SimpleNetworkDevice->EfiBootEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : Could not create event. Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // Create an event to be signalled when Legacy Boot occurs to clean up the IVT
+ //
+ Status = EfiCreateEventLegacyBootEx(
+ TPL_NOTIFY,
+ Undi16SimpleNetworkEvent,
+ NULL,
+ &SimpleNetworkDevice->LegacyBootEvent
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR,"ERROR : Could not create event. Status = %r\n",Status));
+ goto Done;
+ }
+
+ //
+ // Initialize the SimpleNetwork Mode Information
+ //
+ DEBUG ((DEBUG_NET, "Initialize Mode Information\n"));
+
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStopped;
+ SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize = 14;
+ SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable = TRUE;
+ SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported = TRUE;
+ SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount = MAXNUM_MCADDR;
+
+ //
+ // Initialize the SimpleNetwork Private Information
+ //
+ DEBUG ((DEBUG_NET, "Initialize Private Information\n"));
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1,
+ (VOID **) &SimpleNetworkDevice->Xmit
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ 1,
+ &SimpleNetworkDevice->TxRealModeMediaHeader
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ 1,
+ &SimpleNetworkDevice->TxRealModeDataBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ 1,
+ &SimpleNetworkDevice->TxDestAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ SimpleNetworkDevice->Xmit->XmitOffset = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) & 0x000f);
+
+ SimpleNetworkDevice->Xmit->XmitSegment = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) >> 4);
+
+ SimpleNetworkDevice->Xmit->DataBlkCount = 1;
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDPtrType = 1;
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDRsvdByte = 0;
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrOffset = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) & 0x000f);
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrSegment = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) >> 4);
+
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+
+ //
+ // Start() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "Start()\n"));
+
+ Status = Undi16SimpleNetworkStart (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // GetInformation() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "GetInformation()\n"));
+
+ Status = Undi16SimpleNetworkGetInformation (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Build the device path for the child device
+ //
+ ZeroMem (&Node, sizeof (Node));
+ Node.DevPath.Type = MESSAGING_DEVICE_PATH;
+ Node.DevPath.SubType = MSG_MAC_ADDR_DP;
+ SetDevicePathNodeLength (&Node.DevPath, sizeof (MAC_ADDR_DEVICE_PATH));
+ CopyMem (
+ &Node.MacAddr.MacAddress,
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+ SimpleNetworkDevice->DevicePath = AppendDevicePathNode (
+ SimpleNetworkDevice->BaseDevicePath,
+ &Node.DevPath
+ );
+
+ //
+ // GetNicType() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "GetNicType()\n"));
+
+ Status = Undi16SimpleNetworkGetNicType (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // GetNdisInfo() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "GetNdisInfo()\n"));
+
+ Status = Undi16SimpleNetworkGetNdisInfo (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Stop() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "Stop()\n"));
+
+ Status = SimpleNetworkDevice->SimpleNetwork.Stop (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Print Mode information
+ //
+ DEBUG ((DEBUG_NET, "Mode->State = %d\n", SimpleNetworkDevice->SimpleNetworkMode.State));
+ DEBUG ((DEBUG_NET, "Mode->HwAddressSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize));
+ DEBUG ((DEBUG_NET, "Mode->MacAddressChangeable = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable));
+ DEBUG ((DEBUG_NET, "Mode->MultiplTxSupported = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported));
+ DEBUG ((DEBUG_NET, "Mode->NvRamSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamSize));
+ DEBUG ((DEBUG_NET, "Mode->NvRamAccessSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamAccessSize));
+ DEBUG ((DEBUG_NET, "Mode->ReceiveFilterSetting = %d\n", SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting));
+ DEBUG ((DEBUG_NET, "Mode->IfType = %d\n", SimpleNetworkDevice->SimpleNetworkMode.IfType));
+ DEBUG ((DEBUG_NET, "Mode->MCastFilterCount = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount));
+ for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; Index++) {
+ DEBUG ((DEBUG_NET, " Filter[%02d] = ", Index));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index].Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+ }
+
+ DEBUG ((DEBUG_NET, "CurrentAddress = "));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress.Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ DEBUG ((DEBUG_NET, "BroadcastAddress = "));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress.Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ DEBUG ((DEBUG_NET, "PermanentAddress = "));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress.Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ //
+ // The network device was started, information collected, and stopped.
+ // Install protocol interfaces for the SimpleNetwork device.
+ //
+ DEBUG ((DEBUG_NET, "Install Protocol Interfaces on network interface\n"));
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &SimpleNetworkDevice->Handle,
+ &gEfiSimpleNetworkProtocolGuid,
+ &SimpleNetworkDevice->SimpleNetwork,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ &SimpleNetworkDevice->Nii,
+ &gEfiDevicePathProtocolGuid,
+ SimpleNetworkDevice->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Open PCI I/O from the newly created child handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ SimpleNetworkDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ DEBUG ((DEBUG_INIT, "UNDI16 Driver : EFI_SUCCESS\n"));
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (SimpleNetworkDevice != NULL) {
+
+ Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);
+ //
+ // CLOSE + SHUTDOWN
+ //
+ Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);
+ //
+ // CLEANUP
+ //
+ Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);
+ //
+ // STOP
+ //
+ if (SimpleNetworkDevice->UndiLoaded) {
+ Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);
+ }
+
+ if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);
+ }
+
+ if (SimpleNetworkDevice->LegacyBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);
+ }
+
+ if (SimpleNetworkDevice->EfiBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);
+ }
+
+ if (SimpleNetworkDevice->Xmit != NULL) {
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,
+ sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1
+ );
+ }
+
+ if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);
+ }
+
+ if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);
+ }
+
+ if (SimpleNetworkDevice->TxDestAddr != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);
+ }
+
+ gBS->FreePool (SimpleNetworkDevice);
+
+ //
+ // Only restore the vector if it was cached.
+ //
+ if (mCachedInt1A) {
+ RestoreCachedVectorAddress (0x1A);
+ mCachedInt1A = FALSE;
+ }
+ }
+
+ if (PciIo != NULL) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ Supports,
+ NULL
+ );
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+ return Status;
+}
+
+/**
+ Stops the device by given device controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param ChildHandleBuffer An array of child handles to be freed. May be NULL if
+ NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS - The device was stopped.
+ @retval EFI_DEVICE_ERROR - The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+
+ //
+ // Complete all outstanding transactions to Controller.
+ // Don't allow any new transaction to Controller to be started.
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ Supports,
+ NULL
+ );
+ }
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &SimpleNetwork,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SimpleNetwork);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ SimpleNetworkDevice->Handle,
+ &gEfiSimpleNetworkProtocolGuid,
+ &SimpleNetworkDevice->SimpleNetwork,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ &SimpleNetworkDevice->Nii,
+ &gEfiDevicePathProtocolGuid,
+ SimpleNetworkDevice->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+
+ Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);
+ //
+ // CLOSE + SHUTDOWN
+ //
+ Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);
+ //
+ // CLEANUP
+ //
+ Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);
+ //
+ // STOP
+ //
+ if (SimpleNetworkDevice->UndiLoaded) {
+ Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);
+ }
+
+ if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);
+ }
+
+ if (SimpleNetworkDevice->LegacyBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);
+ }
+
+ if (SimpleNetworkDevice->EfiBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);
+ }
+
+ if (SimpleNetworkDevice->Xmit != NULL) {
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,
+ sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1
+ );
+ }
+
+ if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);
+ }
+
+ if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);
+ }
+
+ if (SimpleNetworkDevice->TxDestAddr != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);
+ }
+
+ gBS->FreePool (SimpleNetworkDevice);
+ }
+
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// FIFO Support Functions
+//
+/**
+ Judge whether transmit FIFO is full.
+
+ @param Fifo Point to trasmit FIFO structure.
+
+ @return BOOLEAN whether transmit FIFO is full.
+**/
+BOOLEAN
+SimpleNetworkTransmitFifoFull (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo
+ )
+{
+ if (((Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE) == Fifo->First) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Judge whether transmit FIFO is empty.
+
+ @param Fifo Point to trasmit FIFO structure.
+
+ @return BOOLEAN whether transmit FIFO is empty.
+**/
+BOOLEAN
+SimpleNetworkTransmitFifoEmpty (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo
+ )
+{
+ if (Fifo->Last == Fifo->First) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Add data into transmit buffer.
+
+ @param Fifo Point to trasmit FIFO structure.
+ @param Data The data point want to be added.
+
+ @retval EFI_OUT_OF_RESOURCES FIFO is full
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+SimpleNetworkTransmitFifoAdd (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,
+ VOID *Data
+ )
+{
+ if (SimpleNetworkTransmitFifoFull (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Fifo->Data[Fifo->Last] = Data;
+ Fifo->Last = (Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get a data and remove it from network transmit FIFO.
+
+ @param Fifo Point to trasmit FIFO structure.
+ @param Data On return, point to the data point want to be got and removed.
+
+ @retval EFI_OUT_OF_RESOURCES network transmit buffer is empty.
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+SimpleNetworkTransmitFifoRemove (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,
+ VOID **Data
+ )
+{
+ if (SimpleNetworkTransmitFifoEmpty (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Data = Fifo->Data[Fifo->First];
+ Fifo->First = (Fifo->First + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get recive filter setting according to EFI mask value.
+
+ @param ReceiveFilterSetting filter setting EFI mask value.
+
+ @return UINT16 Undi filter setting value.
+**/
+UINT16
+Undi16GetPacketFilterSetting (
+ UINTN ReceiveFilterSetting
+ )
+{
+ UINT16 PktFilter;
+
+ PktFilter = 0;
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ PktFilter |= FLTR_DIRECTED;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ PktFilter |= FLTR_DIRECTED;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ PktFilter |= FLTR_BRDCST;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ PktFilter |= FLTR_PRMSCS;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ PktFilter |= FLTR_PRMSCS;
+ //
+ // @bug : Do not know if this is right????
+ //
+ }
+ //
+ // @bug : What is FLTR_SRC_RTG?
+ //
+ return PktFilter;
+}
+
+/**
+ Get filter setting from multi cast buffer .
+
+ @param Mode Point to mode structure.
+ @param McastBuffer The multi cast buffer
+ @param HwAddressSize Size of filter value.
+
+**/
+VOID
+Undi16GetMCastFilters (
+ IN EFI_SIMPLE_NETWORK_MODE *Mode,
+ IN OUT PXENV_UNDI_MCAST_ADDR_T *McastBuffer,
+ IN UINTN HwAddressSize
+ )
+{
+ UINTN Index;
+
+ //
+ // @bug : What if Mode->MCastFilterCount > MAXNUM_MCADDR?
+ //
+ McastBuffer->MCastAddrCount = (UINT16) Mode->MCastFilterCount;
+ for (Index = 0; Index < MAXNUM_MCADDR; Index++) {
+ if (Index < McastBuffer->MCastAddrCount) {
+ CopyMem (&McastBuffer->MCastAddr[Index], &Mode->MCastFilter[Index], HwAddressSize);
+ } else {
+ ZeroMem (&McastBuffer->MCastAddr[Index], HwAddressSize);
+ }
+ }
+}
+//
+// Load 16 bit UNDI Option ROM into memory
+//
+/**
+ Loads the undi driver.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_SUCCESS - Successfully loads undi driver.
+ @retval EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.
+**/
+EFI_STATUS
+Undi16SimpleNetworkLoadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN RomAddress;
+ PCI_EXPANSION_ROM_HEADER *PciExpansionRomHeader;
+ PCI_DATA_STRUCTURE *PciDataStructure;
+ PCI_TYPE00 Pci;
+
+ if (!mCachedInt1A) {
+ Status = CacheVectorAddress (0x1A);
+ if (!EFI_ERROR (Status)) {
+ mCachedInt1A = TRUE;
+ }
+ }
+
+ PciIo = SimpleNetworkDevice->PciIo;
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+
+ for (RomAddress = 0xc0000; RomAddress < 0xfffff; RomAddress += 0x800) {
+
+ PciExpansionRomHeader = (PCI_EXPANSION_ROM_HEADER *) RomAddress;
+
+ if (PciExpansionRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ continue;
+ }
+
+ DEBUG ((DEBUG_INIT, "Option ROM found at %X\n", RomAddress));
+
+ PciDataStructure = (PCI_DATA_STRUCTURE *) (RomAddress + PciExpansionRomHeader->PcirOffset);
+
+ if (PciDataStructure->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
+ continue;
+ }
+
+ DEBUG ((DEBUG_INIT, "PCI Data Structure found at %X\n", PciDataStructure));
+
+ if (PciDataStructure->VendorId != Pci.Hdr.VendorId || PciDataStructure->DeviceId != Pci.Hdr.DeviceId) {
+ continue;
+ }
+
+ DEBUG (
+ (DEBUG_INIT,
+ "PCI device with matchinng VendorId and DeviceId (%d,%d)\n",
+ (UINTN) PciDataStructure->VendorId,
+ (UINTN) PciDataStructure->DeviceId)
+ );
+
+ Status = LaunchBaseCode (SimpleNetworkDevice, RomAddress);
+
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Unload 16 bit UNDI Option ROM from memory
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+Undi16SimpleNetworkUnloadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ if (SimpleNetworkDevice->UndiLoaderTable != NULL) {
+ ZeroMem (SimpleNetworkDevice->UndiLoaderTable, SimpleNetworkDevice->UndiLoaderTablePages << EFI_PAGE_SHIFT);
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->UndiLoaderTable,
+ SimpleNetworkDevice->UndiLoaderTablePages
+ );
+ }
+
+ if (SimpleNetworkDevice->DestinationDataSegment != NULL) {
+ ZeroMem (
+ SimpleNetworkDevice->DestinationDataSegment,
+ SimpleNetworkDevice->DestinationDataSegmentPages << EFI_PAGE_SHIFT
+ );
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationDataSegment,
+ SimpleNetworkDevice->DestinationDataSegmentPages
+ );
+ }
+
+ if (SimpleNetworkDevice->DestinationStackSegment != NULL) {
+ ZeroMem (
+ SimpleNetworkDevice->DestinationStackSegment,
+ SimpleNetworkDevice->DestinationStackSegmentPages << EFI_PAGE_SHIFT
+ );
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationStackSegment,
+ SimpleNetworkDevice->DestinationStackSegmentPages
+ );
+ }
+
+ if (SimpleNetworkDevice->DestinationCodeSegment != NULL) {
+ ZeroMem (
+ SimpleNetworkDevice->DestinationCodeSegment,
+ SimpleNetworkDevice->DestinationCodeSegmentPages << EFI_PAGE_SHIFT
+ );
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationCodeSegment,
+ SimpleNetworkDevice->DestinationCodeSegmentPages
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start the UNDI interface.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+ @param Ax PCI address of Undi device.
+
+ @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
+ @retval Others Status of start 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStartUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINT16 Ax
+ )
+{
+ EFI_STATUS Status;
+ PXENV_START_UNDI_T Start;
+
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ //
+ // @bug : What is this state supposed to be???
+ //
+ Start.Status = INIT_PXE_STATUS;
+ Start.Ax = Ax;
+ Start.Bx = 0x0000;
+ Start.Dx = 0x0000;
+ Start.Di = 0x0000;
+ Start.Es = 0x0000;
+
+ Status = PxeStartUndi (SimpleNetworkDevice, &Start);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Start.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+
+/**
+ Stop the UNDI interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM.
+ @retval Others Status of stop 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStopUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ EFI_STATUS Status;
+ PXENV_STOP_UNDI_T Stop;
+
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Stop.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiStop (SimpleNetworkDevice, &Stop);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Stop.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Cleanup Unid network interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to cleanup 16 bit UNDI ROM.
+ @retval Others Status of cleanup 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCleanupUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ EFI_STATUS Status;
+ PXENV_UNDI_CLEANUP_T Cleanup;
+
+ //
+ // Call 16 bit UNDI ROM to cleanup the network interface
+ //
+ Cleanup.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiCleanup (SimpleNetworkDevice, &Cleanup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Cleanup.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Get runtime information for Undi network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get runtime information for Undi network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetInformation (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN Index;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ ZeroMem (&SimpleNetworkDevice->GetInformation, sizeof (PXENV_UNDI_GET_INFORMATION_T));
+
+ SimpleNetworkDevice->GetInformation.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiGetInformation (SimpleNetworkDevice, &SimpleNetworkDevice->GetInformation);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_NET, " GetInformation.Status = %d\n", SimpleNetworkDevice->GetInformation.Status));
+ DEBUG ((DEBUG_NET, " GetInformation.BaseIo = %d\n", SimpleNetworkDevice->GetInformation.BaseIo));
+ DEBUG ((DEBUG_NET, " GetInformation.IntNumber = %d\n", SimpleNetworkDevice->GetInformation.IntNumber));
+ DEBUG ((DEBUG_NET, " GetInformation.MaxTranUnit = %d\n", SimpleNetworkDevice->GetInformation.MaxTranUnit));
+ DEBUG ((DEBUG_NET, " GetInformation.HwType = %d\n", SimpleNetworkDevice->GetInformation.HwType));
+ DEBUG ((DEBUG_NET, " GetInformation.HwAddrLen = %d\n", SimpleNetworkDevice->GetInformation.HwAddrLen));
+ DEBUG ((DEBUG_NET, " GetInformation.ROMAddress = %d\n", SimpleNetworkDevice->GetInformation.ROMAddress));
+ DEBUG ((DEBUG_NET, " GetInformation.RxBufCt = %d\n", SimpleNetworkDevice->GetInformation.RxBufCt));
+ DEBUG ((DEBUG_NET, " GetInformation.TxBufCt = %d\n", SimpleNetworkDevice->GetInformation.TxBufCt));
+
+ DEBUG ((DEBUG_NET, " GetInformation.CurNodeAddr ="));
+ for (Index = 0; Index < 16; Index++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.CurrentNodeAddress[Index]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ DEBUG ((DEBUG_NET, " GetInformation.PermNodeAddr ="));
+ for (Index = 0; Index < 16; Index++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.PermNodeAddress[Index]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->GetInformation.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The information has been retrieved. Fill in Mode data.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize = SimpleNetworkDevice->GetInformation.HwAddrLen;
+
+ SimpleNetworkDevice->SimpleNetworkMode.MaxPacketSize = SimpleNetworkDevice->GetInformation.MaxTranUnit;
+
+ SimpleNetworkDevice->SimpleNetworkMode.IfType = (UINT8) SimpleNetworkDevice->GetInformation.HwType;
+
+ ZeroMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ sizeof SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress
+ );
+
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ &SimpleNetworkDevice->GetInformation.CurrentNodeAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ ZeroMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ sizeof SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress
+ );
+
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ &SimpleNetworkDevice->GetInformation.PermNodeAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ //
+ // hard code broadcast address - not avail in PXE2.1
+ //
+ ZeroMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,
+ sizeof SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress
+ );
+
+ SetMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,
+ 0xff
+ );
+
+ return Status;
+}
+
+/**
+ Get NIC type
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NIC type.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNicType (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (&SimpleNetworkDevice->GetNicType, sizeof (PXENV_UNDI_GET_NIC_TYPE_T));
+
+ SimpleNetworkDevice->GetNicType.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiGetNicType (SimpleNetworkDevice, &SimpleNetworkDevice->GetNicType);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_NET, " GetNicType.Status = %d\n", SimpleNetworkDevice->GetNicType.Status));
+ DEBUG ((DEBUG_NET, " GetNicType.NicType = %d\n", SimpleNetworkDevice->GetNicType.NicType));
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->GetNicType.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The information has been retrieved. Fill in Mode data.
+ //
+ return Status;
+}
+
+/**
+ Get NDIS information
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NDIS information.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (&SimpleNetworkDevice->GetNdisInfo, sizeof (PXENV_UNDI_GET_NDIS_INFO_T));
+
+ SimpleNetworkDevice->GetNdisInfo.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiGetNdisInfo (SimpleNetworkDevice, &SimpleNetworkDevice->GetNdisInfo);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_NET, " GetNdisInfo.Status = %d\n", SimpleNetworkDevice->GetNdisInfo.Status));
+ DEBUG ((DEBUG_NET, " GetNdisInfo.IfaceType = %a\n", SimpleNetworkDevice->GetNdisInfo.IfaceType));
+ DEBUG ((DEBUG_NET, " GetNdisInfo.LinkSpeed = %d\n", SimpleNetworkDevice->GetNdisInfo.LinkSpeed));
+ DEBUG ((DEBUG_NET, " GetNdisInfo.ServiceFlags = %08x\n", SimpleNetworkDevice->GetNdisInfo.ServiceFlags));
+
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->GetNdisInfo.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The information has been retrieved. Fill in Mode data.
+ //
+ return Status;
+}
+
+/**
+ Call Undi ROM 16bit ISR() to check interrupt cause.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param FrameLength The length of frame buffer.
+ @param FrameHeaderLength The length of frame buffer's header if has.
+ @param Frame The frame buffer to process network interrupt.
+ @param ProtType The type network transmit protocol
+ @param PktType The type of package.
+
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM's ISR, or status is invalid.
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+Undi16SimpleNetworkIsr (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN UINTN *FrameLength,
+ IN UINTN *FrameHeaderLength, OPTIONAL
+ IN UINT8 *Frame, OPTIONAL
+ IN UINT8 *ProtType, OPTIONAL
+ IN UINT8 *PktType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ BOOLEAN FrameReceived;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ FrameReceived = FALSE;
+
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_NET, "Isr() IsrValid = %d\n", SimpleNetworkDevice->IsrValid));
+
+ if (!SimpleNetworkDevice->IsrValid) {
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
+ SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
+ SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
+
+ DEBUG ((DEBUG_NET, "Isr() START\n"));
+
+ Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // There have been no events on this UNDI interface, so return EFI_NOT_READY
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OURS) {
+ return EFI_SUCCESS;
+ }
+ //
+ // There is data to process, so call until all events processed.
+ //
+ ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
+ SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
+ SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
+
+ DEBUG ((DEBUG_NET, "Isr() PROCESS\n"));
+
+ Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SimpleNetworkDevice->IsrValid = TRUE;
+ }
+ //
+ // Call UNDI GET_NEXT until DONE
+ //
+ while (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_DONE) {
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // UNDI is busy. Caller will have to call again.
+ // This should never happen with a polled mode driver.
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) {
+ DEBUG ((DEBUG_NET, " BUSY\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Check for invalud UNDI FuncFlag
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE &&
+ SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_TRANSMIT
+ ) {
+ DEBUG ((DEBUG_NET, " Invalid SimpleNetworkDevice->Isr.FuncFlag value %d\n", SimpleNetworkDevice->Isr.FuncFlag));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check for Transmit Event
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
+ DEBUG ((DEBUG_NET, " TRANSMIT\n"));
+ SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+ //
+ // Check for Receive Event
+ //
+ else if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE) {
+ //
+ // note - this code will hang on a receive interrupt in a GetStatus loop
+ //
+ DEBUG ((DEBUG_NET, " RECEIVE\n"));
+ SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.BufferLength = %d\n", SimpleNetworkDevice->Isr.BufferLength));
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameLength = %d\n", SimpleNetworkDevice->Isr.FrameLength));
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameHeaderLength = %d\n", SimpleNetworkDevice->Isr.FrameHeaderLength));
+ DEBUG (
+ (
+ DEBUG_NET, "SimpleNetworkDevice->Isr.Frame = %04x:%04x\n", SimpleNetworkDevice->Isr.FrameSegSel,
+ SimpleNetworkDevice->Isr.FrameOffset
+ )
+ );
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.ProtType = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.PktType = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));
+
+ if (FrameReceived) {
+ return EFI_SUCCESS;
+ }
+
+ if ((Frame == NULL) || (SimpleNetworkDevice->Isr.FrameLength > *FrameLength)) {
+ DEBUG ((DEBUG_NET, "return EFI_BUFFER_TOO_SMALL *FrameLength = %08x\n", *FrameLength));
+ *FrameLength = SimpleNetworkDevice->Isr.FrameLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *FrameLength = SimpleNetworkDevice->Isr.FrameLength;
+ if (FrameHeaderLength != NULL) {
+ *FrameHeaderLength = SimpleNetworkDevice->Isr.FrameHeaderLength;
+ }
+
+ if (ProtType != NULL) {
+ *ProtType = SimpleNetworkDevice->Isr.ProtType;
+ }
+
+ if (PktType != NULL) {
+ *PktType = SimpleNetworkDevice->Isr.PktType;
+ }
+
+ CopyMem (
+ Frame,
+ (VOID *)(UINTN) ((SimpleNetworkDevice->Isr.FrameSegSel << 4) + SimpleNetworkDevice->Isr.FrameOffset),
+ SimpleNetworkDevice->Isr.BufferLength
+ );
+ Frame = Frame + SimpleNetworkDevice->Isr.BufferLength;
+ if (SimpleNetworkDevice->Isr.BufferLength == SimpleNetworkDevice->Isr.FrameLength) {
+ FrameReceived = TRUE;
+ }
+ }
+ //
+ // There is data to process, so call until all events processed.
+ //
+ ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
+ SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
+ SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+
+ DEBUG ((DEBUG_NET, "Isr() GET NEXT\n"));
+
+ Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ // if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
+ // return EFI_DEVICE_ERROR;
+ // }
+ //
+ }
+
+ SimpleNetworkDevice->IsrValid = FALSE;
+ return EFI_SUCCESS;
+}
+//
+// ///////////////////////////////////////////////////////////////////////////////////////
+// Simple Network Protocol Interface Functions using 16 bit UNDI Option ROMs
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Start()
+//
+/**
+ Call 16 bit UNDI ROM to start the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_STARTUP_T Startup;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ return EFI_ALREADY_STARTED;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Startup.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiStartup (SimpleNetworkDevice, &Startup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Startup.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The UNDI interface has been started, so update the State.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;
+
+ //
+ //
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = 0;
+ SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount = 0;
+
+ return Status;
+}
+//
+// Stop()
+//
+/**
+ Call 16 bit UNDI ROM to stop the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStopped;
+
+ return Status;
+}
+
+//
+// Initialize()
+//
+/**
+ Initialize network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtraRxBufferSize The size of extra request receive buffer.
+ @param ExtraTxBufferSize The size of extra request transmit buffer.
+
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_INITIALIZE_T Initialize;
+ PXENV_UNDI_OPEN_T Open;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkInitialized:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Initialize.Status = INIT_PXE_STATUS;
+ Initialize.ProtocolIni = 0;
+
+ Status = PxeUndiInitialize (SimpleNetworkDevice, &Initialize);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Status = %r\n", Status));
+ DEBUG ((DEBUG_ERROR, "Initialize.Status == %xh\n", Initialize.Status));
+
+ if (Initialize.Status == PXENV_STATUS_UNDI_MEDIATEST_FAILED) {
+ Status = EFI_NO_MEDIA;
+ }
+
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Initialize.Status != PXENV_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Initialize.Status = %04x\n", Initialize.Status));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ Open.Status = INIT_PXE_STATUS;
+ Open.OpenFlag = 0;
+ Open.PktFilter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
+ Undi16GetMCastFilters (
+ &SimpleNetworkDevice->SimpleNetworkMode,
+ &Open.McastBuffer,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ Status = PxeUndiOpen (SimpleNetworkDevice, &Open);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Status = %r\n", Status));
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Open.Status != PXENV_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Open.Status = %04x\n", Open.Status));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The UNDI interface has been initialized, so update the State.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkInitialized;
+
+ //
+ // If initialize succeeds, then assume that media is present.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = TRUE;
+
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+ SimpleNetworkDevice->IsrValid = FALSE;
+
+ return Status;
+}
+//
+// Reset()
+//
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtendedVerification Need extended verfication.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_RESET_T Reset;
+ UINT16 Rx_filter;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ Reset.Status = INIT_PXE_STATUS;
+
+ Rx_filter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
+
+ Undi16GetMCastFilters (
+ &SimpleNetworkDevice->SimpleNetworkMode,
+ &Reset.R_Mcast_Buf,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ Status = PxeUndiResetNic (SimpleNetworkDevice, &Reset, Rx_filter);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Reset.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+ SimpleNetworkDevice->IsrValid = FALSE;
+
+ return Status;
+}
+//
+// Shutdown()
+//
+/**
+ Shutdown network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_CLOSE_T Close;
+ PXENV_UNDI_SHUTDOWN_T Shutdown;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ SimpleNetworkDevice->IsrValid = FALSE;
+
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Close.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiClose (SimpleNetworkDevice, &Close);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Close.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ Shutdown.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiShutdown (SimpleNetworkDevice, &Shutdown);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Shutdown.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The UNDI interface has been initialized, so update the State.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;
+
+ //
+ // If shutdown succeeds, then assume that media is not present.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = FALSE;
+
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+
+ //
+ // A short delay. Without this an initialize immediately following
+ // a shutdown will cause some versions of UNDI-16 to stop operating.
+ //
+ gBS->Stall (250000);
+
+ return Status;
+}
+//
+// ReceiveFilters()
+//
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Enable Enable mask value
+ @param Disable Disable mask value
+ @param ResetMCastFilter Whether reset multi cast filter or not
+ @param MCastFilterCnt Count of mutli cast filter for different MAC address
+ @param MCastFilter Buffer for mustli cast filter for different MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS * MCastFilter OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT32 NewFilter;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_CLOSE_T Close;
+ PXENV_UNDI_OPEN_T Open;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // First deal with possible filter setting changes
+ //
+ if ((Enable == 0) && (Disable == 0) && !ResetMCastFilter) {
+ return EFI_SUCCESS;
+ }
+
+ NewFilter = (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting | Enable) &~Disable;
+
+ if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ if ((MCastFilterCnt == 0) || (MCastFilter == 0) || MCastFilterCnt > SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Call 16 bit UNDI ROM to close the network interface
+ //
+ Close.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiClose (SimpleNetworkDevice, &Close);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Close.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ ZeroMem (&Open, sizeof Open);
+
+ Open.Status = INIT_PXE_STATUS;
+ Open.PktFilter = Undi16GetPacketFilterSetting (NewFilter);
+
+ if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ //
+ // Copy the MAC addresses into the UNDI open parameter structure
+ //
+ Open.McastBuffer.MCastAddrCount = (UINT16) MCastFilterCnt;
+ for (Index = 0; Index < MCastFilterCnt; ++Index) {
+ CopyMem (
+ Open.McastBuffer.MCastAddr[Index],
+ &MCastFilter[Index],
+ sizeof Open.McastBuffer.MCastAddr[Index]
+ );
+ }
+ } else if (!ResetMCastFilter) {
+ for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; ++Index) {
+ CopyMem (
+ Open.McastBuffer.MCastAddr[Index],
+ &SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],
+ sizeof Open.McastBuffer.MCastAddr[Index]
+ );
+ }
+ }
+
+ Status = PxeUndiOpen (SimpleNetworkDevice, &Open);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Open.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ SimpleNetworkDevice->IsrValid = FALSE;
+ SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = NewFilter;
+
+ if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount = (UINT32) MCastFilterCnt;
+ for (Index = 0; Index < MCastFilterCnt; ++Index) {
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],
+ &MCastFilter[Index],
+ sizeof (EFI_MAC_ADDRESS)
+ );
+ }
+ }
+ //
+ // Read back multicast addresses.
+ //
+ return EFI_SUCCESS;
+}
+//
+// StationAddress()
+//
+/**
+ Set new MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Reset Whether reset station MAC address to permenent address
+ @param New A pointer to New address
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS * New OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_SET_STATION_ADDR_T SetStationAddr;
+ //
+ // EFI_DEVICE_PATH_PROTOCOL *OldDevicePath;
+ //
+ PXENV_UNDI_CLOSE_T Close;
+ PXENV_UNDI_OPEN_T Open;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ SetStationAddr.Status = INIT_PXE_STATUS;
+
+ if (Reset) {
+ //
+ // If we are reseting the Station Address to the permanent address, and the
+ // Station Address is not programmable, then just return EFI_SUCCESS.
+ //
+ if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {
+ return EFI_SUCCESS;
+ }
+ //
+ // If the address is already the permanent address, then just return success.
+ //
+ if (CompareMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ ) == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the adapters permanent address to the new station address
+ //
+ CopyMem (
+ &SetStationAddr.StationAddress,
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+ } else {
+ //
+ // If we are setting the Station Address, and the
+ // Station Address is not programmable, return invalid parameter.
+ //
+ if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If the address is already the new address, then just return success.
+ //
+ if (CompareMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ New,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ ) == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy New to the new station address
+ //
+ CopyMem (
+ &SetStationAddr.StationAddress,
+ New,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ }
+ //
+ // Call 16 bit UNDI ROM to stop the network interface
+ //
+ Close.Status = INIT_PXE_STATUS;
+
+ PxeUndiClose (SimpleNetworkDevice, &Close);
+
+ //
+ // Call 16-bit UNDI ROM to set the station address
+ //
+ SetStationAddr.Status = PXENV_STATUS_SUCCESS;
+
+ Status = PxeUndiSetStationAddr (SimpleNetworkDevice, &SetStationAddr);
+
+ //
+ // Call 16-bit UNDI ROM to start the network interface
+ //
+ Open.Status = PXENV_STATUS_SUCCESS;
+ Open.OpenFlag = 0;
+ Open.PktFilter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
+ Undi16GetMCastFilters (
+ &SimpleNetworkDevice->SimpleNetworkMode,
+ &Open.McastBuffer,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ PxeUndiOpen (SimpleNetworkDevice, &Open);
+
+ //
+ // Check status from station address change
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SetStationAddr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ &SetStationAddr.StationAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+#if 0 /* The device path is based on the permanent address not the current address. */
+ //
+ // The station address was changed, so update the device path with the new MAC address.
+ //
+ OldDevicePath = SimpleNetworkDevice->DevicePath;
+ SimpleNetworkDevice->DevicePath = DuplicateDevicePath (SimpleNetworkDevice->BaseDevicePath);
+ SimpleNetworkAppendMacAddressDevicePath (
+ &SimpleNetworkDevice->DevicePath,
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress
+ );
+
+ Status = LibReinstallProtocolInterfaces (
+ SimpleNetworkDevice->Handle,
+ &DevicePathProtocol,
+ OldDevicePath,
+ SimpleNetworkDevice->DevicePath,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to reinstall the DevicePath protocol for the Simple Network Device\n"));
+ DEBUG ((DEBUG_ERROR, " Status = %r\n", Status));
+ }
+
+ FreePool (OldDevicePath);
+#endif /* 0 */
+
+ return Status;
+}
+//
+// Statistics()
+//
+/**
+ Resets or collects the statistics on a network interface.
+
+ @param This Protocol instance pointer.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
+ output the size, in bytes, of the resulting table of
+ statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics.
+
+ @retval EFI_SUCCESS The statistics were collected from the network interface.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStatistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS * StatisticsTable OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_CLEAR_STATISTICS_T ClearStatistics;
+ PXENV_UNDI_GET_STATISTICS_T GetStatistics;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((StatisticsSize != NULL) && (*StatisticsSize != 0) && (StatisticsTable == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Reset is TRUE, then clear all the statistics.
+ //
+ if (Reset) {
+
+ DEBUG ((DEBUG_NET, " RESET Statistics\n"));
+
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ ClearStatistics.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiClearStatistics (SimpleNetworkDevice, &ClearStatistics);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (ClearStatistics.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_NET, " RESET Statistics Complete"));
+ }
+
+ if (StatisticsSize != NULL) {
+ EFI_NETWORK_STATISTICS LocalStatisticsTable;
+
+ DEBUG ((DEBUG_NET, " GET Statistics\n"));
+
+ //
+ // If the size if valid, then see if the table is valid
+ //
+ if (StatisticsTable == NULL) {
+ DEBUG ((DEBUG_NET, " StatisticsTable is NULL\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ GetStatistics.Status = INIT_PXE_STATUS;
+ GetStatistics.XmtGoodFrames = 0;
+ GetStatistics.RcvGoodFrames = 0;
+ GetStatistics.RcvCRCErrors = 0;
+ GetStatistics.RcvResourceErrors = 0;
+
+ Status = PxeUndiGetStatistics (SimpleNetworkDevice, &GetStatistics);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (GetStatistics.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Fill in the Statistics Table with the collected values.
+ //
+ SetMem (&LocalStatisticsTable, sizeof LocalStatisticsTable, 0xff);
+
+ LocalStatisticsTable.TxGoodFrames = GetStatistics.XmtGoodFrames;
+ LocalStatisticsTable.RxGoodFrames = GetStatistics.RcvGoodFrames;
+ LocalStatisticsTable.RxCrcErrorFrames = GetStatistics.RcvCRCErrors;
+ LocalStatisticsTable.RxDroppedFrames = GetStatistics.RcvResourceErrors;
+
+ CopyMem (StatisticsTable, &LocalStatisticsTable, *StatisticsSize);
+
+ DEBUG (
+ (DEBUG_NET,
+ " Statistics Collected : Size=%d Buf=%08x\n",
+ *StatisticsSize,
+ StatisticsTable)
+ );
+
+ DEBUG ((DEBUG_NET, " GET Statistics Complete"));
+
+ if (*StatisticsSize < sizeof LocalStatisticsTable) {
+ DEBUG ((DEBUG_NET, " BUFFER TOO SMALL\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *StatisticsSize = sizeof LocalStatisticsTable;
+
+ return Status;
+
+ }
+
+ return EFI_SUCCESS;
+}
+//
+// MCastIpToMac()
+//
+/**
+ Translate IP address to MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param IPv6 IPv6 or IPv4
+ @param IP A pointer to given Ip address.
+ @param MAC On return, translated MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_INVALID_PARAMETER Invalid IP address.
+ @retval EFI_INVALID_PARAMETER Invalid return buffer for holding MAC address.
+ @retval EFI_UNSUPPORTED Do not support IPv6
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkMCastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_GET_MCAST_ADDR_T GetMcastAddr;
+
+ if (This == NULL || IP == NULL || MAC == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // 16 bit UNDI Option ROMS do not support IPv6. Check for IPv6 usage.
+ //
+ if (IPv6) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ GetMcastAddr.Status = INIT_PXE_STATUS;
+ CopyMem (&GetMcastAddr.InetAddr, IP, 4);
+
+ Status = PxeUndiGetMcastAddr (SimpleNetworkDevice, &GetMcastAddr);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (GetMcastAddr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Copy the MAC address from the returned data structure.
+ //
+ CopyMem (
+ MAC,
+ &GetMcastAddr.MediaAddr,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ return Status;
+}
+//
+// NvData()
+//
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This The protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+//
+// GetStatus()
+//
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This The protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN FrameLength;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (InterruptStatus == NULL && TxBuf == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FrameLength = 0;
+ Status = Undi16SimpleNetworkIsr (This, &FrameLength, NULL, NULL, NULL, NULL);
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // See if the caller wants interrupt info.
+ //
+ if (InterruptStatus != NULL) {
+ *InterruptStatus = SimpleNetworkDevice->InterruptStatus;
+ SimpleNetworkDevice->InterruptStatus = 0;
+ }
+ //
+ // See if the caller wants transmit buffer status info.
+ //
+ if (TxBuf != NULL) {
+ *TxBuf = 0;
+ SimpleNetworkTransmitFifoRemove (&(SimpleNetworkDevice->TxBufferFifo), TxBuf);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_TRANSMIT_T XmitInfo;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize < SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (HeaderSize != 0) {
+ if (HeaderSize != SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestAddr == NULL || Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestAddr != NULL) {
+ CopyMem (
+ Buffer,
+ DestAddr,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+ }
+
+ if (SrcAddr == NULL) {
+ SrcAddr = &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress;
+ }
+
+ CopyMem (
+ (UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,
+ SrcAddr,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ if (Protocol != NULL) {
+ *(UINT16 *) ((UINT8 *) Buffer + 2 * SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize) = (UINT16) (((*Protocol & 0xFF) << 8) | ((*Protocol >> 8) & 0xFF));
+ }
+ }
+ //
+ // See if the recycled transmit buffer FIFO is full.
+ // If it is full, then we can not transmit until the caller calls GetStatus() to pull
+ // off recycled transmit buffers.
+ //
+ if (SimpleNetworkTransmitFifoFull (&(SimpleNetworkDevice->TxBufferFifo))) {
+ return EFI_NOT_READY;
+ }
+ //
+ // Output debug trace message.
+ //
+ DEBUG ((DEBUG_NET, "Undi16SimpleNetworkTransmit\n\r "));
+
+ //
+ // Initialize UNDI WRITE parameter structure.
+ //
+ XmitInfo.Status = INIT_PXE_STATUS;
+ XmitInfo.Protocol = P_UNKNOWN;
+ XmitInfo.XmitFlag = XMT_DESTADDR;
+ XmitInfo.DestAddrOffset = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr & 0x000f);
+ XmitInfo.DestAddrSegment = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr >> 4);
+ XmitInfo.TBDOffset = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit & 0x000f);
+ XmitInfo.TBDSegment = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit >> 4);
+ XmitInfo.Reserved[0] = 0;
+ XmitInfo.Reserved[1] = 0;
+
+ CopyMem (
+ SimpleNetworkDevice->TxDestAddr,
+ Buffer,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ CopyMem (
+ SimpleNetworkDevice->TxRealModeMediaHeader,
+ Buffer,
+ SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize
+ );
+
+ SimpleNetworkDevice->Xmit->ImmedLength = (UINT16) SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize;
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen = (UINT16) (BufferSize - SimpleNetworkDevice->Xmit->ImmedLength);
+
+ CopyMem (
+ SimpleNetworkDevice->TxRealModeDataBuffer,
+ (UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize,
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen
+ );
+
+ //
+ // Make API call to UNDI TRANSMIT
+ //
+ XmitInfo.Status = 0;
+
+ Status = PxeUndiTransmit (SimpleNetworkDevice, &XmitInfo);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ switch (XmitInfo.Status) {
+ case PXENV_STATUS_OUT_OF_RESOURCES:
+ return EFI_NOT_READY;
+
+ case PXENV_STATUS_SUCCESS:
+ break;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Add address of Buffer to the recycled transmit buffer FIFO
+ //
+ SimpleNetworkTransmitFifoAdd (&(SimpleNetworkDevice->TxBufferFifo), Buffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Receives a packet from a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN MediaAddrSize;
+ UINT8 ProtType;
+
+ if (This == NULL || BufferSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Undi16SimpleNetworkIsr (
+ This,
+ BufferSize,
+ HeaderSize,
+ Buffer,
+ &ProtType,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) == 0) {
+ return EFI_NOT_READY;
+
+ }
+
+ SimpleNetworkDevice->InterruptStatus &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+
+ MediaAddrSize = This->Mode->HwAddressSize;
+
+ if (SrcAddr != NULL) {
+ CopyMem (SrcAddr, (UINT8 *) Buffer + MediaAddrSize, MediaAddrSize);
+ }
+
+ if (DestAddr != NULL) {
+ CopyMem (DestAddr, Buffer, MediaAddrSize);
+ }
+
+ if (Protocol != NULL) {
+ *((UINT8 *) Protocol) = *((UINT8 *) Buffer + (2 * MediaAddrSize) + 1);
+ *((UINT8 *) Protocol + 1) = *((UINT8 *) Buffer + (2 * MediaAddrSize));
+ }
+
+ DEBUG ((DEBUG_NET, "Packet Received: BufferSize=%d HeaderSize = %d\n", *BufferSize, *HeaderSize));
+
+ return Status;
+
+}
+//
+// WaitForPacket()
+//
+/**
+ wait for a packet to be received.
+
+ @param Event Event used with WaitForEvent() to wait for a packet to be received.
+ @param Context Event Context
+
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkWaitForPacket (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Someone is waiting on the receive packet event, if there's
+ // a packet pending, signal the event
+ //
+ if (!EFI_ERROR (Undi16SimpleNetworkCheckForPacket (Context))) {
+ gBS->SignalEvent (Event);
+ }
+}
+//
+// CheckForPacket()
+//
+/**
+ Check whether packet is ready for receive.
+
+ @param This The protocol instance pointer.
+
+ @retval EFI_SUCCESS Receive data is ready.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCheckForPacket (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN FrameLength;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ FrameLength = 0;
+ Status = Undi16SimpleNetworkIsr (
+ This,
+ &FrameLength,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) != 0) ? EFI_SUCCESS : EFI_NOT_READY;
+}
+
+/**
+ Signal handlers for ExitBootServices event.
+
+ Clean up any Real-mode UNDI residue from the system
+
+ @param Event ExitBootServices event
+ @param Context
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // NOTE: This is not the only way to effect this cleanup. The prescribed mechanism
+ // would be to perform an UNDI STOP command. This strategam has been attempted
+ // but results in problems making some of the EFI core services from TPL_CALLBACK.
+ // This issue needs to be resolved, but the other alternative has been to perform
+ // the unchain logic explicitly, as done below.
+ //
+ RestoreCachedVectorAddress (0x1A);
+}
+
+/**
+ Allocate buffer below 1M for real mode.
+
+ @param NumPages The number pages want to be allocated.
+ @param Buffer On return, allocated buffer.
+
+ @return Status of allocating pages.
+**/
+EFI_STATUS
+BiosSnp16AllocatePagesBelowOneMb (
+ UINTN NumPages,
+ VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+
+ PhysicalAddress = 0x000fffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesData,
+ NumPages,
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Buffer = (VOID *) (UINTN) PhysicalAddress;
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h
new file mode 100644
index 0000000..b29059f
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h
@@ -0,0 +1,1655 @@
+/** @file
+
+Copyright (c) 1999 - 2010, 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.
+
+**/
+
+#ifndef _BIOS_SNP_16_H_
+#define _BIOS_SNP_16_H_
+
+#include <Uefi.h>
+
+#include <Protocol/LegacyBios.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/NetworkInterfaceIdentifier.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include "Pxe.h"
+
+//
+// BIOS Simple Network Protocol Device Structure
+//
+#define EFI_SIMPLE_NETWORK_DEV_SIGNATURE SIGNATURE_32 ('s', 'n', '1', '6')
+
+#define INIT_PXE_STATUS 0xabcd
+
+#define EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE 64
+
+typedef struct {
+ UINT32 First;
+ UINT32 Last;
+ VOID * Data[EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE];
+} EFI_SIMPLE_NETWORK_DEV_FIFO;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork;
+ EFI_SIMPLE_NETWORK_MODE SimpleNetworkMode;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL Nii;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ //
+ // Local Data for Simple Network Protocol interface goes here
+ //
+ BOOLEAN UndiLoaded;
+ EFI_EVENT EfiBootEvent;
+ EFI_EVENT LegacyBootEvent;
+ UINT16 PxeEntrySegment;
+ UINT16 PxeEntryOffset;
+ EFI_SIMPLE_NETWORK_DEV_FIFO TxBufferFifo;
+ EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath;
+ PXE_T *Pxe; ///< Pointer to !PXE structure
+ PXENV_UNDI_GET_INFORMATION_T GetInformation; ///< Data from GET INFORMATION
+ PXENV_UNDI_GET_NIC_TYPE_T GetNicType; ///< Data from GET NIC TYPE
+ PXENV_UNDI_GET_NDIS_INFO_T GetNdisInfo; ///< Data from GET NDIS INFO
+ BOOLEAN IsrValid; ///< TRUE if Isr contains valid data
+ PXENV_UNDI_ISR_T Isr; ///< Data from ISR
+ PXENV_UNDI_TBD_T *Xmit; //
+ VOID *TxRealModeMediaHeader; ///< < 1 MB Size = 0x100
+ VOID *TxRealModeDataBuffer; ///< < 1 MB Size = GetInformation.MaxTranUnit
+ VOID *TxDestAddr; ///< < 1 MB Size = 16
+ UINT8 InterruptStatus; ///< returned/cleared by GetStatus, set in ISR
+ UINTN UndiLoaderTablePages;
+ UINTN DestinationDataSegmentPages;
+ UINTN DestinationStackSegmentPages;
+ UINTN DestinationCodeSegmentPages;
+ VOID *UndiLoaderTable;
+ VOID *DestinationDataSegment;
+ VOID *DestinationStackSegment;
+ VOID *DestinationCodeSegment;
+} EFI_SIMPLE_NETWORK_DEV;
+
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) \
+ CR (a, \
+ EFI_SIMPLE_NETWORK_DEV, \
+ SimpleNetwork, \
+ EFI_SIMPLE_NETWORK_DEV_SIGNATURE \
+ )
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosSnp16DriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosSnp16ComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosSnp16ComponentName2;
+
+
+//
+// Driver Binding Protocol functions
+//
+/**
+ Tests to see if this driver supports a given controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The driver supports given controller.
+ @retval EFI_UNSUPPORT The driver doesn't support given controller.
+ @retval Other Other errors prevent driver finishing to test
+ if the driver supports given controller.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+;
+
+/**
+ Starts the Snp device controller
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS - The device was started.
+ @retval EFI_DEVICE_ERROR - The device could not be started due to a device error.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+;
+
+/**
+ Stops the device by given device controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param ChildHandleBuffer An array of child handles to be freed. May be NULL if
+ NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS - The device was stopped.
+ @retval EFI_DEVICE_ERROR - The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+;
+
+//
+// Simple Network Protocol functions
+//
+/**
+ Call 16 bit UNDI ROM to start the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Call 16 bit UNDI ROM to stop the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Initialize network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtraRxBufferSize The size of extra request receive buffer.
+ @param ExtraTxBufferSize The size of extra request transmit buffer.
+
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+;
+
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtendedVerification Need extended verfication.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+;
+
+/**
+ Shutdown network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Enable Enable mask value
+ @param Disable Disable mask value
+ @param ResetMCastFilter Whether reset multi cast filter or not
+ @param MCastFilterCnt Count of mutli cast filter for different MAC address
+ @param MCastFilter Buffer for mustli cast filter for different MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS * MCastFilter OPTIONAL
+ )
+;
+
+/**
+ Set new MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Reset Whether reset station MAC address to permenent address
+ @param New A pointer to New address
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS * New OPTIONAL
+ )
+;
+
+/**
+ Collect statistics.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Reset Whether cleanup old statistics data.
+ @param StatisticsSize The buffer of statistics table.
+ @param StatisticsTable A pointer to statistics buffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStatistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS * StatisticsTable OPTIONAL
+ )
+;
+
+/**
+ Translate IP address to MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param IPv6 IPv6 or IPv4
+ @param IP A pointer to given Ip address.
+ @param MAC On return, translated MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_INVALID_PARAMETER Invalid IP address.
+ @retval EFI_INVALID_PARAMETER Invalid return buffer for holding MAC address.
+ @retval EFI_UNSUPPORTED Do not support IPv6
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkMCastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+;
+
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This The protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Write,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This The protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ )
+;
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ )
+;
+
+/**
+ Receives a packet from a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ )
+;
+
+/**
+ wait for a packet to be received.
+
+ @param Event Event used with WaitForEvent() to wait for a packet to be received.
+ @param Context Event Context
+
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkWaitForPacket (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+;
+
+/**
+ Check whether packet is ready for receive.
+
+ @param This The protocol instance pointer.
+
+ @retval EFI_SUCCESS Receive data is ready.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCheckForPacket (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Cache Interrupt verctor address converted from IVT number.
+
+ @param VectorNumber IVT number
+
+ @retval EFI_SUCCESS Success to operation.
+**/
+EFI_STATUS
+CacheVectorAddress (
+ UINT8 VectorNumber
+ )
+;
+
+/**
+ Get interrupt vector address according to IVT number.
+
+ @param VectorNumber Given IVT number
+
+ @return cached interrupt vector address.
+**/
+EFI_STATUS
+RestoreCachedVectorAddress (
+ UINT8 VectorNumber
+ )
+;
+
+/**
+ If available, launch the BaseCode from a NIC option ROM.
+ This should install the !PXE and PXENV+ structures in memory for
+ subsequent use.
+
+
+ @param SimpleNetworkDevice Simple network device instance
+ @param RomAddress The ROM base address for NIC rom.
+
+ @retval EFI_NOT_FOUND The check sum does not match
+ @retval EFI_NOT_FOUND Rom ID offset is wrong
+ @retval EFI_NOT_FOUND No Rom ID structure is found
+**/
+EFI_STATUS
+LaunchBaseCode (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINTN RomAddress
+ )
+;
+
+/**
+ PXE
+ START UNDI
+ Op-Code: PXENV_START_UNDI (0000h)
+ Input: Far pointer to a PXENV_START_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This service is used to pass the BIOS parameter registers to the UNDI driver. The UNDI driver is
+ responsible for saving the information it needs to communicate with the hardware.
+ This service is also responsible for hooking the Int 1Ah service routine
+ Note: This API service must be called only once during UNDI Option ROM boot.
+ The UNDI driver is responsible for saving this information and using it every time
+ PXENV_UNDI_STARTUP is called.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 AX;
+ UINT16 BX;
+ UINT16 DX;
+ UINT16 DI;
+ UINT16 ES;
+ } PXENV_START_UNDI_T;
+ Set before calling API service
+ AX, BX, DX, DI, ES: BIOS initialization parameter registers. These
+ fields should contain the same information passed to the option ROM
+ initialization routine by the Host System BIOS. Information about the
+ contents of these registers can be found in the [PnP], [PCI] and
+ [BBS] specifications.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeStartUndi (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_START_UNDI_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI STARTUP
+ Op-Code: PXENV_UNDI_STARTUP (0001h)
+ Input: Far pointer to a PXENV_UNDI_STARTUP_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This API is responsible for initializing the contents of the UNDI code & data segment for proper
+ operation. Information from the !PXE structure and the first PXENV_START_UNDI API call is used
+ to complete this initialization. The rest of the UNDI APIs will not be available until this call has
+ been completed.
+ Note: PXENV_UNDI_STARTUP must not be called again without first calling
+ PXENV_UNDI_SHUTDOWN.
+ PXENV_UNDI_STARTUP and PXENV_UNDI_SHUTDOWN are no longer responsible for
+ chaining interrupt 1Ah. This must be done by the PXENV_START_UNDI and
+ PXENV_STOP_UNDI API calls.
+ This service cannot be used in protected mode.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_STARTUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStartup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_STARTUP_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI CLEANUP
+ Op-Code: PXENV_UNDI_CLEANUP (0002h)
+ Input: Far pointer to a PXENV_UNDI_CLEANUP_T parameter structure.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field
+ in the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call will prepare the network adapter driver to be unloaded from memory. This call must be
+ made just before unloading the Universal NIC Driver. The rest of the API will not be available
+ after this call executes.
+ This service cannot be used in protected mode.
+ typedef struct {
+ PXENX_STATUS Status;
+ } PXENV_UNDI_CLEANUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiCleanup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEANUP_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI INITIALIZE
+ Op-Code: PXENV_UNDI_INITIALIZE (0003h)
+ Input: Far pointer to a PXENV_UNDI_INITIALIZE_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter and programs it with default parameters. The default parameters used
+ are those supplied to the most recent UNDI_STARTUP call. This routine does not enable the
+ receive and transmit units of the network adapter to readily receive or transmit packets. The
+ application must call PXENV_UNDI_OPEN to logically connect the network adapter to the network.
+ This call must be made by an application to establish an interface to the network adapter driver.
+ Note: When the PXE code makes this call to initialize the network adapter, it passes a NULL pointer for
+ the Protocol field in the parameter structure.
+ typedef struct {
+ PXENV_STATUS Status;
+ ADDR32 ProtocolIni;
+ UINT8 reserved[8];
+ } PXENV_UNDI_INITIALIZE_T;
+ Set before calling API service
+ ProtocolIni: Physical address of a memory copy of the driver
+ module from the protocol.ini file obtained from the protocol manager
+ driver (refer to the NDIS 2.0 specification). This parameter is
+ supported for the universal NDIS driver to pass the information
+ contained in the protocol.ini file to the NIC driver for any specific
+ configuration of the NIC. (Note that the module identification in the
+ protocol.ini file was done by NDIS.) This value can be NULL for any
+ other application interfacing to the universal NIC driver
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance.
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitialize (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIALIZE_T *PxeUndiTable
+ )
+;
+
+/**
+ Wrapper routine for reset adapter.
+
+ PXE
+ UNDI RESET ADAPTER
+ Op-Code: PXENV_UNDI_RESET_ADAPTER (0004h)
+ Input: Far pointer to a PXENV_UNDI_RESET_ADAPTER_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets and reinitializes the network adapter with the same set of parameters supplied to
+ Initialize Routine. Unlike Initialize, this call opens the adapter that is, it connects logically to the
+ network. This routine cannot be used to replace Initialize or Shutdown calls.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_RESET_T;
+
+ #define MAXNUM_MCADDR 8
+
+ typedef struct {
+ UINT16 MCastAddrCount;
+ MAC_ADDR McastAddr[MAXNUM_MCADDR];
+ } PXENV_UNDI_MCAST_ADDRESS_t;
+
+ Set before calling API service
+ R_Mcast_Buf: This is a structure of MCastAddrCount and
+ McastAddr.
+ MCastAddrCount: Number of multicast MAC addresses in the
+ buffer.
+ McastAddr: List of up to MAXNUM_MCADDR multicast MAC
+ addresses.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance.
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+ @param RxFilter Filter setting mask value for PXE recive .
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiResetNic (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_RESET_T *PxeUndiTable,
+ IN UINT16 RxFilter
+ )
+;
+
+/**
+ PXE
+ UNDI SHUTDOWN
+ Op-Code: PXENV_UNDI_SHUTDOWN (0005h)
+ Input: Far pointer to a PXENV_UNDI_SHUTDOWN_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the network adapter and leaves it in a safe state for another driver to program it.
+ Note: The contents of the PXENV_UNDI_STARTUP parameter structure need to be saved by the
+ Universal NIC Driver in case PXENV_UNDI_INITIALIZE is called again.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_SHUTDOWN_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiShutdown (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SHUTDOWN_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI OPEN
+ Op-Code: PXENV_UNDI_OPEN (0006h)
+ Input: Far pointer to a PXENV_UNDI_OPEN_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call activates the adapter network connection and sets the adapter ready to accept packets
+ for transmit and receive.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 OpenFlag;
+ UINT16 PktFilter;
+ #define FLTR_DIRECTED 0x0001
+ #define FLTR_BRDCST 0x0002
+ #define FLTR_PRMSCS 0x0004
+ #define FLTR_SRC_RTG 0x0008
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_OPEN_T;
+ Set before calling API service
+ OpenFlag: This is an adapter specific input parameter. This is
+ supported for the universal NDIS 2.0 driver to pass in the open flags
+ provided by the protocol driver. (See the NDIS 2.0 specification.)
+ This can be zero.
+ PktFilter: Filter for receiving packets. This can be one, or more, of
+ the FLTR_xxx constants. Multiple values are arithmetically or-ed
+ together.
+ directed packets are packets that may come to your MAC address
+ or the multicast MAC address.
+ R_Mcast_Buf: See definition in UNDI RESET ADAPTER (0004h).
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiOpen (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_OPEN_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI CLOSE
+ Op-Code: PXENV_UNDI_CLOSE (0007h)
+ Input: Far pointer to a PXENV_UNDI_CLOSE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call disconnects the network adapter from the network. Packets cannot be transmitted or
+ received until the network adapter is open again.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLOSE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClose (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLOSE_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI TRANSMIT PACKET
+ Op-Code: PXENV_UNDI_TRANSMIT (0008h)
+ Input: Far pointer to a PXENV_UNDI_TRANSMIT_T parameter structure that
+ has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX.
+ The status code must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call transmits a buffer to the network. The media header
+ for the packet can be filled by the calling protocol, but it might not be.
+ The network adapter driver will fill it if required by the values in the
+ parameter block. The packet is buffered for transmission provided there is
+ an available buffer, and the function returns PXENV_EXIT_SUCCESS. If no
+ buffer is available the function returns PXENV_EXIT_FAILURE with a status
+ code of PXE_UNDI_STATUS__OUT OF_RESOURCE. The number of buffers is
+ implementation-dependent. An interrupt is generated on completion of the
+ transmission of one or more packets. A call to PXENV_UNDI_TRANSMIT is
+ permitted in the context of a transmit complete interrupt.
+
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 Protocol;
+ #define P_UNKNOWN 0
+ #define P_IP 1
+ #define P_ARP 2
+ #define P_RARP 3
+ UINT8 XmitFlag;
+ #define XMT_DESTADDR 0x0000
+ #define XMT_BROADCAST 0x0001
+ SEGOFF16 DestAddr;
+ SEGOFF16 TBD;
+ UINT32 Reserved[2];
+ } t_PXENV_UNDI_TRANSMIT;
+
+ #define MAX_DATA_BLKS 8
+
+ typedef struct {
+ UINT16 ImmedLength;
+ SEGOFF16 Xmit;
+ UINT16 DataBlkCount;
+ struct DataBlk {
+ UINT8 TDPtrType;
+ UINT8 TDRsvdByte;
+ UINT16 TDDataLen;
+ SEGOFF16 TDDataPtr;
+ } DataBlock[MAX_DATA_BLKS];
+ } PXENV_UNDI_TBD_T
+
+ Set before calling API service
+ Protocol: This is the protocol of the upper layer that is calling UNDI
+ TRANSMIT call. If the upper layer has filled the media header, this
+ field must be P_UNKNOWN.
+ XmitFlag: If this flag is XMT_DESTADDR, the NIC driver expects a
+ pointer to the destination media address in the field DestAddr. If
+ XMT_BROADCAST, the NIC driver fills the broadcast address for the
+ destination.
+ TBD: Segment:Offset address of the transmit buffer descriptor.
+ ImmedLength: Length of the immediate transmit buffer: Xmit.
+ Xmit: Segment:Offset of the immediate transmit buffer.
+ DataBlkCount: Number of blocks in this transmit buffer.
+ TDPtrType:
+ 0 => 32-bit physical address in TDDataPtr (not supported in this
+ version of PXE)
+ 1 => segment:offset in TDDataPtr which can be a real mode or 16-bit
+ protected mode pointer
+ TDRsvdByte: Reserved must be zero.
+ TDDatalen: Data block length in bytes.
+ TDDataPtr: Segment:Offset of the transmit block.
+ DataBlock: Array of transmit data blocks.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiTransmit (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_TRANSMIT_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI SET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_SET_MCAST_ADDRESS (0009h)
+ Input: Far pointer to a PXENV_TFTP_SET_MCAST_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call changes the current list of multicast addresses to the input list and resets the network
+ adapter to accept it. If the number of multicast addresses is zero, multicast is disabled.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_SET_MCAST_ADDR_T;
+ Set before calling API service
+ R_Mcast_Buf: See description in the UNDI RESET ADAPTER
+ (0004h) API.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_MCAST_ADDR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI SET STATION ADDRESS
+ Op-Code: PXENV_UNDI_SET_STATION_ADDRESS (000Ah)
+ Input: Far pointer to a PXENV_UNDI_SET_STATION_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call sets the MAC address to be the input value and is called before opening the network
+ adapter. Later, the open call uses this variable as a temporary MAC address to program the
+ adapter individual address registers.
+ typedef struct {
+ PXENV_STATUS Status;
+ MAC_ADDR StationAddress;
+ } PXENV_UNDI_SET_STATION_ADDR_T;
+ Set before calling API service
+ StationAddress: Temporary MAC address to be used for
+ transmit and receive.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetStationAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_STATION_ADDR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI SET PACKET FILTER
+ Op-Code: PXENV_UNDI_SET_PACKET_FILTER (000Bh)
+ Input: Far pointer to a PXENV_UNDI_SET_PACKET_FILTER_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter's receive unit to accept a new filter, different from the one provided with
+ the open call.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 filter;
+ } PXENV_UNDI_SET_PACKET_FILTER_T;
+ Set before calling API service
+ Filter: See the receive filter values in the UNDI OPEN
+ (0006h) API description.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetPacketFilter (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_PACKET_FILTER_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET INFORMATION
+ Op-Code: PXENV_UNDI_GET_INFORMATION (000Ch)
+ Input: Far pointer to a PXENV_UNDI_GET_INFORMATION_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call copies the network adapter variables, including the MAC address, into the input buffer.
+ Note: The PermNodeAddress field must be valid after PXENV_START_UNDI and
+ PXENV_UNDI_STARTUP have been issued. All other fields must be valid after
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE have been
+ called.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 BaseIo;
+ UINT16 IntNumber;
+ UINT16 MaxTranUnit;
+ UINT16 HwType;
+ #define ETHER_TYPE 1
+ #define EXP_ETHER_TYPE 2
+ #define IEEE_TYPE 6
+ #define ARCNET_TYPE 7
+ UINT16 HwAddrLen;
+ MAC_ADDR CurrentNodeAddress;
+ MAC_ADDR PermNodeAddress;
+ SEGSEL ROMAddress;
+ UINT16 RxBufCt;
+ UINT16 TxBufCt;
+ } PXENV_UNDI_GET_INFORMATION_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ BaseIO: Adapter base I/O address.
+ IntNumber: Adapter IRQ number.
+ MaxTranUnit: Adapter maximum transmit unit.
+ HWType: Type of protocol at the hardware level.
+ HWAddrLen: Length of the hardware address.
+ CurrentNodeAddress: Current hardware address.
+ PermNodeAddress: Permanent hardware address.
+ ROMAddress: Real mode ROM segment address.
+ RxBufCnt: Receive queue length.
+ TxBufCnt: Transmit queue length.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetInformation (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_INFORMATION_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET STATISTICS
+ Op-Code: PXENV_UNDI_GET_STATISTICS (000Dh)
+ Input: Far pointer to a PXENV_UNDI_GET_STATISTICS_T parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call reads statistical information from the network adapter, and returns.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT32 XmtGoodFrames;
+ UINT32 RcvGoodFrames;
+ UINT32 RcvCRCErrors;
+ UINT32 RcvResourceErrors;
+ } PXENV_UNDI_GET_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ XmtGoodFrames: Number of successful transmissions.
+ RcvGoodFrames: Number of good frames received.
+ RcvCRCErrors: Number of frames received with CRC
+ error.
+ RcvResourceErrors: Number of frames discarded
+ because receive queue was full.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATISTICS_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI CLEAR STATISTICS
+ Op-Code: PXENV_UNDI_CLEAR_STATISTICS (000Eh)
+ Input: Far pointer to a PXENV_UNDI_CLEAR_STATISTICS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call clears the statistical information from the network adapter.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLEAR_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClearStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEAR_STATISTICS_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI INITIATE DIAGS
+ Op-Code: PXENV_UNDI_INITIATE_DIAGS (000Fh)
+ Input: Far pointer to a PXENV_UNDI_INITIATE_DIAGS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call can be used to initiate the run-time diagnostics. It causes the network adapter to run
+ hardware diagnostics and to update its status information.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_INITIATE_DIAGS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitiateDiags (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIATE_DIAGS_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI FORCE INTERRUPT
+ Op-Code: PXENV_UNDI_FORCE_INTERRUPT (0010h)
+ Input: Far pointer to a PXENV_UNDI_FORCE_INTERRUPT_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call forces the network adapter to generate an interrupt. When a receive interrupt occurs, the
+ network adapter driver usually queues the packet and calls the application's callback receive
+ routine with a pointer to the packet received. Then, the callback routine either can copy the packet
+ to its buffer or can decide to delay the copy to a later time. If the packet is not immediately copied,
+ the network adapter driver does not remove it from the input queue. When the application wants to
+ copy the packet, it can call the PXENV_UNDI_FORCE_INTERRUPT routine to simulate the receive
+ interrupt.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_FORCE_INTERRUPT_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiForceInterrupt (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_FORCE_INTERRUPT_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_GET_MCAST_ADDRESS (0011h)
+ Input: Far pointer to a PXENV_GET_MCAST_ADDRESS_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call converts the given IP multicast address to a hardware multicast address.
+ typedef struct {
+ PXENV_STATUS Status;
+ IP4 InetAddr;
+ MAC_ADDR MediaAddr;
+ } PXENV_UNDI_GET_MCAST_ADDR_T;
+ Set before calling API service
+ InetAddr: IP multicast address.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ MediaAddr: MAC multicast address.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_MCAST_ADDR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET NIC TYPE
+ Op-Code: PXENV_UNDI_GET_NIC_TYPE (0012h)
+ Input: Far pointer to a PXENV_UNDI_GET_NIC_TYPE_T parameter structure that has been initialized by
+ the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned the parameter structure must contain the
+ NIC information.
+ Description: This call, if successful, provides the NIC-specific information necessary to identify the network
+ adapter that is used to boot the system.
+ Note: The application first gets the DHCPDISCOVER packet using GET_CACHED_INFO and checks if
+ the UNDI is supported before making this call. If the UNDI is not supported, the NIC-specific
+ information can be obtained from the DHCPDISCOVER packet itself.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef {
+ PXENV_STATUS Status;
+ UINT8 NicType;
+ #define PCI_NIC 2
+ #define PnP_NIC 3
+ #define CardBus_NIC 4
+ Union {
+ Struct {
+ UINT16 Vendor_ID;
+ UINT16 Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT8 Rev;
+ UINT16 BusDevFunc;
+ UINT16 SubVendor_ID;
+ UINT16 SubDevice_ID;
+ } pci, cardbus;
+ struct {
+ UINT32 EISA_Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT16 CardSelNum;
+ } pnp;
+ } info;
+ } PXENV_UNDI_GET_NIC_TYPE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ NICType: Type of NIC information stored in the parameter
+ structure.
+ Info: Information about the fields in this union can be found
+ in the [PnP] and [PCI] specifications
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNicType (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NIC_TYPE_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET IFACE INFO
+ Op-Code: PXENV_UNDI_GET_IFACE_INFO (0013h)
+ Input: Far pointer to a PXENV_UNDI_GET_IFACE_INFO_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned, the parameter structure must contain the
+ interface specific information.
+ Description: This call, if successful, provides the network interface specific information such as the interface
+ type at the link layer (Ethernet, Tokenring) and the link speed. This information can be used in the
+ universal drivers such as NDIS or Miniport to communicate to the upper protocol modules.
+ Note: UNDI follows the NDIS2 specification in giving this information. It is the responsibility of the
+ universal driver to translate/convert this information into a format that is required in its specification
+ or to suit the expectation of the upper level protocol modules.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef struct {
+ PXENV_STATUS Status
+ UINT8 IfaceType[16];
+ UINT32 LinkSpeed;
+ UINT32 ServiceFlags;
+ UINT32 Reserved[4];
+ } PXENV_UNDI_GET_NDIS_INFO_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ IfaceType: Name of MAC type in ASCIIZ format. This is
+ used by the universal NDIS driver to specify its driver type
+ to the protocol driver.
+ LinkSpeed: Defined in the NDIS 2.0 specification.
+ ServiceFlags: Defined in the NDIS 2.0 specification.
+ Reserved: Must be zero.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NDIS_INFO_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a PXENV_UNDI_ISR_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+ Note: Interrupt Service Routine Operation:
+ In this design the UNDI does not hook the interrupt for the Network Interface. Instead, the
+ application or the protocol driver hooks the interrupt and calls UNDI with the PXENV_UNDI_ISR
+ API call for interrupt verification (PXENV_UNDI_ISR_IN_START) and processing
+ (PXENV_UNDI_ISR_IN_PROCESS and PXENV_UNDI_ISR_GET_NEXT).
+ When the Network Interface HW generates an interrupt the protocol driver interrupt service
+ routine (ISR) gets control and takes care of the interrupt processing at the PIC level. The ISR then
+ calls the UNDI using the PXENV_UNDI_ISR API with the value PXENV_UNDI_ISR_IN_START for
+ the FuncFlag parameter. At this time UNDI must disable the interrupts at the Network Interface
+ level and read any status values required to further process the interrupt. UNDI must return as
+ quickly as possible with one of the two values, PXENV_UNDI_ISR_OUT_OURS or
+ PXENV_UNDI_ISR_OUT_NOT_OURS, for the parameter FuncFlag depending on whether the
+ interrupt was generated by this particular Network Interface or not.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_NOT_OURS, then the interrupt was
+ not generated by our NIC, and interrupt processing is complete.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_OURS, the protocol driver must start
+ a handler thread and send an end-of-interrupt (EOI) command to the PIC. Interrupt processing is
+ now complete.
+ The protocol driver strategy routine will call UNDI using this same API with FuncFlag equal to
+ PXENV_UNDI_ISR_IN_PROCESS. At this time UNDI must find the cause of this interrupt and
+ return the status in the FuncFlag. It first checks if there is a frame received and if so it returns the
+ first buffer pointer of that frame in the parameter block.
+ The protocol driver calls UNDI repeatedly with the FuncFlag equal to
+ PXENV_UNDI_ISR_IN_GET_NEXT to get all the buffers in a frame and also all the received
+ frames in the queue. On this call, UNDI must remember the previous buffer given to the protoco,l
+ remove it from the receive queue and recycle it. In case of a multi-buffered frame, if the previous
+ buffer is not the last buffer in the frame it must return the next buffer in the frame in the parameter
+ block. Otherwise it must return the first buffer in the next frame.
+ If there is no received frame pending to be processed, UNDI processes the transmit completes and
+ if there is no other interrupt status to be processed, UNDI re-enables the interrupt at the
+ NETWORK INTERFACE level and returns PXENV_UNDI_ISR_OUT_DONE in the FuncFlag.
+ IMPORTANT: It is possible for the protocol driver to be interrupted again while in the
+ strategy routine when the UNDI re-enables interrupts.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiIsr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_ISR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ STOP UNDI
+ Op-Code: PXENV_STOP_UNDI (0015h)
+ Input: Far pointer to a PXENV_STOP_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This routine is responsible for unhooking the Int 1Ah service routine.
+ Note: This API service must be called only once at the end of UNDI Option ROM boot. One of the valid
+ status codes is PXENV_STATUS_KEEP. If this status is returned, UNDI must not be removed from
+ base memory. Also, UNDI must not be removed from base memory if BC is not removed from base
+ memory.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_STOP_UNDI_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStop (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_STOP_UNDI_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET STATE
+ Op-Code: PXENV_UNDI_GET_STATE (0015h)
+ Input: Far pointer to a PXENV_UNDI_GET_STATE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. The UNDI_STATE field in the parameter structure must be set to one of the valid state
+ constants
+ Description: This call can be used to obtain state of the UNDI engine in order to avoid issuing adverse call
+ sequences
+ typedef struct {
+ #define PXE_UNDI_GET_STATE_STARTED 1
+ #define PXE_UNDI_GET_STATE_INITIALIZED 2
+ #define PXE_UNDI_GET_STATE_OPENED 3
+ PXENV_STATUS Status;
+ UINT8 UNDIstate;
+ } PXENV_UNDI_GET_STATE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ State: See definitions of the state constants.
+ Note. UNDI implementation is responsible for maintaining
+ internal state machine.
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a t_PXENV_UNDI_ISR parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetState (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATE_T *PxeUndiTable
+ )
+;
+
+/**
+ Effect the Far Call into the PXE Layer
+
+ Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API
+ services will not work, unless there are three 16-bit parameters pushed onto the stack.
+ push DS ;Far pointer to parameter structure
+ push offset pxe_data_call_struct ;is pushed onto stack.
+ push Index ;UINT16 is pushed onto stack.
+ call dword ptr (s_PXE ptr es:[di]).EntryPointSP
+ add sp, 6 ;Caller cleans up stack.
+
+ @param SimpleNetworkDevice Device instance for simple network
+ @param Table Point to parameter/retun value table for legacy far call
+ @param TableSize The size of paramter/return value table
+ @param CallIndex The index of legacy call.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+MakePxeCall (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT VOID *Table,
+ IN UINTN TableSize,
+ IN UINT16 CallIndex
+ )
+;
+
+/**
+ Allocate buffer below 1M for real mode.
+
+ @param NumPages The number pages want to be allocated.
+ @param Buffer On return, allocated buffer.
+
+ @return Status of allocating pages.
+**/
+EFI_STATUS
+BiosSnp16AllocatePagesBelowOneMb (
+ UINTN NumPages,
+ VOID **Buffer
+ )
+;
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c
new file mode 100644
index 0000000..a95d834
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c
@@ -0,0 +1,309 @@
+/** @file
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosSnp16ComponentName = {
+ BiosSnp16ComponentNameGetDriverName,
+ BiosSnp16ComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosSnp16ComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosSnp16ComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosSnp16ComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosSnp16DriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[UNDI] Simple Network Protocol Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosSnp16DriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosSnp16ComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c
new file mode 100644
index 0000000..0b3543e
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c
@@ -0,0 +1,956 @@
+/** @file
+ Helper Routines that use a PXE-enabled NIC option ROM.
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+#define TO_SEGMENT(x) ((UINT16) (RShiftU64 ((UINT32)(UINTN) (x), 4) & 0xF000))
+#define TO_OFFSET(x) ((UINT16) ((UINT32)(UINTN) (x) & 0xFFFF))
+#define PARAGRAPH_SIZE 0x10
+#define IVT_BASE 0x00000000
+
+#pragma pack(1)
+typedef struct {
+ UINT16 Signature; ///< 0xaa55
+ UINT8 ROMlength; ///< size of this ROM in 512 byte blocks
+ UINT8 InitEntryPoint[4]; ///< a jump to the initialization routine
+ UINT8 Reserved[0xf]; ///< various
+ UINT16 PxeRomIdOffset; ///< offset of UNDI, $BC$, or BUSD ROM ID structure
+ UINT16 PcirHeaderOffset; ///< offset of PCI Expansion Header
+ UINT16 PnpHeaderOffset; ///< offset of Plug and Play Expansion Header
+} OPTION_ROM_HEADER;
+#pragma pack()
+
+UINT32 CachedVectorAddress[0x100];
+
+/**
+ Cache Interrupt verctor address converted from IVT number.
+
+ @param VectorNumber IVT number
+
+ @retval EFI_SUCCESS Success to operation.
+**/
+EFI_STATUS
+CacheVectorAddress (
+ UINT8 VectorNumber
+ )
+{
+ UINT32 *Address;
+
+ Address = (UINT32 *)(UINTN) (IVT_BASE + VectorNumber * 4);
+ CachedVectorAddress[VectorNumber] = *Address;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get interrupt vector address according to IVT number.
+
+ @param VectorNumber Given IVT number
+
+ @return cached interrupt vector address.
+**/
+EFI_STATUS
+RestoreCachedVectorAddress (
+ UINT8 VectorNumber
+ )
+{
+ UINT32 *Address;
+
+ Address = (UINT32 *)(UINTN) (IVT_BASE + VectorNumber * 4);
+ *Address = CachedVectorAddress[VectorNumber];
+ return EFI_SUCCESS;
+}
+
+/**
+ Print Undi loader table.
+
+ @param UndiLoaderStructure Point to Undi Loader table structure.
+
+**/
+VOID
+Print_Undi_Loader_Table (
+ VOID *UndiLoaderStructure
+ )
+{
+ UNDI_LOADER_T *DisplayPointer;
+
+ DisplayPointer = (UNDI_LOADER_T *) UndiLoaderStructure;
+
+ DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));
+ DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) UndiLoaderStructure));
+
+ DEBUG ((DEBUG_NET, "\n\rStatus = 0x%X\n\r", DisplayPointer->Status));
+ DEBUG ((DEBUG_NET, "\t_AX_= 0x%X\n\r", DisplayPointer->Ax));
+ DEBUG ((DEBUG_NET, "\t_BX_= 0x%X\n\r", DisplayPointer->Bx));
+ DEBUG ((DEBUG_NET, "\t_DX_= 0x%X\n\r", DisplayPointer->Dx));
+ DEBUG ((DEBUG_NET, "\t_DI_= 0x%X\n\r", DisplayPointer->Di));
+ DEBUG ((DEBUG_NET, "\t_ES_= 0x%X\n\r", DisplayPointer->Es));
+ DEBUG ((DEBUG_NET, "\tUNDI_DS= 0x%X\n\r", DisplayPointer->Undi_Ds));
+ DEBUG ((DEBUG_NET, "\tUNDI_CS= 0x%X\n\r", DisplayPointer->Undi_Cs));
+ DEBUG ((DEBUG_NET, "\tPXEptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Segment));
+ DEBUG ((DEBUG_NET, "\tPXEptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Offset));
+ DEBUG ((DEBUG_NET, "\tPXENVptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Segment));
+ DEBUG ((DEBUG_NET, "\tPXENVptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Offset));
+}
+
+/**
+ Simple table dumper. The ROMID table is necessary in order to effect
+ the "Early UNDI" trick. Herein, the UNDI layer can be loaded in the
+ pre-boot phase without having to download a Network Boot Program
+ across the wire. It is required in the implementation in that we
+ are not using PXE.
+
+ @param RomIDStructure Point to RomID structure.
+
+**/
+VOID
+Print_ROMID_Table (
+ IN VOID *RomIDStructure
+ )
+{
+ UNDI_ROMID_T *DisplayPointer;
+
+ DisplayPointer = (UNDI_ROMID_T *) RomIDStructure;
+
+ DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));
+ DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) RomIDStructure));
+
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rROMID %c%c%c%c\n\r",
+ DisplayPointer->Signature[0],
+ DisplayPointer->Signature[1],
+ DisplayPointer->Signature[2],
+ DisplayPointer->Signature[3])
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "Length of this structure in bytes = 0x%X\n\r",
+ DisplayPointer->StructLength)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
+ DisplayPointer->StructCksum)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Structure format revision number= 0x%X\n\r",
+ DisplayPointer->StructRev)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "API Revision number = 0x%X 0x%X 0x%X\n\r",
+ DisplayPointer->UNDI_Rev[0],
+ DisplayPointer->UNDI_Rev[1],
+ DisplayPointer->UNDI_Rev[2])
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",
+ DisplayPointer->UNDI_Loader)
+ );
+ DEBUG ((DEBUG_NET, "From the data above, the absolute entry point of the UNDI loader is\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "\tat address 0x%X\n\r",
+ (UINT32) (DisplayPointer->UNDI_Loader + ((UINT32) (UINTN)(DisplayPointer - 0x20) & 0xFFFF0)))
+ );
+ DEBUG ((DEBUG_NET, "Minimum stack segment size, in bytes,\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "needed to load and run the UNDI= 0x%X \n\r",
+ DisplayPointer->StackSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "UNDI runtime code and data = 0x%X\n\r",
+ DisplayPointer->DataSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Segment size = 0x%X\n\r",
+ DisplayPointer->CodeSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rBus Type = %c%c%c%c\n\r",
+ DisplayPointer->BusType[0],
+ DisplayPointer->BusType[1],
+ DisplayPointer->BusType[2],
+ DisplayPointer->BusType[3])
+ );
+}
+
+/**
+ Print PXE table.
+
+ @param PxeTable Point to PXE table structure
+
+**/
+VOID
+Print_PXE_Table (
+ IN VOID* PxeTable
+ )
+{
+ PXE_T *DisplayPointer;
+ UINTN Index;
+ UINT8 *Dptr;
+
+ DisplayPointer = (PXE_T *) PxeTable;
+ Dptr = (UINT8 *) PxeTable;
+
+ DEBUG ((DEBUG_NET, "This is the PXE table at address 0x%X\n\r", PxeTable));
+
+ DEBUG ((DEBUG_NET, "A dump of the 0x%X bytes is:\n\r", sizeof (PXE_T)));
+
+ for (Index = 0; Index < sizeof (PXE_T); Index++) {
+ if ((Index % 0x10) == 0) {
+ DEBUG ((DEBUG_NET, "\t\n\r"));
+ }
+
+ DEBUG ((DEBUG_NET, " 0x%X ", *Dptr++));
+ }
+
+ DEBUG ((DEBUG_NET, "\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rPXE %c%c%c%c%c%c\n\r",
+ DisplayPointer->Signature[0],
+ DisplayPointer->Signature[1],
+ DisplayPointer->Signature[2],
+ DisplayPointer->Signature[3])
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Length of this structure in bytes = 0x%X\n\r",
+ DisplayPointer->StructLength)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
+ DisplayPointer->StructCksum)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Structure format revision number = 0x%X\n\r",
+ DisplayPointer->StructRev)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Must be zero, is equal to 0x%X\n\r",
+ DisplayPointer->Reserved1)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Far pointer to UNDI ROMID = 0x%X\n\r",
+ (UINT32) (DisplayPointer->Undi.Segment << 0x4 | DisplayPointer->Undi.Offset))
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Far pointer to base-code ROMID = 0x%X\n\r",
+ (UINT32) ((DisplayPointer->Base.Segment << 0x04) | DisplayPointer->Base.Offset))
+ );
+ DEBUG ((DEBUG_NET, "16bit stack segment API entry point. This will be seg:off in \n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "real mode and sel:off in 16:16 protected mode = 0x%X:0x%X\n\r",
+ DisplayPointer->EntryPointSP.Segment,
+ DisplayPointer->EntryPointSP.Offset)
+ );
+
+ DEBUG ((DEBUG_NET, "\n\tNOTE to the implementer\n\tThis is the entry to use for call-ins\n\r"));
+
+ DEBUG ((DEBUG_NET, "32bit stack Segment API entry point. This will be sel:off. \n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "In real mode, sel == 0 = 0x%X:0x%X\n\r",
+ DisplayPointer->EntryPointESP.Segment,
+ DisplayPointer->EntryPointESP.Offset)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Reserved2 value, must be zero, is equal to 0x%X\n\r",
+ DisplayPointer->Reserved2)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Number of segment descriptors in this structur = 0x%X\n\r",
+ (UINT8) DisplayPointer->SegDescCnt)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "First segment descriptor in GDT assigned to PXE = 0x%X\n\r",
+ (UINT16) DisplayPointer->FirstSelector)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->Stack.Seg_Addr,
+ (UINT32) DisplayPointer->Stack.Phy_Addr,
+ (UINT16) DisplayPointer->Stack.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The UNDIData is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->UNDIData.Seg_Addr,
+ (UINT32) DisplayPointer->UNDIData.Phy_Addr,
+ (UINT16) DisplayPointer->UNDIData.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The UNDICodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->UNDICode.Seg_Addr,
+ (UINT32) DisplayPointer->UNDICode.Phy_Addr,
+ (UINT16) DisplayPointer->UNDICode.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->UNDICodeWrite.Seg_Addr,
+ (UINT32) DisplayPointer->UNDICodeWrite.Phy_Addr,
+ (UINT16) DisplayPointer->UNDICodeWrite.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The BC_Data is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->BC_Data.Seg_Addr,
+ (UINT32) DisplayPointer->BC_Data.Phy_Addr,
+ (UINT16) DisplayPointer->BC_Data.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The BC_Code is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->BC_Code.Seg_Addr,
+ (UINT32) DisplayPointer->BC_Code.Phy_Addr,
+ (UINT16) DisplayPointer->BC_Code.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The BC_CodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->BC_CodeWrite.Seg_Addr,
+ (UINT32) DisplayPointer->BC_CodeWrite.Phy_Addr,
+ (UINT16) DisplayPointer->BC_CodeWrite.Seg_Size)
+ );
+}
+
+/**
+ Print PXENV table.
+
+ @param PxenvTable Point to PXENV
+
+**/
+VOID
+Print_PXENV_Table (
+ IN VOID *PxenvTable
+ )
+{
+ PXENV_T *DisplayPointer;
+
+ DisplayPointer = (PXENV_T *) PxenvTable;
+
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rPXENV+ %c%c%c%c%c%c\n\r",
+ DisplayPointer->Signature[0],
+ DisplayPointer->Signature[1],
+ DisplayPointer->Signature[2],
+ DisplayPointer->Signature[3],
+ DisplayPointer->Signature[4],
+ DisplayPointer->Signature[5])
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "PXE version number. \n\r\tLSB is minor version. \n\r\tMSB is major version = 0x%X\n\r",
+ DisplayPointer->Version)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",
+ DisplayPointer->StructLength)
+ );
+ DEBUG ((DEBUG_NET, "Used to make structure checksum equal zero is now = 0x%X\n\r", DisplayPointer->StructCksum));
+ DEBUG ((DEBUG_NET, "Real mode API entry point segment:Offset. = 0x%X\n\r", DisplayPointer->RMEntry));
+ DEBUG ((DEBUG_NET, "Protected mode API entry point = 0x%X\n\r", DisplayPointer->PMEntryOff));
+ DEBUG ((DEBUG_NET, " segment:Offset. This will always be zero. \n\r"));
+ DEBUG ((DEBUG_NET, "Protected mode API calls = 0x%X\n\r", DisplayPointer->PMEntrySeg));
+ DEBUG ((DEBUG_NET, "Real mode stack segment = 0x%X\n\r", DisplayPointer->StackSeg));
+ DEBUG ((DEBUG_NET, "Stack segment size in bytes = 0x%X\n\r", DisplayPointer->StackSize));
+ DEBUG ((DEBUG_NET, "Real mode base-code code segment = 0x%X\n\r", DisplayPointer->BaseCodeSeg));
+ DEBUG ((DEBUG_NET, "Base-code code segment size = 0x%X\n\r", DisplayPointer->BaseCodeSize));
+ DEBUG ((DEBUG_NET, "Real mode base-code data segment = 0x%X\n\r", DisplayPointer->BaseDataSeg));
+ DEBUG ((DEBUG_NET, "Base-code data segment size = 0x%X\n\r", DisplayPointer->BaseDataSize));
+
+ DEBUG (
+ (DEBUG_NET,
+ "UNDI code segment size in bytes = 0x%X\n\r",
+ DisplayPointer->UNDICodeSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",
+ DisplayPointer->RuntimePtr)
+ );
+ DEBUG (
+ (
+ DEBUG_NET,
+ "From above, we have a linear address of 0x%X\n\r",
+ (UINT32)
+ (
+ ((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF) +
+ (((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF0000) >> 12)
+ )
+ )
+ );
+}
+
+
+#define OPTION_ROM_PTR ((OPTION_ROM_HEADER *) RomAddress)
+
+/**
+ If available, launch the BaseCode from a NIC option ROM.
+ This should install the !PXE and PXENV+ structures in memory for
+ subsequent use.
+
+
+ @param SimpleNetworkDevice Simple network device instance
+ @param RomAddress The ROM base address for NIC rom.
+
+ @retval EFI_NOT_FOUND The check sum does not match
+ @retval EFI_NOT_FOUND Rom ID offset is wrong
+ @retval EFI_NOT_FOUND No Rom ID structure is found
+**/
+EFI_STATUS
+LaunchBaseCode (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINTN RomAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET InOutRegs;
+ UNDI_ROMID_T *RomIdTableAddress;
+ UNDI_LOADER_T *UndiLoaderTable;
+ UINT16 Segment;
+ UINT16 *StackPointer;
+ VOID *Buffer;
+ UINTN Size;
+ PXE_T *Pxe;
+ UINT32 RomLength;
+ UINTN PciSegment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ BOOLEAN ThunkFailed;
+
+ DEBUG ((DEBUG_NET, "\n\r\n\rCheck for the UNDI ROMID Signature\n\r"));
+
+ //
+ // paranoia - check structures for validity
+ //
+ RomLength = OPTION_ROM_PTR->ROMlength << 9;
+ if (CalculateSum8 ((UINT8 *) RomAddress, RomLength) != 0) {
+ DEBUG ((DEBUG_ERROR, "ROM Header Checksum Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ RomIdTableAddress = (UNDI_ROMID_T *) (RomAddress + OPTION_ROM_PTR->PxeRomIdOffset);
+
+ if ((UINTN) (OPTION_ROM_PTR->PxeRomIdOffset + RomIdTableAddress->StructLength) > RomLength) {
+ DEBUG ((DEBUG_ERROR, "ROM ID Offset Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+ //
+ // see if this is a header for an UNDI ROM ID structure (vs. a $BC$ or BUSD type)
+ //
+ if (CompareMem (RomIdTableAddress->Signature, UNDI_ROMID_SIG, sizeof RomIdTableAddress->Signature) != 0) {
+ DEBUG ((DEBUG_ERROR, "No ROM ID Structure found....\n\r"));
+ return EFI_NOT_FOUND;
+ //
+ // its not - keep looking
+ //
+ }
+
+ if (CalculateSum8 ((UINT8 *) RomIdTableAddress, RomIdTableAddress->StructLength) != 0) {
+ DEBUG ((DEBUG_ERROR, "ROM ID Checksum Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ Print_ROMID_Table (RomIdTableAddress);
+
+ DEBUG (
+ (DEBUG_NET,
+ "The ROM ID is located at 0x%X\n\r",
+ RomIdTableAddress)
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "With an UNDI Loader located at 0x%X\n\r",
+ RomAddress + RomIdTableAddress->UNDI_Loader)
+ );
+
+ //
+ // found an UNDI ROM ID structure
+ //
+ SimpleNetworkDevice->Nii.ImageAddr = RomAddress;
+ SimpleNetworkDevice->Nii.ImageSize = RomLength;
+ SimpleNetworkDevice->Nii.MajorVer = RomIdTableAddress->UNDI_Rev[2];
+ SimpleNetworkDevice->Nii.MinorVer = RomIdTableAddress->UNDI_Rev[1];
+
+ DEBUG ((DEBUG_NET, "Allocate area for the UNDI_LOADER_T structure\n\r"));
+ //
+ // Allocate 1 page below 1MB to put real mode thunk code in
+ //
+ // Undi Loader Table is a PXE Specification prescribed data structure
+ // that is used to transfer information into and out of the Undi layer.
+ // Note how it must be located below 1 MB.
+ //
+ SimpleNetworkDevice->UndiLoaderTablePages = EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE + sizeof (UNDI_LOADER_T));
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->UndiLoaderTablePages,
+ &SimpleNetworkDevice->UndiLoaderTable
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UndiLoaderTable = SimpleNetworkDevice->UndiLoaderTable;
+
+ DEBUG ((DEBUG_NET, "Allocate area for the real-mode stack whose sole purpose\n\r"));
+ DEBUG ((DEBUG_NET, "in life right now is to store a SEG:OFFSET combo pair that\n\r"));
+ DEBUG ((DEBUG_NET, "points to an Undi_Loader_t table structure\n\r"));
+
+ Size = 0x100;
+ Status = gBS->AllocatePool (EfiLoaderData, Size, &Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Now we want to put a pointer to the Under Loader Table in our MemPage
+ // Buffer. This will be the argument stack for the call into the Undi Loader
+ //
+ StackPointer = (UINT16 *) Buffer;
+ *StackPointer++ = TO_OFFSET (UndiLoaderTable);
+ //
+ // push the OFFSET
+ //
+ *StackPointer++ = TO_SEGMENT (UndiLoaderTable);
+ //
+ // push the SEGMENT
+ //
+ StackPointer = (UINT16 *) Buffer;
+ //
+ // reset the stack pointer
+ //
+ DEBUG (
+ (DEBUG_NET,
+ "After the fixups, the stack pointer is 0x%X\n\r",
+ (UINT64)(UINTN) StackPointer)
+ );
+
+ //
+ // Allocate memory for the Deployed UNDI.
+ // The UNDI is essentially telling us how much space it needs, and
+ // it is up to the EFI driver to allocate sufficient, boot-time
+ // persistent resources for the call
+ //
+ SimpleNetworkDevice->DestinationDataSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->DataSize);
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->DestinationDataSegmentPages,
+ &SimpleNetworkDevice->DestinationDataSegment
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+
+ UndiLoaderTable->Undi_Ds = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationDataSegment >> 4);
+
+ //
+ // Allocate memory for the Deployed UNDI stack
+ // The UNDI is essentially telling us how much space it needs, and
+ // it is up to the EFI driver to allocate sufficient, boot-time
+ // persistent resources for the call
+ //
+ SimpleNetworkDevice->DestinationStackSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->StackSize);
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->DestinationStackSegmentPages,
+ &SimpleNetworkDevice->DestinationStackSegment
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+ //
+ // Allocate memory for the Deployed UNDI.
+ // The UNDI is essentially telling us how much space it needs, and
+ // it is up to the EFI driver to allocate sufficient, boot-time
+ // persistent resources for the call
+ //
+ SimpleNetworkDevice->DestinationCodeSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->CodeSize);
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->DestinationCodeSegmentPages,
+ &SimpleNetworkDevice->DestinationCodeSegment
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+
+ UndiLoaderTable->Undi_Cs = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationCodeSegment >> 4);
+
+ //
+ // these are in the Input and Output Parameter to be sent to the UNDI Loader code
+ //
+ UndiLoaderTable->Status = 0xAA55;
+ //
+ // -------------------- Changed by Michael_Huang@3Com.com -----------------
+ // UndiLoaderTable->_AX is AX value when UNDI ROM is initialized by BIOS, it is the PCI bus device
+ // function of the NIC. Please refer to PXE Spec for detail info.
+ // old code is:
+ // UndiLoaderTable->Ax = 0x0;
+ // -----------------------------------------------------------------------
+ //
+ SimpleNetworkDevice->PciIo->GetLocation (
+ SimpleNetworkDevice->PciIo,
+ &PciSegment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ UndiLoaderTable->Ax = (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function));
+ UndiLoaderTable->Bx = 0x0;
+ UndiLoaderTable->Dx = 0x0;
+ UndiLoaderTable->Di = 0x0;
+ UndiLoaderTable->Es = 0x0;
+
+ //
+ // set these OUT values to zero in order to ensure that
+ // uninitialized memory is not mistaken for display data
+ //
+ UndiLoaderTable->PXEptr.Offset = 0;
+ UndiLoaderTable->PXEptr.Segment = 0;
+ UndiLoaderTable->PXENVptr.Segment = 0;
+ UndiLoaderTable->PXENVptr.Offset = 0;
+
+ DEBUG (
+ (DEBUG_INIT,
+ "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",
+ Bus,
+ Device,
+ Function)
+ );
+
+ //
+ // These are the values that set up the ACTUAL IA32 machine state, whether in
+ // Real16 in EFI32 or the IVE for IA64
+ // register values are unused except for CS:IP and SS:SP
+ //
+ InOutRegs.X.AX = 0;
+ InOutRegs.X.BX = 0;
+ InOutRegs.X.CX = 0;
+ InOutRegs.X.DX = 0;
+ InOutRegs.X.SI = 0;
+ InOutRegs.X.DI = 0;
+ InOutRegs.X.BP = 0;
+ InOutRegs.X.DS = 0;
+ InOutRegs.X.ES = 0;
+ //
+ // just to be clean
+ //
+ DEBUG ((DEBUG_NET, "The way this game works is that the SS:SP +4 should point\n\r"));
+ DEBUG ((DEBUG_NET, "to the contents of the UndiLoaderTable\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "The Undi Loader Table is at address = 0x%X\n\r",
+ (UINT32)(UINTN) UndiLoaderTable)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The segment and offsets are 0x%X and 0x%X, resp\n",
+ TO_SEGMENT (UndiLoaderTable),
+ TO_OFFSET (UndiLoaderTable))
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "The Linear Address of the UNDI Loader entry is 0x%X\n",
+ RomAddress + RomIdTableAddress->UNDI_Loader)
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "The Address offset of the UNDI Loader entry is 0x%X\n",
+ RomIdTableAddress->UNDI_Loader)
+ );
+
+ DEBUG ((DEBUG_NET, "Before the call, we have...\n\r"));
+ Print_Undi_Loader_Table (UndiLoaderTable);
+
+ Segment = ((UINT16) (RShiftU64 (RomAddress, 4) & 0xFFFF));
+ DEBUG ((DEBUG_NET, "The Segment of the call is 0x%X\n\r", Segment));
+
+ //
+ // make the call into the UNDI Code
+ //
+ DEBUG ((DEBUG_INIT, "Make the call into the UNDI code now\n\r"));
+
+ DEBUG ((DEBUG_NET, "\nThe 20-BIt address of the Call, and the location \n\r"));
+ DEBUG ((DEBUG_NET, "\twhere we should be able to set a breakpoint is \n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",
+ Segment * 0x10 + RomIdTableAddress->UNDI_Loader,
+ Segment,
+ RomIdTableAddress->UNDI_Loader)
+ );
+
+ ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (
+ SimpleNetworkDevice->LegacyBios,
+ Segment, // Input segment
+ (UINT16) RomIdTableAddress->UNDI_Loader, // Offset
+ &InOutRegs, // Ptr to Regs
+ Buffer, // Reference to Stack
+ Size // Size of the Stack
+ );
+ if (ThunkFailed) {
+ return EFI_ABORTED;
+ }
+
+ DEBUG (
+ (DEBUG_NET,
+ "The return code UndiLoaderTable->Status is = 0x%X\n\r",
+ UndiLoaderTable->Status)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "This error code should match eax, which is = 0x%X\n\r",
+ InOutRegs.X.AX)
+ );
+
+ DEBUG ((DEBUG_NET, "Now returned from the UNDI code\n\r"));
+
+ DEBUG ((DEBUG_NET, "After the call, we have...\n\r"));
+ Print_Undi_Loader_Table (UndiLoaderTable);
+
+ DEBUG ((DEBUG_NET, "Display the PXENV+ and !PXE tables exported by NIC\n\r"));
+ Print_PXENV_Table ((VOID *)(UINTN)((UndiLoaderTable->PXENVptr.Segment << 4) | UndiLoaderTable->PXENVptr.Offset));
+ Print_PXE_Table ((VOID *)(UINTN)((UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset));
+
+ Pxe = (PXE_T *)(UINTN)((UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset);
+ SimpleNetworkDevice->Nii.Id = (UINT64)(UINTN) Pxe;
+
+ //
+ // FreePool (Buffer);
+ // paranoia - make sure a valid !PXE structure
+ //
+ if (CompareMem (Pxe->Signature, PXE_SIG, sizeof Pxe->Signature) != 0) {
+ DEBUG ((DEBUG_ERROR, "!PXE Structure not found....\n\r"));
+ return EFI_NOT_FOUND;
+ //
+ // its not - keep looking
+ //
+ }
+
+ if (CalculateSum8 ((UINT8 *) Pxe, Pxe->StructLength) != 0) {
+ DEBUG ((DEBUG_ERROR, "!PXE Checksum Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (Pxe->StructLength < (UINT8 *) &Pxe->FirstSelector - (UINT8 *) Pxe->Signature) {
+ DEBUG ((DEBUG_ERROR, "!PXE Length Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ if ((((UINTN) Pxe->Undi.Segment) << 4) + Pxe->Undi.Offset != (UINTN) RomIdTableAddress) {
+ DEBUG ((DEBUG_ERROR, "!PXE RomId Address Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+ //
+ // This is the magic to bind the global PXE interface
+ // This dirtiness is for non-protocol shrouded access
+ //
+ SimpleNetworkDevice->PxeEntrySegment = Pxe->EntryPointSP.Segment;
+
+ if (SimpleNetworkDevice->PxeEntrySegment == 0) {
+ DEBUG ((DEBUG_ERROR, "!PXE EntryPointSP segment Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ SimpleNetworkDevice->PxeEntryOffset = Pxe->EntryPointSP.Offset;
+
+ DEBUG (
+ (
+ DEBUG_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment, SimpleNetworkDevice->
+ PxeEntryOffset
+ )
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Effect the Far Call into the PXE Layer
+
+ Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API
+ services will not work, unless there are three 16-bit parameters pushed onto the stack.
+ push DS ;Far pointer to parameter structure
+ push offset pxe_data_call_struct ;is pushed onto stack.
+ push Index ;UINT16 is pushed onto stack.
+ call dword ptr (s_PXE ptr es:[di]).EntryPointSP
+ add sp, 6 ;Caller cleans up stack.
+
+ @param SimpleNetworkDevice Device instance for simple network
+ @param Table Point to parameter/retun value table for legacy far call
+ @param TableSize The size of paramter/return value table
+ @param CallIndex The index of legacy call.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+MakePxeCall (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT VOID *Table,
+ IN UINTN TableSize,
+ IN UINT16 CallIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET InOutRegs;
+ UINT16 *BPtr;
+ VOID *Buffer;
+ UINTN Size;
+ VOID *MemPageAddress;
+ UINTN Index;
+ BOOLEAN ThunkFailed;
+
+ DEBUG ((DEBUG_NET, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex, Table, TableSize));
+
+ if (SimpleNetworkDevice->PxeEntrySegment == 0 && SimpleNetworkDevice->PxeEntryOffset == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Allocate a transient data structure for the argument table
+ // This table needs to have the input XXX_t structure copied into here.
+ // The PXE UNDI can only grab this table when it's below one-MB, and
+ // this implementation will not try to push this table on the stack
+ // (although this is a possible optimization path since EFI always allocates
+ // 4K as a minimum page size...............)
+ //
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ TableSize / EFI_PAGE_SIZE + 1,
+ &MemPageAddress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+ //
+ // Copy the > 1MB pool table to a sub-1MB buffer
+ //
+ CopyMem (MemPageAddress, Table, TableSize);
+
+ //
+ // Allocate space for IA-32 register context
+ //
+ ZeroMem (&InOutRegs, sizeof (InOutRegs));
+ InOutRegs.X.ES = SimpleNetworkDevice->PxeEntrySegment;
+ InOutRegs.X.DI = SimpleNetworkDevice->PxeEntryOffset;
+
+ //
+ // The game here is to build the stack which will subsequently
+ // get copied down below 1 MB by the FarCall primitive.
+ // This is now our working stack
+ //
+ Size = 6;
+ Status = gBS->AllocatePool (
+ EfiRuntimeServicesData,
+ Size,
+ &Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BPtr = (UINT16 *) Buffer;
+ *BPtr++ = CallIndex;
+ //
+ // SP + 2
+ //
+ *BPtr++ = TO_OFFSET (MemPageAddress);
+ *BPtr++ = TO_SEGMENT (MemPageAddress);
+
+ DEBUG ((DEBUG_NET, "State before FarCall86\n"));
+ DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));
+ BPtr = (UINT16 *) Buffer;
+ DEBUG ((DEBUG_NET, " Buffer = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));
+ DEBUG ((DEBUG_NET, " MemPage = "));
+ for (Index = 0; Index < TableSize; Index++) {
+ DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (
+ SimpleNetworkDevice->LegacyBios,
+ SimpleNetworkDevice->PxeEntrySegment, // Input segment
+ SimpleNetworkDevice->PxeEntryOffset,
+ &InOutRegs, // Ptr to Regs
+ Buffer, // Reference to Stack
+ 6 // Size of the Stack
+ );
+ if (ThunkFailed) {
+ return EFI_ABORTED;
+ }
+
+ DEBUG ((DEBUG_NET, "State after FarCall86\n"));
+ DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));
+ BPtr = (UINT16 *) Buffer;
+ DEBUG ((DEBUG_NET, " Buffer = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));
+ DEBUG ((DEBUG_NET, " MemPage = "));
+ for (Index = 0; Index < TableSize; Index++) {
+ DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ //
+ // Copy the sub 1MB table to > 1MB table
+ //
+ CopyMem (Table, MemPageAddress, TableSize);
+
+ //
+ // For PXE UNDI call, AX contains the return status.
+ // Convert the PXE UNDI Status to EFI_STATUS type
+ //
+ if (InOutRegs.X.AX == PXENV_EXIT_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ //
+ // Clean up house
+ //
+ gBS->FreePool (Buffer);
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) MemPageAddress, TableSize / EFI_PAGE_SIZE + 1);
+
+ return Status;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h
new file mode 100644
index 0000000..54503a8
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h
@@ -0,0 +1,613 @@
+/** @file
+ These are PXE Specification 2.1-compliant data structures and defines.
+
+ This file relies upon the existence of a PXE-compliant ROM
+ in memory, as defined by the Preboot Execution Environment
+ Specification (PXE), Version 2.1, located at
+
+ http://developer.intel.com/ial/wfm/wfmspecs.htm
+
+Copyright (c) 1999 - 2010, 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.
+
+**/
+
+#ifndef _PXEDEF_H_
+#define _PXEDEF_H_
+
+#pragma pack(1)
+
+//
+// PXE structure signatures
+//
+#define BC_ROMID_SIG "$BC$"
+#define UNDI_ROMID_SIG "UNDI"
+#define BUSD_ROMID_SIG "BUSD"
+
+#define PXE_SIG "!PXE"
+#define PXENV_SIG "PXENV+"
+
+#define BC_ROMID_REV 0x00
+#define UNDI_ROMID_REV 0x00
+#define BUSD_ROMID_REV 0x00
+
+#define PXE_REV 0x00
+#define PXENV_REV 0x0201
+
+#define PXENV_PTR SIGNATURE_32 ('P', 'X', 'E', 'N')
+#define PXE_PTR SIGNATURE_32 ('!', 'P', 'X', 'E')
+#define UNDI_ROMID_SIG_PTR SIGNATURE_32 ('U', 'N', 'D', 'I')
+
+typedef UINT16 SEGSEL; // Real mode segment or protected mode selector.
+typedef UINT16 OFF16; // Unsigned 16bit offset.
+typedef UINT32 ADDR32;
+
+//
+// Bus types
+//
+#define PXENV_BUS_ISA 0
+#define PXENV_BUS_EISA 1
+#define PXENV_BUS_MCA 2
+#define PXENV_BUS_PCI 3
+#define PXENV_BUS_VESA 4
+#define PXENV_BUS_PCMCIA 5
+
+//
+//
+// Result codes returned in AX by a PXENV API service.
+//
+#define PXENV_EXIT_SUCCESS 0x0000
+#define PXENV_EXIT_FAILURE 0x0001
+
+//
+// Status codes returned in the status word of PXENV API parameter structures.
+//
+// Generic API errors - these do not match up with the M0x or E0x messages
+// that are reported by the loader.
+//
+#define PXENV_STATUS_SUCCESS 0x00
+#define PXENV_STATUS_FAILURE 0x01
+#define PXENV_STATUS_BAD_FUNC 0x02
+#define PXENV_STATUS_UNSUPPORTED 0x03
+#define PXENV_STATUS_KEEP_UNDI 0x04
+#define PXENV_STATUS_KEEP_ALL 0x05
+#define PXENV_STATUS_OUT_OF_RESOURCES 0x06
+
+typedef enum {
+ PxeEnvStatus_Success,
+ PxeEnvStatus_Failure,
+ PxeEnvStatus_BadFunc,
+ PxeEnvStatus_Unsupported,
+ PxeEnvStatus_KeepUndi,
+ PxeEnvStatus_KeepAll
+} EFI_PXE_STATUS;
+
+/* Driver errors (0x60 to 0x6F) */
+
+// These errors are for UNDI compatible NIC drivers.
+#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
+#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
+#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
+#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
+#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
+#define PXENV_STATUS_UNDI_BAD_MAC_ADDR 0x67
+#define PXENV_STATUS_UNDI_BAD_EEPROM_CKSUM 0x68
+#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
+#define PXENV_STATUS_UNDI_INVALID_STATE 0x6A
+#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6B
+#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6C
+
+typedef struct {
+ UINT16 Seg_Addr;
+ UINT32 Phy_Addr;
+ UINT16 Seg_Size;
+} NEWSEGDESC_T;
+
+typedef struct {
+ OFF16 Offset;
+ SEGSEL Segment;
+} SEGOFF16;
+
+typedef struct {
+ UINT8 Signature[4]; ///< Structure signature is not NULL terminated.
+ UINT8 StructLength; ///< Length of this structure in bytes.
+ UINT8 StructCksum; ///< Use to make byte checksum of this structure == zero.
+ UINT8 StructRev; ///< Structure format revision number.
+ UINT8 UNDI_Rev[3]; ///< API revision number stored in Intel order.
+ //
+ // Revision 2.1.0 == 0x00, 0x01, 0x02
+ //
+ UINT16 UNDI_Loader; ///< Offset of UNDI loader routine in the option ROM image.
+ UINT16 StackSize; ///< Minimum stack segment size, in bytes, needed to load and run the UNDI.
+ UINT16 DataSize; ///< UNDI runtime code and data
+ UINT16 CodeSize; ///< segment sizes.
+ UINT8 BusType[4]; ///< 'ISAR', 'EISA', 'PCIR', 'PCCR'
+} UNDI_ROMID_T;
+
+typedef struct {
+ UINT8 Signature[4]; ///< Structure signature is not NULL terminated.
+ UINT8 StructLength; ///< Length of this structure in bytes.
+ UINT8 StructCksum; ///< Use to make byte checksum of this structure == zero.
+ UINT8 StructRev; ///< Structure format revision number.
+ UINT8 BC_Rev[3]; ///< API revision number stored in Intel order.
+ //
+ // Revision 2.1.0 == 0x00, 0x01, 0x02
+ //
+ UINT16 BC_Loader; ///< Offset of base-code loader routine in the option ROM image.
+ UINT16 StackSize; ///< Minimum stack segment size (bytes) needed to load/run base-code.
+ UINT16 DataSize; ///< Base-code runtime code and data
+ UINT16 CodeSize; ///< segment sizes.
+} BC_ROMID_T;
+
+typedef struct {
+ UINT8 Signature[4]; ///< Structure signature is not NULL terminated.
+ UINT8 StructLength; ///< Length of this structure in bytes.
+ UINT8 StructCksum; ///< Use to make byte checksum of this structure == zero.
+ UINT8 StructRev; ///< Structure format revision number.
+ UINT8 Reserved1; ///< must be zero
+ ///
+ /// UNDI_ROMID_T __FAR *UNDI;// Far pointer to UNDI ROMID
+ ///
+ SEGOFF16 Undi;
+
+ ///
+ /// BC_ROMID_T __FAR *Base; // Far pointer to base-code ROMID
+ ///
+ SEGOFF16 Base;
+
+ ///
+ /// UINT16 (__FAR __CDECL *EntryPointSP)(UINT16 func, VOID __FAR *param);
+ /// 16bit stack segment API entry point. This will be seg:off in
+ /// real mode and sel:off in 16:16 protected mode.
+ ///
+ SEGOFF16 EntryPointSP;
+
+ ///
+ /// UINT16 (__FAR __CDECL *EntryPointESP)(UINT16 func, VOID __FAR *param);
+ /// 32bit stack segment API entry point. This will be sel:off.
+ /// In real mode, sel == 0
+ ///
+ SEGOFF16 EntryPointESP;
+ ///
+ /// UINT16 (__FAR __CDECL *StatusCallout)(UINT16 param);
+ /// Address of DHCP/TFTP status callout routine.
+ ///
+ SEGOFF16 StatusCallout;
+ UINT8 Reserved2; ///< must be zero
+ UINT8 SegDescCnt; ///< Number of segment descriptors in this structure.
+ UINT16 FirstSelector; ///< First segment descriptor in GDT assigned to PXE.
+ NEWSEGDESC_T Stack;
+ NEWSEGDESC_T UNDIData;
+ NEWSEGDESC_T UNDICode;
+ NEWSEGDESC_T UNDICodeWrite;
+ NEWSEGDESC_T BC_Data;
+ NEWSEGDESC_T BC_Code;
+ NEWSEGDESC_T BC_CodeWrite;
+} PXE_T;
+
+typedef struct {
+ CHAR8 Signature[6]; ///< "PXENV+"
+ UINT16 Version; ///< PXE version number. LSB is minor version. MSB is major version.
+ UINT8 StructLength; ///< Length of PXE-2.0 Entry Point structure in bytes.
+ UINT8 StructCksum; ///< Used to make structure checksum equal zero.
+ UINT32 RMEntry; ///< Real mode API entry point segment:offset.
+ UINT32 PMEntryOff; ///< Protected mode API entry point
+ UINT16 PMEntrySeg; ///< segment:offset. This will always be zero. Protected mode API calls
+ ///< must be made through the API entry points in the PXE Runtime ID structure.
+
+ UINT16 StackSeg; ///< Real mode stack segment.
+ UINT16 StackSize; ///< Stack segment size in bytes.
+ UINT16 BaseCodeSeg; ///< Real mode base-code code segment.
+ UINT16 BaseCodeSize; ///< Base-code code segment size
+ UINT16 BaseDataSeg; ///< Real mode base-code data segment.
+ UINT16 BaseDataSize; ///< Base-code data segment size
+ UINT16 UNDIDataSeg; ///< Real mode UNDI data segment.
+ UINT16 UNDIDataSize; ///< UNDI data segment size in bytes.
+ UINT16 UNDICodeSeg; ///< Real mode UNDI code segment.
+ UINT16 UNDICodeSize; ///< UNDI code segment size in bytes.
+ PXE_T *RuntimePtr; ///< Real mode segment:offset pointer to PXE Runtime ID structure.
+} PXENV_T;
+
+typedef struct {
+ OUT UINT16 Status;
+ IN OUT UINT16 Ax;
+ IN OUT UINT16 Bx;
+ IN OUT UINT16 Dx;
+ IN OUT UINT16 Di;
+ IN OUT UINT16 Es;
+ IN OUT UINT16 Undi_Ds;
+ IN OUT UINT16 Undi_Cs;
+ OUT SEGOFF16 PXEptr;
+ OUT SEGOFF16 PXENVptr;
+} UNDI_LOADER_T;
+
+//
+// Put in some UNDI-specific arguments
+//
+#define PXENV_START_UNDI 0x0000
+#define PXENV_UNDI_STARTUP 0x0001
+#define PXENV_UNDI_CLEANUP 0x0002
+#define PXENV_UNDI_INITIALIZE 0x0003
+#define PXENV_UNDI_RESET_NIC 0x0004
+#define PXENV_UNDI_SHUTDOWN 0x0005
+#define PXENV_UNDI_OPEN 0x0006
+#define PXENV_UNDI_CLOSE 0x0007
+#define PXENV_UNDI_TRANSMIT 0x0008
+#define PXENV_UNDI_SET_MCAST_ADDR 0x0009
+#define PXENV_UNDI_SET_STATION_ADDR 0x000A
+#define PXENV_UNDI_SET_PACKET_FILTER 0x000B
+#define PXENV_UNDI_GET_INFORMATION 0x000C
+#define PXENV_UNDI_GET_STATISTICS 0x000D
+#define PXENV_UNDI_CLEAR_STATISTICS 0x000E
+#define PXENV_UNDI_INITIATE_DIAGS 0x000F
+#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
+#define PXENV_UNDI_GET_MCAST_ADDR 0x0011
+#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+#define PXENV_UNDI_GET_NDIS_INFO 0x0013
+#define PXENV_UNDI_ISR 0x0014
+#define PXENV_STOP_UNDI 0x0015
+#define PXENV_UNDI_GET_STATE 0x0016
+
+#define ADDR_LEN 16
+#define MAXNUM_MCADDR 8
+#define IPLEN 4 ///< length of an IP address
+#define XMT_DESTADDR 0x0000 ///< destination address given
+#define XMT_BROADCAST 0x0001 ///< use broadcast address
+
+typedef struct {
+ UINT16 MCastAddrCount; ///< In: Number of multi-cast
+
+ /* addresses. */
+ UINT8 MCastAddr[MAXNUM_MCADDR][ADDR_LEN]; /* In: */
+
+ /* list of multi-cast addresses. */
+
+ /* Each address can take up to */
+
+ /* ADDR_LEN bytes and a maximum */
+
+ /* of MAXNUM_MCADDR address can */
+
+ /* be provided*/
+} PXENV_UNDI_MCAST_ADDR_T;
+
+/* Definitions of TFTP API parameter structures.
+ */
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT16 Ax; ///< In: These register fields must be
+ IN UINT16 Bx; ///< filled in with the same data
+ IN UINT16 Dx; ///< that was passed to the MLID
+ IN UINT16 Di; ///< option ROM boot code by the
+ IN UINT16 Es; ///< system BIOS.
+} PXENV_START_UNDI_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_STARTUP_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_CLEANUP_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+
+ ///
+ /// This is an input parameter and is a 32-bit physical address of
+ /// a memory copy of the driver module in the protocol.ini file
+ /// obtained from the Protocol Manager driver(refer to NDIS 2.0
+ /// specifications). This parameter is basically supported for
+ /// the universal NDIS driver to pass the information contained in
+ /// protocol.ini file to the NIC driver for any specific
+ /// configuration of the NIC. (Note that the module
+ /// identification in the protocol.ini file was done by NDIS
+ /// itself.) This value can be NULL for for any other application
+ /// interfacing to the Universal NIC Driver.
+ ///
+ IN UINT32 ProtocolIni;
+ UINT8 Reserved[8];
+} PXENV_UNDI_INITIALIZE_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN PXENV_UNDI_MCAST_ADDR_T R_Mcast_Buf; ///< multicast address list
+ /* see note below */
+} PXENV_UNDI_RESET_T;
+
+/*++
+ Note: The NIC driver does not remember the multicast
+ addresses provided in any call. So the application must
+ provide the multicast address list with all the calls that
+ reset the receive unit of the adapter.
+ --*/
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_SHUTDOWN_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+
+ ///
+ /// This is an input parameter and is adapter specific. This is
+ /// supported for Universal NDIS 2.0 driver to pass down the Open
+ /// flags provided by the protocol driver (See NDIS 2.0
+ /// specifications). This can be zero.
+ ///
+ IN UINT16 OpenFlag; ///< In: See description below
+ IN UINT16 PktFilter; ///< In: Filter for receiving
+
+ /* packet. It takes the following */
+
+ /* values, multiple values can be */
+
+ /* ORed together. */
+#define FLTR_DIRECTED 0x0001 ///< directed/multicast
+#define FLTR_BRDCST 0x0002 ///< broadcast packets
+#define FLTR_PRMSCS 0x0004 ///< any packet on LAN
+#define FLTR_SRC_RTG 0x0008 ///< source routing packet
+ IN PXENV_UNDI_MCAST_ADDR_T McastBuffer; /* In: */
+ /* See t_PXENV_UNDI_MCAST_ADDR. */
+} PXENV_UNDI_OPEN_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_CLOSE_T;
+
+#define MAX_DATA_BLKS 8
+
+typedef struct {
+ IN UINT16 ImmedLength; ///< In: Data buffer length in
+
+ /* bytes. */
+ UINT16 XmitOffset; ///< 16-bit segment & offset of the
+ UINT16 XmitSegment; ///< immediate data buffer.
+ UINT16 DataBlkCount; ///< In: Number of data blocks.
+ struct DataBlk {
+ UINT8 TDPtrType; ///< 0 => 32 bit Phys pointer in TDDataPtr, not supported in this version of LSA
+ ///< 1 => seg:offser in TDDataPtr which can be a real mode or 16-bit protected mode pointer
+ UINT8 TDRsvdByte; ///< Reserved, must be zero.
+ UINT16 TDDataLen; ///< Data block length in bytes.
+ UINT16 TDDataPtrOffset; ///< Far pointer to data buffer.
+ UINT16 TDDataPtrSegment; ///< Far pointer to data buffer.
+ } DataBlock[MAX_DATA_BLKS];
+}
+PXENV_UNDI_TBD_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+
+ ///
+ /// This is the protocol of the upper layer that is calling
+ /// NICTransmit call. If the upper layer has filled the media
+ /// header this field must be 0.
+ ///
+ IN UINT8 Protocol;
+#define P_UNKNOWN 0
+#define P_IP 1
+#define P_ARP 2
+#define P_RARP 3
+
+ ///
+ /// If this flag is 0, the NIC driver expects a pointer to the
+ /// destination media address in the field DestMediaAddr. If 1,
+ /// the NIC driver fills the broadcast address for the
+ /// destination.
+ ///
+ IN UINT8 XmitFlag;
+#define XMT_DESTADDR 0x0000 ///< destination address given
+#define XMT_BROADCAST 0x0001 ///< use broadcast address
+
+ ///
+ /// This is a pointer to the hardware address of the destination
+ /// media. It can be null if the destination is not known in
+ /// which case the XmitFlag contains 1 for broadcast. Destination
+ /// media address must be obtained by the upper level protocol
+ /// (with Address Resolution Protocol) and NIC driver does not do
+ /// any address resolution.
+ ///
+ IN UINT16 DestAddrOffset; ///< 16-bit segment & offset of the
+ IN UINT16 DestAddrSegment; ///< destination media address
+
+
+ IN UINT16 TBDOffset; ///< 16-bit segment & offset of the
+ IN UINT16 TBDSegment; ///< transmit buffer descriptor of type
+
+ /// XmitBufferDesc
+ IN UINT32 Reserved[2];
+} PXENV_UNDI_TRANSMIT_T;
+
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN PXENV_UNDI_MCAST_ADDR_T McastBuffer; ///< In:
+} PXENV_UNDI_SET_MCAST_ADDR_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT8 StationAddress[ADDR_LEN]; ///< new address to be set
+} PXENV_UNDI_SET_STATION_ADDR_T;
+
+typedef struct s_PXENV_UNDI_SET_PACKET_FILTER {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT8 Filter; ///< In: Receive filter value.
+} PXENV_UNDI_SET_PACKET_FILTER_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ OUT UINT16 BaseIo; ///< Out: Adapter's Base IO
+ OUT UINT16 IntNumber; ///< Out: IRQ number
+ OUT UINT16 MaxTranUnit; ///< Out: MTU
+ OUT UINT16 HwType; ///< Out: type of protocol at hardware level
+
+#define ETHER_TYPE 1
+#define EXP_ETHER_TYPE 2
+#define IEEE_TYPE 6
+#define ARCNET_TYPE 7
+ /*++
+ other numbers can be obtained from rfc1010 for "Assigned
+ Numbers". This number may not be validated by the application
+ and hence adding new numbers to the list should be fine at any
+ time.
+ --*/
+ OUT UINT16 HwAddrLen; ///< Out: actual length of hardware address
+ OUT UINT8 CurrentNodeAddress[ADDR_LEN]; ///< Out: Current hardware address
+ OUT UINT8 PermNodeAddress[ADDR_LEN]; ///< Out: Permanent hardware address
+ OUT UINT16 ROMAddress; ///< Out: ROM address
+ OUT UINT16 RxBufCt; ///< Out: receive Queue length
+ OUT UINT16 TxBufCt; ///< Out: Transmit Queue length
+} PXENV_UNDI_GET_INFORMATION_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ OUT UINT32 XmtGoodFrames; ///< Out: No. of good transmissions
+ OUT UINT32 RcvGoodFrames; ///< Out: No. of good frames received
+ OUT UINT32 RcvCRCErrors; ///< Out: No. of frames with CRC error
+ OUT UINT32 RcvResourceErrors; ///< Out: no. of frames discarded
+ /* Out: receive Queue full */
+} PXENV_UNDI_GET_STATISTICS_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_CLEAR_STATISTICS_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_INITIATE_DIAGS_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_FORCE_INTERRUPT_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT32 InetAddr; ///< In: IP Multicast Address
+ OUT UINT8 MediaAddr[ADDR_LEN]; ///< Out: corresponding hardware
+ /* multicast address */
+} PXENV_UNDI_GET_MCAST_ADDR_T;
+
+typedef struct {
+ OUT UINT16 Vendor_ID; ///< OUT:
+ OUT UINT16 Dev_ID; ///< OUT:
+ OUT UINT8 Base_Class; ///< OUT:
+ OUT UINT8 Sub_Class; ///< OUT:
+ OUT UINT8 Prog_Intf; ///< OUT: program interface
+ OUT UINT8 Rev; ///< OUT: Revision number
+ OUT UINT16 BusDevFunc; ///< OUT: Bus, Device & Function numbers
+ OUT UINT16 SubVendor_ID; ///< OUT:
+ OUT UINT16 SubDevice_ID; ///< OUT:
+} PCI_INFO_T;
+
+typedef struct {
+ OUT UINT32 EISA_Dev_ID; ///< Out:
+ OUT UINT8 Base_Class; ///< OUT:
+ OUT UINT8 Sub_Class; ///< OUT:
+ OUT UINT8 Prog_Intf; ///< OUT: program interface
+ OUT UINT16 CardSelNum; ///< OUT: Card Selector Number
+ OUT UINT8 Reserved; ///< to make it 10 bytes
+} PNP_INFO_T;
+
+
+typedef union {
+ PCI_INFO_T Pci;
+ PNP_INFO_T Pnp;
+} PCI_PNP_INFO_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< OUT: PXENV_STATUS_xxx
+ OUT UINT8 NicType; ///< OUT: 2=PCI, 3=PnP
+ PCI_PNP_INFO_T PciPnpInfo;
+} PXENV_UNDI_GET_NIC_TYPE_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< OUT: PXENV_STATUS_xxx
+ OUT UINT8 IfaceType[16]; ///< OUT: Type name of MAC, AsciiZ
+
+ /* format. This is used by the */
+
+ /* Universal NDIS Driver to fill */
+
+ /* the driver type in it's MAC */
+
+ /* Service specific */
+
+ /* characteristic table */
+ OUT UINT32 LinkSpeed; ///< OUT:
+ OUT UINT32 ServiceFlags; ///< OUT: as defined in NDIS Spec 2.0X
+ OUT UINT32 Reserved[4]; ///< OUT: will be filled with 0s till defined
+} PXENV_UNDI_GET_NDIS_INFO_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< OUT: PXENV_STATUS_xxx
+ IN OUT UINT16 FuncFlag; ///< In: PXENV_UNDI_ISR_IN_xxx
+
+ /* Out: PXENV_UNDI_ISR_OUT_xxx */
+ OUT UINT16 BufferLength;
+ OUT UINT16 FrameLength;
+ OUT UINT16 FrameHeaderLength;
+ OUT UINT16 FrameOffset;
+ OUT UINT16 FrameSegSel;
+ OUT UINT8 ProtType;
+ OUT UINT8 PktType;
+} PXENV_UNDI_ISR_T;
+
+#define PXENV_UNDI_ISR_IN_START 1 /* This function must be first */
+
+/* when an interrupt is received. */
+
+/* It will tell us if the intr */
+
+/* was generated by our device. */
+#define PXENV_UNDI_ISR_IN_PROCESS 2 /* Call to start processing one of */
+
+/* our interrupts. */
+#define PXENV_UNDI_ISR_IN_GET_NEXT 3 /* Call to start/continue receiving */
+
+/* data from receive buffer(s). */
+
+/*++
+
+ Possible responses from PXENV_UNDI_ISR_IN_START
+
+ --*/
+#define PXENV_UNDI_ISR_OUT_OURS 0 ///< This is our interrupt. Deal with it.
+#define PXENV_UNDI_ISR_OUT_NOT_OURS 1 ///< This is not our interrupt.
+
+/*++
+
+ Possible responses from PXENV_UNDI_ISR_IN_PROCESS and
+ PXENV_UNDI_ISR_IN_PROCESS
+
+--*/
+#define PXENV_UNDI_ISR_OUT_DONE 0 ///< We are done processing this interrupt.
+#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 ///< We completed a transmit interrupt.
+#define PXENV_UNDI_ISR_OUT_RECEIVE 3 ///< Get data from receive buffer.
+
+#define PXENV_UNDI_ISR_OUT_BUSY 4 /* ? */
+
+typedef struct {
+ UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_STOP_UNDI_T;
+
+#define PXENV_UNDI_STARTED 1 ///< not even initialized
+#define PXENV_UNDI_INITIALIZED 2 ///< initialized and closed (not opened)
+#define PXENV_UNDI_OPENED 3 ///< initialized & opened
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ UINT16 UNDI_State;
+} PXENV_UNDI_GET_STATE_T;
+
+#pragma pack()
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c
new file mode 100644
index 0000000..d35fc3f
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c
@@ -0,0 +1,1254 @@
+/** @file
+ Wrapper routines that use a PXE-enabled NIC option ROM to
+ supply internal routines for an EFI SNI (Simple Network
+ Interface) Protocol.
+
+ This file relies upon the existence of a PXE-compliant ROM
+ in memory, as defined by the Preboot Execution Environment
+ Specification (PXE), Version 2.1, located at
+
+ http://developer.intel.com/ial/wfm/wfmspecs.htm
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+/**
+ PXE
+ START UNDI
+ Op-Code: PXENV_START_UNDI (0000h)
+ Input: Far pointer to a PXENV_START_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This service is used to pass the BIOS parameter registers to the UNDI driver. The UNDI driver is
+ responsible for saving the information it needs to communicate with the hardware.
+ This service is also responsible for hooking the Int 1Ah service routine
+ Note: This API service must be called only once during UNDI Option ROM boot.
+ The UNDI driver is responsible for saving this information and using it every time
+ PXENV_UNDI_STARTUP is called.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 AX;
+ UINT16 BX;
+ UINT16 DX;
+ UINT16 DI;
+ UINT16 ES;
+ } PXENV_START_UNDI_T;
+ Set before calling API service
+ AX, BX, DX, DI, ES: BIOS initialization parameter registers. These
+ fields should contain the same information passed to the option ROM
+ initialization routine by the Host System BIOS. Information about the
+ contents of these registers can be found in the [PnP], [PCI] and
+ [BBS] specifications.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeStartUndi (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_START_UNDI_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_START_UNDI_T),
+ PXENV_START_UNDI
+ );
+}
+
+/**
+ PXE
+ UNDI STARTUP
+ Op-Code: PXENV_UNDI_STARTUP (0001h)
+ Input: Far pointer to a PXENV_UNDI_STARTUP_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This API is responsible for initializing the contents of the UNDI code & data segment for proper
+ operation. Information from the !PXE structure and the first PXENV_START_UNDI API call is used
+ to complete this initialization. The rest of the UNDI APIs will not be available until this call has
+ been completed.
+ Note: PXENV_UNDI_STARTUP must not be called again without first calling
+ PXENV_UNDI_SHUTDOWN.
+ PXENV_UNDI_STARTUP and PXENV_UNDI_SHUTDOWN are no longer responsible for
+ chaining interrupt 1Ah. This must be done by the PXENV_START_UNDI and
+ PXENV_STOP_UNDI API calls.
+ This service cannot be used in protected mode.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_STARTUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStartup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_STARTUP_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_STARTUP_T),
+ PXENV_UNDI_STARTUP
+ );
+}
+
+/**
+ PXE
+ UNDI CLEANUP
+ Op-Code: PXENV_UNDI_CLEANUP (0002h)
+ Input: Far pointer to a PXENV_UNDI_CLEANUP_T parameter structure.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field
+ in the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call will prepare the network adapter driver to be unloaded from memory. This call must be
+ made just before unloading the Universal NIC Driver. The rest of the API will not be available
+ after this call executes.
+ This service cannot be used in protected mode.
+ typedef struct {
+ PXENX_STATUS Status;
+ } PXENV_UNDI_CLEANUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiCleanup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEANUP_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_CLEANUP_T),
+ PXENV_UNDI_CLEANUP
+ );
+}
+
+/**
+ PXE
+ UNDI INITIALIZE
+ Op-Code: PXENV_UNDI_INITIALIZE (0003h)
+ Input: Far pointer to a PXENV_UNDI_INITIALIZE_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter and programs it with default parameters. The default parameters used
+ are those supplied to the most recent UNDI_STARTUP call. This routine does not enable the
+ receive and transmit units of the network adapter to readily receive or transmit packets. The
+ application must call PXENV_UNDI_OPEN to logically connect the network adapter to the network.
+ This call must be made by an application to establish an interface to the network adapter driver.
+ Note: When the PXE code makes this call to initialize the network adapter, it passes a NULL pointer for
+ the Protocol field in the parameter structure.
+ typedef struct {
+ PXENV_STATUS Status;
+ ADDR32 ProtocolIni;
+ UINT8 reserved[8];
+ } PXENV_UNDI_INITIALIZE_T;
+ Set before calling API service
+ ProtocolIni: Physical address of a memory copy of the driver
+ module from the protocol.ini file obtained from the protocol manager
+ driver (refer to the NDIS 2.0 specification). This parameter is
+ supported for the universal NDIS driver to pass the information
+ contained in the protocol.ini file to the NIC driver for any specific
+ configuration of the NIC. (Note that the module identification in the
+ protocol.ini file was done by NDIS.) This value can be NULL for any
+ other application interfacing to the universal NIC driver
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitialize (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIALIZE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_INITIALIZE_T),
+ PXENV_UNDI_INITIALIZE
+ );
+}
+
+/**
+ Wrapper routine for reset adapter.
+
+ PXE
+ UNDI RESET ADAPTER
+ Op-Code: PXENV_UNDI_RESET_ADAPTER (0004h)
+ Input: Far pointer to a PXENV_UNDI_RESET_ADAPTER_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets and reinitializes the network adapter with the same set of parameters supplied to
+ Initialize Routine. Unlike Initialize, this call opens the adapter that is, it connects logically to the
+ network. This routine cannot be used to replace Initialize or Shutdown calls.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_RESET_T;
+
+ #define MAXNUM_MCADDR 8
+
+ typedef struct {
+ UINT16 MCastAddrCount;
+ MAC_ADDR McastAddr[MAXNUM_MCADDR];
+ } PXENV_UNDI_MCAST_ADDRESS_t;
+
+ Set before calling API service
+ R_Mcast_Buf: This is a structure of MCastAddrCount and
+ McastAddr.
+ MCastAddrCount: Number of multicast MAC addresses in the
+ buffer.
+ McastAddr: List of up to MAXNUM_MCADDR multicast MAC
+ addresses.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance.
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+ @param RxFilter Filter setting mask value for PXE recive .
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiResetNic (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_RESET_T *PxeUndiTable,
+ IN UINT16 RxFilter
+ )
+{
+ PXENV_UNDI_OPEN_T Open;
+ PXENV_UNDI_CLOSE_T Close;
+ UINTN Status;
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_RESET_T),
+ PXENV_UNDI_RESET_NIC
+ );
+ if (!EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Close.Status = PXENV_STATUS_SUCCESS;
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ &Close,
+ sizeof (Close),
+ PXENV_UNDI_CLOSE
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_RESET_T),
+ PXENV_UNDI_RESET_NIC
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Open.Status = PXENV_STATUS_SUCCESS;
+ Open.OpenFlag = 0;
+ Open.PktFilter = RxFilter;
+ CopyMem (
+ &Open.McastBuffer,
+ &PxeUndiTable->R_Mcast_Buf,
+ sizeof (PXENV_UNDI_MCAST_ADDR_T)
+ );
+
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ &Open,
+ sizeof (Open),
+ PXENV_UNDI_OPEN
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ PXE
+ UNDI SHUTDOWN
+ Op-Code: PXENV_UNDI_SHUTDOWN (0005h)
+ Input: Far pointer to a PXENV_UNDI_SHUTDOWN_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the network adapter and leaves it in a safe state for another driver to program it.
+ Note: The contents of the PXENV_UNDI_STARTUP parameter structure need to be saved by the
+ Universal NIC Driver in case PXENV_UNDI_INITIALIZE is called again.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_SHUTDOWN_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiShutdown (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SHUTDOWN_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SHUTDOWN_T),
+ PXENV_UNDI_SHUTDOWN
+ );
+}
+
+/**
+ PXE
+ UNDI OPEN
+ Op-Code: PXENV_UNDI_OPEN (0006h)
+ Input: Far pointer to a PXENV_UNDI_OPEN_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call activates the adapter network connection and sets the adapter ready to accept packets
+ for transmit and receive.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 OpenFlag;
+ UINT16 PktFilter;
+ #define FLTR_DIRECTED 0x0001
+ #define FLTR_BRDCST 0x0002
+ #define FLTR_PRMSCS 0x0004
+ #define FLTR_SRC_RTG 0x0008
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_OPEN_T;
+ Set before calling API service
+ OpenFlag: This is an adapter specific input parameter. This is
+ supported for the universal NDIS 2.0 driver to pass in the open flags
+ provided by the protocol driver. (See the NDIS 2.0 specification.)
+ This can be zero.
+ PktFilter: Filter for receiving packets. This can be one, or more, of
+ the FLTR_xxx constants. Multiple values are arithmetically or-ed
+ together.
+ directed packets are packets that may come to your MAC address
+ or the multicast MAC address.
+ R_Mcast_Buf: See definition in UNDI RESET ADAPTER (0004h).
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiOpen (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_OPEN_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_OPEN_T),
+ PXENV_UNDI_OPEN
+ );
+}
+
+/**
+ PXE
+ UNDI CLOSE
+ Op-Code: PXENV_UNDI_CLOSE (0007h)
+ Input: Far pointer to a PXENV_UNDI_CLOSE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call disconnects the network adapter from the network. Packets cannot be transmitted or
+ received until the network adapter is open again.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLOSE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClose (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLOSE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_CLOSE_T),
+ PXENV_UNDI_CLOSE
+ );
+}
+
+/**
+ PXE
+ UNDI TRANSMIT PACKET
+ Op-Code: PXENV_UNDI_TRANSMIT (0008h)
+ Input: Far pointer to a PXENV_UNDI_TRANSMIT_T parameter structure that
+ has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX.
+ The status code must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call transmits a buffer to the network. The media header
+ for the packet can be filled by the calling protocol, but it might not be.
+ The network adapter driver will fill it if required by the values in the
+ parameter block. The packet is buffered for transmission provided there is
+ an available buffer, and the function returns PXENV_EXIT_SUCCESS. If no
+ buffer is available the function returns PXENV_EXIT_FAILURE with a status
+ code of PXE_UNDI_STATUS__OUT OF_RESOURCE. The number of buffers is
+ implementation-dependent. An interrupt is generated on completion of the
+ transmission of one or more packets. A call to PXENV_UNDI_TRANSMIT is
+ permitted in the context of a transmit complete interrupt.
+
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 Protocol;
+ #define P_UNKNOWN 0
+ #define P_IP 1
+ #define P_ARP 2
+ #define P_RARP 3
+ UINT8 XmitFlag;
+ #define XMT_DESTADDR 0x0000
+ #define XMT_BROADCAST 0x0001
+ SEGOFF16 DestAddr;
+ SEGOFF16 TBD;
+ UINT32 Reserved[2];
+ } t_PXENV_UNDI_TRANSMIT;
+
+ #define MAX_DATA_BLKS 8
+
+ typedef struct {
+ UINT16 ImmedLength;
+ SEGOFF16 Xmit;
+ UINT16 DataBlkCount;
+ struct DataBlk {
+ UINT8 TDPtrType;
+ UINT8 TDRsvdByte;
+ UINT16 TDDataLen;
+ SEGOFF16 TDDataPtr;
+ } DataBlock[MAX_DATA_BLKS];
+ } PXENV_UNDI_TBD_T
+
+ Set before calling API service
+ Protocol: This is the protocol of the upper layer that is calling UNDI
+ TRANSMIT call. If the upper layer has filled the media header, this
+ field must be P_UNKNOWN.
+ XmitFlag: If this flag is XMT_DESTADDR, the NIC driver expects a
+ pointer to the destination media address in the field DestAddr. If
+ XMT_BROADCAST, the NIC driver fills the broadcast address for the
+ destination.
+ TBD: Segment:Offset address of the transmit buffer descriptor.
+ ImmedLength: Length of the immediate transmit buffer: Xmit.
+ Xmit: Segment:Offset of the immediate transmit buffer.
+ DataBlkCount: Number of blocks in this transmit buffer.
+ TDPtrType:
+ 0 => 32-bit physical address in TDDataPtr (not supported in this
+ version of PXE)
+ 1 => segment:offset in TDDataPtr which can be a real mode or 16-bit
+ protected mode pointer
+ TDRsvdByte: Reserved must be zero.
+ TDDatalen: Data block length in bytes.
+ TDDataPtr: Segment:Offset of the transmit block.
+ DataBlock: Array of transmit data blocks.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiTransmit (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_TRANSMIT_T *PxeUndiTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_TRANSMIT_T),
+ PXENV_UNDI_TRANSMIT
+ );
+ if (Status == EFI_SUCCESS) {
+ return EFI_SUCCESS;
+ }
+
+ switch (PxeUndiTable->Status) {
+ case PXENV_STATUS_OUT_OF_RESOURCES:
+ return EFI_NOT_READY;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ PXE
+ UNDI SET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_SET_MCAST_ADDRESS (0009h)
+ Input: Far pointer to a PXENV_TFTP_SET_MCAST_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call changes the current list of multicast addresses to the input list and resets the network
+ adapter to accept it. If the number of multicast addresses is zero, multicast is disabled.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_SET_MCAST_ADDR_T;
+ Set before calling API service
+ R_Mcast_Buf: See description in the UNDI RESET ADAPTER
+ (0004h) API.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_MCAST_ADDR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SET_MCAST_ADDR_T),
+ PXENV_UNDI_SET_MCAST_ADDR
+ );
+}
+
+/**
+ PXE
+ UNDI SET STATION ADDRESS
+ Op-Code: PXENV_UNDI_SET_STATION_ADDRESS (000Ah)
+ Input: Far pointer to a PXENV_UNDI_SET_STATION_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call sets the MAC address to be the input value and is called before opening the network
+ adapter. Later, the open call uses this variable as a temporary MAC address to program the
+ adapter individual address registers.
+ typedef struct {
+ PXENV_STATUS Status;
+ MAC_ADDR StationAddress;
+ } PXENV_UNDI_SET_STATION_ADDR_T;
+ Set before calling API service
+ StationAddress: Temporary MAC address to be used for
+ transmit and receive.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetStationAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_STATION_ADDR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SET_STATION_ADDR_T),
+ PXENV_UNDI_SET_STATION_ADDR
+ );
+}
+
+/**
+ PXE
+ UNDI SET PACKET FILTER
+ Op-Code: PXENV_UNDI_SET_PACKET_FILTER (000Bh)
+ Input: Far pointer to a PXENV_UNDI_SET_PACKET_FILTER_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter's receive unit to accept a new filter, different from the one provided with
+ the open call.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 filter;
+ } PXENV_UNDI_SET_PACKET_FILTER_T;
+ Set before calling API service
+ Filter: See the receive filter values in the UNDI OPEN
+ (0006h) API description.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetPacketFilter (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_PACKET_FILTER_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SET_PACKET_FILTER_T),
+ PXENV_UNDI_SET_PACKET_FILTER
+ );
+}
+
+/**
+ PXE
+ UNDI GET INFORMATION
+ Op-Code: PXENV_UNDI_GET_INFORMATION (000Ch)
+ Input: Far pointer to a PXENV_UNDI_GET_INFORMATION_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call copies the network adapter variables, including the MAC address, into the input buffer.
+ Note: The PermNodeAddress field must be valid after PXENV_START_UNDI and
+ PXENV_UNDI_STARTUP have been issued. All other fields must be valid after
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE have been
+ called.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 BaseIo;
+ UINT16 IntNumber;
+ UINT16 MaxTranUnit;
+ UINT16 HwType;
+ #define ETHER_TYPE 1
+ #define EXP_ETHER_TYPE 2
+ #define IEEE_TYPE 6
+ #define ARCNET_TYPE 7
+ UINT16 HwAddrLen;
+ MAC_ADDR CurrentNodeAddress;
+ MAC_ADDR PermNodeAddress;
+ SEGSEL ROMAddress;
+ UINT16 RxBufCt;
+ UINT16 TxBufCt;
+ } PXENV_UNDI_GET_INFORMATION_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ BaseIO: Adapter base I/O address.
+ IntNumber: Adapter IRQ number.
+ MaxTranUnit: Adapter maximum transmit unit.
+ HWType: Type of protocol at the hardware level.
+ HWAddrLen: Length of the hardware address.
+ CurrentNodeAddress: Current hardware address.
+ PermNodeAddress: Permanent hardware address.
+ ROMAddress: Real mode ROM segment address.
+ RxBufCnt: Receive queue length.
+ TxBufCnt: Transmit queue length.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetInformation (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_INFORMATION_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_INFORMATION_T),
+ PXENV_UNDI_GET_INFORMATION
+ );
+}
+
+/**
+ PXE
+ UNDI GET STATISTICS
+ Op-Code: PXENV_UNDI_GET_STATISTICS (000Dh)
+ Input: Far pointer to a PXENV_UNDI_GET_STATISTICS_T parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call reads statistical information from the network adapter, and returns.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT32 XmtGoodFrames;
+ UINT32 RcvGoodFrames;
+ UINT32 RcvCRCErrors;
+ UINT32 RcvResourceErrors;
+ } PXENV_UNDI_GET_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ XmtGoodFrames: Number of successful transmissions.
+ RcvGoodFrames: Number of good frames received.
+ RcvCRCErrors: Number of frames received with CRC
+ error.
+ RcvResourceErrors: Number of frames discarded
+ because receive queue was full.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATISTICS_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_STATISTICS_T),
+ PXENV_UNDI_GET_STATISTICS
+ );
+}
+
+/**
+ PXE
+ UNDI CLEAR STATISTICS
+ Op-Code: PXENV_UNDI_CLEAR_STATISTICS (000Eh)
+ Input: Far pointer to a PXENV_UNDI_CLEAR_STATISTICS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call clears the statistical information from the network adapter.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLEAR_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClearStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEAR_STATISTICS_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_CLEAR_STATISTICS_T),
+ PXENV_UNDI_CLEAR_STATISTICS
+ );
+}
+
+/**
+ PXE
+ UNDI INITIATE DIAGS
+ Op-Code: PXENV_UNDI_INITIATE_DIAGS (000Fh)
+ Input: Far pointer to a PXENV_UNDI_INITIATE_DIAGS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call can be used to initiate the run-time diagnostics. It causes the network adapter to run
+ hardware diagnostics and to update its status information.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_INITIATE_DIAGS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitiateDiags (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIATE_DIAGS_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_INITIATE_DIAGS_T),
+ PXENV_UNDI_INITIATE_DIAGS
+ );
+}
+
+/**
+ PXE
+ UNDI FORCE INTERRUPT
+ Op-Code: PXENV_UNDI_FORCE_INTERRUPT (0010h)
+ Input: Far pointer to a PXENV_UNDI_FORCE_INTERRUPT_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call forces the network adapter to generate an interrupt. When a receive interrupt occurs, the
+ network adapter driver usually queues the packet and calls the application's callback receive
+ routine with a pointer to the packet received. Then, the callback routine either can copy the packet
+ to its buffer or can decide to delay the copy to a later time. If the packet is not immediately copied,
+ the network adapter driver does not remove it from the input queue. When the application wants to
+ copy the packet, it can call the PXENV_UNDI_FORCE_INTERRUPT routine to simulate the receive
+ interrupt.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_FORCE_INTERRUPT_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiForceInterrupt (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_FORCE_INTERRUPT_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_FORCE_INTERRUPT_T),
+ PXENV_UNDI_FORCE_INTERRUPT
+ );
+}
+
+/**
+ PXE
+ UNDI GET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_GET_MCAST_ADDRESS (0011h)
+ Input: Far pointer to a PXENV_GET_MCAST_ADDRESS_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call converts the given IP multicast address to a hardware multicast address.
+ typedef struct {
+ PXENV_STATUS Status;
+ IP4 InetAddr;
+ MAC_ADDR MediaAddr;
+ } PXENV_UNDI_GET_MCAST_ADDR_T;
+ Set before calling API service
+ InetAddr: IP multicast address.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ MediaAddr: MAC multicast address.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_MCAST_ADDR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_MCAST_ADDR_T),
+ PXENV_UNDI_GET_MCAST_ADDR
+ );
+}
+
+/**
+ PXE
+ UNDI GET NIC TYPE
+ Op-Code: PXENV_UNDI_GET_NIC_TYPE (0012h)
+ Input: Far pointer to a PXENV_UNDI_GET_NIC_TYPE parameter structure that has been initialized by
+ the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned the parameter structure must contain the
+ NIC information.
+ Description: This call, if successful, provides the NIC-specific information necessary to identify the network
+ adapter that is used to boot the system.
+ Note: The application first gets the DHCPDISCOVER packet using GET_CACHED_INFO and checks if
+ the UNDI is supported before making this call. If the UNDI is not supported, the NIC-specific
+ information can be obtained from the DHCPDISCOVER packet itself.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef {
+ PXENV_STATUS Status;
+ UINT8 NicType;
+ #define PCI_NIC 2
+ #define PnP_NIC 3
+ #define CardBus_NIC 4
+ Union {
+ Struct {
+ UINT16 Vendor_ID;
+ UINT16 Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT8 Rev;
+ UINT16 BusDevFunc;
+ UINT16 SubVendor_ID;
+ UINT16 SubDevice_ID;
+ } pci, cardbus;
+ struct {
+ UINT32 EISA_Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT16 CardSelNum;
+ } pnp;
+ } info;
+ } PXENV_UNDI_GET_NIC_TYPE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ NICType: Type of NIC information stored in the parameter
+ structure.
+ Info: Information about the fields in this union can be found
+ in the [PnP] and [PCI] specifications
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNicType (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NIC_TYPE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_NIC_TYPE_T),
+ PXENV_UNDI_GET_NIC_TYPE
+ );
+}
+
+/**
+ PXE
+ UNDI GET IFACE INFO
+ Op-Code: PXENV_UNDI_GET_IFACE_INFO (0013h)
+ Input: Far pointer to a PXENV_UNDI_GET_IFACE_INFO_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned, the parameter structure must contain the
+ interface specific information.
+ Description: This call, if successful, provides the network interface specific information such as the interface
+ type at the link layer (Ethernet, Tokenring) and the link speed. This information can be used in the
+ universal drivers such as NDIS or Miniport to communicate to the upper protocol modules.
+ Note: UNDI follows the NDIS2 specification in giving this information. It is the responsibility of the
+ universal driver to translate/convert this information into a format that is required in its specification
+ or to suit the expectation of the upper level protocol modules.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef struct {
+ PXENV_STATUS Status
+ UINT8 IfaceType[16];
+ UINT32 LinkSpeed;
+ UINT32 ServiceFlags;
+ UINT32 Reserved[4];
+ } PXENV_UNDI_GET_NDIS_INFO_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ IfaceType: Name of MAC type in ASCIIZ format. This is
+ used by the universal NDIS driver to specify its driver type
+ to the protocol driver.
+ LinkSpeed: Defined in the NDIS 2.0 specification.
+ ServiceFlags: Defined in the NDIS 2.0 specification.
+ Reserved: Must be zero.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NDIS_INFO_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_NDIS_INFO_T),
+ PXENV_UNDI_GET_NDIS_INFO
+ );
+}
+
+/**
+ PXE
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a PXENV_UNDI_ISR_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+ Note: Interrupt Service Routine Operation:
+ In this design the UNDI does not hook the interrupt for the Network Interface. Instead, the
+ application or the protocol driver hooks the interrupt and calls UNDI with the PXENV_UNDI_ISR
+ API call for interrupt verification (PXENV_UNDI_ISR_IN_START) and processing
+ (PXENV_UNDI_ISR_IN_PROCESS and PXENV_UNDI_ISR_GET_NEXT).
+ When the Network Interface HW generates an interrupt the protocol driver interrupt service
+ routine (ISR) gets control and takes care of the interrupt processing at the PIC level. The ISR then
+ calls the UNDI using the PXENV_UNDI_ISR API with the value PXENV_UNDI_ISR_IN_START for
+ the FuncFlag parameter. At this time UNDI must disable the interrupts at the Network Interface
+ level and read any status values required to further process the interrupt. UNDI must return as
+ quickly as possible with one of the two values, PXENV_UNDI_ISR_OUT_OURS or
+ PXENV_UNDI_ISR_OUT_NOT_OURS, for the parameter FuncFlag depending on whether the
+ interrupt was generated by this particular Network Interface or not.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_NOT_OURS, then the interrupt was
+ not generated by our NIC, and interrupt processing is complete.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_OURS, the protocol driver must start
+ a handler thread and send an end-of-interrupt (EOI) command to the PIC. Interrupt processing is
+ now complete.
+ The protocol driver strategy routine will call UNDI using this same API with FuncFlag equal to
+ PXENV_UNDI_ISR_IN_PROCESS. At this time UNDI must find the cause of this interrupt and
+ return the status in the FuncFlag. It first checks if there is a frame received and if so it returns the
+ first buffer pointer of that frame in the parameter block.
+ The protocol driver calls UNDI repeatedly with the FuncFlag equal to
+ PXENV_UNDI_ISR_IN_GET_NEXT to get all the buffers in a frame and also all the received
+ frames in the queue. On this call, UNDI must remember the previous buffer given to the protoco,l
+ remove it from the receive queue and recycle it. In case of a multi-buffered frame, if the previous
+ buffer is not the last buffer in the frame it must return the next buffer in the frame in the parameter
+ block. Otherwise it must return the first buffer in the next frame.
+ If there is no received frame pending to be processed, UNDI processes the transmit completes and
+ if there is no other interrupt status to be processed, UNDI re-enables the interrupt at the
+ NETWORK INTERFACE level and returns PXENV_UNDI_ISR_OUT_DONE in the FuncFlag.
+ IMPORTANT: It is possible for the protocol driver to be interrupted again while in the
+ strategy routine when the UNDI re-enables interrupts.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiIsr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_ISR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_ISR_T),
+ PXENV_UNDI_ISR
+ );
+}
+
+/**
+ PXE
+ STOP UNDI
+ Op-Code: PXENV_STOP_UNDI (0015h)
+ Input: Far pointer to a PXENV_STOP_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This routine is responsible for unhooking the Int 1Ah service routine.
+ Note: This API service must be called only once at the end of UNDI Option ROM boot. One of the valid
+ status codes is PXENV_STATUS_KEEP. If this status is returned, UNDI must not be removed from
+ base memory. Also, UNDI must not be removed from base memory if BC is not removed from base
+ memory.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_STOP_UNDI_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStop (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_STOP_UNDI_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_STOP_UNDI_T),
+ PXENV_STOP_UNDI
+ );
+}
+
+/**
+ PXE
+ UNDI GET STATE
+ Op-Code: PXENV_UNDI_GET_STATE (0015h)
+ Input: Far pointer to a PXENV_UNDI_GET_STATE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. The UNDI_STATE field in the parameter structure must be set to one of the valid state
+ constants
+ Description: This call can be used to obtain state of the UNDI engine in order to avoid issuing adverse call
+ sequences
+ typedef struct {
+ #define PXE_UNDI_GET_STATE_STARTED 1
+ #define PXE_UNDI_GET_STATE_INITIALIZED 2
+ #define PXE_UNDI_GET_STATE_OPENED 3
+ PXENV_STATUS Status;
+ UINT8 UNDIstate;
+ } PXENV_UNDI_GET_STATE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ State: See definitions of the state constants.
+ Note. UNDI implementation is responsible for maintaining
+ internal state machine.
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a t_PXENV_UNDI_ISR parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetState (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_STATE_T),
+ PXENV_UNDI_GET_STATE
+ );
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf
new file mode 100644
index 0000000..c37c4ab
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf
@@ -0,0 +1,67 @@
+## @file
+# Thunk wrapper UEFI driver to produce EFI SNP protocol based on legacy 16 NIC ROM.
+#
+# Copyright (c) 1999 - 2010, 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.
+#
+##
+
+[Defines]
+ BASE_NAME = BiosSnp16
+ FILE_GUID = D0CAA91E-2DE4-4b0d-B3DC-09C67E854E34
+ MODULE_TYPE = UEFI_DRIVER
+ INF_VERSION = 0x00010005
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BiosSnp16DriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gBiosSnp16DriverBinding
+# COMPONENT_NAME = gBiosSnp16ComponentName
+#
+
+[Sources]
+ BiosSnp16.h
+ BiosSnp16.c
+ Misc.c
+ Pxe.h
+ PxeUndi.c
+ ComponentName.c
+
+
+[Libraryclasses]
+ UefiDriverEntryPoint
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiLib
+ BaseLib
+ DevicePathLib
+ MemoryAllocationLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid
+
+[Protocols]
+ gEfiNetworkInterfaceIdentifierProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiSimpleNetworkProtocolGuid
+ gEfiPciIoProtocolGuid
+ gEfiLegacyBiosProtocolGuid
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
new file mode 100644
index 0000000..76591e7
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
@@ -0,0 +1,3164 @@
+/** @file
+ ConsoleOut Routines that speak VGA.
+
+Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosVideo.h"
+
+//
+// EFI Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {
+ BiosVideoDriverBindingSupported,
+ BiosVideoDriverBindingStart,
+ BiosVideoDriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+//
+// Global lookup tables for VGA graphics modes
+//
+UINT8 mVgaLeftMaskTable[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+
+UINT8 mVgaRightMaskTable[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+
+UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor[] = {
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0x98, 0x00, 0x00, 0x00 },
+ { 0x00, 0x98, 0x00, 0x00 },
+ { 0x98, 0x98, 0x00, 0x00 },
+ { 0x00, 0x00, 0x98, 0x00 },
+ { 0x98, 0x00, 0x98, 0x00 },
+ { 0x00, 0x98, 0x98, 0x00 },
+ { 0x98, 0x98, 0x98, 0x00 },
+ { 0x10, 0x10, 0x10, 0x00 },
+ { 0xff, 0x10, 0x10, 0x00 },
+ { 0x10, 0xff, 0x10, 0x00 },
+ { 0xff, 0xff, 0x10, 0x00 },
+ { 0x10, 0x10, 0xff, 0x00 },
+ { 0xf0, 0x10, 0xff, 0x00 },
+ { 0x10, 0xff, 0xff, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00 }
+};
+
+//
+// Standard timing defined by VESA EDID
+//
+VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = {
+ //
+ // Established Timing I
+ //
+ {800, 600, 60},
+ {800, 600, 56},
+ {640, 480, 75},
+ {640, 480, 72},
+ {640, 480, 67},
+ {640, 480, 60},
+ {720, 400, 88},
+ {720, 400, 70},
+ //
+ // Established Timing II
+ //
+ {1280, 1024, 75},
+ {1024, 768, 75},
+ {1024, 768, 70},
+ {1024, 768, 60},
+ {1024, 768, 87},
+ {832, 624, 75},
+ {800, 600, 75},
+ {800, 600, 72},
+ //
+ // Established Timing III
+ //
+ {1152, 870, 75}
+};
+
+/**
+ Supported.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this
+ driver, Otherwise, this controller cannot be
+ managed by this driver
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ EFI_DEV_PATH *Node;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ if (Status == EFI_ALREADY_STARTED) {
+ //
+ // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure,
+ // because VgaMiniPort protocol is installed on controller handle directly.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+ //
+ // See if this is a PCI Graphics Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {
+
+ Status = EFI_SUCCESS;
+ //
+ // If this is a graphics controller,
+ // go further check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (!IsDevicePathEnd (Node)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
+ Node->DevPath.SubType != ACPI_ADR_DP ||
+ DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ }
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Install Graphics Output Protocol onto VGA device handles.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Flags;
+ UINT64 OriginalPciAttributes;
+ UINT64 Supports;
+ BOOLEAN PciAttributesSaved;
+
+ //
+ // Initialize local variables
+ //
+ PciIo = NULL;
+ ParentDevicePath = NULL;
+
+ //
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ PciAttributesSaved = FALSE;
+ //
+ // Save original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ PciAttributesSaved = TRUE;
+
+ //
+ // Get supported PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Supports &= (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
+ if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ //
+ // Prepare for status code
+ //
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
+ ParentDevicePath
+ );
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,
+ ParentDevicePath
+ );
+ goto Done;
+ }
+ //
+ // Check to see if there is a legacy option ROM image associated with this PCI device
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Post the legacy option ROM if it is available.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_PC_RESET,
+ ParentDevicePath
+ );
+ Status = LegacyBios->InstallPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ &Flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
+ ParentDevicePath
+ );
+ goto Done;
+ }
+
+ if (RemainingDevicePath != NULL) {
+ if (IsDevicePathEnd (RemainingDevicePath) &&
+ (FeaturePcdGet (PcdBiosVideoCheckVbeEnable) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable))) {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // don't create any child device and return EFI_SUCESS
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // Create child handle and install GraphicsOutputProtocol on it
+ //
+ Status = BiosVideoChildHandleInstall (
+ This,
+ Controller,
+ PciIo,
+ LegacyBios,
+ ParentDevicePath,
+ RemainingDevicePath,
+ OriginalPciAttributes
+ );
+
+Done:
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
+ ParentDevicePath
+ );
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,
+ ParentDevicePath
+ );
+ if (PciAttributesSaved) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ OriginalPciAttributes,
+ NULL
+ );
+ }
+ //
+ // Release PCI I/O Protocols on the controller handle.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Stop.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param NumberOfChildren Number of children handle created by this driver
+ @param ChildHandleBuffer Buffer containing child handle created
+
+ @retval EFI_SUCCESS Driver disconnected successfully from controller
+ @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+
+ AllChildrenStopped = TRUE;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close PCI I/O protocol on the controller handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param This Calling context.
+ @param ParentHandle Parent Handle
+ @param ParentPciIo Parent PciIo interface
+ @param ParentLegacyBios Parent LegacyBios interface
+ @param ParentDevicePath Parent Device Path
+ @param RemainingDevicePath Remaining Device Path
+ @param OriginalPciAttributes Original PCI Attributes
+
+ @retval EFI_SUCCESS If a child handle was added
+ @retval other A child handle was not added
+
+**/
+EFI_STATUS
+BiosVideoChildHandleInstall (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_PCI_IO_PROTOCOL *ParentPciIo,
+ IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN UINT64 OriginalPciAttributes
+ )
+{
+ EFI_STATUS Status;
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ PCI_TYPE00 Pci;
+ ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
+ BOOLEAN ProtocolInstalled;
+
+ //
+ // Allocate the private device structure for video device
+ //
+ BiosVideoPrivate = (BIOS_VIDEO_DEV *) AllocateZeroPool (
+ sizeof (BIOS_VIDEO_DEV)
+ );
+ if (NULL == BiosVideoPrivate) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // See if this is a VGA compatible controller or not
+ //
+ Status = ParentPciIo->Pci.Read (
+ ParentPciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
+ ParentDevicePath
+ );
+ goto Done;
+ }
+ BiosVideoPrivate->VgaCompatible = FALSE;
+ if (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01) {
+ BiosVideoPrivate->VgaCompatible = TRUE;
+ }
+
+ if (Pci.Hdr.ClassCode[2] == 0x03 && Pci.Hdr.ClassCode[1] == 0x00 && Pci.Hdr.ClassCode[0] == 0x00) {
+ BiosVideoPrivate->VgaCompatible = TRUE;
+ }
+
+ if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
+ //
+ // Create EXIT_BOOT_SERIVES Event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ BiosVideoNotifyExitBootServices,
+ BiosVideoPrivate,
+ &gEfiEventExitBootServicesGuid,
+ &BiosVideoPrivate->ExitBootServicesEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Initialize the child private structure
+ //
+ BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;
+
+ //
+ // Fill in Graphics Output specific mode structures
+ //
+ BiosVideoPrivate->HardwareNeedsStarting = TRUE;
+ BiosVideoPrivate->ModeData = NULL;
+ BiosVideoPrivate->LineBuffer = NULL;
+ BiosVideoPrivate->VgaFrameBuffer = NULL;
+ BiosVideoPrivate->VbeFrameBuffer = NULL;
+
+ //
+ // Fill in the Graphics Output Protocol
+ //
+ BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;
+ BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode;
+
+
+ //
+ // Allocate buffer for Graphics Output Protocol mode information
+ //
+ BiosVideoPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (
+ sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)
+ );
+ if (NULL == BiosVideoPrivate->GraphicsOutput.Mode) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ BiosVideoPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
+ sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
+ );
+ if (NULL == BiosVideoPrivate->GraphicsOutput.Mode->Info) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Assume that Graphics Output Protocol will be produced until proven otherwise
+ //
+ BiosVideoPrivate->ProduceGraphicsOutput = TRUE;
+
+ //
+ // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
+ //
+ if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {
+ if (RemainingDevicePath == NULL) {
+ ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
+ AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
+ AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
+ AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
+ SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
+
+ BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
+ );
+ } else {
+ BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
+ }
+
+ //
+ // Creat child handle and device path protocol firstly
+ //
+ BiosVideoPrivate->Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BiosVideoPrivate->Handle,
+ &gEfiDevicePathProtocolGuid,
+ BiosVideoPrivate->GopDevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Fill in the VGA Mini Port Protocol fields
+ //
+ BiosVideoPrivate->VgaMiniPort.SetMode = BiosVideoVgaMiniPortSetMode;
+ BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000;
+ BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
+ BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5;
+ BiosVideoPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+
+ //
+ // Child handle need to consume the Legacy Bios protocol
+ //
+ BiosVideoPrivate->LegacyBios = ParentLegacyBios;
+
+ //
+ // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
+ //
+ BiosVideoPrivate->PciIo = ParentPciIo;
+ BiosVideoPrivate->OriginalPciAttributes = OriginalPciAttributes;
+
+ //
+ // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
+ //
+ if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable)) {
+ Status = BiosVideoCheckForVbe (BiosVideoPrivate);
+ DEBUG ((EFI_D_INFO, "BiosVideoCheckForVbe - %r\n", Status));
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support
+ // for the standard 640x480 16 color VGA mode
+ //
+ DEBUG ((EFI_D_INFO, "VgaCompatible - %x\n", BiosVideoPrivate->VgaCompatible));
+ if (BiosVideoPrivate->VgaCompatible) {
+ if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable)) {
+ Status = BiosVideoCheckForVga (BiosVideoPrivate);
+ DEBUG ((EFI_D_INFO, "BiosVideoCheckForVga - %r\n", Status));
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
+ // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol.
+ //
+ BiosVideoPrivate->ProduceGraphicsOutput = FALSE;
+
+ //
+ // INT services are available, so on the 80x25 and 80x50 text mode are supported
+ //
+ BiosVideoPrivate->VgaMiniPort.MaxMode = 2;
+ }
+ }
+
+ ProtocolInstalled = FALSE;
+
+ if (BiosVideoPrivate->ProduceGraphicsOutput) {
+ //
+ // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BiosVideoPrivate->Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &BiosVideoPrivate->GraphicsOutput,
+ &gEfiEdidDiscoveredProtocolGuid,
+ &BiosVideoPrivate->EdidDiscovered,
+ &gEfiEdidActiveProtocolGuid,
+ &BiosVideoPrivate->EdidActive,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Open the Parent Handle for the child
+ //
+ Status = gBS->OpenProtocol (
+ ParentHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &BiosVideoPrivate->PciIo,
+ This->DriverBindingHandle,
+ BiosVideoPrivate->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ProtocolInstalled = TRUE;
+ }
+ }
+
+ if (!ProtocolInstalled) {
+ //
+ // Install VGA Mini Port Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ParentHandle,
+ &gEfiVgaMiniPortProtocolGuid,
+ &BiosVideoPrivate->VgaMiniPort,
+ NULL
+ );
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if ((BiosVideoPrivate != NULL) && (BiosVideoPrivate->ExitBootServicesEvent != NULL)) {
+ gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
+ }
+ //
+ // Free private data structure
+ //
+ BiosVideoDeviceReleaseResource (BiosVideoPrivate);
+ }
+
+ return Status;
+}
+
+
+/**
+ Deregister an video child handle and free resources.
+
+ @param This Protocol instance pointer.
+ @param Controller Video controller handle
+ @param Handle Video child handle
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+BiosVideoChildHandleUninstall (
+ EFI_DRIVER_BINDING_PROTOCOL *This,
+ EFI_HANDLE Controller,
+ EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ BiosVideoPrivate = NULL;
+ GraphicsOutput = NULL;
+ PciIo = NULL;
+ Status = EFI_UNSUPPORTED;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
+ }
+
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiVgaMiniPortProtocolGuid,
+ (VOID **) &VgaMiniPort,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);
+ }
+ }
+
+ if (BiosVideoPrivate == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set the 80x25 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x03;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x14;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ //
+ // Restore original PCI attributes
+ //
+ Status = BiosVideoPrivate->PciIo->Attributes (
+ BiosVideoPrivate->PciIo,
+ EfiPciIoAttributeOperationSet,
+ BiosVideoPrivate->OriginalPciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close PCI I/O protocol that opened by child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Handle
+ );
+
+ //
+ // Uninstall protocols on child handle
+ //
+ if (BiosVideoPrivate->ProduceGraphicsOutput) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ BiosVideoPrivate->Handle,
+ &gEfiDevicePathProtocolGuid,
+ BiosVideoPrivate->GopDevicePath,
+ &gEfiGraphicsOutputProtocolGuid,
+ &BiosVideoPrivate->GraphicsOutput,
+ &gEfiEdidDiscoveredProtocolGuid,
+ &BiosVideoPrivate->EdidDiscovered,
+ &gEfiEdidActiveProtocolGuid,
+ &BiosVideoPrivate->EdidActive,
+ NULL
+ );
+ }
+ if (!BiosVideoPrivate->ProduceGraphicsOutput) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ &BiosVideoPrivate->VgaMiniPort,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
+ //
+ // Close EXIT_BOOT_SERIVES Event
+ //
+ gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
+ }
+
+ //
+ // Release all allocated resources
+ //
+ BiosVideoDeviceReleaseResource (BiosVideoPrivate);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Release resource for biso video instance.
+
+ @param BiosVideoPrivate Video child device private data structure
+
+**/
+VOID
+BiosVideoDeviceReleaseResource (
+ BIOS_VIDEO_DEV *BiosVideoPrivate
+ )
+{
+ if (BiosVideoPrivate == NULL) {
+ return ;
+ }
+
+ //
+ // Release all the resourses occupied by the BIOS_VIDEO_DEV
+ //
+
+ //
+ // Free VGA Frame Buffer
+ //
+ if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VgaFrameBuffer);
+ }
+ //
+ // Free VBE Frame Buffer
+ //
+ if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VbeFrameBuffer);
+ }
+ //
+ // Free line buffer
+ //
+ if (BiosVideoPrivate->LineBuffer != NULL) {
+ FreePool (BiosVideoPrivate->LineBuffer);
+ }
+ //
+ // Free mode data
+ //
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ }
+ //
+ // Free memory allocated below 1MB
+ //
+ if (BiosVideoPrivate->PagesBelow1MB != 0) {
+ gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
+ }
+
+ if (BiosVideoPrivate->VbeSaveRestorePages != 0) {
+ gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);
+ }
+
+ //
+ // Free graphics output protocol occupied resource
+ //
+ if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
+ if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
+ }
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
+ }
+ //
+ // Free EDID discovered protocol occupied resource
+ //
+ if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) {
+ FreePool (BiosVideoPrivate->EdidDiscovered.Edid);
+ }
+ //
+ // Free EDID active protocol occupied resource
+ //
+ if (BiosVideoPrivate->EdidActive.Edid != NULL) {
+ FreePool (BiosVideoPrivate->EdidActive.Edid);
+ }
+
+ if (BiosVideoPrivate->GopDevicePath!= NULL) {
+ FreePool (BiosVideoPrivate->GopDevicePath);
+ }
+
+ FreePool (BiosVideoPrivate);
+
+ return ;
+}
+
+
+/**
+ Generate a search key for a specified timing data.
+
+ @param EdidTiming Pointer to EDID timing
+
+ @return The 32 bit unique key for search.
+
+**/
+UINT32
+CalculateEdidKey (
+ VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Key;
+
+ //
+ // Be sure no conflicts for all standard timing defined by VESA.
+ //
+ Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
+ return Key;
+}
+
+
+/**
+ Parse the Established Timing and Standard Timing in EDID data block.
+
+ @param EdidBuffer Pointer to EDID data block
+ @param ValidEdidTiming Valid EDID timing information
+
+ @retval TRUE The EDID data is valid.
+ @retval FALSE The EDID data is invalid.
+
+**/
+BOOLEAN
+ParseEdidData (
+ UINT8 *EdidBuffer,
+ VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming
+ )
+{
+ UINT8 CheckSum;
+ UINT32 Index;
+ UINT32 ValidNumber;
+ UINT32 TimingBits;
+ UINT8 *BufferIndex;
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT8 AspectRatio;
+ UINT8 RefreshRate;
+ VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming;
+ VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;
+
+ EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer;
+
+ //
+ // Check the checksum of EDID data
+ //
+ CheckSum = 0;
+ for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) {
+ CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
+ }
+ if (CheckSum != 0) {
+ return FALSE;
+ }
+
+ ValidNumber = 0;
+ gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0);
+
+ if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
+ (EdidDataBlock->EstablishedTimings[1] != 0) ||
+ (EdidDataBlock->EstablishedTimings[2] != 0)
+ ) {
+ //
+ // Established timing data
+ //
+ TimingBits = EdidDataBlock->EstablishedTimings[0] |
+ (EdidDataBlock->EstablishedTimings[1] << 8) |
+ ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
+ for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
+ if ((TimingBits & 0x1) != 0) {
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);
+ ValidNumber ++;
+ }
+ TimingBits = TimingBits >> 1;
+ }
+ } else {
+ //
+ // If no Established timing data, read the standard timing data
+ //
+ BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
+ for (Index = 0; Index < 8; Index ++) {
+ if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
+ //
+ // A valid Standard Timing
+ //
+ HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
+ AspectRatio = (UINT8) (BufferIndex[1] >> 6);
+ switch (AspectRatio) {
+ case 0:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
+ break;
+ case 1:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ case 2:
+ VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
+ break;
+ case 3:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
+ break;
+ default:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ }
+ RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
+ TempTiming.HorizontalResolution = HorizontalResolution;
+ TempTiming.VerticalResolution = VerticalResolution;
+ TempTiming.RefreshRate = RefreshRate;
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
+ ValidNumber ++;
+ }
+ BufferIndex += 2;
+ }
+ }
+
+ ValidEdidTiming->ValidNumber = ValidNumber;
+ return TRUE;
+}
+
+
+/**
+ Search a specified Timing in all the valid EDID timings.
+
+ @param ValidEdidTiming All valid EDID timing information.
+ @param EdidTiming The Timing to search for.
+
+ @retval TRUE Found.
+ @retval FALSE Not found.
+
+**/
+BOOLEAN
+SearchEdidTiming (
+ VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming,
+ VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Index;
+ UINT32 Key;
+
+ Key = CalculateEdidKey (EdidTiming);
+
+ for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
+ if (Key == ValidEdidTiming->Key[Index]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Check for VBE device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS VBE device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVbe (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT16 *ModeNumberPtr;
+ BOOLEAN ModeFound;
+ BOOLEAN EdidFound;
+ BIOS_VIDEO_MODE_DATA *ModeBuffer;
+ BIOS_VIDEO_MODE_DATA *CurrentModeData;
+ UINTN PreferMode;
+ UINTN ModeNumber;
+ VESA_BIOS_EXTENSIONS_EDID_TIMING Timing;
+ VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;
+ EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
+ UINT32 EdidAttributes;
+ BOOLEAN EdidOverrideFound;
+ UINTN EdidOverrideDataSize;
+ UINT8 *EdidOverrideDataBlock;
+ UINTN EdidActiveDataSize;
+ UINT8 *EdidActiveDataBlock;
+
+ EdidFound = TRUE;
+ EdidOverrideFound = FALSE;
+ EdidOverrideDataBlock = NULL;
+ EdidActiveDataSize = 0;
+ EdidActiveDataBlock = NULL;
+
+ //
+ // Allocate buffer under 1MB for VBE data structures
+ //
+ BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
+ sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +
+ sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
+ sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +
+ sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
+ );
+
+ BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ BiosVideoPrivate->NumberOfPagesBelow1MB,
+ &BiosVideoPrivate->PagesBelow1MB
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));
+
+ //
+ // Fill in the VBE related data structures
+ //
+ BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
+ BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
+ BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
+ BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);
+ BiosVideoPrivate->VbeSaveRestorePages = 0;
+ BiosVideoPrivate->VbeSaveRestoreBuffer = 0;
+
+ //
+ // Test to see if the Video Adapter is compliant with VBE 3.0
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
+ gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
+ BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);
+
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // See if the VESA call succeeded
+ //
+ if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ return Status;
+ }
+ //
+ // Check for 'VESA' signature
+ //
+ if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
+ return Status;
+ }
+ //
+ // Check to see if this is VBE 2.0 or higher
+ //
+ if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
+ return Status;
+ }
+
+ EdidFound = FALSE;
+ EdidAttributes = 0xff;
+ EdidOverrideDataSize = 0;
+
+ //
+ // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiEdidOverrideProtocolGuid,
+ NULL,
+ (VOID **) &EdidOverride
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
+ //
+ EdidOverrideDataBlock = AllocatePool (sizeof (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2));
+ if (NULL == EdidOverrideDataBlock) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = EdidOverride->GetEdid (
+ EdidOverride,
+ BiosVideoPrivate->Handle,
+ &EdidAttributes,
+ &EdidOverrideDataSize,
+ (UINT8 **) &EdidOverrideDataBlock
+ );
+ if (!EFI_ERROR (Status) &&
+ EdidAttributes == 0 &&
+ EdidOverrideDataSize != 0) {
+ //
+ // Succeeded to get EDID Override Data
+ //
+ EdidOverrideFound = TRUE;
+ }
+ }
+
+ if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
+ //
+ // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
+ // read EDID information through INT10 call
+ //
+
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
+ Regs.X.BX = 1;
+ Regs.X.CX = 0;
+ Regs.X.DX = 0;
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
+
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ //
+ // See if the VESA call succeeded
+ //
+ if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ //
+ // Set EDID Discovered Data
+ //
+ BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
+ BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
+ VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
+ BiosVideoPrivate->VbeEdidDataBlock
+ );
+
+ if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ EdidFound = TRUE;
+ }
+ }
+
+ if (EdidFound) {
+ EdidActiveDataSize = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
+ EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;
+ } else if (EdidOverrideFound) {
+ EdidActiveDataSize = EdidOverrideDataSize;
+ EdidActiveDataBlock = EdidOverrideDataBlock;
+ EdidFound = TRUE;
+ }
+
+ if (EdidFound) {
+ //
+ // Parse EDID data structure to retrieve modes supported by monitor
+ //
+ if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {
+ //
+ // Copy EDID Override Data to EDID Active Data
+ //
+ BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
+ BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
+ EdidActiveDataSize,
+ EdidActiveDataBlock
+ );
+ if (NULL == BiosVideoPrivate->EdidActive.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ } else {
+ BiosVideoPrivate->EdidActive.SizeOfEdid = 0;
+ BiosVideoPrivate->EdidActive.Edid = NULL;
+ EdidFound = FALSE;
+ }
+
+ //
+ // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
+ //
+ ModeNumberPtr = (UINT16 *)
+ (
+ (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
+ ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
+ );
+
+ PreferMode = 0;
+ ModeNumber = 0;
+
+ for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) {
+ //
+ // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
+ //
+ if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
+ continue;
+ }
+ //
+ // Get the information about the mode
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
+ Regs.X.CX = *ModeNumberPtr;
+ gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
+
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ //
+ // See if the call succeeded. If it didn't, then try the next mode.
+ //
+ if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ continue;
+ }
+ //
+ // See if the mode supports color. If it doesn't then try the next mode.
+ //
+ if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
+ continue;
+ }
+ //
+ // See if the mode supports graphics. If it doesn't then try the next mode.
+ //
+ if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
+ continue;
+ }
+ //
+ // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
+ //
+ if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
+ continue;
+ }
+ //
+ // See if the mode supports 32 bit color. If it doesn't then try the next mode.
+ // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
+ // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
+ //
+ if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
+ continue;
+ }
+
+ if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
+ continue;
+ }
+
+ if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
+ continue;
+ }
+ //
+ // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
+ //
+ if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
+ continue;
+ }
+
+ if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {
+ //
+ // EDID exist, check whether this mode match with any mode in EDID
+ //
+ Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
+ Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
+ if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {
+ continue;
+ }
+ }
+
+ //
+ // Select a reasonable mode to be set for current display mode
+ //
+ ModeFound = FALSE;
+
+ if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
+ BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
+ ) {
+ ModeFound = TRUE;
+ }
+ if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
+ BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
+ ) {
+ ModeFound = TRUE;
+ PreferMode = ModeNumber;
+ }
+ if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
+ BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
+ ) {
+ ModeFound = TRUE;
+ }
+
+ if ((!EdidFound) && (!ModeFound)) {
+ //
+ // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
+ //
+ continue;
+ }
+
+ //
+ // Add mode to the list of available modes
+ //
+ ModeNumber ++;
+ ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
+ ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)
+ );
+ if (NULL == ModeBuffer) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (ModeNumber > 1) {
+ CopyMem (
+ ModeBuffer,
+ BiosVideoPrivate->ModeData,
+ (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
+ );
+ }
+
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ }
+
+ CurrentModeData = &ModeBuffer[ModeNumber - 1];
+ CurrentModeData->VbeModeNumber = *ModeNumberPtr;
+ if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
+ CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
+ CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
+ CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
+ CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
+ CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
+ CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
+ CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
+ CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;
+ CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);
+ } else {
+ CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
+ CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
+ CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
+ CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
+ CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
+ CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
+ CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
+ CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;
+ CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);
+ }
+
+ CurrentModeData->PixelFormat = PixelBitMask;
+ if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&
+ (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
+ if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
+ CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
+ } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
+ CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ }
+ }
+
+ CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;
+ CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;
+ CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;
+ CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;
+ CurrentModeData->FrameBufferSize = BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024;
+
+ CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
+ CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
+ CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
+
+ CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
+
+ BiosVideoPrivate->ModeData = ModeBuffer;
+ }
+ //
+ // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
+ //
+ if (ModeNumber == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Assign Gop's Blt function
+ //
+ BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt;
+
+ BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;
+ //
+ // Current mode is unknow till now, set it to an invalid mode.
+ //
+ BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
+
+ //
+ // Find the best mode to initialize
+ //
+ Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);
+ if (EFI_ERROR (Status)) {
+ for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {
+ Status = BiosVideoGraphicsOutputSetMode (
+ &BiosVideoPrivate->GraphicsOutput,
+ (UINT32) PreferMode
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ if (PreferMode == ModeNumber) {
+ //
+ // None mode is set successfully.
+ //
+ goto Done;
+ }
+ }
+
+Done:
+ //
+ // If there was an error, then free the mode structure
+ //
+ if (EFI_ERROR (Status)) {
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ BiosVideoPrivate->ModeData = NULL;
+ BiosVideoPrivate->MaxMode = 0;
+ }
+ if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
+ if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
+ BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
+ }
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
+ BiosVideoPrivate->GraphicsOutput.Mode= NULL;
+ }
+ if (EdidOverrideDataBlock != NULL) {
+ FreePool (EdidOverrideDataBlock);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Check for VGA device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS Standard VGA device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVga (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ )
+{
+ EFI_STATUS Status;
+ BIOS_VIDEO_MODE_DATA *ModeBuffer;
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Assign Gop's Blt function
+ //
+ BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt;
+
+ //
+ // Add mode to the list of available modes
+ // caller should guarantee that Mode has been allocated.
+ //
+ ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);
+ BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;
+
+ ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
+ sizeof (BIOS_VIDEO_MODE_DATA)
+ );
+ if (NULL == ModeBuffer) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ModeBuffer->VbeModeNumber = 0x0012;
+ ModeBuffer->BytesPerScanLine = 640;
+ ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000);
+ ModeBuffer->HorizontalResolution = 640;
+ ModeBuffer->VerticalResolution = 480;
+ ModeBuffer->PixelFormat = PixelBltOnly;
+ ModeBuffer->BitsPerPixel = 8;
+ ModeBuffer->ColorDepth = 32;
+ ModeBuffer->RefreshRate = 60;
+
+ BiosVideoPrivate->ModeData = ModeBuffer;
+
+ //
+ // Test to see if the Video Adapter support the 640x480 16 color mode
+ //
+ BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
+ Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);
+
+Done:
+ //
+ // If there was an error, then free the mode structure
+ //
+ if (EFI_ERROR (Status)) {
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ BiosVideoPrivate->ModeData = NULL;
+ }
+ if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
+ if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
+ BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
+ }
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
+ BiosVideoPrivate->GraphicsOutput.Mode = NULL;
+ }
+ }
+ return Status;
+}
+
+//
+// Graphics Output Protocol Member Functions for VESA BIOS Extensions
+//
+
+/**
+ Graphics Output protocol interface to get video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param SizeOfInfo A pointer to the size, in bytes, of the Info
+ buffer.
+ @param Info Caller allocated buffer that returns information
+ about ModeNumber.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
+ video mode.
+ @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
+ @retval EFI_INVALID_PARAMETER One of the input args was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ BIOS_VIDEO_MODE_DATA *ModeData;
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ if (BiosVideoPrivate->HardwareNeedsStarting) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
+ BiosVideoPrivate->GopDevicePath
+ );
+ return EFI_NOT_STARTED;
+ }
+
+ if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
+ sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
+ );
+ if (NULL == *Info) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+
+ ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
+ (*Info)->Version = 0;
+ (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
+ (*Info)->VerticalResolution = ModeData->VerticalResolution;
+ (*Info)->PixelFormat = ModeData->PixelFormat;
+ CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
+
+ (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function to set video mode.
+
+ @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV.
+ @param ModeData The mode data to be set.
+ @param DevicePath Pointer to Device Path Protocol.
+
+ @retval EFI_SUCCESS Graphics mode was changed.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request.
+ @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
+
+**/
+EFI_STATUS
+BiosVideoSetModeWorker (
+ IN BIOS_VIDEO_DEV *BiosVideoPrivate,
+ IN BIOS_VIDEO_MODE_DATA *ModeData,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET Regs;
+
+ if (BiosVideoPrivate->LineBuffer != NULL) {
+ FreePool (BiosVideoPrivate->LineBuffer);
+ }
+
+ if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VgaFrameBuffer);
+ }
+
+ if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VbeFrameBuffer);
+ }
+
+ BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (
+ ModeData->BytesPerScanLine
+ );
+ if (NULL == BiosVideoPrivate->LineBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Clear all registers
+ //
+ ZeroMem (&Regs, sizeof (Regs));
+
+ if (ModeData->VbeModeNumber < 0x100) {
+ //
+ // Allocate a working buffer for BLT operations to the VGA frame buffer
+ //
+ BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);
+ if (NULL == BiosVideoPrivate->VgaFrameBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Set VGA Mode
+ //
+ Regs.X.AX = ModeData->VbeModeNumber;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ } else {
+ //
+ // Allocate a working buffer for BLT operations to the VBE frame buffer
+ //
+ BiosVideoPrivate->VbeFrameBuffer =
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
+ ModeData->BytesPerScanLine * ModeData->VerticalResolution
+ );
+ if (NULL == BiosVideoPrivate->VbeFrameBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Set VBE mode
+ //
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
+ Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
+ ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ //
+ // Check to see if the call succeeded
+ //
+ if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
+ DevicePath
+ );
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Initialize the state of the VbeFrameBuffer
+ //
+ Status = BiosVideoPrivate->PciIo->Mem.Read (
+ BiosVideoPrivate->PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) ModeData->LinearFrameBuffer,
+ (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,
+ BiosVideoPrivate->VbeFrameBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Graphics Output protocol interface to set video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to be set.
+
+ @retval EFI_SUCCESS Graphics mode was changed.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request.
+ @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
+ IN UINT32 ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ BIOS_VIDEO_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
+
+ if (ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (ModeNumber == This->Mode->Mode) {
+ //
+ // Clear screen to black
+ //
+ ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ BiosVideoGraphicsOutputVbeBlt (
+ This,
+ &Background,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->HorizontalResolution,
+ ModeData->VerticalResolution,
+ 0
+ );
+ return EFI_SUCCESS;
+ }
+
+ Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ This->Mode->Mode = ModeNumber;
+ This->Mode->Info->Version = 0;
+ This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
+ This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
+ This->Mode->Info->PixelFormat = ModeData->PixelFormat;
+ CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));
+ This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
+ This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+
+ //
+ // Frame BufferSize remain unchanged
+ //
+ This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;
+ This->Mode->FrameBufferSize = ModeData->FrameBufferSize;
+
+ BiosVideoPrivate->HardwareNeedsStarting = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
+
+ @param PciIo The pointer of EFI_PCI_IO_PROTOCOL
+ @param VbeBuffer The data to transfer to screen
+ @param MemAddress Physical frame buffer base address
+ @param DestinationX The X coordinate of the destination for BltOperation
+ @param DestinationY The Y coordinate of the destination for BltOperation
+ @param TotalBytes The total bytes of copy
+ @param VbePixelWidth Bytes per pixel
+ @param BytesPerScanLine Bytes per scan line
+
+**/
+VOID
+CopyVideoBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 *VbeBuffer,
+ IN VOID *MemAddress,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN TotalBytes,
+ IN UINT32 VbePixelWidth,
+ IN UINTN BytesPerScanLine
+ )
+{
+ UINTN FrameBufferAddr;
+ UINTN CopyBlockNum;
+ UINTN RemainingBytes;
+ UINTN UnalignedBytes;
+ EFI_STATUS Status;
+
+ FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
+
+ //
+ // If TotalBytes is less than 4 bytes, only start byte copy.
+ //
+ if (TotalBytes < 4) {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ TotalBytes,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
+ //
+ // If VbeBuffer is not 4-byte aligned, start byte copy.
+ //
+ UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
+
+ if (UnalignedBytes != 0) {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ UnalignedBytes,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ FrameBufferAddr += UnalignedBytes;
+ VbeBuffer += UnalignedBytes;
+ }
+
+ //
+ // Calculate 4-byte block count and remaining bytes.
+ //
+ CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
+ RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
+
+ //
+ // Copy 4-byte block and remaining bytes to physical frame buffer.
+ //
+ if (CopyBlockNum != 0) {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ CopyBlockNum,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (RemainingBytes != 0) {
+ FrameBufferAddr += (CopyBlockNum << 2);
+ VbeBuffer += (CopyBlockNum << 2);
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ RemainingBytes,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Worker function to block transfer for VBE device.
+
+ @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+ @param Mode Mode data.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+BiosVideoVbeBltWorker (
+ IN BIOS_VIDEO_DEV *BiosVideoPrivate,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta,
+ IN BIOS_VIDEO_MODE_DATA *Mode
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_TPL OriginalTPL;
+ UINTN DstY;
+ UINTN SrcY;
+ UINTN DstX;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ VOID *MemAddress;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
+ UINTN BytesPerScanLine;
+ UINTN Index;
+ UINT8 *VbeBuffer;
+ UINT8 *VbeBuffer1;
+ UINT8 *BltUint8;
+ UINT32 VbePixelWidth;
+ UINT32 Pixel;
+ UINTN TotalBytes;
+
+ PciIo = BiosVideoPrivate->PciIo;
+
+ VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer;
+ MemAddress = Mode->LinearFrameBuffer;
+ BytesPerScanLine = Mode->BytesPerScanLine;
+ VbePixelWidth = Mode->BitsPerPixel / 8;
+ BltUint8 = (UINT8 *) BltBuffer;
+ TotalBytes = Width * VbePixelWidth;
+
+ if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // We need to fill the Virtual Screen buffer with the blt data.
+ // The virtual screen is upside down, as the first row is the bootom row of
+ // the image.
+ //
+ if (BltOperation == EfiBltVideoToBltBuffer) {
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ if (SourceY + Height > Mode->VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > Mode->HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ if (DestinationY + Height > Mode->VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > Mode->HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ }
+ //
+ // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
+ // We would not want a timer based event (Cursor, ...) to come in while we are
+ // doing this operation.
+ //
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ switch (BltOperation) {
+ case EfiBltVideoToBltBuffer:
+ for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ //
+ // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ //
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
+ for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
+ Pixel = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
+ Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
+ Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
+ Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
+ Blt->Reserved = 0;
+ Blt++;
+ VbeBuffer += VbePixelWidth;
+ }
+
+ }
+ break;
+
+ case EfiBltVideoToVideo:
+ for (Index = 0; Index < Height; Index++) {
+ if (DestinationY <= SourceY) {
+ SrcY = SourceY + Index;
+ DstY = DestinationY + Index;
+ } else {
+ SrcY = SourceY + Height - Index - 1;
+ DstY = DestinationY + Height - Index - 1;
+ }
+
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
+ VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
+
+ gBS->CopyMem (
+ VbeBuffer,
+ VbeBuffer1,
+ TotalBytes
+ );
+
+ //
+ // Update physical frame buffer.
+ //
+ CopyVideoBuffer (
+ PciIo,
+ VbeBuffer,
+ MemAddress,
+ DestinationX,
+ DstY,
+ TotalBytes,
+ VbePixelWidth,
+ BytesPerScanLine
+ );
+ }
+ break;
+
+ case EfiBltVideoFill:
+ VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
+ //
+ // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
+ //
+ Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
+ (
+ (Blt->Green & Mode->Green.Mask) <<
+ Mode->Green.Position
+ ) |
+ ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
+
+ for (Index = 0; Index < Width; Index++) {
+ gBS->CopyMem (
+ VbeBuffer,
+ &Pixel,
+ VbePixelWidth
+ );
+ VbeBuffer += VbePixelWidth;
+ }
+
+ VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
+ for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
+ gBS->CopyMem (
+ (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
+ VbeBuffer,
+ TotalBytes
+ );
+ }
+
+ for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
+ //
+ // Update physical frame buffer.
+ //
+ CopyVideoBuffer (
+ PciIo,
+ VbeBuffer,
+ MemAddress,
+ DestinationX,
+ DstY,
+ TotalBytes,
+ VbePixelWidth,
+ BytesPerScanLine
+ );
+ }
+ break;
+
+ case EfiBltBufferToVideo:
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
+ for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
+ //
+ // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
+ //
+ Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
+ ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
+ ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
+ gBS->CopyMem (
+ VbeBuffer,
+ &Pixel,
+ VbePixelWidth
+ );
+ Blt++;
+ VbeBuffer += VbePixelWidth;
+ }
+
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
+
+ //
+ // Update physical frame buffer.
+ //
+ CopyVideoBuffer (
+ PciIo,
+ VbeBuffer,
+ MemAddress,
+ DestinationX,
+ DstY,
+ TotalBytes,
+ VbePixelWidth,
+ BytesPerScanLine
+ );
+ }
+ break;
+
+ default: ;
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Graphics Output protocol instance to block transfer for VBE device.
+
+ @param This Pointer to Graphics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVbeBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ BIOS_VIDEO_MODE_DATA *Mode;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+ Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode];
+
+ return BiosVideoVbeBltWorker (
+ BiosVideoPrivate,
+ BltBuffer,
+ BltOperation,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta,
+ Mode
+ );
+}
+
+/**
+ Write graphics controller registers.
+
+ @param PciIo Pointer to PciIo protocol instance of the
+ controller
+ @param Address Register address
+ @param Data Data to be written to register
+
+ @return None
+
+**/
+VOID
+WriteGraphicsController (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Address,
+ IN UINTN Data
+ )
+{
+ Address = Address | (Data << 8);
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
+ 1,
+ &Address
+ );
+}
+
+
+/**
+ Read the four bit plane of VGA frame buffer.
+
+ @param PciIo Pointer to PciIo protocol instance of the
+ controller
+ @param HardwareBuffer Hardware VGA frame buffer address
+ @param MemoryBuffer Memory buffer address
+ @param WidthInBytes Number of bytes in a line to read
+ @param Height Height of the area to read
+
+ @return None
+
+**/
+VOID
+VgaReadBitPlanes (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 *HardwareBuffer,
+ UINT8 *MemoryBuffer,
+ UINTN WidthInBytes,
+ UINTN Height
+ )
+{
+ UINTN BitPlane;
+ UINTN Rows;
+ UINTN FrameBufferOffset;
+ UINT8 *Source;
+ UINT8 *Destination;
+
+ //
+ // Program the Mode Register Write mode 0, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
+ );
+
+ for (BitPlane = 0, FrameBufferOffset = 0;
+ BitPlane < VGA_NUMBER_OF_BIT_PLANES;
+ BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
+ ) {
+ //
+ // Program the Read Map Select Register to select the correct bit plane
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
+ BitPlane
+ );
+
+ Source = HardwareBuffer;
+ Destination = MemoryBuffer + FrameBufferOffset;
+
+ for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Source,
+ WidthInBytes,
+ (VOID *) Destination
+ );
+ }
+ }
+}
+
+
+/**
+ Internal routine to convert VGA color to Grahpics Output color.
+
+ @param MemoryBuffer Buffer containing VGA color
+ @param CoordinateX The X coordinate of pixel on screen
+ @param CoordinateY The Y coordinate of pixel on screen
+ @param BltBuffer Buffer to contain converted Grahpics Output color
+
+ @return None
+
+**/
+VOID
+VgaConvertToGraphicsOutputColor (
+ UINT8 *MemoryBuffer,
+ UINTN CoordinateX,
+ UINTN CoordinateY,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
+ )
+{
+ UINTN Mask;
+ UINTN Bit;
+ UINTN Color;
+
+ MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));
+ Mask = mVgaBitMaskTable[CoordinateX & 0x07];
+ for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
+ if ((*MemoryBuffer & Mask) != 0) {
+ Color |= Bit;
+ }
+ }
+
+ *BltBuffer = mVgaColorToGraphicsOutputColor[Color];
+}
+
+/**
+ Internal routine to convert Grahpics Output color to VGA color.
+
+ @param BltBuffer buffer containing Grahpics Output color
+
+ @return Converted VGA color
+
+**/
+UINT8
+VgaConvertColor (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
+ )
+{
+ UINT8 Color;
+
+ Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
+ if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
+ Color |= 0x08;
+ }
+
+ return Color;
+}
+
+
+/**
+ Grahpics Output protocol instance to block transfer for VGA device.
+
+ @param This Pointer to Grahpics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVgaBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_TPL OriginalTPL;
+ UINT8 *MemAddress;
+ UINTN BytesPerScanLine;
+ UINTN Bit;
+ UINTN Index;
+ UINTN Index1;
+ UINTN StartAddress;
+ UINTN Bytes;
+ UINTN Offset;
+ UINT8 LeftMask;
+ UINT8 RightMask;
+ UINTN Address;
+ UINTN AddressFix;
+ UINT8 *Address1;
+ UINT8 *SourceAddress;
+ UINT8 *DestinationAddress;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Data;
+ UINT8 PixelColor;
+ UINT8 *VgaFrameBuffer;
+ UINTN SourceOffset;
+ UINTN SourceWidth;
+ UINTN Rows;
+ UINTN Columns;
+ UINTN CoordinateX;
+ UINTN CoordinateY;
+ UINTN CurrentMode;
+
+ if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ CurrentMode = This->Mode->Mode;
+ PciIo = BiosVideoPrivate->PciIo;
+ MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;
+ BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;
+ VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
+
+
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // We need to fill the Virtual Screen buffer with the blt data.
+ // The virtual screen is upside down, as the first row is the bootom row of
+ // the image.
+ //
+ if (BltOperation == EfiBltVideoToBltBuffer) {
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ }
+ //
+ // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
+ // We would not want a timer based event (Cursor, ...) to come in while we are
+ // doing this operation.
+ //
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Compute some values we need for VGA
+ //
+ switch (BltOperation) {
+ case EfiBltVideoToBltBuffer:
+
+ SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
+ SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
+
+ //
+ // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
+ //
+ VgaReadBitPlanes (
+ PciIo,
+ MemAddress + SourceOffset,
+ VgaFrameBuffer + SourceOffset,
+ SourceWidth,
+ Height
+ );
+
+ //
+ // Convert VGA Bit Planes to a Graphics Output 32-bit color value
+ //
+ BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
+ for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {
+ for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {
+ VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);
+ }
+
+ BltBuffer -= Width;
+ }
+
+ break;
+
+ case EfiBltVideoToVideo:
+ //
+ // Check for an aligned Video to Video operation
+ //
+ if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
+ //
+ // Program the Mode Register Write mode 1, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
+ );
+
+ SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
+ DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
+ Bytes = Width >> 3;
+ for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
+ PciIo->CopyMem (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) (DestinationAddress + Offset),
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) (SourceAddress + Offset),
+ Bytes
+ );
+ }
+ } else {
+ SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
+ SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
+
+ //
+ // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
+ //
+ VgaReadBitPlanes (
+ PciIo,
+ MemAddress + SourceOffset,
+ VgaFrameBuffer + SourceOffset,
+ SourceWidth,
+ Height
+ );
+ }
+
+ break;
+
+ case EfiBltVideoFill:
+ StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
+ Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
+ LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
+ RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
+ if (Bytes == 0) {
+ LeftMask = (UINT8) (LeftMask & RightMask);
+ RightMask = 0;
+ }
+
+ if (LeftMask == 0xff) {
+ StartAddress--;
+ Bytes++;
+ LeftMask = 0;
+ }
+
+ if (RightMask == 0xff) {
+ Bytes++;
+ RightMask = 0;
+ }
+
+ PixelColor = VgaConvertColor (BltBuffer);
+
+ //
+ // Program the Mode Register Write mode 2, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
+ );
+
+ //
+ // Program the Data Rotate/Function Select Register to replace
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
+ );
+
+ if (LeftMask != 0) {
+ //
+ // Program the BitMask register with the Left column mask
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ LeftMask
+ );
+
+ for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
+ //
+ // Read data from the bit planes into the latches
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &Data
+ );
+ //
+ // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
+ //
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &PixelColor
+ );
+ }
+ }
+
+ if (Bytes > 1) {
+ //
+ // Program the BitMask register with the middle column mask of 0xff
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ 0xff
+ );
+
+ for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthFillUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ Bytes - 1,
+ &PixelColor
+ );
+ }
+ }
+
+ if (RightMask != 0) {
+ //
+ // Program the BitMask register with the Right column mask
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ RightMask
+ );
+
+ for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
+ //
+ // Read data from the bit planes into the latches
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &Data
+ );
+ //
+ // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
+ //
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &PixelColor
+ );
+ }
+ }
+ break;
+
+ case EfiBltBufferToVideo:
+ StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
+ LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
+
+ //
+ // Program the Mode Register Write mode 2, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
+ );
+
+ //
+ // Program the Data Rotate/Function Select Register to replace
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
+ );
+
+ for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
+ for (Index1 = 0; Index1 < Width; Index1++) {
+ BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
+ }
+ AddressFix = Address;
+
+ for (Bit = 0; Bit < 8; Bit++) {
+ //
+ // Program the BitMask register with the Left column mask
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ LeftMask
+ );
+
+ for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
+ //
+ // Read data from the bit planes into the latches
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address1,
+ 1,
+ &Data
+ );
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address1,
+ 1,
+ &BiosVideoPrivate->LineBuffer[Index1]
+ );
+ }
+
+ LeftMask = (UINT8) (LeftMask >> 1);
+ if (LeftMask == 0) {
+ LeftMask = 0x80;
+ AddressFix++;
+ }
+ }
+ }
+
+ break;
+
+ default: ;
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+//
+// VGA Mini Port Protocol Functions
+//
+
+/**
+ VgaMiniPort protocol interface to set mode.
+
+ @param This Pointer to VgaMiniPort protocol instance
+ @param ModeNumber The index of the mode
+
+ @retval EFI_UNSUPPORTED The requested mode is not supported
+ @retval EFI_SUCCESS The requested mode is set successfully
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoVgaMiniPortSetMode (
+ IN EFI_VGA_MINI_PORT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure the ModeNumber is a valid value
+ //
+ if (ModeNumber >= This->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device structure for this device
+ //
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
+
+ switch (ModeNumber) {
+ case 0:
+ //
+ // Set the 80x25 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x83;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x14;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ break;
+
+ case 1:
+ //
+ // Set the 80x50 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x83;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x12;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Event handler for Exit Boot Service.
+
+ @param Event The event that be siganlled when exiting boot service.
+ @param Context Pointer to instance of BIOS_VIDEO_DEV.
+
+**/
+VOID
+EFIAPI
+BiosVideoNotifyExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+
+ BiosVideoPrivate = (BIOS_VIDEO_DEV *)Context;
+
+ //
+ // Set the 80x25 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x03;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x83;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x04;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+}
+
+/**
+ The user Entry Point for module UefiBiosVideo. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoEntryPoint(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosVideoDriverBinding,
+ ImageHandle,
+ &gBiosVideoComponentName,
+ &gBiosVideoComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
+ //
+ return gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ NULL
+ );
+}
+
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h
new file mode 100644
index 0000000..45a75b9
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h
@@ -0,0 +1,532 @@
+/** @file
+
+Copyright (c) 2006 - 2010, 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.
+
+**/
+
+#ifndef _BIOS_GRAPHICS_OUTPUT_H_
+#define _BIOS_GRAPHICS_OUTPUT_H_
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/VgaMiniPort.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EdidOverride.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+#include "VesaBiosExtensions.h"
+
+//
+// Packed format support: The number of bits reserved for each of the colors and the actual
+// position of RGB in the frame buffer is specified in the VBE Mode information
+//
+typedef struct {
+ UINT8 Position; // Position of the color
+ UINT8 Mask; // The number of bits expressed as a mask
+} BIOS_VIDEO_COLOR_PLACEMENT;
+
+//
+// BIOS Graphics Output Graphical Mode Data
+//
+typedef struct {
+ UINT16 VbeModeNumber;
+ UINT16 BytesPerScanLine;
+ VOID *LinearFrameBuffer;
+ UINTN FrameBufferSize;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ UINT32 BitsPerPixel;
+ BIOS_VIDEO_COLOR_PLACEMENT Red;
+ BIOS_VIDEO_COLOR_PLACEMENT Green;
+ BIOS_VIDEO_COLOR_PLACEMENT Blue;
+ BIOS_VIDEO_COLOR_PLACEMENT Reserved;
+ EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
+ EFI_PIXEL_BITMASK PixelBitMask;
+} BIOS_VIDEO_MODE_DATA;
+
+//
+// BIOS video child handle private data Structure
+//
+#define BIOS_VIDEO_DEV_SIGNATURE SIGNATURE_32 ('B', 'V', 'M', 'p')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+
+ //
+ // Consumed Protocols
+ //
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ //
+ // Original PCI attributes
+ //
+ UINT64 OriginalPciAttributes;
+
+ //
+ // Produced Protocols
+ //
+ EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput;
+ EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered;
+ EFI_EDID_ACTIVE_PROTOCOL EdidActive;
+ EFI_VGA_MINI_PORT_PROTOCOL VgaMiniPort;
+
+ //
+ // General fields
+ //
+ BOOLEAN VgaCompatible;
+ BOOLEAN ProduceGraphicsOutput;
+
+ //
+ // Graphics Output Protocol related fields
+ //
+ BOOLEAN HardwareNeedsStarting;
+ UINTN CurrentMode;
+ UINTN MaxMode;
+ BIOS_VIDEO_MODE_DATA *ModeData;
+ UINT8 *LineBuffer;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
+ UINT8 *VgaFrameBuffer;
+
+ //
+ // VESA Bios Extensions related fields
+ //
+ UINTN NumberOfPagesBelow1MB; // Number of 4KB pages in PagesBelow1MB
+ EFI_PHYSICAL_ADDRESS PagesBelow1MB; // Buffer for all VBE Information Blocks
+ VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *VbeInformationBlock; // 0x200 bytes. Must be allocated below 1MB
+ VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *VbeModeInformationBlock; // 0x100 bytes. Must be allocated below 1MB
+ VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *VbeEdidDataBlock; // 0x80 bytes. Must be allocated below 1MB
+ VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *VbeCrtcInformationBlock; // 59 bytes. Must be allocated below 1MB
+ UINTN VbeSaveRestorePages; // Number of 4KB pages in VbeSaveRestoreBuffer
+ EFI_PHYSICAL_ADDRESS VbeSaveRestoreBuffer; // Must be allocated below 1MB
+ //
+ // Status code
+ //
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+
+ EFI_EVENT ExitBootServicesEvent;
+} BIOS_VIDEO_DEV;
+
+#define BIOS_VIDEO_DEV_FROM_PCI_IO_THIS(a) CR (a, BIOS_VIDEO_DEV, PciIo, BIOS_VIDEO_DEV_SIGNATURE)
+#define BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS(a) CR (a, BIOS_VIDEO_DEV, GraphicsOutput, BIOS_VIDEO_DEV_SIGNATURE)
+#define BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS(a) CR (a, BIOS_VIDEO_DEV, VgaMiniPort, BIOS_VIDEO_DEV_SIGNATURE)
+
+#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER 0xffff
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosVideoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosVideoComponentName2;
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Supported.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this
+ driver, Otherwise, this controller cannot be
+ managed by this driver
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Install Graphics Output Protocol onto VGA device handles.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Stop.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param NumberOfChildren Number of children handle created by this driver
+ @param ChildHandleBuffer Buffer containing child handle created
+
+ @retval EFI_SUCCESS Driver disconnected successfully from controller
+ @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Private worker functions
+//
+
+/**
+ Check for VBE device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS VBE device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVbe (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+
+/**
+ Check for VGA device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS Standard VGA device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVga (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+
+
+
+/**
+ Release resource for biso video instance.
+
+ @param BiosVideoPrivate Video child device private data structure
+
+**/
+VOID
+BiosVideoDeviceReleaseResource (
+ BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+//
+// BIOS Graphics Output Protocol functions
+//
+
+/**
+ Graphics Output protocol interface to get video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param SizeOfInfo A pointer to the size, in bytes, of the Info
+ buffer.
+ @param Info Caller allocated buffer that returns information
+ about ModeNumber.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @retval EFI_BUFFER_TOO_SMALL The Info buffer was too small.
+ @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
+ video mode.
+ @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
+ @retval EFI_INVALID_PARAMETER One of the input args was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ );
+
+
+/**
+ Graphics Output protocol interface to set video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to be set.
+
+ @retval EFI_SUCCESS Graphics mode was changed.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request.
+ @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
+ IN UINT32 ModeNumber
+ );
+
+
+/**
+ Graphics Output protocol instance to block transfer for VBE device.
+
+ @param This Pointer to Graphics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVbeBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ );
+
+
+/**
+ Grahpics Output protocol instance to block transfer for VGA device.
+
+ @param This Pointer to Grahpics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVgaBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ );
+
+//
+// BIOS VGA Mini Port Protocol functions
+//
+
+/**
+ VgaMiniPort protocol interface to set mode.
+
+ @param This Pointer to VgaMiniPort protocol instance
+ @param ModeNumber The index of the mode
+
+ @retval EFI_UNSUPPORTED The requested mode is not supported
+ @retval EFI_SUCCESS The requested mode is set successfully
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoVgaMiniPortSetMode (
+ IN EFI_VGA_MINI_PORT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Event handler for Exit Boot Service.
+
+ @param Event The event that be siganlled when exiting boot service.
+ @param Context Pointer to instance of BIOS_VIDEO_DEV.
+
+**/
+VOID
+EFIAPI
+BiosVideoNotifyExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Standard VGA Definitions
+//
+#define VGA_HORIZONTAL_RESOLUTION 640
+#define VGA_VERTICAL_RESOLUTION 480
+#define VGA_NUMBER_OF_BIT_PLANES 4
+#define VGA_PIXELS_PER_BYTE 8
+#define VGA_BYTES_PER_SCAN_LINE (VGA_HORIZONTAL_RESOLUTION / VGA_PIXELS_PER_BYTE)
+#define VGA_BYTES_PER_BIT_PLANE (VGA_VERTICAL_RESOLUTION * VGA_BYTES_PER_SCAN_LINE)
+
+#define VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER 0x3ce
+#define VGA_GRAPHICS_CONTROLLER_DATA_REGISTER 0x3cf
+
+#define VGA_GRAPHICS_CONTROLLER_SET_RESET_REGISTER 0x00
+
+#define VGA_GRAPHICS_CONTROLLER_ENABLE_SET_RESET_REGISTER 0x01
+
+#define VGA_GRAPHICS_CONTROLLER_COLOR_COMPARE_REGISTER 0x02
+
+#define VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER 0x03
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE 0x00
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_AND 0x08
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_OR 0x10
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_XOR 0x18
+
+#define VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER 0x04
+
+#define VGA_GRAPHICS_CONTROLLER_MODE_REGISTER 0x05
+#define VGA_GRAPHICS_CONTROLLER_READ_MODE_0 0x00
+#define VGA_GRAPHICS_CONTROLLER_READ_MODE_1 0x08
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0 0x00
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1 0x01
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2 0x02
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_3 0x03
+
+#define VGA_GRAPHICS_CONTROLLER_MISCELLANEOUS_REGISTER 0x06
+
+#define VGA_GRAPHICS_CONTROLLER_COLOR_DONT_CARE_REGISTER 0x07
+
+#define VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER 0x08
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param This Calling context.
+ @param ParentHandle Parent Handle
+ @param ParentPciIo Parent PciIo interface
+ @param ParentLegacyBios Parent LegacyBios interface
+ @param ParentDevicePath Parent Device Path
+ @param RemainingDevicePath Remaining Device Path
+ @param OriginalPciAttributes Original PCI Attributes
+
+ @retval EFI_SUCCESS If a child handle was added
+ @retval other A child handle was not added
+
+**/
+EFI_STATUS
+BiosVideoChildHandleInstall (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_PCI_IO_PROTOCOL *ParentPciIo,
+ IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN UINT64 OriginalPciAttributes
+ );
+
+/**
+ Deregister an video child handle and free resources.
+
+ @param This Protocol instance pointer.
+ @param Controller Video controller handle
+ @param Handle Video child handle
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+BiosVideoChildHandleUninstall (
+ EFI_DRIVER_BINDING_PROTOCOL *This,
+ EFI_HANDLE Controller,
+ EFI_HANDLE Handle
+ );
+
+/**
+ Release resource for biso video instance.
+
+ @param BiosVideoPrivate Video child device private data structure
+
+**/
+VOID
+BiosVideoDeviceReleaseResource (
+ BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c
new file mode 100644
index 0000000..1d70e5c
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c
@@ -0,0 +1,313 @@
+/** @file
+
+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.
+
+**/
+
+#include "BiosVideo.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosVideoComponentName = {
+ BiosVideoComponentNameGetDriverName,
+ BiosVideoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosVideoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosVideoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosVideoComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosVideoDriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[INT10] Video Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosVideoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosVideoComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h
new file mode 100644
index 0000000..dcda3fc
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h
@@ -0,0 +1,451 @@
+/** @file
+
+Copyright (c) 2006 - 2010, 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.
+
+**/
+
+#ifndef _VESA_BIOS_EXTENSIONS_H_
+#define _VESA_BIOS_EXTENSIONS_H_
+
+//
+// Turn on byte packing of data structures
+//
+#pragma pack(1)
+//
+// VESA BIOS Extensions status codes
+//
+#define VESA_BIOS_EXTENSIONS_STATUS_SUCCESS 0x004f
+
+//
+// VESA BIOS Extensions Services
+//
+#define VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION 0x4f00
+
+/*++
+
+ Routine Description:
+ Function 00 : Return Controller Information
+
+ Arguments:
+ Inputs:
+ AX = 0x4f00
+ ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK structure
+ Outputs:
+ AX = Return Status
+
+--*/
+#define VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION 0x4f01
+
+/*++
+
+ Routine Description:
+ Function 01 : Return Mode Information
+
+ Arguments:
+ Inputs:
+ AX = 0x4f01
+ CX = Mode Number
+ ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK structure
+ Outputs:
+ AX = Return Status
+
+--*/
+#define VESA_BIOS_EXTENSIONS_SET_MODE 0x4f02
+
+/*++
+
+ Routine Description:
+ Function 02 : Set Mode
+
+ Arguments:
+ Inputs:
+ AX = 0x4f02
+ BX = Desired mode to set
+ D0-D8 = Mode Number
+ D9-D10 = Reserved (must be 0)
+ D11 = 0 - Use current default refresh rate
+ = 1 - Use user specfieid CRTC values for refresh rate
+ D12-D13 = Reserved (must be 0)
+ D14 = 0 - Use windowed frame buffer model
+ = 1 - Use linear/flat frame buffer model
+ D15 = 0 - Clear display memory
+ = 1 - Don't clear display memory
+ ES:DI = Pointer to buffer to the VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK structure
+ Outputs:
+ AX = Return Status
+
+--*/
+#define VESA_BIOS_EXTENSIONS_RETURN_CURRENT_MODE 0x4f03
+
+/*++
+
+ Routine Description:
+ Function 03 : Return Current Mode
+
+ Arguments:
+ Inputs:
+ AX = 0x4f03
+ Outputs:
+ AX = Return Status
+ BX = Current mode
+ D0-D13 = Mode Number
+ D14 = 0 - Windowed frame buffer model
+ = 1 - Linear/flat frame buffer model
+ D15 = 0 - Memory cleared at last mode set
+ = 1 - Memory not cleared at last mode set
+
+--*/
+#define VESA_BIOS_EXTENSIONS_SAVE_RESTORE_STATE 0x4f04
+
+/*++
+
+ Routine Description:
+ Function 04 : Save/Restore State
+
+ Arguments:
+ Inputs:
+ AX = 0x4f03
+ DL = 0x00 - Return Save/Restore State buffer size
+ = 0x01 - Save State
+ = 0x02 - Restore State
+ CX = Requested Status
+ D0 = Save/Restore controller hardware state
+ D1 = Save/Restore BIOS data state
+ D2 = Save/Restore DAC state
+ D3 = Save/Restore Regsiter state
+ ES:BX = Pointer to buffer if DL=1 or DL=2
+ Outputs:
+ AX = Return Status
+ BX = Number of 64 byte blocks to hold the state buffer if DL=0
+
+--*/
+#define VESA_BIOS_EXTENSIONS_EDID 0x4f15
+
+/*++
+
+ Routine Description:
+ Function 15 : implement VBE/DDC service
+
+ Arguments:
+ Inputs:
+ AX = 0x4f15
+ BL = 0x00 - Report VBE/DDC Capabilities
+ CX = 0x00 - Controller unit number (00 = primary controller)
+ ES:DI = Null pointer, must be 0:0 in version 1.0
+ Outputs:
+ AX = Return Status
+ BH = Approx. time in seconds, rounded up, to transfer one EDID block(128 bytes)
+ BL = DDC level supported
+ D0 = 0 DDC1 not supported
+ = 1 DDC1 supported
+ D1 = 0 DDC2 not supported
+ = 1 DDC2 supported
+ D2 = 0 Screen not blanked during data transfer
+ = 1 Screen blanked during data transfer
+
+ Inputs:
+ AX = 0x4f15
+ BL = 0x01 - Read EDID
+ CX = 0x00 - Controller unit number (00 = primary controller)
+ DX = 0x00 - EDID block number
+ ES:DI = Pointer to buffer in which the EDID block is returned
+ Outputs:
+ AX = Return Status
+--*/
+
+//
+// Timing data from EDID data block
+//
+#define VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE 128
+#define VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
+
+typedef struct {
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT16 RefreshRate;
+} VESA_BIOS_EXTENSIONS_EDID_TIMING;
+
+typedef struct {
+ UINT32 ValidNumber;
+ UINT32 Key[VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER];
+} VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING;
+
+typedef struct {
+ UINT8 Header[8]; //EDID header "00 FF FF FF FF FF FF 00"
+ UINT16 ManufactureName; //EISA 3-character ID
+ UINT16 ProductCode; //Vendor assigned code
+ UINT32 SerialNumber; //32-bit serial number
+ UINT8 WeekOfManufacture; //Week number
+ UINT8 YearOfManufacture; //Year
+ UINT8 EdidVersion; //EDID Structure Version
+ UINT8 EdidRevision; //EDID Structure Revision
+ UINT8 VideoInputDefinition;
+ UINT8 MaxHorizontalImageSize; //cm
+ UINT8 MaxVerticalImageSize; //cm
+ UINT8 DisplayTransferCharacteristic;
+ UINT8 FeatureSupport;
+ UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
+ UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
+ UINT8 RedX; //Red-x Bits 9 - 2
+ UINT8 RedY; //Red-y Bits 9 - 2
+ UINT8 GreenX; //Green-x Bits 9 - 2
+ UINT8 GreenY; //Green-y Bits 9 - 2
+ UINT8 BlueX; //Blue-x Bits 9 - 2
+ UINT8 BlueY; //Blue-y Bits 9 - 2
+ UINT8 WhiteX; //White-x Bits 9 - 2
+ UINT8 WhiteY; //White-x Bits 9 - 2
+ UINT8 EstablishedTimings[3];
+ UINT8 StandardTimingIdentification[16];
+ UINT8 DetailedTimingDescriptions[72];
+ UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
+ UINT8 Checksum;
+} VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK;
+
+//
+// Super VGA Information Block
+//
+typedef struct {
+ UINT32 VESASignature; // 'VESA' 4 byte signature
+ UINT16 VESAVersion; // VBE version number
+ UINT32 OEMStringPtr; // Pointer to OEM string
+ UINT32 Capabilities; // Capabilities of video card
+ UINT32 VideoModePtr; // Pointer to an array of 16-bit supported modes values terminated by 0xFFFF
+ UINT16 TotalMemory; // Number of 64kb memory blocks
+ UINT16 OemSoftwareRev; // VBE implementation Software revision
+ UINT32 OemVendorNamePtr; // VbeFarPtr to Vendor Name String
+ UINT32 OemProductNamePtr; // VbeFarPtr to Product Name String
+ UINT32 OemProductRevPtr; // VbeFarPtr to Product Revision String
+ UINT8 Reserved[222]; // Reserved for VBE implementation scratch area
+ UINT8 OemData[256]; // Data area for OEM strings. Pad to 512 byte block size
+} VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK;
+
+//
+// Super VGA Information Block VESASignature values
+//
+#define VESA_BIOS_EXTENSIONS_VESA_SIGNATURE SIGNATURE_32 ('V', 'E', 'S', 'A')
+#define VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE SIGNATURE_32 ('V', 'B', 'E', '2')
+
+//
+// Super VGA Information Block VESAVersion values
+//
+#define VESA_BIOS_EXTENSIONS_VERSION_1_2 0x0102
+#define VESA_BIOS_EXTENSIONS_VERSION_2_0 0x0200
+#define VESA_BIOS_EXTENSIONS_VERSION_3_0 0x0300
+
+//
+// Super VGA Information Block Capabilities field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_8_BIT_DAC 0x01 // 0: DAC width is fixed at 6 bits/color
+// 1: DAC width switchable to 8 bits/color
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_VGA 0x02 // 0: Controller is VGA compatible
+// 1: Controller is not VGA compatible
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_NORMAL_RAMDAC 0x04 // 0: Normal RAMDAC operation
+// 1: Use blank bit in function 9 to program RAMDAC
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_STEREOSCOPIC 0x08 // 0: No hardware stereoscopic signal support
+// 1: Hardware stereoscopic signal support
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_VESA_EVC 0x10 // 0: Stero signaling supported via external VESA stereo connector
+// 1: Stero signaling supported via VESA EVC connector
+//
+// Super VGA mode number bite field definitions
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA 0x0100 // 0: Not a VESA defined VBE mode
+// 1: A VESA defined VBE mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_REFRESH_CONTROL_USER 0x0800 // 0: Use current BIOS default referesh rate
+// 1: Use the user specified CRTC values for refresh rate
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER 0x4000 // 0: Use a banked/windowed frame buffer
+// 1: Use a linear/flat frame buffer
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_PRESERVE_MEMORY 0x8000 // 0: Clear display memory
+// 1: Preseve display memory
+//
+// Super VGA Information Block mode list terminator value
+//
+#define VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST 0xffff
+
+//
+// Window Function
+//
+typedef
+VOID
+(*VESA_BIOS_EXTENSIONS_WINDOW_FUNCTION) (
+ VOID
+ );
+
+//
+// Super VGA Mode Information Block
+//
+typedef struct {
+ //
+ // Manadory fields for all VESA Bios Extensions revisions
+ //
+ UINT16 ModeAttributes; // Mode attributes
+ UINT8 WinAAttributes; // Window A attributes
+ UINT8 WinBAttributes; // Window B attributes
+ UINT16 WinGranularity; // Window granularity in k
+ UINT16 WinSize; // Window size in k
+ UINT16 WinASegment; // Window A segment
+ UINT16 WinBSegment; // Window B segment
+ UINT32 WindowFunction; // Pointer to window function
+ UINT16 BytesPerScanLine; // Bytes per scanline
+ //
+ // Manadory fields for VESA Bios Extensions 1.2 and above
+ //
+ UINT16 XResolution; // Horizontal resolution
+ UINT16 YResolution; // Vertical resolution
+ UINT8 XCharSize; // Character cell width
+ UINT8 YCharSize; // Character cell height
+ UINT8 NumberOfPlanes; // Number of memory planes
+ UINT8 BitsPerPixel; // Bits per pixel
+ UINT8 NumberOfBanks; // Number of CGA style banks
+ UINT8 MemoryModel; // Memory model type
+ UINT8 BankSize; // Size of CGA style banks
+ UINT8 NumberOfImagePages; // Number of images pages
+ UINT8 Reserved1; // Reserved
+ UINT8 RedMaskSize; // Size of direct color red mask
+ UINT8 RedFieldPosition; // Bit posn of lsb of red mask
+ UINT8 GreenMaskSize; // Size of direct color green mask
+ UINT8 GreenFieldPosition; // Bit posn of lsb of green mask
+ UINT8 BlueMaskSize; // Size of direct color blue mask
+ UINT8 BlueFieldPosition; // Bit posn of lsb of blue mask
+ UINT8 RsvdMaskSize; // Size of direct color res mask
+ UINT8 RsvdFieldPosition; // Bit posn of lsb of res mask
+ UINT8 DirectColorModeInfo; // Direct color mode attributes
+ //
+ // Manadory fields for VESA Bios Extensions 2.0 and above
+ //
+ UINT32 PhysBasePtr; // Physical Address for flat memory frame buffer
+ UINT32 Reserved2; // Reserved
+ UINT16 Reserved3; // Reserved
+ //
+ // Manadory fields for VESA Bios Extensions 3.0 and above
+ //
+ UINT16 LinBytesPerScanLine; // Bytes/scan line for linear modes
+ UINT8 BnkNumberOfImagePages; // Number of images for banked modes
+ UINT8 LinNumberOfImagePages; // Number of images for linear modes
+ UINT8 LinRedMaskSize; // Size of direct color red mask (linear mode)
+ UINT8 LinRedFieldPosition; // Bit posiiton of lsb of red mask (linear modes)
+ UINT8 LinGreenMaskSize; // Size of direct color green mask (linear mode)
+ UINT8 LinGreenFieldPosition; // Bit posiiton of lsb of green mask (linear modes)
+ UINT8 LinBlueMaskSize; // Size of direct color blue mask (linear mode)
+ UINT8 LinBlueFieldPosition; // Bit posiiton of lsb of blue mask (linear modes)
+ UINT8 LinRsvdMaskSize; // Size of direct color reserved mask (linear mode)
+ UINT8 LinRsvdFieldPosition; // Bit posiiton of lsb of reserved mask (linear modes)
+ UINT32 MaxPixelClock; // Maximum pixel clock (in Hz) for graphics mode
+ UINT8 Pad[190]; // Pad to 256 byte block size
+} VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK;
+
+//
+// Super VGA Mode Information Block ModeAttributes field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_HARDWARE 0x0001 // 0: Mode not supported in handware
+// 1: Mode supported in handware
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_TTY 0x0004 // 0: TTY Output functions not supported by BIOS
+// 1: TTY Output functions supported by BIOS
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR 0x0008 // 0: Monochrome mode
+// 1: Color mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS 0x0010 // 0: Text mode
+// 1: Graphics mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_VGA 0x0020 // 0: VGA compatible mode
+// 1: Not a VGA compatible mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_WINDOWED 0x0040 // 0: VGA compatible windowed memory mode
+// 1: Not a VGA compatible windowed memory mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER 0x0080 // 0: No linear fram buffer mode available
+// 1: Linear frame buffer mode available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DOUBLE_SCAN 0x0100 // 0: No double scan mode available
+// 1: Double scan mode available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_INTERLACED 0x0200 // 0: No interlaced mode is available
+// 1: Interlaced mode is available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NO_TRIPPLE_BUFFER 0x0400 // 0: No hardware triple buffer mode support available
+// 1: Hardware triple buffer mode support available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_STEREOSCOPIC 0x0800 // 0: No hardware steroscopic display support
+// 1: Hardware steroscopic display support
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DUAL_DISPLAY 0x1000 // 0: No dual display start address support
+// 1: Dual display start address support
+//
+// Super VGA Mode Information Block WinAAttribite/WinBAttributes field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_RELOCATABLE 0x01 // 0: Single non-relocatable window only
+// 1: Relocatable window(s) are supported
+//
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_READABLE 0x02 // 0: Window is not readable
+// 1: Window is readable
+//
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_WRITABLE 0x04 // 0: Window is not writable
+// 1: Window is writable
+//
+// Super VGA Mode Information Block DirectColorMode field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_PROG_COLOR_RAMP 0x01 // 0: Color ram is fixed
+// 1: Color ramp is programmable
+//
+#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_RSVD_USABLE 0x02 // 0: Bits in Rsvd field are reserved
+// 1: Bits in Rsdv field are usable
+//
+// Super VGA Memory Models
+//
+typedef enum {
+ MemPL = 3, // Planar memory model
+ MemPK = 4, // Packed pixel memory model
+ MemRGB= 6, // Direct color RGB memory model
+ MemYUV= 7 // Direct color YUV memory model
+} VESA_BIOS_EXTENSIONS_MEMORY_MODELS;
+
+//
+// Super VGA CRTC Information Block
+//
+typedef struct {
+ UINT16 HorizontalTotal; // Horizontal total in pixels
+ UINT16 HorizontalSyncStart; // Horizontal sync start in pixels
+ UINT16 HorizontalSyncEnd; // Horizontal sync end in pixels
+ UINT16 VericalTotal; // Vertical total in pixels
+ UINT16 VericalSyncStart; // Vertical sync start in pixels
+ UINT16 VericalSyncEnd; // Vertical sync end in pixels
+ UINT8 Flags; // Flags (Interlaced/DoubleScan/etc).
+ UINT32 PixelClock; // Pixel clock in units of Hz
+ UINT16 RefreshRate; // Refresh rate in units of 0.01 Hz
+ UINT8 Reserved[40]; // Pad
+} VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK;
+
+#define VESA_BIOS_EXTENSIONS_CRTC_FLAGS_DOUBLE_SCAN 0x01 // 0: Graphics mode is not souble scanned
+// 1: Graphics mode is double scanned
+//
+#define VESA_BIOS_EXTENSIONS_CRTC_FLAGSINTERLACED 0x02 // 0: Graphics mode is not interlaced
+// 1: Graphics mode is interlaced
+//
+#define VESA_BIOS_EXTENSIONS_CRTC_HORIZONTAL_SYNC_NEGATIVE 0x04 // 0: Horizontal sync polarity is positive(+)
+// 0: Horizontal sync polarity is negative(-)
+//
+#define VESA_BIOS_EXTENSIONS_CRTC_VERITICAL_SYNC_NEGATIVE 0x08 // 0: Verical sync polarity is positive(+)
+// 0: Verical sync polarity is negative(-)
+//
+// Turn off byte packing of data structures
+//
+#pragma pack()
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
new file mode 100644
index 0000000..bf5f255
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
@@ -0,0 +1,80 @@
+## @file
+# Video driver based on legacy bios.
+#
+# This driver by using Legacy Bios protocol service to support csm Video
+# and produce Graphics Output Protocol.
+#
+# Copyright (c) 2007 - 2011, 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BiosVideoDxe
+ FILE_GUID = 0B04B2ED-861C-42cd-A22F-C3AAFACCB896
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BiosVideoEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gBiosVideoDriverBinding
+# COMPONENT_NAME = gBiosVideoComponentName
+#
+
+[Sources]
+ BiosVideo.c
+ BiosVideo.h
+ ComponentName.c
+ VesaBiosExtensions.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ ReportStatusCodeLib
+ DebugLib
+ PcdLib
+
+
+[Guids]
+ gEfiLegacyBiosGuid # ALWAYS_PRODUCED
+ gEfiEventExitBootServicesGuid
+
+[Protocols]
+ gEfiVgaMiniPortProtocolGuid # PROTOCOL BY_START
+ gEfiEdidDiscoveredProtocolGuid # PROTOCOL BY_START
+ gEfiGraphicsOutputProtocolGuid # PROTOCOL BY_START
+ gEfiEdidActiveProtocolGuid # PROTOCOL BY_START
+ gEfiLegacyBiosProtocolGuid # PROTOCOL TO_START
+ gEfiPciIoProtocolGuid # PROTOCOL TO_START
+ gEfiDevicePathProtocolGuid # PROTOCOL TO_START
+ gEfiEdidOverrideProtocolGuid # PROTOCOL TO_START
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoSetTextVgaModeEnable
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVbeEnable
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVgaEnable
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S
new file mode 100644
index 0000000..a785256
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S
@@ -0,0 +1,67 @@
+## @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.
+#
+##
+
+ASM_GLOBAL ASM_PFX(InterruptRedirectionTemplate)
+
+#----------------------------------------------------------------------------
+# 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_PFX(InterruptRedirectionTemplate):
+ int $0x8
+ .byte 0xcf
+ nop
+ int $0x9
+ .byte 0xcf
+ nop
+ int $0xa
+ .byte 0xcf
+ nop
+ int $0xb
+ .byte 0xcf
+ nop
+ int $0xc
+ .byte 0xcf
+ nop
+ int $0xd
+ .byte 0xcf
+ nop
+ int $0xe
+ .byte 0xcf
+ nop
+ int $0xf
+ .byte 0xcf
+ nop
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm
new file mode 100644
index 0000000..410ce5b
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm
@@ -0,0 +1,73 @@
+;; @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.
+;
+;;
+
+.686P
+.MODEL FLAT, C
+.CODE
+
+;----------------------------------------------------------------------------
+; 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.
+;
+;----------------------------------------------------------------------------
+
+InterruptRedirectionTemplate PROC C
+ int 08h
+ DB 0cfh ; IRET
+ nop
+ int 09h
+ DB 0cfh ; IRET
+ nop
+ int 0ah
+ DB 0cfh ; IRET
+ nop
+ int 0bh
+ DB 0cfh ; IRET
+ nop
+ int 0ch
+ DB 0cfh ; IRET
+ nop
+ int 0dh
+ DB 0cfh ; IRET
+ nop
+ int 0eh
+ DB 0cfh ; IRET
+ nop
+ int 0fh
+ DB 0cfh ; IRET
+ nop
+InterruptRedirectionTemplate ENDP
+
+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
index 0000000..b6787ae
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c
@@ -0,0 +1,277 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ //
+ // Shadow All Opion ROM
+ //
+ LegacyBiosShadowAllLegacyOproms (This);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ To boot from an unconventional device like parties and/or execute
+ HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the
+ parent device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data.
+ The caller must provide a pointer to the specific
+ Service Area and not the start all Service Areas.
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ )
+{
+ return EFI_INVALID_PARAMETER;
+}
+
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ )
+{
+ *Size = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS LoadedImageBase;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ EFI_HANDLE NewImageHandle;
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID *) &LoadedImage
+ );
+
+ if (!EFI_ERROR (Status)) {
+ LoadedImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImage->ImageBase;
+ if (LoadedImageBase > 0xffffffff) {
+ NumberOfPages = (UINTN) (DivU64x32(LoadedImage->ImageSize, EFI_PAGE_SIZE) + 1);
+
+ //
+ // Allocate buffer below 4GB here
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ 0x7FFFFFFF,
+ NumberOfPages, // do we have to convert this to pages??
+ &MemoryAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+ ImageContext.Handle = (VOID *)(UINTN)LoadedImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)MemoryAddress;
+ //
+ // Align buffer on section boundry
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+
+ //
+ // Create a new handle with gEfiCallerIdGuid to be used as the ImageHandle fore the reloaded image
+ //
+ NewImageHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &NewImageHandle,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+ //
+ // return error directly the BS will unload this image
+ //
+ return EFI_ABORTED;
+ }
+ }
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h
new file mode 100644
index 0000000..26aa3a6
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h
@@ -0,0 +1,102 @@
+/** @file
+
+Copyright (c) 2007 - 2010, 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.
+
+**/
+
+#ifndef _IPF_THUNK_H_
+#define _IPF_THUNK_H_
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Sal.h>
+
+/**
+ Template of real mode code.
+
+ @param CodeStart Start address of code.
+ @param CodeEnd End address of code
+ @param ReverseThunkStart Start of reverse thunk.
+ @param IntThunk Low memory thunk.
+
+**/
+VOID
+RealModeTemplate (
+ OUT UINTN *CodeStart,
+ OUT UINTN *CodeEnd,
+ OUT UINTN *ReverseThunkStart,
+ LOW_MEMORY_THUNK *IntThunk
+ );
+
+/**
+ Register physical address of Esal Data Area
+
+ @param ReverseThunkCodeAddress Reverse Thunk Address
+ @param IntThunkAddress IntThunk Address
+
+ @retval EFI_SUCCESS ESAL data area set successfully.
+
+**/
+EFI_STATUS
+EsalSetSalDataArea (
+ IN UINTN ReverseThunkCodeAddress,
+ IN UINTN IntThunkAddress
+ );
+
+/**
+ Get address of reverse thunk.
+
+ @retval EFI_SAL_SUCCESS Address of reverse thunk returned successfully.
+
+**/
+SAL_RETURN_REGS
+EsalGetReverseThunkAddress (
+ VOID
+ );
+
+typedef struct {
+ UINT32 Eax; // 0
+ UINT32 Ecx; // 4
+ UINT32 Edx; // 8
+ UINT32 Ebx; // 12
+ UINT32 Esp; // 16
+ UINT32 Ebp; // 20
+ UINT32 Esi; // 24
+ UINT32 Edi; // 28
+ UINT32 Eflag; // 32
+ UINT32 Eip; // 36
+ UINT16 Cs; // 40
+ UINT16 Ds; // 42
+ UINT16 Es; // 44
+ UINT16 Fs; // 46
+ UINT16 Gs; // 48
+ UINT16 Ss; // 50
+} IPF_DWORD_REGS;
+
+/**
+ Entrypoint of IA32 code.
+
+ @param CallTypeData Data of call type
+ @param DwordRegister Register set of IA32 general registers
+ and segment registers
+ @param StackPointer Stack pointer.
+ @param StackSize Size of stack.
+
+**/
+VOID
+EfiIaEntryPoint (
+ UINT64 CallTypeData,
+ IPF_DWORD_REGS *DwordRegister,
+ UINT64 StackPointer,
+ UINT64 StackSize
+ );
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i
new file mode 100644
index 0000000..441bb25
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i
@@ -0,0 +1,89 @@
+//// @file
+//
+// 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.
+//
+////
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define LOW_STACK_SIZE (8*1024) // 8k?
+
+//
+// Low memory Thunk Structure
+//
+#define Code 0
+#define LowReverseThunkStart Code + 4096
+#define GdtDesc LowReverseThunkStart + 4
+#define IdtDesc GdtDesc + 6
+#define FlatSs IdtDesc + 6
+#define FlatEsp FlatSs + 4
+#define LowCodeSelector FlatEsp + 4
+#define LowDataSelector LowCodeSelector + 4
+#define LowStack LowDataSelector + 4
+#define RealModeIdtDesc LowStack + 4
+#define RealModeGdt RealModeIdtDesc + 6
+#define RealModeGdtDesc RealModeGdt + (8 * NUM_REAL_GDT_ENTRIES)
+#define RevRealDs RealModeGdtDesc + 6
+#define RevRealSs RevRealDs + 2
+#define RevRealEsp RevRealSs + 2
+#define RevRealIdtDesc RevRealEsp + 4
+#define RevFlatDataSelector RevRealIdtDesc + 6
+#define RevFlatStack RevFlatDataSelector + 2
+#define Stack RevFlatStack + 4
+#define RevThunkStack Stack + LOW_STACK_SIZE
+
+#define EfiToLegacy16InitTable RevThunkStack + LOW_STACK_SIZE
+#define InitTableBiosLessThan1MB EfiToLegacy16InitTable
+#define InitTableHiPmmMemory InitTableBiosLessThan1MB + 4
+#define InitTablePmmMemorySizeInBytes InitTableHiPmmMemory + 4
+#define InitTableReverseThunkCallSegment InitTablePmmMemorySizeInBytes + 4
+#define InitTableReverseThunkCallOffset InitTableReverseThunkCallSegment + 2
+#define InitTableNumberE820Entries InitTableReverseThunkCallOffset + 2
+#define InitTableOsMemoryAbove1Mb InitTableNumberE820Entries + 4
+#define InitTableThunkStart InitTableOsMemoryAbove1Mb + 4
+#define InitTableThunkSizeInBytes InitTableThunkStart + 4
+#define InitTable16InitTableEnd InitTableThunkSizeInBytes + 4
+
+#define EfiToLegacy16BootTable InitTable16InitTableEnd
+#define BootTableBiosLessThan1MB EfiToLegacy16BootTable
+#define BootTableHiPmmMemory BootTableBiosLessThan1MB + 4
+#define BootTablePmmMemorySizeInBytes BootTableHiPmmMemory + 4
+#define BootTableReverseThunkCallSegment BootTablePmmMemorySizeInBytes + 4
+#define BootTableReverseThunkCallOffset BootTableReverseThunkCallSegment + 2
+#define BootTableNumberE820Entries BootTableReverseThunkCallOffset + 2
+#define BootTableOsMemoryAbove1Mb BootTableNumberE820Entries + 4
+#define BootTableThunkStart BootTableOsMemoryAbove1Mb + 4
+#define BootTableThunkSizeInBytes BootTableThunkStart + 4
+#define EfiToLegacy16BootTableEnd BootTableThunkSizeInBytes + 4
+
+#define InterruptRedirectionCode EfiToLegacy16BootTableEnd
+#define PciHandler InterruptRedirectionCode + 32
+
+
+//
+// Register Sets (16 Bit)
+//
+
+#define AX 0
+#define BX 2
+#define CX 4
+#define DX 6
+#define SI 8
+#define DI 10
+#define Flags 12
+#define ES 14
+#define CS 16
+#define SS 18
+#define DS 20
+#define BP 22
+
+
+
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s
new file mode 100644
index 0000000..d08f781
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s
@@ -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
index 0000000..ca59b97
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c
@@ -0,0 +1,550 @@
+/** @file
+ Call into 16-bit BIOS code
+
+ BugBug: Thunker does A20 gate. Can we get rid of this code or
+ put it into Legacy16 code.
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include "IpfThunk.h"
+
+/**
+ Gets the current flat GDT and IDT descriptors and store them in
+ Private->IntThunk. These values are used by the Thunk code.
+ This method must be called before every thunk in order to assure
+ that the correct GDT and IDT are restored after the thunk.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosGetFlatDescs (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ BIOS interrupt call function.
+
+ @param BiosInt Int number of BIOS call
+ @param Segment Segment number
+ @param Offset Offset in segment
+ @param Regs IA32 Register set.
+ @param Stack Base address of stack
+ @param StackSize Size of stack
+
+ @retval EFI_SUCCESS BIOS interrupt call succeeds.
+
+**/
+EFI_STATUS
+BiosIntCall (
+ IN UINT16 BiosInt,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ IPF_DWORD_REGS DwordRegs;
+ UINT64 IntTypeVariable;
+
+ IntTypeVariable = 0x8000000000000000;
+ IntTypeVariable |= BiosInt;
+
+ DwordRegs.Cs = Segment;
+ DwordRegs.Eip = Offset;
+
+ DwordRegs.Ds = Regs->X.DS;
+ DwordRegs.Es = Regs->X.ES;
+ DwordRegs.Fs = Regs->X.ES;
+ DwordRegs.Gs = Regs->X.ES;
+ DwordRegs.Ss = 0xFFFF;
+
+ DwordRegs.Eax = Regs->X.AX;
+ DwordRegs.Ebx = Regs->X.BX;
+ //
+ // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
+ // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
+ //
+ DwordRegs.Ecx = Regs->E.ECX;
+ DwordRegs.Edx = Regs->X.DX;
+
+ DwordRegs.Ebp = Regs->X.BP;
+ DwordRegs.Eflag = *((UINT16 *) &Regs->X.Flags);
+
+ DwordRegs.Edi = Regs->X.DI;
+ DwordRegs.Esi = Regs->X.SI;
+ DwordRegs.Esp = 0xFFFFFFFF;
+
+ EfiIaEntryPoint (IntTypeVariable, &DwordRegs, ((UINTN) Stack + StackSize), StackSize);
+
+ Regs->X.CS = DwordRegs.Cs;
+
+ Regs->X.DS = (UINT16) DwordRegs.Ds;
+ Regs->X.SS = (UINT16) DwordRegs.Ss;
+
+ Regs->E.EAX = DwordRegs.Eax;
+ Regs->E.EBX = DwordRegs.Ebx;
+ Regs->E.ECX = DwordRegs.Ecx;
+ Regs->E.EDX = DwordRegs.Edx;
+
+ Regs->E.EBP = DwordRegs.Ebp;
+ CopyMem (&Regs->X.Flags, &DwordRegs.Eflag, sizeof (EFI_FLAGS_REG));
+
+ Regs->E.EDI = DwordRegs.Edi;
+ Regs->E.ESI = DwordRegs.Esi;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Template of real mode code.
+
+ @param CodeStart Start address of code.
+ @param CodeEnd End address of code
+ @param ReverseThunkStart Start of reverse thunk.
+ @param IntThunk Low memory thunk.
+
+**/
+VOID
+RealModeTemplate (
+ OUT UINTN *CodeStart,
+ OUT UINTN *CodeEnd,
+ OUT UINTN *ReverseThunkStart,
+ LOW_MEMORY_THUNK *IntThunk
+ )
+{
+ SAL_RETURN_REGS SalStatus;
+
+ SalStatus = EsalGetReverseThunkAddress ();
+
+ *CodeStart = SalStatus.r9;
+ *CodeEnd = SalStatus.r10;
+ *ReverseThunkStart = SalStatus.r11;
+
+}
+
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ GDT32 *CodeGdt;
+ GDT32 *DataGdt;
+ UINTN CodeStart;
+ UINTN CodeEnd;
+ UINTN ReverseThunkStart;
+ UINT32 Base;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINTN TempData;
+
+ ASSERT (Private);
+
+ IntThunk = Private->IntThunk;
+
+ //
+ // Clear the reserved descriptor
+ //
+ ZeroMem (&(IntThunk->RealModeGdt[0]), sizeof (GDT32));
+
+ //
+ // Setup a descriptor for real-mode code
+ //
+ CodeGdt = &(IntThunk->RealModeGdt[1]);
+
+ //
+ // Fill in the descriptor with our real-mode segment value
+ //
+ CodeGdt->Type = 0xA;
+ //
+ // code/read
+ //
+ CodeGdt->System = 1;
+ CodeGdt->Dpl = 0;
+ CodeGdt->Present = 1;
+ CodeGdt->Software = 0;
+ CodeGdt->Reserved = 0;
+ CodeGdt->DefaultSize = 0;
+ //
+ // 16 bit operands
+ //
+ CodeGdt->Granularity = 0;
+
+ CodeGdt->LimitHi = 0;
+ CodeGdt->LimitLo = 0xffff;
+
+ Base = (*((UINT32 *) &IntThunk->Code));
+ CodeGdt->BaseHi = (Base >> 24) & 0xFF;
+ CodeGdt->BaseMid = (Base >> 16) & 0xFF;
+ CodeGdt->BaseLo = Base & 0xFFFF;
+
+ //
+ // Setup a descriptor for read-mode data
+ //
+ DataGdt = &(IntThunk->RealModeGdt[2]);
+ CopyMem (DataGdt, CodeGdt, sizeof (GDT32));
+
+ DataGdt->Type = 0x2;
+ //
+ // read/write data
+ //
+ DataGdt->BaseHi = 0x0;
+ //
+ // Base = 0
+ //
+ DataGdt->BaseMid = 0x0;
+ //
+ DataGdt->BaseLo = 0x0;
+ //
+ DataGdt->LimitHi = 0x0F;
+ //
+ // Limit = 4Gb
+ //
+ DataGdt->LimitLo = 0xFFFF;
+ //
+ DataGdt->Granularity = 0x1;
+ //
+ //
+ // Compute selector value
+ //
+ IntThunk->RealModeGdtDesc.Limit = (UINT16) (sizeof (IntThunk->RealModeGdt) - 1);
+ CopyMem (&IntThunk->RealModeGdtDesc.Base, (UINT32 *) &IntThunk->RealModeGdt, sizeof (UINT32));
+ //
+ // IntThunk->RealModeGdtDesc.Base = *((UINT32*) &IntThunk->RealModeGdt);
+ //
+ IntThunk->RealModeIdtDesc.Limit = 0xFFFF;
+ IntThunk->RealModeIdtDesc.Base = 0;
+ IntThunk->LowCodeSelector = (UINT32) ((UINTN) CodeGdt - IntThunk->RealModeGdtDesc.Base);
+ IntThunk->LowDataSelector = (UINT32) ((UINTN) DataGdt - IntThunk->RealModeGdtDesc.Base);
+
+ //
+ // Initialize low real-mode code thunk
+ //
+ RealModeTemplate (&CodeStart, &CodeEnd, &ReverseThunkStart, IntThunk);
+
+ TempData = (UINTN) &(IntThunk->Code);
+ IntThunk->LowReverseThunkStart = ((UINT32) TempData + (UINT32) (ReverseThunkStart - CodeStart));
+
+ EsalSetSalDataArea (TempData, (UINTN) IntThunk);
+ CopyMem (IntThunk->Code, (VOID *) CodeStart, CodeEnd - CodeStart);
+
+ IntThunk->EfiToLegacy16InitTable.ReverseThunkCallSegment = EFI_SEGMENT (*((UINT32 *) &IntThunk->LowReverseThunkStart));
+ IntThunk->EfiToLegacy16InitTable.ReverseThunkCallOffset = EFI_OFFSET (*((UINT32 *) &IntThunk->LowReverseThunkStart));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Thunk to 16-bit real mode and execute a software interrupt with a vector
+ of BiosInt. Regs will contain the 16-bit register context on entry and
+ exit.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the
+ target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ UINTN IaSegment;
+ UINTN IaOffset;
+ UINTN *Address;
+ UINTN TempData;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ IntThunk = Private->IntThunk;
+
+ //
+ // Get the current flat GDT, IDT, and SS and store them in Private->IntThunk.
+ //
+ Status = LegacyBiosGetFlatDescs (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 1;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+ //
+ // Clear the error flag; thunk code may set it.
+ //
+ Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
+
+ //
+ // Copy regs to low memory stack
+ //
+ Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+ CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ //
+ // Provide low stack esp
+ //
+ TempData = ((UINTN) Stack16) - ((UINTN) IntThunk);
+ IntThunk->LowStack = *((UINT32 *) &TempData);
+
+ //
+ // Stack for reverse thunk flat mode.
+ // It must point to top of stack (end of stack space).
+ //
+ TempData = ((UINTN) IntThunk->RevThunkStack) + LOW_STACK_SIZE;
+ IntThunk->RevFlatStack = *((UINT32 *) &TempData);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call the real mode thunk code
+ //
+ TempData = BiosInt * 4;
+ Address = (UINTN *) TempData;
+ IaOffset = 0xFFFF & (*Address);
+ IaSegment = 0xFFFF & ((*Address) >> 16);
+
+ Status = BiosIntCall (
+ BiosInt,
+ (UINT16) IaSegment,
+ (UINT16) IaOffset,
+ (EFI_IA32_REGISTER_SET *) Stack16,
+ IntThunk,
+ IntThunk->LowStack
+ );
+
+ //
+ // Check for errors with the thunk
+ //
+ switch (Status) {
+ case THUNK_OK:
+ break;
+
+ case THUNK_ERR_A20_UNSUP:
+ case THUNK_ERR_A20_FAILED:
+ default:
+ //
+ // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
+ //
+ Regs->X.Flags.CF = 1;
+ break;
+ }
+
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Return the resulting registers
+ //
+ CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
+
+ return (BOOLEAN) (Regs->X.Flags.CF != 0);
+}
+
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the
+ target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ UINTN IaSegment;
+ UINTN IaOffset;
+ UINTN TempData;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ IntThunk = Private->IntThunk;
+ IaSegment = Segment;
+ IaOffset = Offset;
+
+ //
+ // Get the current flat GDT and IDT and store them in Private->IntThunk.
+ //
+ Status = LegacyBiosGetFlatDescs (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 1;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+ //
+ // Clear the error flag; thunk code may set it.
+ //
+ Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy Stack to low memory stack
+ //
+ Stack16 -= StackSize / sizeof (UINT16);
+ CopyMem (Stack16, Stack, StackSize);
+ }
+ //
+ // Copy regs to low memory stack
+ //
+ Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+ CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ //
+ // Provide low stack esp
+ //
+ TempData = ((UINTN) Stack16) - ((UINTN) IntThunk);
+ IntThunk->LowStack = *((UINT32 *) &TempData);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call the real mode thunk code
+ //
+ Status = BiosIntCall (
+ 0x100,
+ (UINT16) IaSegment,
+ (UINT16) IaOffset,
+ (EFI_IA32_REGISTER_SET *) Stack16,
+ IntThunk,
+ IntThunk->LowStack
+ );
+
+ //
+ // Check for errors with the thunk
+ //
+ switch (Status) {
+ case THUNK_OK:
+ break;
+
+ case THUNK_ERR_A20_UNSUP:
+ case THUNK_ERR_A20_FAILED:
+ default:
+ //
+ // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
+ //
+ Regs->X.Flags.CF = 1;
+ break;
+ }
+ //
+ // Restore protected mode interrupt state
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Return the resulting registers
+ //
+ CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
+ Stack16 += sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy low memory stack to Stack
+ //
+ CopyMem (Stack, Stack16, StackSize);
+ Stack16 += StackSize / sizeof (UINT16);
+ }
+
+ return (BOOLEAN) (Regs->X.Flags.CF != 0);
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c
new file mode 100644
index 0000000..c15e599
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c
@@ -0,0 +1,384 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+// Give floppy 3 states
+// FLOPPY_PRESENT_WITH_MEDIA = Floppy controller present and media is inserted
+// FLOPPY_NOT_PRESENT = No floppy controller present
+// FLOPPY_PRESENT_NO_MEDIA = Floppy controller present but no media inserted
+//
+#define FLOPPY_NOT_PRESENT 0
+#define FLOPPY_PRESENT_WITH_MEDIA 1
+#define FLOPPY_PRESENT_NO_MEDIA 2
+
+BBS_TABLE *mBbsTable;
+BOOLEAN mBbsTableDoneFlag = FALSE;
+BOOLEAN IsHaveMediaInFloppy = TRUE;
+
+/**
+ Checks the state of the floppy and if media is inserted.
+
+ This routine checks the state of the floppy and if media is inserted.
+ There are 3 cases:
+ No floppy present - Set BBS entry to ignore
+ Floppy present & no media - Set BBS entry to lowest priority. We cannot
+ set it to ignore since 16-bit CSM will
+ indicate no floppy and thus drive A: is
+ unusable. CSM-16 will not try floppy since
+ lowest priority and thus not incur boot
+ time penality.
+ Floppy present & media - Set BBS entry to some priority.
+
+ @return State of floppy media
+
+**/
+UINT8
+HasMediaInFloppy (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+
+ HandleBuffer = NULL;
+ HandleCount = 0;
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ //
+ // If don't find any ISA/IO protocol assume no floppy. Need for floppy
+ // free system
+ //
+ if (HandleCount == 0) {
+ return FLOPPY_NOT_PRESENT;
+ }
+
+ ASSERT (HandleBuffer != NULL);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {
+ continue;
+ }
+ //
+ // Update blockio in case the floppy is inserted in during BdsTimeout
+ //
+ Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (BlkIo->Media->MediaPresent) {
+ FreePool (HandleBuffer);
+ return FLOPPY_PRESENT_WITH_MEDIA;
+ } else {
+ FreePool (HandleBuffer);
+ return FLOPPY_PRESENT_NO_MEDIA;
+ }
+ }
+
+ FreePool (HandleBuffer);
+
+ return FLOPPY_NOT_PRESENT;
+
+}
+
+
+/**
+ Complete build of BBS TABLE.
+
+ @param Private Legacy BIOS Instance data
+ @param BbsTable BBS Table passed to 16-bit code
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+LegacyBiosBuildBbs (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BBS_TABLE *BbsTable
+ )
+{
+ UINTN BbsIndex;
+ HDD_INFO *HddInfo;
+ UINTN HddIndex;
+ UINTN Index;
+
+ //
+ // First entry is floppy.
+ // Next 2*MAX_IDE_CONTROLLER entries are for onboard IDE.
+ // Next n entries are filled in after each ROM is dispatched.
+ // Entry filled in if follow BBS spec. See LegacyPci.c
+ // Next entries are for non-BBS compliant ROMS. They are filled in by
+ // 16-bit code during Legacy16UpdateBbs invocation. Final BootPriority
+ // occurs after that invocation.
+ //
+ // Floppy
+ // Set default state.
+ //
+ IsHaveMediaInFloppy = HasMediaInFloppy ();
+ if (IsHaveMediaInFloppy == FLOPPY_PRESENT_WITH_MEDIA) {
+ BbsTable[0].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ } else {
+ if (IsHaveMediaInFloppy == FLOPPY_PRESENT_NO_MEDIA) {
+ BbsTable[0].BootPriority = BBS_LOWEST_PRIORITY;
+ } else {
+ BbsTable[0].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ }
+
+ BbsTable[0].Bus = 0xff;
+ BbsTable[0].Device = 0xff;
+ BbsTable[0].Function = 0xff;
+ BbsTable[0].DeviceType = BBS_FLOPPY;
+ BbsTable[0].Class = 01;
+ BbsTable[0].SubClass = 02;
+ BbsTable[0].StatusFlags.OldPosition = 0;
+ BbsTable[0].StatusFlags.Reserved1 = 0;
+ BbsTable[0].StatusFlags.Enabled = 0;
+ BbsTable[0].StatusFlags.Failed = 0;
+ BbsTable[0].StatusFlags.MediaPresent = 0;
+ BbsTable[0].StatusFlags.Reserved2 = 0;
+
+ //
+ // Onboard HDD - Note Each HDD controller controls 2 drives
+ // Master & Slave
+ //
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+ //
+ // Get IDE Drive Info
+ //
+ LegacyBiosBuildIdeData (Private, &HddInfo, 0);
+
+ for (HddIndex = 0; HddIndex < MAX_IDE_CONTROLLER; HddIndex++) {
+
+ BbsIndex = HddIndex * 2 + 1;
+ for (Index = 0; Index < 2; ++Index) {
+
+ BbsTable[BbsIndex + Index].Bus = HddInfo[HddIndex].Bus;
+ BbsTable[BbsIndex + Index].Device = HddInfo[HddIndex].Device;
+ BbsTable[BbsIndex + Index].Function = HddInfo[HddIndex].Function;
+ BbsTable[BbsIndex + Index].Class = 01;
+ BbsTable[BbsIndex + Index].SubClass = 01;
+ BbsTable[BbsIndex + Index].StatusFlags.OldPosition = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Reserved1 = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Enabled = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Failed = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.MediaPresent = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Reserved2 = 0;
+
+ //
+ // If no controller found or no device found set to ignore
+ // else set to unprioritized and set device type
+ //
+ if (HddInfo[HddIndex].CommandBaseAddress == 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ } else {
+ if (Index == 0) {
+ if ((HddInfo[HddIndex].Status & (HDD_MASTER_IDE | HDD_MASTER_ATAPI_CDROM | HDD_MASTER_ATAPI_ZIPDISK)) != 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ if ((HddInfo[HddIndex].Status & HDD_MASTER_IDE) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ } else if ((HddInfo[HddIndex].Status & HDD_MASTER_ATAPI_CDROM) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
+ } else {
+ //
+ // for ZIPDISK
+ //
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ }
+ } else {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ } else {
+ if ((HddInfo[HddIndex].Status & (HDD_SLAVE_IDE | HDD_SLAVE_ATAPI_CDROM | HDD_SLAVE_ATAPI_ZIPDISK)) != 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ if ((HddInfo[HddIndex].Status & HDD_SLAVE_IDE) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ } else if ((HddInfo[HddIndex].Status & HDD_SLAVE_ATAPI_CDROM) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
+ } else {
+ //
+ // for ZIPDISK
+ //
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ }
+ } else {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+// HDD_INFO *LocalHddInfo;
+// IN BBS_TABLE *LocalBbsTable;
+ UINTN NumHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN TempData;
+ UINT32 Granularity;
+
+ HandleBuffer = NULL;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+// LocalHddInfo = EfiToLegacy16BootTable->HddInfo;
+// LocalBbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+
+ if (!mBbsTableDoneFlag) {
+ mBbsTable = Private->BbsTablePtr;
+
+ //
+ // Always enable disk controllers so 16-bit CSM code has valid information for all
+ // drives.
+ //
+ //
+ // Get PciRootBridgeIO protocol
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+
+ if (NumHandles == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ mBbsTableDoneFlag = TRUE;
+ for (Index = 0; Index < NumHandles; Index++) {
+ //
+ // Connect PciRootBridgeIO protocol handle with FALSE parameter to let
+ // PCI bus driver enumerate all subsequent handles
+ //
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+
+ }
+
+ LegacyBiosBuildBbs (Private, mBbsTable);
+
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
+
+ //
+ // Call into Legacy16 code to add to BBS table for non BBS compliant OPROMs.
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16UpdateBbs;
+
+ //
+ // Pass in handoff data
+ //
+ TempData = (UINTN) EfiToLegacy16BootTable;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ *HddCount = MAX_IDE_CONTROLLER;
+ *HddInfo = EfiToLegacy16BootTable->HddInfo;
+ *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c
new file mode 100644
index 0000000..c45d5d4
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c
@@ -0,0 +1,66 @@
+/** @file
+ This code fills in BDA (0x400) and EBDA (pointed to by 0x4xx)
+ information. There is support for doing initializeation before
+ Legacy16 is loaded and before a legacy boot is attempted.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Fill in the standard BDA and EBDA stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitBda (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ BDA_STRUC *Bda;
+ UINT8 *Ebda;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+ Ebda = (UINT8 *) ((UINTN) 0x9fc00);
+
+ ZeroMem (Bda, 0x100);
+ ZeroMem (Ebda, 0x400);
+ //
+ // 640k-1k for EBDA
+ //
+ Bda->MemSize = 0x27f;
+ Bda->KeyHead = 0x1e;
+ Bda->KeyTail = 0x1e;
+ Bda->FloppyData = 0x00;
+ Bda->FloppyTimeout = 0xff;
+
+ Bda->KeyStart = 0x001E;
+ Bda->KeyEnd = 0x003E;
+ Bda->KeyboardStatus = 0x10;
+ Bda->Ebda = 0x9fc0;
+
+ //
+ // Move LPT time out here and zero out LPT4 since some SCSI OPROMS
+ // use this as scratch pad (LPT4 is Reserved)
+ //
+ Bda->Lpt1_2Timeout = 0x1414;
+ Bda->Lpt3_4Timeout = 0x1400;
+
+ *Ebda = 0x01;
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
new file mode 100644
index 0000000..75add5e
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
@@ -0,0 +1,1007 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
+
+//
+// define maximum number of HDD system supports
+//
+#define MAX_HDD_ENTRIES 0x30
+
+//
+// Module Global:
+// Since this driver will only ever produce one instance of the Private Data
+// protocol you are not required to dynamically allocate the PrivateData.
+//
+LEGACY_BIOS_INSTANCE mPrivateData;
+
+//
+// The end of OPROM shadow address
+//
+UINTN mEndOpromShadowAddress = 0;
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param AllocateType Allocated Legacy Memory Type
+ @param StartPageAddress Start address of range
+ @param Pages Number of pages to allocate
+ @param Result Result of allocation
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemPage;
+
+ //
+ // Allocate Pages of memory less <= StartPageAddress
+ //
+ MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;
+ Status = gBS->AllocatePages (
+ AllocateType,
+ EfiBootServicesCode,
+ Pages,
+ &MemPage
+ );
+ //
+ // Do not ASSERT on Status error but let caller decide since some cases
+ // memory is already taken but that is ok.
+ //
+ if (!EFI_ERROR (Status)) {
+ *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;
+ }
+ //
+ // If reach here the status = EFI_SUCCESS
+ //
+ return Status;
+}
+
+
+/**
+ This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
+ 64 KB blocks.
+
+ Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
+ invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of required region
+ @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
+ block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
+ block
+ @param Alignment Address alignment. Bit mapped. First non-zero
+ bit from right is alignment.
+ @param LegacyMemoryAddress Region Assigned
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Procedure previously invoked
+ @retval Other Region not assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN UINTN Region,
+ IN UINTN Alignment,
+ OUT VOID **LegacyMemoryAddress
+ )
+{
+
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_STATUS Status;
+ UINT32 Granularity;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.BX = (UINT16) Region;
+ Regs.X.CX = (UINT16) LegacyMemorySize;
+ Regs.X.DX = (UINT16) Alignment;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX == 0) {
+ *LegacyMemoryAddress = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ return Status;
+}
+
+
+/**
+ This function is called when copying data to the region assigned by
+ EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of data to copy
+ @param LegacyMemoryAddress Legacy Region destination address Note: must
+ be in region assigned by
+ LegacyBiosGetLegacyRegion
+ @param LegacyMemorySourceAddress Source of data
+
+ @retval EFI_SUCCESS The data was copied successfully.
+ @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCopyLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN VOID *LegacyMemoryAddress,
+ IN VOID *LegacyMemorySourceAddress
+ )
+{
+
+ LEGACY_BIOS_INSTANCE *Private;
+ UINT32 Granularity;
+
+ if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||
+ ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)
+ ) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // There is no protection from writes over lapping if this function is
+ // called multiple times.
+ //
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+ CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
+ the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
+ been shadowed.
+
+ @param Private Legacy BIOS context data
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+ShadowAndStartLegacy16 (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINT8 *PtrEnd;
+ BOOLEAN Done;
+ EFI_COMPATIBILITY16_TABLE *Table;
+ UINT8 CheckSum;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ VOID *LegacyBiosImage;
+ UINTN LegacyBiosImageSize;
+ UINTN E820Size;
+ UINT32 *ClearPtr;
+ BBS_TABLE *BbsTable;
+ LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;
+ UINTN Index;
+ UINT32 TpmPointer;
+ VOID *TpmBinaryImage;
+ UINTN TpmBinaryImageSize;
+ UINTN Location;
+ UINTN Alignment;
+ UINTN TempData;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT16 OldMask;
+ UINT16 NewMask;
+ UINT32 Granularity;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ Location = 0;
+ Alignment = 0;
+
+ //
+ // we allocate the C/D/E/F segment as RT code so no one will use it any more.
+ //
+ Address = 0xC0000;
+ gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
+ if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
+ //
+ // If it is already reserved, we should be safe, or else we allocate it.
+ //
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiRuntimeServicesCode,
+ 0x40000/EFI_PAGE_SIZE,
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
+ //
+ DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));
+ }
+ }
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"StartLegacy",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformBinarySystemRom,
+ &LegacyBiosImage,
+ &LegacyBiosImageSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->BiosStart = (UINT32) (0x100000 - LegacyBiosImageSize);
+ Private->OptionRom = 0xc0000;
+ Private->LegacyBiosImageSize = (UINT32) LegacyBiosImageSize;
+
+ //
+ // Can only shadow into memory allocated for legacy useage.
+ //
+ ASSERT (Private->BiosStart > Private->OptionRom);
+
+ //
+ // Shadow Legacy BIOS. Turn on memory and copy image
+ //
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
+
+ ClearPtr = (VOID *) ((UINTN) 0xc0000);
+
+ //
+ // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
+ // regions to be used by EMM386 etc.
+ //
+ SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);
+
+ TempData = Private->BiosStart;
+
+ CopyMem (
+ (VOID *) TempData,
+ LegacyBiosImage,
+ (UINTN) LegacyBiosImageSize
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);
+
+ //
+ // Search for Legacy16 table in Shadowed ROM
+ //
+ Done = FALSE;
+ Table = NULL;
+ for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {
+ if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
+ Table = (EFI_COMPATIBILITY16_TABLE *) Ptr;
+ PtrEnd = Ptr + Table->TableLength;
+ for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {
+ CheckSum = (UINT8) (CheckSum +*Ptr);
+ }
+
+ Done = TRUE;
+ }
+ }
+
+ if (Table == NULL) {
+ DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (!Done) {
+ //
+ // Legacy16 table header checksum error.
+ //
+ DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));
+ }
+
+ //
+ // Remember location of the Legacy16 table
+ //
+ Private->Legacy16Table = Table;
+ Private->Legacy16CallSegment = Table->Compatibility16CallSegment;
+ Private->Legacy16CallOffset = Table->Compatibility16CallOffset;
+ EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
+ Private->Legacy16InitPtr = EfiToLegacy16InitTable;
+ Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable;
+ Private->InternalIrqRoutingTable = NULL;
+ Private->NumberIrqRoutingEntries = 0;
+ Private->BbsTablePtr = NULL;
+ Private->LegacyEfiHddTable = NULL;
+ Private->DiskEnd = 0;
+ Private->Disk4075 = 0;
+ Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;
+ Private->NumberHddControllers = MAX_IDE_CONTROLLER;
+ Private->Dump[0] = 'D';
+ Private->Dump[1] = 'U';
+ Private->Dump[2] = 'M';
+ Private->Dump[3] = 'P';
+
+ ZeroMem (
+ Private->Legacy16BootPtr,
+ sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)
+ );
+
+ //
+ // Store away a copy of the EFI System Table
+ //
+ Table->EfiSystemTable = (UINT32) (UINTN) gST;
+
+ //
+ // Get the end of OPROM shadow address
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformEndOpromShadowAddr,
+ NULL,
+ NULL,
+ &mEndOpromShadowAddress,
+ NULL,
+ 0,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ mEndOpromShadowAddress = 0xDFFFF;
+ }
+
+ //
+ // IPF CSM integration -Bug
+ //
+ // Construct the Legacy16 boot memory map. This sets up number of
+ // E820 entries.
+ //
+ LegacyBiosBuildE820 (Private, &E820Size);
+ //
+ // Initialize BDA and EBDA standard values needed to load Legacy16 code
+ //
+ LegacyBiosInitBda (Private);
+ LegacyBiosInitCmos (Private);
+
+ //
+ // All legacy interrupt should be masked when do initialization work from legacy 16 code.
+ //
+ Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
+ NewMask = 0xFFFF;
+ Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);
+
+ //
+ // Call into Legacy16 code to do an INIT
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16InitializeYourself;
+ Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));
+ Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ //
+ // Restore original legacy interrupt mask value
+ //
+ Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"BackFromInitYourself",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ // Copy E820 table after InitializeYourself is completed
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) E820Size;
+ Regs.X.DX = 1;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Table->E820Length = (UINT32) E820Size;
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
+ } else {
+ TempData = Table->E820Pointer;
+ CopyMem ((VOID *) TempData, Private->E820Table, E820Size);
+ }
+ //
+ // Get PnPInstallationCheck Info.
+ //
+ Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment;
+ Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset;
+
+ //
+ // Check if PCI Express is supported. If yes, Save base address.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformPciExpressBase,
+ NULL,
+ NULL,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ Private->Legacy16Table->PciExpressBase = (UINT32)Location;
+ Location = 0;
+ }
+ //
+ // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
+ // into, copy it and update pointer to binary image. This needs to be
+ // done prior to any OPROM for security purposes.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformBinaryTpmBinary,
+ &TpmBinaryImage,
+ &TpmBinaryImageSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) TpmBinaryImageSize;
+ Regs.X.DX = 1;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));
+ } else {
+ CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);
+ Table->TpmSegment = Regs.X.DS;
+ Table->TpmOffset = Regs.X.BX;
+
+ }
+ }
+ //
+ // Lock the Legacy BIOS region
+ //
+ Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);
+
+ //
+ // Get the BbsTable from LOW_MEMORY_THUNK
+ //
+ BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;
+ ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));
+
+ EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable;
+ Private->BbsTablePtr = (VOID *) BbsTable;
+ //
+ // Skip Floppy and possible onboard IDE drives
+ //
+ EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;
+
+ for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {
+ BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ //
+ // Allocate space for Legacy HDD table
+ //
+ LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));
+ ASSERT (LegacyEfiHddTable);
+
+ Private->LegacyEfiHddTable = LegacyEfiHddTable;
+ Private->LegacyEfiHddTableIndex = 0x00;
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"EndOfLoadFv",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Shadow all legacy16 OPROMs that haven't been shadowed.
+ Warning: Use this with caution. This routine disconnects all EFI
+ drivers. If used externally then caller must re-connect EFI
+ drivers.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS OPROMs shadowed
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosShadowAllLegacyOproms (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+
+ //
+ // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ // EFI_LEGACY16_TABLE *Legacy16Table;
+ //
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ //
+ // LegacyBiosPlatform = Private->LegacyBiosPlatform;
+ // Legacy16Table = Private->Legacy16Table;
+ //
+ // Shadow PCI ROMs. We must do this near the end since this will kick
+ // of Native EFI drivers that may be needed to collect info for Legacy16
+ //
+ // WARNING: PciIo is gone after this call.
+ //
+ PciProgramAllInterruptLineRegisters (Private);
+
+ PciShadowRoms (Private);
+
+ //
+ // Shadow PXE base code, BIS etc.
+ //
+ // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
+ // &Private->OptionRom,
+ // Legacy16Table);
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the PCI BIOS interface version.
+
+ @param Private Driver private data.
+
+ @return The PCI interface version number in Binary Coded Decimal (BCD) format.
+ E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
+
+**/
+UINT16
+GetPciInterfaceVersion (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_IA32_REGISTER_SET Reg;
+ BOOLEAN ThunkFailed;
+ UINT16 PciInterfaceVersion;
+
+ PciInterfaceVersion = 0;
+
+ Reg.X.AX = 0xB101;
+ Reg.E.EDI = 0;
+
+ ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);
+ if (!ThunkFailed) {
+ //
+ // From PCI Firmware 3.0 Specification:
+ // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
+ // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
+ // presence of the PCI function set. [BX] will further indicate the version level, with enough
+ // granularity to allow for incremental changes in the code that don't affect the function interface.
+ // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
+ // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
+ //
+ if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {
+ PciInterfaceVersion = Reg.X.BX;
+ }
+ }
+ return PciInterfaceVersion;
+}
+
+/**
+ Install Driver to produce Legacy BIOS protocol.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Legacy BIOS protocol installed
+ @retval No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstall (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ VOID *MemoryPtr;
+ EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;
+ UINTN Index;
+ UINT32 *BaseVectorMaster;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ UINT32 *ClearPtr;
+ EFI_PHYSICAL_ADDRESS MemStart;
+ UINT32 IntRedirCode;
+ UINT32 Granularity;
+ BOOLEAN DecodeOn;
+ UINT32 MemorySize;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ UINT64 Length;
+
+ //
+ // Load this driver's image to memory
+ //
+ Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = &mPrivateData;
+ ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));
+
+ //
+ // Grab a copy of all the protocols we depend on. Any error would
+ // be a dispatcher bug!.
+ //
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Locate Memory Test Protocol if exists
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **) &Private->GenericMemoryTest
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Make sure all memory from 0-640K is tested
+ //
+ for (StartAddress = 0; StartAddress < 0xa0000; ) {
+ gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
+ StartAddress = Descriptor.BaseAddress + Descriptor.Length;
+ continue;
+ }
+ Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);
+ Private->GenericMemoryTest->CompatibleRangeTest (
+ Private->GenericMemoryTest,
+ StartAddress,
+ Length
+ );
+ StartAddress = StartAddress + Length;
+ }
+ //
+ // Make sure all memory from 1MB to 16MB is tested and added to memory map
+ //
+ for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {
+ gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
+ StartAddress = Descriptor.BaseAddress + Descriptor.Length;
+ continue;
+ }
+ Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);
+ Private->GenericMemoryTest->CompatibleRangeTest (
+ Private->GenericMemoryTest,
+ StartAddress,
+ Length
+ );
+ StartAddress = StartAddress + Length;
+ }
+
+ Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;
+
+ Private->LegacyBios.Int86 = LegacyBiosInt86;
+ Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;
+ Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;
+ Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;
+ Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;
+ Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;
+ Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;
+ Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;
+ Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;
+ Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;
+ Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;
+ Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;
+
+ Private->ImageHandle = ImageHandle;
+
+ //
+ // Enable read attribute of legacy region.
+ //
+ DecodeOn = TRUE;
+ Private->LegacyRegion->Decode (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity,
+ &DecodeOn
+ );
+ //
+ // Set Cachebility for legacy region
+ // BUGBUG: Comments about this legacy region cacheability setting
+ // This setting will make D865GCHProduction CSM Unhappy
+ //
+ if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {
+ gDS->SetMemorySpaceAttributes (
+ 0x0,
+ 0xA0000,
+ EFI_MEMORY_WB
+ );
+ gDS->SetMemorySpaceAttributes (
+ 0xc0000,
+ 0x40000,
+ EFI_MEMORY_WB
+ );
+ }
+
+ gDS->SetMemorySpaceAttributes (
+ 0xA0000,
+ 0x20000,
+ EFI_MEMORY_UC
+ );
+
+ //
+ // Allocate 0 - 4K for real mode interupt vectors and BDA.
+ //
+ AllocateLegacyMemory (
+ AllocateAddress,
+ 0,
+ 1,
+ &MemoryAddress
+ );
+ ASSERT (MemoryAddress == 0x000000000);
+
+ ClearPtr = (VOID *) ((UINTN) 0x0000);
+
+ //
+ // Initialize region from 0x0000 to 4k. This initializes interrupt vector
+ // range.
+ //
+ gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
+ ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);
+
+ //
+ // Allocate pages for OPROM usage
+ //
+ MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);
+ ASSERT ((MemorySize & 0xFFF) == 0);
+
+ Status = AllocateLegacyMemory (
+ AllocateAddress,
+ CONVENTIONAL_MEMORY_TOP - MemorySize,
+ EFI_SIZE_TO_PAGES (MemorySize),
+ &MemoryAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);
+
+ //
+ // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
+ // don't use PMM but look for zeroed memory. Note that various non-BBS
+ // SCSIs expect different areas to be free
+ //
+ for (MemStart = 0x60000; MemStart < 0x88000; MemStart += 0x1000) {
+ Status = AllocateLegacyMemory (
+ AllocateAddress,
+ MemStart,
+ 1,
+ &MemoryAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ MemoryPtr = (VOID *) ((UINTN) MemoryAddress);
+ ZeroMem (MemoryPtr, 0x1000);
+ } else {
+ DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));
+ }
+ }
+
+ //
+ // Allocate a 64k area (16 4k pages) for 16-bit code for scratch pad and zero it out
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ CONVENTIONAL_MEMORY_TOP,
+ 16,
+ &MemoryAddressUnder1MB
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), 0x10000);
+
+ //
+ // Allocate space for thunker and Init Thunker
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ CONVENTIONAL_MEMORY_TOP,
+ (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,
+ &MemoryAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+ Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
+ EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));
+
+ Status = LegacyBiosInitializeThunk (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init the legacy memory map in memory < 1 MB.
+ //
+ EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB;
+ EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB;
+ EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = 0x10000;
+
+ //
+ // Allocate 4 MB of PMM Memory under 16 MB
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ 0x1000000,
+ 0x400,
+ &MemoryAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = PMM_MEMORY_SIZE;
+ }
+
+ //
+ // ShutdownAPs();
+ //
+ // Start the Legacy BIOS;
+ //
+ Status = ShadowAndStartLegacy16 (Private);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Initialize interrupt redirection code and entries;
+ // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
+ //
+ CopyMem (
+ Private->IntThunk->InterruptRedirectionCode,
+ (VOID *) (UINTN) InterruptRedirectionTemplate,
+ sizeof (Private->IntThunk->InterruptRedirectionCode)
+ );
+
+ //
+ // Save Unexpected interrupt vector so can restore it just prior to boot
+ //
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ Private->BiosUnexpectedInt = BaseVectorMaster[0];
+ IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;
+ for (Index = 0; Index < 8; Index++) {
+ BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
+ }
+ //
+ // Save EFI value
+ //
+ Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));
+
+ //
+ // Make a new handle and install the protocol
+ //
+ Private->Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Private->Handle,
+ &gEfiLegacyBiosProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Private->LegacyBios
+ );
+ Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);
+
+ DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
+ (UINT8) (Private->Csm16PciInterfaceVersion >> 8),
+ (UINT8) Private->Csm16PciInterfaceVersion
+ ));
+ ASSERT (Private->Csm16PciInterfaceVersion != 0);
+ return Status;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
new file mode 100644
index 0000000..4e310aa
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
@@ -0,0 +1,143 @@
+## @file
+# Legacy Bios Module to support CSM.
+#
+# This driver installs Legacy Bios Protocol to support CSM module work in EFI system.
+#
+# Copyright (c) 2006 - 2011, 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyBiosDxe
+ FILE_GUID = F122A15C-C10B-4d54-8F48-60F4F06DD1AD
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = LegacyBiosInstall
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ LegacyCmos.c
+ LegacyIde.c
+ LegacyBios.c
+ LegacyBda.c
+ LegacyBiosInterface.h
+ LegacyPci.c
+
+[Sources.Ia32]
+ IA32/InterruptTable.S
+ IA32/InterruptTable.asm
+ Thunk.c
+ LegacyBootSupport.c
+ LegacyBbs.c
+ LegacySio.c
+
+[Sources.X64]
+ X64/InterruptTable.asm
+ X64/InterruptTable.S
+ Thunk.c
+ LegacyBootSupport.c
+ LegacyBbs.c
+ LegacySio.c
+
+[Sources.IPF]
+ Ipf/IpfThunk.s
+ Ipf/Thunk.c
+ Ipf/IpfThunk.i
+ Ipf/IpfBootSupport.c
+ Ipf/IpfThunk.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ DxeServicesTableLib
+ PcdLib
+ ReportStatusCodeLib
+ PeCoffLib
+ CacheMaintenanceLib
+ DebugAgentLib
+
+[LibraryClasses.IA32]
+ IoLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+
+[LibraryClasses.X64]
+ IoLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+
+[LibraryClasses.IPF]
+ IoLib
+ UefiRuntimeServicesTableLib
+
+
+[Guids]
+ gEfiDiskInfoIdeInterfaceGuid # ALWAYS_CONSUMED
+ gEfiLegacyBiosGuid # ALWAYS_PRODUCED
+
+[Guids.IA32]
+ gEfiSmbiosTableGuid # ALWAYS_CONSUMED
+ gEfiAcpi20TableGuid # ALWAYS_CONSUMED
+ gEfiAcpi10TableGuid # ALWAYS_CONSUMED
+
+[Guids.X64]
+ gEfiSmbiosTableGuid # ALWAYS_CONSUMED
+ gEfiAcpi20TableGuid # ALWAYS_CONSUMED
+ gEfiAcpi10TableGuid # ALWAYS_CONSUMED
+
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiCpuArchProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiIsaIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiBlockIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiGenericMemTestProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDiskInfoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleTextInProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacy8259ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyBiosPlatformProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyInterruptProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyRegion2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyBiosProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiTimerArchProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize
+
+[Depex]
+ gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid
+
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h
new file mode 100644
index 0000000..c398d1e
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h
@@ -0,0 +1,1501 @@
+/** @file
+
+Copyright (c) 2006 - 2011, 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.
+
+**/
+
+#ifndef _LEGACY_BIOS_INTERFACE_
+#define _LEGACY_BIOS_INTERFACE_
+
+
+#include <FrameworkDxe.h>
+
+#include <Guid/SmBios.h>
+#include <Guid/Acpi.h>
+#include <Guid/DxeServices.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/StatusCodeDataTypeId.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/LegacyRegion2.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/LegacyInterrupt.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/LegacyBiosPlatform.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Legacy8259.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/Timer.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugAgentLib.h>
+
+//
+// System Tickers
+//
+#define DEFAULT_LAGACY_TIMER_TICK_DURATION 549254
+// BUGBUG: This entry maybe changed to PCD in future and wait for
+// redesign of BDS library
+//
+#define MAX_BBS_ENTRIES 0x100
+
+//
+// Thunk Status Codes
+// (These apply only to errors with the thunk and not to the code that was
+// thunked to.)
+//
+#define THUNK_OK 0x00
+#define THUNK_ERR_A20_UNSUP 0x01
+#define THUNK_ERR_A20_FAILED 0x02
+
+//
+// Vector base definitions
+//
+//
+// 8259 Hardware definitions
+//
+#define LEGACY_MODE_BASE_VECTOR_MASTER 0x08
+#define LEGACY_MODE_BASE_VECTOR_SLAVE 0x70
+
+//
+// The original PC used INT8-F for master PIC. Since these mapped over
+// processor exceptions TIANO moved the master PIC to INT68-6F.
+//
+// The vector base for slave PIC is set as 0x70 for PC-AT compatibility.
+//
+#define PROTECTED_MODE_BASE_VECTOR_MASTER 0x68
+#define PROTECTED_MODE_BASE_VECTOR_SLAVE 0x70
+
+//
+// Trace defines
+//
+//
+#define LEGACY_BDA_TRACE 0x000
+#define LEGACY_BIOS_TRACE 0x040
+#define LEGACY_BOOT_TRACE 0x080
+#define LEGACY_CMOS_TRACE 0x0C0
+#define LEGACY_IDE_TRACE 0x100
+#define LEGACY_MP_TRACE 0x140
+#define LEGACY_PCI_TRACE 0x180
+#define LEGACY_SIO_TRACE 0x1C0
+
+#define LEGACY_PCI_TRACE_000 LEGACY_PCI_TRACE + 0x00
+#define LEGACY_PCI_TRACE_001 LEGACY_PCI_TRACE + 0x01
+#define LEGACY_PCI_TRACE_002 LEGACY_PCI_TRACE + 0x02
+#define LEGACY_PCI_TRACE_003 LEGACY_PCI_TRACE + 0x03
+#define LEGACY_PCI_TRACE_004 LEGACY_PCI_TRACE + 0x04
+#define LEGACY_PCI_TRACE_005 LEGACY_PCI_TRACE + 0x05
+#define LEGACY_PCI_TRACE_006 LEGACY_PCI_TRACE + 0x06
+#define LEGACY_PCI_TRACE_007 LEGACY_PCI_TRACE + 0x07
+#define LEGACY_PCI_TRACE_008 LEGACY_PCI_TRACE + 0x08
+#define LEGACY_PCI_TRACE_009 LEGACY_PCI_TRACE + 0x09
+#define LEGACY_PCI_TRACE_00A LEGACY_PCI_TRACE + 0x0A
+#define LEGACY_PCI_TRACE_00B LEGACY_PCI_TRACE + 0x0B
+#define LEGACY_PCI_TRACE_00C LEGACY_PCI_TRACE + 0x0C
+#define LEGACY_PCI_TRACE_00D LEGACY_PCI_TRACE + 0x0D
+#define LEGACY_PCI_TRACE_00E LEGACY_PCI_TRACE + 0x0E
+#define LEGACY_PCI_TRACE_00F LEGACY_PCI_TRACE + 0x0F
+
+
+typedef struct {
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINT32 ShadowAddress;
+ UINT32 ShadowedSize;
+ UINT8 DiskStart;
+ UINT8 DiskEnd;
+} ROM_INSTANCE_ENTRY;
+
+//
+// Values for RealModeGdt
+//
+#if defined (MDE_CPU_IA32)
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB
+#define INITIAL_VALUE_BELOW_1K 0x0
+
+#elif defined (MDE_CPU_X64)
+
+#define NUM_REAL_GDT_ENTRIES 8
+#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB
+#define INITIAL_VALUE_BELOW_1K 0x0
+
+#elif defined (MDE_CPU_IPF)
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define CONVENTIONAL_MEMORY_TOP 0x80000 // 512 KB
+#define INITIAL_VALUE_BELOW_1K 0xff
+
+#endif
+
+//
+// Miscellaneous numbers
+//
+#define PMM_MEMORY_SIZE 0x400000 // 4 MB
+
+#pragma pack(1)
+
+//
+// Define what a processor GDT looks like
+//
+typedef struct {
+ UINT32 LimitLo : 16;
+ UINT32 BaseLo : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHi : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHi : 8;
+} GDT32;
+
+typedef struct {
+ UINT16 LimitLow;
+ UINT16 BaseLow;
+ UINT8 BaseMid;
+ UINT8 Attribute;
+ UINT8 LimitHi;
+ UINT8 BaseHi;
+} GDT64;
+
+//
+// Define what a processor descriptor looks like
+// This data structure must be kept in sync with ASM STRUCT in Thunk.inc
+//
+typedef struct {
+ UINT16 Limit;
+ UINT64 Base;
+} DESCRIPTOR64;
+
+typedef struct {
+ UINT16 Limit;
+ UINT32 Base;
+} DESCRIPTOR32;
+
+//
+// Low stub lay out
+//
+#define LOW_STACK_SIZE (8 * 1024) // 8k?
+#define EFI_MAX_E820_ENTRY 100
+#define FIRST_INSTANCE 1
+#define NOT_FIRST_INSTANCE 0
+
+#if defined (MDE_CPU_IA32)
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+ //
+ // The address of the Reverse Thunk code
+ // Note that this member CONTAINS the address of the relocated reverse thunk
+ // code unlike the member variable 'Code', which IS the address of the Thunk
+ // code.
+ //
+ UINT32 LowReverseThunkStart;
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR32 GdtDesc; // Protected mode GDT
+ DESCRIPTOR32 IdtDesc; // Protected mode IDT
+ UINT32 FlatSs;
+ UINT32 FlatEsp;
+
+ UINT32 LowCodeSelector; // Low code selector in GDT
+ UINT32 LowDataSelector; // Low data selector in GDT
+ UINT32 LowStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT32 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // Members specifically for the reverse thunk
+ // The RevReal* members are used to store the current state of real mode
+ // before performing the reverse thunk. The RevFlat* members must be set
+ // before calling the reverse thunk assembly code.
+ //
+ UINT16 RevRealDs;
+ UINT16 RevRealSs;
+ UINT32 RevRealEsp;
+ DESCRIPTOR32 RevRealIdtDesc;
+ UINT16 RevFlatDataSelector; // Flat data selector in GDT
+ UINT32 RevFlatStack;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Stack for flat mode after reverse thunk
+ // @bug - This may no longer be necessary if the reverse thunk interface
+ // is changed to have the flat stack in a different location.
+ //
+ CHAR8 RevThunkStack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#elif defined (MDE_CPU_X64)
+
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR64 X64GdtDesc; // Protected mode GDT
+ DESCRIPTOR64 X64IdtDesc; // Protected mode IDT
+ UINTN X64Ss;
+ UINTN X64Esp;
+
+ UINTN RealStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT64 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ UINT64 PageMapLevel4;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#elif defined (MDE_CPU_IPF)
+
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+ //
+ // The address of the Reverse Thunk code
+ // Note that this member CONTAINS the address of the relocated reverse thunk
+ // code unlike the member variable 'Code', which IS the address of the Thunk
+ // code.
+ //
+ UINT32 LowReverseThunkStart;
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR32 GdtDesc; // Protected mode GDT
+ DESCRIPTOR32 IdtDesc; // Protected mode IDT
+ UINT32 FlatSs;
+ UINT32 FlatEsp;
+
+ UINT32 LowCodeSelector; // Low code selector in GDT
+ UINT32 LowDataSelector; // Low data selector in GDT
+ UINT32 LowStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT32 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // Members specifically for the reverse thunk
+ // The RevReal* members are used to store the current state of real mode
+ // before performing the reverse thunk. The RevFlat* members must be set
+ // before calling the reverse thunk assembly code.
+ //
+ UINT16 RevRealDs;
+ UINT16 RevRealSs;
+ UINT32 RevRealEsp;
+ DESCRIPTOR32 RevRealIdtDesc;
+ UINT16 RevFlatDataSelector; // Flat data selector in GDT
+ UINT32 RevFlatStack;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Stack for flat mode after reverse thunk
+ // @bug - This may no longer be necessary if the reverse thunk interface
+ // is changed to have the flat stack in a different location.
+ //
+ CHAR8 RevThunkStack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#endif
+
+//
+// PnP Expansion Header
+//
+typedef struct {
+ UINT32 PnpSignature;
+ UINT8 Revision;
+ UINT8 Length;
+ UINT16 NextHeader;
+ UINT8 Reserved1;
+ UINT8 Checksum;
+ UINT32 DeviceId;
+ UINT16 MfgPointer;
+ UINT16 ProductNamePointer;
+ UINT8 Class;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 DeviceIndicators;
+ UINT16 Bcv;
+ UINT16 DisconnectVector;
+ UINT16 Bev;
+ UINT16 Reserved2;
+ UINT16 StaticResourceVector;
+} LEGACY_PNP_EXPANSION_HEADER;
+
+typedef struct {
+ UINT8 PciSegment;
+ UINT8 PciBus;
+ UINT8 PciDevice;
+ UINT8 PciFunction;
+ UINT16 Vid;
+ UINT16 Did;
+ UINT16 SysSid;
+ UINT16 SVid;
+ UINT8 Class;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 Reserved;
+ UINTN RomStart;
+ UINTN ManufacturerString;
+ UINTN ProductNameString;
+} LEGACY_ROM_AND_BBS_TABLE;
+
+//
+// Structure how EFI has mapped a devices HDD drive numbers.
+// Boot to EFI aware OS or shell requires this mapping when
+// 16-bit CSM assigns drive numbers.
+// This mapping is ignored booting to a legacy OS.
+//
+typedef struct {
+ UINT8 PciSegment;
+ UINT8 PciBus;
+ UINT8 PciDevice;
+ UINT8 PciFunction;
+ UINT8 StartDriveNumber;
+ UINT8 EndDriveNumber;
+} LEGACY_EFI_HDD_TABLE;
+
+//
+// This data is passed to Leacy16Boot
+//
+typedef enum {
+ EfiAcpiAddressRangeMemory = 1,
+ EfiAcpiAddressRangeReserved = 2,
+ EfiAcpiAddressRangeACPI = 3,
+ EfiAcpiAddressRangeNVS = 4
+} EFI_ACPI_MEMORY_TYPE;
+
+typedef struct {
+ UINT64 BaseAddr;
+ UINT64 Length;
+ EFI_ACPI_MEMORY_TYPE Type;
+} EFI_E820_ENTRY64;
+
+typedef struct {
+ UINT32 BassAddrLow;
+ UINT32 BaseAddrHigh;
+ UINT32 LengthLow;
+ UINT32 LengthHigh;
+ EFI_ACPI_MEMORY_TYPE Type;
+} EFI_E820_ENTRY;
+
+#pragma pack()
+
+extern BBS_TABLE *mBbsTable;
+
+extern EFI_GENERIC_MEMORY_TEST_PROTOCOL *gGenMemoryTest;
+
+extern UINTN mEndOpromShadowAddress;
+
+#define PORT_70 0x70
+#define PORT_71 0x71
+
+#define CMOS_0A 0x0a ///< Status register A
+#define CMOS_0D 0x0d ///< Status register D
+#define CMOS_0E 0x0e ///< Diagnostic Status
+#define CMOS_0F 0x0f ///< Shutdown status
+#define CMOS_10 0x10 ///< Floppy type
+#define CMOS_12 0x12 ///< IDE type
+#define CMOS_14 0x14 ///< Same as BDA 40:10
+#define CMOS_15 0x15 ///< Low byte of base memory in 1k increments
+#define CMOS_16 0x16 ///< High byte of base memory in 1k increments
+#define CMOS_17 0x17 ///< Low byte of 1MB+ memory in 1k increments - max 15 MB
+#define CMOS_18 0x18 ///< High byte of 1MB+ memory in 1k increments - max 15 MB
+#define CMOS_19 0x19 ///< C: extended drive type
+#define CMOS_1A 0x1a ///< D: extended drive type
+#define CMOS_2E 0x2e ///< Most significient byte of standard checksum
+#define CMOS_2F 0x2f ///< Least significient byte of standard checksum
+#define CMOS_30 0x30 ///< CMOS 0x17
+#define CMOS_31 0x31 ///< CMOS 0x18
+#define CMOS_32 0x32 ///< Century byte
+
+
+#define LEGACY_BIOS_INSTANCE_SIGNATURE SIGNATURE_32 ('L', 'B', 'I', 'T')
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_LEGACY_BIOS_PROTOCOL LegacyBios;
+
+ EFI_HANDLE ImageHandle;
+
+ //
+ // CPU Architectural Protocol
+ //
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+
+ //
+ // Protocol to Lock and Unlock 0xc0000 - 0xfffff
+ //
+ EFI_LEGACY_REGION2_PROTOCOL *LegacyRegion;
+
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+
+ //
+ // Interrupt control for thunk and PCI IRQ
+ //
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+
+ //
+ // PCI Interrupt PIRQ control
+ //
+ EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
+
+ //
+ // Generic Memory Test
+ //
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenericMemoryTest;
+
+ //
+ // TRUE if PCI Interupt Line registers have been programmed.
+ //
+ BOOLEAN PciInterruptLine;
+
+ //
+ // Code space below 1MB needed by thunker to transition to real mode.
+ // Contains stack and real mode code fragments
+ //
+ LOW_MEMORY_THUNK *IntThunk;
+
+ //
+ // Starting shadow address of the Legacy BIOS
+ //
+ UINT32 BiosStart;
+ UINT32 LegacyBiosImageSize;
+
+ //
+ // Start of variables used by CsmItp.mac ITP macro file and/os LegacyBios
+ //
+ UINT8 Dump[4];
+
+ //
+ // $EFI Legacy16 code entry info in memory < 1 MB;
+ //
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ VOID *Legacy16InitPtr;
+ VOID *Legacy16BootPtr;
+ VOID *InternalIrqRoutingTable;
+ UINT32 NumberIrqRoutingEntries;
+ VOID *BbsTablePtr;
+ VOID *HddTablePtr;
+ UINT32 NumberHddControllers;
+
+ //
+ // Cached copy of Legacy16 entry point
+ //
+ UINT16 Legacy16CallSegment;
+ UINT16 Legacy16CallOffset;
+
+ //
+ // Returned from $EFI and passed in to OPROMS
+ //
+ UINT16 PnPInstallationCheckSegment;
+ UINT16 PnPInstallationCheckOffset;
+
+ //
+ // E820 table
+ //
+ EFI_E820_ENTRY E820Table[EFI_MAX_E820_ENTRY];
+ UINT32 NumberE820Entries;
+
+ //
+ // True if legacy VGA INT 10h handler installed
+ //
+ BOOLEAN VgaInstalled;
+
+ //
+ // Number of IDE drives
+ //
+ UINT8 IdeDriveCount;
+
+ //
+ // Current Free Option ROM space. An option ROM must NOT go past
+ // BiosStart.
+ //
+ UINT32 OptionRom;
+
+ //
+ // Save Legacy16 unexpected interrupt vector. Reprogram INT 68-6F from
+ // EFI values to legacy value just before boot.
+ //
+ UINT32 BiosUnexpectedInt;
+ UINT32 ThunkSavedInt[8];
+ UINT16 ThunkSeg;
+ LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;
+ UINT16 LegacyEfiHddTableIndex;
+ UINT8 DiskEnd;
+ UINT8 Disk4075;
+ UINT16 TraceIndex;
+ UINT16 Trace[0x200];
+
+ //
+ // Indicate that whether GenericLegacyBoot is entered or not
+ //
+ BOOLEAN LegacyBootEntered;
+
+ //
+ // CSM16 PCI Interface Version
+ //
+ UINT16 Csm16PciInterfaceVersion;
+
+} LEGACY_BIOS_INSTANCE;
+
+
+#pragma pack(1)
+
+/*
+ 40:00-01 Com1
+ 40:02-03 Com2
+ 40:04-05 Com3
+ 40:06-07 Com4
+ 40:08-09 Lpt1
+ 40:0A-0B Lpt2
+ 40:0C-0D Lpt3
+ 40:0E-0E Ebda segment
+ 40:10-11 MachineConfig
+ 40:12 Bda12 - skip
+ 40:13-14 MemSize below 1MB
+ 40:15-16 Bda15_16 - skip
+ 40:17 Keyboard Shift status
+ 40:18-19 Bda18_19 - skip
+ 40:1A-1B Key buffer head
+ 40:1C-1D Key buffer tail
+ 40:1E-3D Bda1E_3D- key buffer -skip
+ 40:3E-3F FloppyData 3E = Calibration status 3F = Motor status
+ 40:40 FloppyTimeout
+ 40:41-74 Bda41_74 - skip
+ 40:75 Number of HDD drives
+ 40:76-77 Bda76_77 - skip
+ 40:78-79 78 = Lpt1 timeout, 79 = Lpt2 timeout
+ 40:7A-7B 7A = Lpt3 timeout, 7B = Lpt4 timeout
+ 40:7C-7D 7C = Com1 timeout, 7D = Com2 timeout
+ 40:7E-7F 7E = Com3 timeout, 7F = Com4 timeout
+ 40:80-81 Pointer to start of key buffer
+ 40:82-83 Pointer to end of key buffer
+ 40:84-87 Bda84_87 - skip
+ 40:88 HDD Data Xmit rate
+ 40:89-8f skip
+ 40:90 Floppy data rate
+ 40:91-95 skip
+ 40:96 Keyboard Status
+ 40:97 LED Status
+ 40:98-101 skip
+*/
+typedef struct {
+ UINT16 Com1;
+ UINT16 Com2;
+ UINT16 Com3;
+ UINT16 Com4;
+ UINT16 Lpt1;
+ UINT16 Lpt2;
+ UINT16 Lpt3;
+ UINT16 Ebda;
+ UINT16 MachineConfig;
+ UINT8 Bda12;
+ UINT16 MemSize;
+ UINT8 Bda15_16[0x02];
+ UINT8 ShiftStatus;
+ UINT8 Bda18_19[0x02];
+ UINT16 KeyHead;
+ UINT16 KeyTail;
+ UINT16 Bda1E_3D[0x10];
+ UINT16 FloppyData;
+ UINT8 FloppyTimeout;
+ UINT8 Bda41_74[0x34];
+ UINT8 NumberOfDrives;
+ UINT8 Bda76_77[0x02];
+ UINT16 Lpt1_2Timeout;
+ UINT16 Lpt3_4Timeout;
+ UINT16 Com1_2Timeout;
+ UINT16 Com3_4Timeout;
+ UINT16 KeyStart;
+ UINT16 KeyEnd;
+ UINT8 Bda84_87[0x4];
+ UINT8 DataXmit;
+ UINT8 Bda89_8F[0x07];
+ UINT8 FloppyXRate;
+ UINT8 Bda91_95[0x05];
+ UINT8 KeyboardStatus;
+ UINT8 LedStatus;
+} BDA_STRUC;
+#pragma pack()
+
+#define LEGACY_BIOS_INSTANCE_FROM_THIS(this) CR (this, LEGACY_BIOS_INSTANCE, LegacyBios, LEGACY_BIOS_INSTANCE_SIGNATURE)
+
+/**
+ Thunk to 16-bit real mode and execute a software interrupt with a vector
+ of BiosInt. Regs will contain the 16-bit register context on entry and
+ exit.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ );
+
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in
+ the target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ );
+
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded
+ @param RomImage Return the legacy PCI ROM for this device
+ @param RomSize Size of ROM Image
+ @param Flags Indicates if ROM found and if PC-AT.
+
+ @retval EFI_SUCCESS Legacy Option ROM availible for this device
+ @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCheckPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *Flags
+ );
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ );
+
+
+/**
+ To boot from an unconventional device like parties and/or execute
+ HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the parent
+ device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data.
+ The caller must provide a pointer to the specific
+ Service Area and not the start all Service Areas.
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ );
+
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded. This value is NULL if RomImage is
+ non-NULL. This is the normal case.
+ @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
+ if there is no hardware associated with the ROM
+ and thus no PciHandle, otherwise is must be NULL.
+ Example is PXE base code.
+ @param Flags Indicates if ROM found and if PC-AT.
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+ @param RomShadowedSize Size of RomShadowAddress in bytes
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_INVALID_PARAMETER PciHandle not found
+ @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
+ ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL * This,
+ IN EFI_HANDLE PciHandle,
+ IN VOID **RomImage,
+ OUT UINTN *Flags,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINT32 *RomShadowedSize OPTIONAL
+ );
+
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ );
+
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ );
+
+
+/**
+ Shadow all legacy16 OPROMs that haven't been shadowed.
+ Warning: Use this with caution. This routine disconnects all EFI
+ drivers. If used externally then caller must re-connect EFI
+ drivers.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS OPROMs shadowed
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosShadowAllLegacyOproms (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ );
+
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ );
+
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard BDA and EBDA stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitBda (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Collect IDE Inquiry data from the IDE disks
+
+ @param Private Legacy BIOS Instance data
+ @param HddInfo Hdd Information
+ @param Flag Reconnect IdeController or not
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildIdeData (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN HDD_INFO **HddInfo,
+ IN UINT16 Flag
+ );
+
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableIdeController (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ If the IDE channel is in compatibility (legacy) mode, remove all
+ PCI I/O BAR addresses from the controller.
+
+ @param IdeController The handle of target IDE controller
+
+
+**/
+VOID
+InitLegacyIdeController (
+ IN EFI_HANDLE IdeController
+ );
+
+
+/**
+ Program the interrupt routing register in all the PCI devices. On a PC AT system
+ this register contains the 8259 IRQ vector that matches it's PCI interrupt.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_ALREADY_STARTED All PCI devices have been processed.
+
+**/
+EFI_STATUS
+PciProgramAllInterruptLineRegisters (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Collect EFI Info about legacy devices.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
+ to chose the order. Skip any devices that have already have legacy
+ BIOS run.
+
+ @param Private Protocol instance pointer.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_UNSUPPORTED Cannot get VGA device handle.
+
+**/
+EFI_STATUS
+PciShadowRoms (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard BDA and EBDA stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteBdaBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard CMOS stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitCmos (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard CMOS stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteStandardCmosBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Contains the code that is copied into low memory (below 640K).
+ This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+ This template must be copied into low memory, and the IDT entries
+ 0x68-0x6F must be point to the low memory copy of this code. Each
+ entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+ computed.
+
+**/
+VOID
+InterruptRedirectionTemplate (
+ VOID
+ );
+
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ );
+
+/**
+ This function is to put all AP in halt state.
+
+ @param Private Legacy BIOS Instance data
+
+**/
+VOID
+ShutdownAPs (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+/**
+ Worker function for LegacyBiosGetFlatDescs, retrieving content of
+ specific registers.
+
+ @param IntThunk Pointer to IntThunk of Legacy BIOS context.
+
+**/
+VOID
+GetRegisters (
+ LOW_MEMORY_THUNK *IntThunk
+ );
+
+/**
+ Routine for calling real thunk code.
+
+ @param RealCode The address of thunk code.
+ @param BiosInt The Bios interrupt vector number.
+ @param CallAddress The address of 16-bit mode call.
+
+ @return Status returned by real thunk code
+
+**/
+UINTN
+CallRealThunkCode (
+ UINT8 *RealCode,
+ UINT8 BiosInt,
+ UINT32 CallAddress
+ );
+
+/**
+ Routine for generating soft interrupt.
+
+ @param Vector The interrupt vector number.
+
+**/
+VOID
+GenerateSoftInit (
+ UINT8 Vector
+ );
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param AllocateType Allocated Legacy Memory Type
+ @param StartPageAddress Start address of range
+ @param Pages Number of pages to allocate
+ @param Result Result of allocation
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Result
+ );
+
+/**
+ Get a region from the LegacyBios for Tiano usage. Can only be invoked once.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of required region
+ @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
+ block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
+ block
+ @param Alignment Address alignment. Bit mapped. First non-zero
+ bit from right is alignment.
+ @param LegacyMemoryAddress Region Assigned
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Procedure previously invoked
+ @retval Other Region not assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN UINTN Region,
+ IN UINTN Alignment,
+ OUT VOID **LegacyMemoryAddress
+ );
+
+/**
+ Get a region from the LegacyBios for Tiano usage. Can only be invoked once.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of data to copy
+ @param LegacyMemoryAddress Legacy Region destination address Note: must
+ be in region assigned by
+ LegacyBiosGetLegacyRegion
+ @param LegacyMemorySourceAddress Source of data
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Destination outside assigned region
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCopyLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN VOID *LegacyMemoryAddress,
+ IN VOID *LegacyMemorySourceAddress
+ );
+
+/**
+ Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
+ the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
+ been shadowed.
+
+ @param Private Legacy BIOS context data
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+ShadowAndStartLegacy16 (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+/**
+ Checks the state of the floppy and if media is inserted.
+
+ This routine checks the state of the floppy and if media is inserted.
+ There are 3 cases:
+ No floppy present - Set BBS entry to ignore
+ Floppy present & no media - Set BBS entry to lowest priority. We cannot
+ set it to ignore since 16-bit CSM will
+ indicate no floppy and thus drive A: is
+ unusable. CSM-16 will not try floppy since
+ lowest priority and thus not incur boot
+ time penality.
+ Floppy present & media - Set BBS entry to some priority.
+
+ @return State of floppy media
+
+**/
+UINT8
+HasMediaInFloppy (
+ VOID
+ );
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ This requires updating the checksum, if it exists.
+
+ @param IdentifyDriveData ATA Identify Data
+ @param Checksum checksum of the ATA Identify Data
+
+ @retval EFI_SUCCESS checksum calculated
+ @retval EFI_SECURITY_VIOLATION IdentifyData invalid
+
+**/
+EFI_STATUS
+CalculateIdentifyDriveChecksum (
+ IN UINT8 *IdentifyDriveData,
+ OUT UINT8 *Checksum
+ );
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ );
+
+/**
+ Complete build of BBS TABLE.
+
+ @param Private Legacy BIOS Instance data
+ @param BbsTable BBS Table passed to 16-bit code
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+LegacyBiosBuildBbs (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BBS_TABLE *BbsTable
+ );
+
+/**
+ Read CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to read.
+
+ @return The data value from the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyReadStandardCmos (
+ IN UINT8 Index
+ );
+
+/**
+ Write CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to write.
+ @param[in] Value The value of CMOS register to write.
+
+ @return The value written to the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyWriteStandardCmos (
+ IN UINT8 Index,
+ IN UINT8 Value
+ );
+
+/**
+ Calculate the new standard CMOS checksum and write it.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Calculate 16-bit checksum successfully
+
+**/
+EFI_STATUS
+LegacyCalculateWriteStandardCmosChecksum (
+ VOID
+ );
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
+ @param[out] RomImage Return the legacy PCI ROM for this device
+ @param[out] RomSize Size of ROM Image
+ @param[out] RuntimeImageLength Runtime size of ROM Image
+ @param[out] Flags Indicates if ROM found and if PC-AT.
+ @param[out] OpromRevision Revision of the PCI Rom
+ @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
+
+ @return EFI_SUCCESS Legacy Option ROM availible for this device
+ @return EFI_ALREADY_STARTED This device is already managed by its Oprom
+ @return EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+LegacyBiosCheckPciRomEx (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *RuntimeImageLength, OPTIONAL
+ OUT UINTN *Flags, OPTIONAL
+ OUT UINT8 *OpromRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ );
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+InternalLegacyBiosFarCall (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ );
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c
new file mode 100644
index 0000000..40d027a
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c
@@ -0,0 +1,2032 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+#define BOOT_LEGACY_OS 0
+#define BOOT_EFI_OS 1
+#define BOOT_UNCONVENTIONAL_DEVICE 2
+
+UINT32 mLoadOptionsSize = 0;
+UINTN mBootMode = BOOT_LEGACY_OS;
+VOID *mLoadOptions = NULL;
+BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL;
+BBS_BBS_DEVICE_PATH mBbsDevicePathNode;
+UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 };
+UINTN mBbsEntry = 0;
+VOID *mBeerData = NULL;
+VOID *mServiceAreaData = NULL;
+UINT64 mLowWater = 0xffffffffffffffffULL;
+
+extern BBS_TABLE *mBbsTable;
+
+/**
+ Print the BBS Table.
+
+ @param BbsTable The BBS table.
+
+
+**/
+VOID
+PrintBbsTable (
+ IN BBS_TABLE *BbsTable
+ )
+{
+ UINT16 Index;
+ UINT16 SubIndex;
+ CHAR8 *String;
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
+ DEBUG ((EFI_D_INFO, "=================================================================\n"));
+ for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
+ //
+ // Filter
+ //
+ if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+ continue;
+ }
+
+ DEBUG ((
+ EFI_D_INFO,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
+ (UINTN) Index,
+ (UINTN) BbsTable[Index].BootPriority,
+ (UINTN) BbsTable[Index].Bus,
+ (UINTN) BbsTable[Index].Device,
+ (UINTN) BbsTable[Index].Function,
+ (UINTN) BbsTable[Index].Class,
+ (UINTN) BbsTable[Index].SubClass,
+ (UINTN) BbsTable[Index].DeviceType,
+ (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags
+ ));
+ DEBUG ((
+ EFI_D_INFO,
+ " %04x:%04x %04x:%04x %04x:%04x",
+ (UINTN) BbsTable[Index].BootHandlerSegment,
+ (UINTN) BbsTable[Index].BootHandlerOffset,
+ (UINTN) BbsTable[Index].MfgStringSegment,
+ (UINTN) BbsTable[Index].MfgStringOffset,
+ (UINTN) BbsTable[Index].DescStringSegment,
+ (UINTN) BbsTable[Index].DescStringOffset
+ ));
+
+ //
+ // Print DescString
+ //
+ String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);
+ if (String != NULL) {
+ DEBUG ((EFI_D_INFO," ("));
+ for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {
+ DEBUG ((EFI_D_INFO, "%c", String[SubIndex]));
+ }
+ DEBUG ((EFI_D_INFO,")"));
+ }
+ DEBUG ((EFI_D_INFO,"\n"));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ return ;
+}
+
+/**
+ Print the BBS Table.
+
+ @param HddInfo The HddInfo table.
+
+
+**/
+VOID
+PrintHddInfo (
+ IN HDD_INFO *HddInfo
+ )
+{
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ DEBUG ((EFI_D_INFO, "Index - %04x\n", Index));
+ DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status));
+ DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));
+ DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress));
+ DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress));
+ DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));
+ DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq));
+ DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));
+ DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ return ;
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ );
+
+/**
+ Update SIO data.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+UpdateSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index1;
+ UINT8 LegacyInterrupts[16];
+ EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
+ UINTN RoutingTableEntries;
+ EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;
+ UINTN NumberPriorityEntries;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ UINT8 HddIrq;
+ UINT16 LegacyInt;
+ UINT16 LegMask;
+ UINT32 Register;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ LegacyInt = 0;
+ HandleBuffer = NULL;
+
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ LegacyBiosBuildSioData (Private);
+ SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);
+
+ //
+ // Create list of legacy interrupts.
+ //
+ for (Index = 0; Index < 4; Index++) {
+ LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;
+ }
+
+ for (Index = 4; Index < 7; Index++) {
+ LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;
+ }
+
+ LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;
+
+ //
+ // Get Legacy Hdd IRQs. If native mode treat as PCI
+ //
+ for (Index = 0; Index < 2; Index++) {
+ HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;
+ if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {
+ LegacyInterrupts[Index + 8] = HddIrq;
+ }
+ }
+
+ Private->LegacyBiosPlatform->GetRoutingTable (
+ Private->LegacyBiosPlatform,
+ (VOID *) &RoutingTable,
+ &RoutingTableEntries,
+ NULL,
+ NULL,
+ (VOID **) &IrqPriorityTable,
+ &NumberPriorityEntries
+ );
+ //
+ // Remove legacy interrupts from the list of PCI interrupts available.
+ //
+ for (Index = 0; Index <= 0x0b; Index++) {
+ for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {
+ if (LegacyInterrupts[Index] != 0) {
+ LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index]));
+ if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {
+ IrqPriorityTable[Index1].Used = LEGACY_USED;
+ }
+ }
+ }
+ }
+
+ Private->Legacy8259->GetMask (
+ Private->Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ //
+ // Set SIO interrupts and disable mouse. Let mouse driver
+ // re-enable it.
+ //
+ LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000);
+ Private->Legacy8259->SetMask (
+ Private->Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ //
+ // Disable mouse in keyboard controller
+ //
+ Register = 0xA7;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);
+
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ This requires updating the checksum, if it exists.
+
+ @param IdentifyDriveData ATA Identify Data
+ @param Checksum checksum of the ATA Identify Data
+
+ @retval EFI_SUCCESS checksum calculated
+ @retval EFI_SECURITY_VIOLATION IdentifyData invalid
+
+**/
+EFI_STATUS
+CalculateIdentifyDriveChecksum (
+ IN UINT8 *IdentifyDriveData,
+ OUT UINT8 *Checksum
+ )
+{
+ UINTN Index;
+ UINT8 LocalChecksum;
+ LocalChecksum = 0;
+ *Checksum = 0;
+ if (IdentifyDriveData[510] != 0xA5) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ for (Index = 0; Index < 512; Index++) {
+ LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]);
+ }
+
+ *Checksum = LocalChecksum;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ )
+{
+ UINT16 NumberCylinders;
+ UINT16 NumberHeads;
+ UINT16 NumberSectorsTrack;
+ UINT32 CapacityInSectors;
+ UINT8 OriginalChecksum;
+ UINT8 FinalChecksum;
+ EFI_STATUS Status;
+ ATAPI_IDENTIFY *ReadInfo;
+
+ //
+ // Status indicates if Integrity byte is correct. Checksum should be
+ // 0 if valid.
+ //
+ ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData;
+ Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);
+ if (OriginalChecksum != 0) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ //
+ // If NumberCylinders = 0 then do data(Controller present but don drive attached).
+ //
+ NumberCylinders = ReadInfo->Raw[1];
+ if (NumberCylinders != 0) {
+ ReadInfo->Raw[54] = NumberCylinders;
+
+ NumberHeads = ReadInfo->Raw[3];
+ ReadInfo->Raw[55] = NumberHeads;
+
+ NumberSectorsTrack = ReadInfo->Raw[6];
+ ReadInfo->Raw[56] = NumberSectorsTrack;
+
+ //
+ // Copy Multisector info and set valid bit.
+ //
+ ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100);
+ CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack));
+ ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16);
+ ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff);
+ if (Status == EFI_SUCCESS) {
+ //
+ // Forece checksum byte to 0 and get new checksum.
+ //
+ ReadInfo->Raw[255] &= 0xff;
+ CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);
+
+ //
+ // Force new checksum such that sum is 0.
+ //
+ FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum);
+ ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8));
+ }
+ }
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ Do for all drives.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+UpdateAllIdentifyDriveData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINTN Index;
+ HDD_INFO *HddInfo;
+
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ //
+ // Each controller can have 2 devices. Update for each device
+ //
+ if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {
+ UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0]));
+ }
+
+ if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {
+ UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0]));
+ }
+ }
+}
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableIdeController (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ EFI_HANDLE IdeController;
+ UINT8 ByteBuffer;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ Status = gBS->HandleProtocol (
+ IdeController,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ByteBuffer = 0x1f;
+ if (!EFI_ERROR (Status)) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);
+ }
+ }
+}
+
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableAllControllers (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ EFI_STATUS Status;
+
+ //
+ //
+ //
+ EnableIdeController (Private);
+
+ //
+ // Assumption is table is built from low bus to high bus numbers.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ //
+ // We do not enable PPB here. This is for HotPlug Consideration.
+ // The Platform HotPlug Driver is responsible for Padding enough hot plug
+ // resources. It is also responsible for enable this bridge. If it
+ // does not pad it. It will cause some early Windows fail to installation.
+ // If the platform driver does not pad resource for PPB, PPB should be in
+ // un-enabled state to let Windows know that this PPB is not configured by
+ // BIOS. So Windows will allocate default resource for PPB.
+ //
+ // The reason for why we enable the command register is:
+ // The CSM will use the IO bar to detect some IRQ status, if the command
+ // is disabled, the IO resource will be out of scope.
+ // For example:
+ // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
+ // comes up, the handle will check the IO space to identify is the
+ // controller generated the IRQ source.
+ // If the IO command is not enabled, the IRQ handler will has wrong
+ // information. It will cause IRQ storm when the correctly IRQ handler fails
+ // to run.
+ //
+ if (!(IS_PCI_VGA (&PciConfigHeader) ||
+ IS_PCI_OLD_VGA (&PciConfigHeader) ||
+ IS_PCI_IDE (&PciConfigHeader) ||
+ IS_PCI_P2P (&PciConfigHeader) ||
+ IS_PCI_P2P_SUB (&PciConfigHeader) ||
+ IS_PCI_LPC (&PciConfigHeader) )) {
+
+ PciConfigHeader.Hdr.Command |= 0x1f;
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);
+ }
+ }
+}
+
+/**
+ The following routines are identical in operation, so combine
+ for code compaction:
+ EfiGetPlatformBinaryGetMpTable
+ EfiGetPlatformBinaryGetOemIntData
+ EfiGetPlatformBinaryGetOem32Data
+ EfiGetPlatformBinaryGetOem16Data
+
+ @param This Protocol instance pointer.
+ @param Id Table/Data identifier
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Invalid ID
+ @retval EFI_OUT_OF_RESOURCES no resource to get data or table
+
+**/
+EFI_STATUS
+LegacyGetDataOrTable (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_GET_PLATFORM_INFO_MODE Id
+ )
+{
+ VOID *Table;
+ UINT32 TablePtr;
+ UINTN TableSize;
+ UINTN Alignment;
+ UINTN Location;
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ EFI_IA32_REGISTER_SET Regs;
+ LEGACY_BIOS_INSTANCE *Private;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+ Legacy16Table = Private->Legacy16Table;
+
+ //
+ // Phase 1 - get an address allocated in 16-bit code
+ //
+ while (TRUE) {
+ switch (Id) {
+ case EfiGetPlatformBinaryMpTable:
+ case EfiGetPlatformBinaryOemIntData:
+ case EfiGetPlatformBinaryOem32Data:
+ case EfiGetPlatformBinaryOem16Data:
+ {
+ Status = LegacyBiosPlatform->GetPlatformInfo (
+ LegacyBiosPlatform,
+ Id,
+ (VOID *) &Table,
+ &TableSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));
+ DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));
+ break;
+ }
+
+ default:
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) TableSize;
+ Regs.X.BX = (UINT16) Location;
+ Regs.X.DX = (UINT16) Alignment;
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id));
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ break;
+ }
+ }
+ //
+ // Phase 2 Call routine second time with address to allow address adjustment
+ //
+ Status = LegacyBiosPlatform->GetPlatformInfo (
+ LegacyBiosPlatform,
+ Id,
+ (VOID *) &Table,
+ &TableSize,
+ &Location,
+ &Alignment,
+ Regs.X.DS,
+ Regs.X.BX
+ );
+ switch (Id) {
+ case EfiGetPlatformBinaryMpTable:
+ {
+ Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Legacy16Table->MpTableLength = (UINT32)TableSize;
+ DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOemIntData:
+ {
+
+ Legacy16Table->OemIntSegment = Regs.X.DS;
+ Legacy16Table->OemIntOffset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOem32Data:
+ {
+ Legacy16Table->Oem32Segment = Regs.X.DS;
+ Legacy16Table->Oem32Offset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOem16Data:
+ {
+ //
+ // Legacy16Table->Oem16Segment = Regs.X.DS;
+ // Legacy16Table->Oem16Offset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));
+ break;
+ }
+
+ default:
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Phase 3 Copy table to final location
+ //
+ TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+
+ CopyMem (
+ (VOID *) (UINTN)TablePtr,
+ Table,
+ TableSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+GenericLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ UINTN CopySize;
+ VOID *AcpiPtr;
+ HDD_INFO *HddInfo;
+ HDD_INFO *LocalHddInfo;
+ UINTN Index;
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ UINT32 *BdaPtr;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ BBS_TABLE *LocalBbsTable;
+ UINT32 *BaseVectorMaster;
+ EFI_TIME BootTime;
+ UINT32 LocalTime;
+ EFI_HANDLE IdeController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ VOID *SmbiosTable;
+ VOID *AcpiTable;
+ UINTN ShadowAddress;
+ UINT32 Granularity;
+ EFI_TIMER_ARCH_PROTOCOL *Timer;
+ UINT64 TimerPeriod;
+
+ LocalHddInfo = NULL;
+ HddCount = 0;
+ BbsCount = 0;
+ LocalBbsTable = NULL;
+ TimerPeriod = 0;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ DEBUG_CODE (
+ DEBUG ((EFI_D_ERROR, "Start of legacy boot\n"));
+ );
+
+ Legacy16Table = Private->Legacy16Table;
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ HddInfo = &EfiToLegacy16BootTable->HddInfo[0];
+
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+
+ EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;
+ EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;
+
+ //
+ // Before starting the Legacy boot check the system ticker.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiTimerArchProtocolGuid,
+ NULL,
+ (VOID **) &Timer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Timer->GetTimerPeriod (
+ Timer,
+ &TimerPeriod
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (TimerPeriod != DEFAULT_LAGACY_TIMER_TICK_DURATION) {
+ Status = Timer->SetTimerPeriod (
+ Timer,
+ DEFAULT_LAGACY_TIMER_TICK_DURATION
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // If booting to a legacy OS then force HDD drives to the appropriate
+ // boot mode by calling GetIdeHandle.
+ // A reconnect -r can force all HDDs back to native mode.
+ //
+ IdeController = NULL;
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ Status = LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ }
+ }
+ //
+ // Unlock the Legacy BIOS region
+ //
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ //
+ // Reconstruct the Legacy16 boot memory map
+ //
+ LegacyBiosBuildE820 (Private, &CopySize);
+ if (CopySize > Private->Legacy16Table->E820Length) {
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) CopySize;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16Table->Compatibility16CallSegment,
+ Private->Legacy16Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Private->Legacy16Table->E820Length = (UINT32) CopySize;
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
+ } else {
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
+ Private->E820Table,
+ CopySize
+ );
+ }
+ } else {
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
+ Private->E820Table,
+ CopySize
+ );
+ Private->Legacy16Table->E820Length = (UINT32) CopySize;
+ }
+ //
+ // Get SMBIOS and ACPI table pointers
+ //
+ SmbiosTable = NULL;
+ EfiGetSystemConfigurationTable (
+ &gEfiSmbiosTableGuid,
+ &SmbiosTable
+ );
+ //
+ // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
+ //
+ if (SmbiosTable == NULL) {
+ DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));
+ }
+ EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)SmbiosTable;
+
+ AcpiTable = NULL;
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiAcpi20TableGuid,
+ &AcpiTable
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiAcpi10TableGuid,
+ &AcpiTable
+ );
+ }
+ //
+ // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
+ //
+ if (AcpiTable == NULL) {
+ DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));
+ }
+ EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;
+
+ //
+ // Get RSD Ptr table rev at offset 15 decimal
+ // Rev = 0 Length is 20 decimal
+ // Rev != 0 Length is UINT32 at offset 20 decimal
+ //
+ if (AcpiTable != NULL) {
+
+ AcpiPtr = AcpiTable;
+ if (*((UINT8 *) AcpiPtr + 15) == 0) {
+ CopySize = 20;
+ } else {
+ AcpiPtr = ((UINT8 *) AcpiPtr + 20);
+ CopySize = (*(UINT32 *) AcpiPtr);
+ }
+
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,
+ AcpiTable,
+ CopySize
+ );
+ }
+ //
+ // Make sure all PCI Interrupt Line register are programmed to match 8259
+ //
+ PciProgramAllInterruptLineRegisters (Private);
+
+ //
+ // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
+ // can lock it.
+ //
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ Private->BiosStart,
+ Private->LegacyBiosImageSize,
+ &Granularity
+ );
+
+ //
+ // Configure Legacy Device Magic
+ //
+ // Only do this code if booting legacy OS
+ //
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ UpdateSioData (Private);
+ }
+ //
+ // Setup BDA and EBDA standard areas before Legacy Boot
+ //
+ LegacyBiosCompleteBdaBeforeBoot (Private);
+ LegacyBiosCompleteStandardCmosBeforeBoot (Private);
+
+ //
+ // We must build IDE data, if it hasn't been done, before PciShadowRoms
+ // to insure EFI drivers are connected.
+ //
+ LegacyBiosBuildIdeData (Private, &HddInfo, 1);
+ UpdateAllIdentifyDriveData (Private);
+
+ //
+ // Clear IO BAR, if IDE controller in legacy mode.
+ //
+ InitLegacyIdeController (IdeController);
+
+ //
+ // Generate number of ticks since midnight for BDA. DOS requires this
+ // for its time. We have to make assumptions as to how long following
+ // code takes since after PciShadowRoms PciIo is gone. Place result in
+ // 40:6C-6F
+ //
+ // Adjust value by 1 second.
+ //
+ gRT->GetTime (&BootTime, NULL);
+ LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
+ LocalTime += 1;
+
+ //
+ // Multiply result by 18.2 for number of ticks since midnight.
+ // Use 182/10 to avoid floating point math.
+ //
+ LocalTime = (LocalTime * 182) / 10;
+ BdaPtr = (UINT32 *) (UINTN)0x46C;
+ *BdaPtr = LocalTime;
+
+ //
+ // Shadow PCI ROMs. We must do this near the end since this will kick
+ // of Native EFI drivers that may be needed to collect info for Legacy16
+ //
+ // WARNING: PciIo is gone after this call.
+ //
+ PciShadowRoms (Private);
+
+ //
+ // Shadow PXE base code, BIS etc.
+ //
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
+ ShadowAddress = Private->OptionRom;
+ Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookShadowServiceRoms,
+ 0,
+ 0,
+ &ShadowAddress,
+ Legacy16Table,
+ NULL
+ );
+ Private->OptionRom = (UINT32)ShadowAddress;
+ //
+ // Register Legacy SMI Handler
+ //
+ LegacyBiosPlatform->SmmInit (
+ LegacyBiosPlatform,
+ EfiToLegacy16BootTable
+ );
+
+ //
+ // Let platform code know the boot options
+ //
+ LegacyBiosGetBbsInfo (
+ This,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ PrintBbsTable (LocalBbsTable);
+ PrintHddInfo (LocalHddInfo);
+
+ //
+ // If drive wasn't spun up then BuildIdeData may have found new drives.
+ // Need to update BBS boot priority.
+ //
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&
+ (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)
+ ) {
+ LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+
+ if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&
+ (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)
+ ) {
+ LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+
+ LegacyBiosPlatform->PrepareToBoot (
+ LegacyBiosPlatform,
+ mBbsDevicePathPtr,
+ mBbsTable,
+ mLoadOptionsSize,
+ mLoadOptions,
+ (VOID *) &Private->IntThunk->EfiToLegacy16BootTable
+ );
+
+ //
+ // If no boot device return to BDS
+ //
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ for (Index = 0; Index < BbsCount; Index++){
+ if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&
+ (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
+ (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {
+ break;
+ }
+ }
+ if (Index == BbsCount) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Let the Legacy16 code know the device path type for legacy boot
+ //
+ EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;
+
+ //
+ // Copy MP table, if it exists.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);
+
+ if (!Private->LegacyBootEntered) {
+ //
+ // Copy OEM INT Data, if it exists. Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);
+
+ //
+ // Copy OEM16 Data, if it exists.Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);
+
+ //
+ // Copy OEM32 Data, if it exists.Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);
+ }
+
+ //
+ // Call into Legacy16 code to prepare for INT 19h
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16PrepareToBoot;
+
+ //
+ // Pass in handoff data
+ //
+ Regs.X.ES = EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);
+ Regs.X.BX = EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Lock the Legacy BIOS region
+ //
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+ //
+ // Lock attributes of the Legacy Region if chipset supports
+ //
+ Private->LegacyRegion->BootLock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+
+ //
+ // Call into Legacy16 code to do the INT 19h
+ //
+ EnableAllControllers (Private);
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ //
+ // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
+ //
+ EfiSignalEventLegacyBoot ();
+ DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));
+ //
+ // Raise TPL to high level to disable CPU interrupts
+ //
+ gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Put the 8259 into its legacy mode by reprogramming the vector bases
+ //
+ Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
+ //
+ // PC History
+ // The original PC used INT8-F for master PIC. Since these mapped over
+ // processor exceptions TIANO moved the master PIC to INT68-6F.
+ // We need to set these back to the Legacy16 unexpected interrupt(saved
+ // in LegacyBios.c) since some OS see that these have values different from
+ // what is expected and invoke them. Since the legacy OS corrupts EFI
+ // memory, there is no handler for these interrupts and OS blows up.
+ //
+ // We need to save the TIANO values for the rare case that the Legacy16
+ // code cannot boot but knows memory hasn't been destroyed.
+ //
+ // To compound the problem, video takes over one of these INTS and must be
+ // be left.
+ // @bug - determine if video hooks INT(in which case we must find new
+ // set of TIANO vectors) or takes it over.
+ //
+ //
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ for (Index = 0; Index < 8; Index++) {
+ Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
+ if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {
+ BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
+ }
+ }
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16Boot;
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ for (Index = 0; Index < 8; Index++) {
+ BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
+ }
+ }
+ Private->LegacyBootEntered = TRUE;
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ //
+ // Should never return unless never passed control to 0:7c00(first stage
+ // OS loader) and only then if no bootable device found.
+ //
+ return EFI_DEVICE_ERROR;
+ } else {
+ //
+ // If boot to EFI then expect to return to caller
+ //
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ LEGACY_BIOS_INSTANCE *Private;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ mBootMode = BOOT_EFI_OS;
+ mBbsDevicePathPtr = NULL;
+ Status = GenericLegacyBoot (This);
+ *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
+ return Status;
+}
+
+/**
+ To boot from an unconventional device like parties and/or execute HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the parent
+ device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
+ caller must provide a pointer to the specific Service
+ Area and not the start all Service Areas.
+
+ @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+***/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ LEGACY_BIOS_INSTANCE *Private;
+ UD_TABLE *UcdTable;
+ UINTN Index;
+ UINT16 BootPriority;
+ BBS_TABLE *BbsTable;
+
+ BootPriority = 0;
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
+ mBbsDevicePathPtr = &mBbsDevicePathNode;
+ mAttributes = Attributes;
+ mBbsEntry = BbsEntry;
+ mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
+
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+
+ //
+ // Do input parameter checking
+ //
+ if ((Attributes.DirectoryServiceValidity == 0) &&
+ (Attributes.RabcaUsedFlag == 0) &&
+ (Attributes.ExecuteHddDiagnosticsFlag == 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
+ (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UcdTable = (UD_TABLE *) AllocatePool (
+ sizeof (UD_TABLE)
+ );
+ if (NULL == UcdTable) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
+ UcdTable->Attributes = Attributes;
+ UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;
+ //
+ // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
+ // to assign drive numbers but bot boot from. Only newly created entries
+ // will be valid.
+ //
+ BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
+ BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
+ }
+ //
+ // If parent is onboard IDE then assign controller & device number
+ // else they are 0.
+ //
+ if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
+ UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);
+ }
+
+ if (BeerData != NULL) {
+ CopyMem (
+ (VOID *) UcdTable->BeerData,
+ BeerData,
+ (UINTN) 128
+ );
+ }
+
+ if (ServiceAreaData != NULL) {
+ CopyMem (
+ (VOID *) UcdTable->ServiceAreaData,
+ ServiceAreaData,
+ (UINTN) 64
+ );
+ }
+ //
+ // For each new entry do the following:
+ // 1. Increment current number of BBS entries
+ // 2. Copy parent entry to new entry.
+ // 3. Zero out BootHandler Offset & segment
+ // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
+ // and Floppy(0x01) for PARTIES boot.
+ // 5. Assign new priority.
+ //
+ if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
+ EfiToLegacy16BootTable->NumberBbsEntries += 1;
+
+ CopyMem (
+ (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
+ (VOID *) &BbsTable[BbsEntry].BootPriority,
+ sizeof (BBS_TABLE)
+ );
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80;
+
+ UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
+ BootPriority += 1;
+
+ //
+ // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
+ //
+ mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
+ }
+
+ if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
+ EfiToLegacy16BootTable->NumberBbsEntries += 1;
+ CopyMem (
+ (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
+ (VOID *) &BbsTable[BbsEntry].BootPriority,
+ sizeof (BBS_TABLE)
+ );
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01;
+ UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
+
+ //
+ // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
+ //
+ mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
+ }
+ //
+ // Build the BBS Device Path for this boot selection
+ //
+ mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
+ mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
+ SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
+ mBbsDevicePathNode.StatusFlag = 0;
+ mBbsDevicePathNode.String[0] = 0;
+
+ Status = GenericLegacyBoot (This);
+ return Status;
+}
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ )
+{
+ EFI_STATUS Status;
+
+ mBbsDevicePathPtr = BbsDevicePath;
+ mLoadOptionsSize = LoadOptionsSize;
+ mLoadOptions = LoadOptions;
+ mBootMode = BOOT_LEGACY_OS;
+ Status = GenericLegacyBoot (This);
+
+ return Status;
+}
+
+/**
+ Convert EFI Memory Type to E820 Memory Type.
+
+ @param Type EFI Memory Type
+
+ @return ACPI Memory Type for EFI Memory Type
+
+**/
+EFI_ACPI_MEMORY_TYPE
+EfiMemoryTypeToE820Type (
+ IN UINT32 Type
+ )
+{
+ switch (Type) {
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ return EfiAcpiAddressRangeMemory;
+
+ case EfiACPIReclaimMemory:
+ return EfiAcpiAddressRangeACPI;
+
+ case EfiACPIMemoryNVS:
+ return EfiAcpiAddressRangeNVS;
+
+ //
+ // All other types map to reserved.
+ // Adding the code just waists FLASH space.
+ //
+ // case EfiReservedMemoryType:
+ // case EfiUnusableMemory:
+ // case EfiMemoryMappedIO:
+ // case EfiMemoryMappedIOPortSpace:
+ // case EfiPalCode:
+ //
+ default:
+ return EfiAcpiAddressRangeReserved;
+ }
+}
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_E820_ENTRY64 *E820Table;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR *EfiEntry;
+ EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
+ EFI_MEMORY_DESCRIPTOR TempEfiEntry;
+ UINTN EfiMemoryMapSize;
+ UINTN EfiMapKey;
+ UINTN EfiDescriptorSize;
+ UINT32 EfiDescriptorVersion;
+ UINTN Index;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ UINTN TempIndex;
+ UINTN IndexSort;
+ UINTN TempNextIndex;
+ EFI_E820_ENTRY64 TempE820;
+ EFI_ACPI_MEMORY_TYPE TempType;
+ BOOLEAN ChangedFlag;
+ UINTN Above1MIndex;
+ UINT64 MemoryBlockLength;
+
+ E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;
+
+ //
+ // Get the EFI memory map.
+ //
+ EfiMemoryMapSize = 0;
+ EfiMemoryMap = NULL;
+ Status = gBS->GetMemoryMap (
+ &EfiMemoryMapSize,
+ EfiMemoryMap,
+ &EfiMapKey,
+ &EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ //
+ // Use size returned back plus 1 descriptor for the AllocatePool.
+ // We don't just multiply by 2 since the "for" loop below terminates on
+ // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
+ // we process bogus entries and create bogus E820 entries.
+ //
+ EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
+ ASSERT (EfiMemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &EfiMemoryMapSize,
+ EfiMemoryMap,
+ &EfiMapKey,
+ &EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (EfiMemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Punch in the E820 table for memory less than 1 MB.
+ // Assume ZeroMem () has been done on data structure.
+ //
+ //
+ // First entry is 0 to (640k - EBDA)
+ //
+ E820Table[0].BaseAddr = 0;
+ E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
+ E820Table[0].Type = EfiAcpiAddressRangeMemory;
+
+ //
+ // Second entry is (640k - EBDA) to 640k
+ //
+ E820Table[1].BaseAddr = E820Table[0].Length;
+ E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length);
+ E820Table[1].Type = EfiAcpiAddressRangeReserved;
+
+ //
+ // Third Entry is legacy BIOS
+ // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
+ // to page in memory under 1MB.
+ // Omit region from 0xE0000 to start of BIOS, if any. This can be
+ // used for a multiple reasons including OPROMS.
+ //
+
+ //
+ // The CSM binary image size is not the actually size that CSM binary used,
+ // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
+ //
+ E820Table[2].BaseAddr = 0xE0000;
+ E820Table[2].Length = 0x20000;
+ E820Table[2].Type = EfiAcpiAddressRangeReserved;
+
+ Above1MIndex = 2;
+
+ //
+ // Process the EFI map to produce E820 map;
+ //
+
+ //
+ // Sort memory map from low to high
+ //
+ EfiEntry = EfiMemoryMap;
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+ while (EfiEntry < EfiMemoryMapEnd) {
+ while (NextEfiEntry < EfiMemoryMapEnd) {
+ if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
+ CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
+ }
+
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ }
+
+ EfiEntry = EfiMemoryMap;
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+ for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
+ MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
+ if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
+ //
+ // Skip the memory block is under 1MB
+ //
+ } else {
+ if (EfiEntry->PhysicalStart < 0x100000) {
+ //
+ // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
+ //
+ MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart;
+ EfiEntry->PhysicalStart = 0x100000;
+ }
+
+ //
+ // Convert memory type to E820 type
+ //
+ TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
+
+ if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
+ //
+ // Grow an existing entry
+ //
+ E820Table[Index].Length += MemoryBlockLength;
+ } else {
+ //
+ // Make a new entry
+ //
+ ++Index;
+ E820Table[Index].BaseAddr = EfiEntry->PhysicalStart;
+ E820Table[Index].Length = MemoryBlockLength;
+ E820Table[Index].Type = TempType;
+ }
+ }
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ }
+
+ FreePool (EfiMemoryMap);
+
+ //
+ // Process the reserved memory map to produce E820 map ;
+ //
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ ResourceHob = Hob.ResourceDescriptor;
+ if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
+ (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) ||
+ (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) &&
+ (ResourceHob->PhysicalStart > 0x100000) &&
+ (Index < EFI_MAX_E820_ENTRY - 1)) {
+ ++Index;
+ E820Table[Index].BaseAddr = ResourceHob->PhysicalStart;
+ E820Table[Index].Length = ResourceHob->ResourceLength;
+ E820Table[Index].Type = EfiAcpiAddressRangeReserved;
+ }
+ }
+ }
+
+ Index ++;
+ Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
+ Private->NumberE820Entries = (UINT32)Index;
+ *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
+
+ //
+ // Sort E820Table from low to high
+ //
+ for (TempIndex = 0; TempIndex < Index; TempIndex++) {
+ ChangedFlag = FALSE;
+ for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
+ if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
+ ChangedFlag = TRUE;
+ TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr;
+ TempE820.Length = E820Table[TempNextIndex - 1].Length;
+ TempE820.Type = E820Table[TempNextIndex - 1].Type;
+
+ E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr;
+ E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length;
+ E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type;
+
+ E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr;
+ E820Table[TempNextIndex].Length = TempE820.Length;
+ E820Table[TempNextIndex].Type = TempE820.Type;
+ }
+ }
+
+ if (!ChangedFlag) {
+ break;
+ }
+ }
+
+ //
+ // Remove the overlap range
+ //
+ for (TempIndex = 1; TempIndex < Index; TempIndex++) {
+ if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&
+ ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
+ (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {
+ //
+ //Overlap range is found
+ //
+ ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
+
+ if (TempIndex == Index - 1) {
+ E820Table[TempIndex].BaseAddr = 0;
+ E820Table[TempIndex].Length = 0;
+ E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0;
+ Index--;
+ break;
+ } else {
+ for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {
+ E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
+ E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length;
+ E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type;
+ }
+ Index--;
+ }
+ }
+ }
+
+
+
+ Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
+ Private->NumberE820Entries = (UINT32)Index;
+ *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
+
+ //
+ // Determine OS usable memory above 1Mb
+ //
+ Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
+ for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
+ if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory
+ //
+ // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
+ //
+ if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
+ Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);
+ } else {
+ break; // break at first not normal memory, because SMM may use reserved memory.
+ }
+ }
+ }
+
+ Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
+
+ //
+ // Print DEBUG information
+ //
+ for (TempIndex = 0; TempIndex < Index; TempIndex++) {
+ DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
+ TempIndex,
+ E820Table[TempIndex].BaseAddr,
+ (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
+ E820Table[TempIndex].Type
+ ));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard BDA and EBDA stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteBdaBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ BDA_STRUC *Bda;
+ UINT16 MachineConfig;
+ DEVICE_PRODUCER_DATA_HEADER *SioPtr;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+ MachineConfig = 0;
+
+ SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
+ Bda->Com1 = SioPtr->Serial[0].Address;
+ Bda->Com2 = SioPtr->Serial[1].Address;
+ Bda->Com3 = SioPtr->Serial[2].Address;
+ Bda->Com4 = SioPtr->Serial[3].Address;
+
+ if (SioPtr->Serial[0].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[1].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[2].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[3].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ Bda->Lpt1 = SioPtr->Parallel[0].Address;
+ Bda->Lpt2 = SioPtr->Parallel[1].Address;
+ Bda->Lpt3 = SioPtr->Parallel[2].Address;
+
+ if (SioPtr->Parallel[0].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ if (SioPtr->Parallel[1].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ if (SioPtr->Parallel[2].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);
+ if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
+ MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
+ Bda->FloppyXRate = 0x07;
+ }
+
+ Bda->Lpt1_2Timeout = 0x1414;
+ Bda->Lpt3_4Timeout = 0x1414;
+ Bda->Com1_2Timeout = 0x0101;
+ Bda->Com3_4Timeout = 0x0101;
+
+ //
+ // Force VGA and Coprocessor, indicate 101/102 keyboard
+ //
+ MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
+ Bda->MachineConfig = MachineConfig;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+ BDA_STRUC *Bda;
+ UINT8 LocalLeds;
+ EFI_IA32_REGISTER_SET Regs;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ LocalLeds = Leds;
+ Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
+ LocalLeds = (UINT8) (LocalLeds << 4);
+ Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
+ LocalLeds = (UINT8) (Leds & 0x20);
+ Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
+ //
+ // Call into Legacy16 code to allow it to do any processing
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16SetKeyboardLeds;
+ Regs.H.CL = Leds;
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16Table->Compatibility16CallSegment,
+ Private->Legacy16Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard CMOS stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteStandardCmosBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINT8 Bda;
+ UINT8 Floppy;
+ UINT32 Size;
+
+ //
+ // Update CMOS locations
+ // 10 floppy
+ // 12,19,1A - ignore as OS don't use them and there is no standard due
+ // to large capacity drives
+ // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
+ //
+ Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
+
+ //
+ // Force display enabled
+ //
+ Floppy = 0x00;
+ if ((Bda & BIT0) != 0) {
+ Floppy = BIT6;
+ }
+
+ //
+ // Check if 2.88MB floppy set
+ //
+ if ((Bda & (BIT7 | BIT6)) != 0) {
+ Floppy = (UINT8)(Floppy | BIT1);
+ }
+
+ LegacyWriteStandardCmos (CMOS_10, Floppy);
+ LegacyWriteStandardCmos (CMOS_14, Bda);
+
+ //
+ // Force Status Register A to set rate selection bits and divider
+ //
+ LegacyWriteStandardCmos (CMOS_0A, 0x26);
+
+ //
+ // redo memory size since it can change
+ //
+ Size = 15 * SIZE_1MB;
+ if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
+ Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
+ }
+
+ LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
+ LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
+
+ LegacyCalculateWriteStandardCmosChecksum ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c
new file mode 100644
index 0000000..0fbf902
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c
@@ -0,0 +1,124 @@
+/** @file
+ This code fills in standard CMOS values and updates the standard CMOS
+ checksum. The Legacy16 code or LegacyBiosPlatform.c is responsible for
+ non-standard CMOS locations and non-standard checksums.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Read CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to read.
+
+ @return The data value from the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyReadStandardCmos (
+ IN UINT8 Index
+ )
+{
+ IoWrite8 (PORT_70, Index);
+ return IoRead8 (PORT_71);
+}
+
+/**
+ Write CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to write.
+ @param[in] Value The value of CMOS register to write.
+
+ @return The value written to the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyWriteStandardCmos (
+ IN UINT8 Index,
+ IN UINT8 Value
+ )
+{
+ IoWrite8 (PORT_70, Index);
+ return IoWrite8 (PORT_71, Value);
+}
+
+/**
+ Calculate the new standard CMOS checksum and write it.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Calculate 16-bit checksum successfully
+
+**/
+EFI_STATUS
+LegacyCalculateWriteStandardCmosChecksum (
+ VOID
+ )
+{
+ UINT8 Register;
+ UINT16 Checksum;
+
+ for (Checksum = 0, Register = 0x10; Register < 0x2e; Register++) {
+ Checksum = (UINT16)(Checksum + LegacyReadStandardCmos (Register));
+ }
+ LegacyWriteStandardCmos (CMOS_2E, (UINT8)(Checksum >> 8));
+ LegacyWriteStandardCmos (CMOS_2F, (UINT8)(Checksum & 0xff));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard CMOS stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitCmos (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINT32 Size;
+
+ //
+ // Clear all errors except RTC lost power
+ //
+ LegacyWriteStandardCmos (CMOS_0E, (UINT8)(LegacyReadStandardCmos (CMOS_0E) & BIT7));
+
+ //
+ // Update CMOS locations 15,16,17,18,30,31 and 32
+ // CMOS 16,15 = 640Kb = 0x280
+ // CMOS 18,17 = 31,30 = 15Mb max in 1Kb increments =0x3C00 max
+ // CMOS 32 = 0x20
+ //
+ LegacyWriteStandardCmos (CMOS_15, 0x80);
+ LegacyWriteStandardCmos (CMOS_16, 0x02);
+
+ Size = 15 * SIZE_1MB;
+ if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
+ Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
+ }
+
+ LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
+ LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
+
+ LegacyCalculateWriteStandardCmosChecksum ();
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c
new file mode 100644
index 0000000..4e52fe9
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c
@@ -0,0 +1,300 @@
+/** @file
+ Collect IDE information from Native EFI Driver
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+BOOLEAN mIdeDataBuiltFlag = FALSE;
+
+/**
+ Collect IDE Inquiry data from the IDE disks
+
+ @param Private Legacy BIOS Instance data
+ @param HddInfo Hdd Information
+ @param Flag Reconnect IdeController or not
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildIdeData (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN HDD_INFO **HddInfo,
+ IN UINT16 Flag
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE IdeController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_DISK_INFO_PROTOCOL *DiskInfo;
+ UINT32 IdeChannel;
+ UINT32 IdeDevice;
+ UINT32 Size;
+ UINT8 *InquiryData;
+ UINT32 InquiryDataSize;
+ HDD_INFO *LocalHddInfo;
+ UINT32 PciIndex;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
+ PCI_DEVICE_PATH *PciDevicePath;
+
+ //
+ // Only build data once
+ // We have a problem with GetBbsInfo in that it can be invoked two
+ // places. Once in BDS, when all EFI drivers are connected and once in
+ // LegacyBoot after all EFI drivers are disconnected causing this routine
+ // to hang. In LegacyBoot this function is also called before EFI drivers
+ // are disconnected.
+ // Cases covered
+ // GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
+ // GetBbsInfo not invoked in BDS. First invocation of this function
+ // proceeds normally and second via GetBbsInfo ignored.
+ //
+ PciDevicePath = NULL;
+ LocalHddInfo = *HddInfo;
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ //
+ // Force IDE drive spin up!
+ //
+ if (Flag != 0) {
+ gBS->DisconnectController (
+ IdeController,
+ NULL,
+ NULL
+ );
+ }
+
+ gBS->ConnectController (IdeController, NULL, NULL, FALSE);
+
+ //
+ // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
+ // And GetIdeHandle will switch to Legacy mode, if required.
+ //
+ Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ }
+
+ mIdeDataBuiltFlag = TRUE;
+
+ //
+ // Get Identity command from all drives
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDiskInfoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ Private->IdeDriveCount = (UINT8) HandleCount;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDiskInfoProtocolGuid,
+ (VOID **) &DiskInfo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
+ //
+ // Locate which PCI device
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &DevicePath
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ TempDevicePathNode = NextDevicePathNode (DevicePathNode);
+ if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
+ ( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
+ ( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
+ ( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {
+ PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
+ break;
+ }
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (PciDevicePath == NULL) {
+ continue;
+ }
+
+ //
+ // Find start of PCI device in HddInfo. The assumption of the data
+ // structure is 2 controllers(channels) per PCI device and each
+ // controller can have 2 drives(devices).
+ // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
+ // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
+ // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
+ // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
+ // @bug eventually need to pass in max number of entries
+ // for end of for loop
+ //
+ for (PciIndex = 0; PciIndex < 8; PciIndex++) {
+ if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
+ (PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
+ ) {
+ break;
+ }
+ }
+
+ if (PciIndex == 8) {
+ continue;
+ }
+
+ Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (ATAPI_IDENTIFY);
+ DiskInfo->Identify (
+ DiskInfo,
+ &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
+ &Size
+ );
+ if (IdeChannel == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
+ } else if (IdeChannel == 1) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
+ }
+
+ InquiryData = NULL;
+ InquiryDataSize = 0;
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ NULL,
+ &InquiryDataSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ InquiryData = (UINT8 *) AllocatePool (
+ InquiryDataSize
+ );
+ if (InquiryData != NULL) {
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ InquiryData,
+ &InquiryDataSize
+ );
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If ATAPI device then Inquiry will pass and ATA fail.
+ //
+ if (!EFI_ERROR (Status)) {
+ ASSERT (InquiryData != NULL);
+ //
+ // If IdeDevice = 0 then set master bit, else slave bit
+ //
+ if (IdeDevice == 0) {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
+ }
+ } else {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
+ }
+ }
+ FreePool (InquiryData);
+ } else {
+ if (IdeDevice == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
+ } else {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
+ }
+ }
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ If the IDE channel is in compatibility (legacy) mode, remove all
+ PCI I/O BAR addresses from the controller.
+
+ @param IdeController The handle of target IDE controller
+
+
+**/
+VOID
+InitLegacyIdeController (
+ IN EFI_HANDLE IdeController
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Pi;
+ UINT32 IOBarClear;
+ EFI_STATUS Status;
+
+ //
+ // If the IDE channel is in compatibility (legacy) mode, remove all
+ // PCI I/O BAR addresses from the controller. Some software gets
+ // confused if an IDE controller is in compatibility (legacy) mode
+ // and has PCI I/O resources allocated
+ //
+ Status = gBS->HandleProtocol (
+ IdeController,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ IOBarClear = 0x00;
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 1, &Pi);
+ if ((Pi & 0x01) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
+ }
+ if ((Pi & 0x04) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
+ }
+ }
+
+ return ;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c
new file mode 100644
index 0000000..a53b57a
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c
@@ -0,0 +1,2901 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci30.h>
+
+#define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff)
+
+#define MAX_BRIDGE_INDEX 0x20
+typedef struct {
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINT8 PrimaryBus;
+ UINT8 SecondaryBus;
+ UINT8 SubordinateBus;
+} BRIDGE_TABLE;
+
+#define ROM_MAX_ENTRIES 24
+BRIDGE_TABLE Bridges[MAX_BRIDGE_INDEX];
+UINTN SortedBridgeIndex[MAX_BRIDGE_INDEX];
+UINTN NumberOfBridges;
+LEGACY_PNP_EXPANSION_HEADER *mBasePnpPtr;
+UINT16 mBbsRomSegment;
+UINTN mHandleCount;
+EFI_HANDLE mVgaHandle;
+BOOLEAN mIgnoreBbsUpdateFlag;
+BOOLEAN mVgaInstallationInProgress = FALSE;
+UINT32 mRomCount = 0x00;
+ROM_INSTANCE_ENTRY mRomEntry[ROM_MAX_ENTRIES];
+
+
+/**
+ Query shadowed legacy ROM parameters registered by RomShadow() previously.
+
+ @param PciHandle PCI device whos ROM has been shadowed
+ @param DiskStart DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param DiskEnd DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param RomShadowAddress Address where ROM was shadowed
+ @param ShadowedSize Runtime size of ROM
+
+ @retval EFI_SUCCESS Query Logging successful.
+ @retval EFI_NOT_FOUND No logged data found about PciHandle.
+
+**/
+EFI_STATUS
+GetShadowedRomParameters (
+ IN EFI_HANDLE PciHandle,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINTN *ShadowedSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+
+ for(Index = 0; Index < mRomCount; Index++) {
+ if ((mRomEntry[Index].PciSegment == PciSegment) &&
+ (mRomEntry[Index].PciBus == PciBus) &&
+ (mRomEntry[Index].PciDevice == PciDevice) &&
+ (mRomEntry[Index].PciFunction == PciFunction)) {
+ break;
+ }
+ }
+
+ if (Index == mRomCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (DiskStart != NULL) {
+ *DiskStart = mRomEntry[Index].DiskStart;
+ }
+
+ if (DiskEnd != NULL) {
+ *DiskEnd = mRomEntry[Index].DiskEnd;
+ }
+
+ if (RomShadowAddress != NULL) {
+ *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;
+ }
+
+ if (ShadowedSize != NULL) {
+ *ShadowedSize = mRomEntry[Index].ShadowedSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Every legacy ROM that is shadowed by the Legacy BIOS driver will be
+ registered into this API so that the policy code can know what has
+ happend
+
+ @param PciHandle PCI device whos ROM is being shadowed
+ @param ShadowAddress Address that ROM was shadowed
+ @param ShadowedSize Runtime size of ROM
+ @param DiskStart DiskStart value from
+ EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param DiskEnd DiskEnd value from
+ EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+
+ @retval EFI_SUCCESS Logging successful.
+ @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option
+ ROM.
+
+**/
+EFI_STATUS
+RomShadow (
+ IN EFI_HANDLE PciHandle,
+ IN UINT32 ShadowAddress,
+ IN UINT32 ShadowedSize,
+ IN UINT8 DiskStart,
+ IN UINT8 DiskEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // See if there is room to register another option ROM
+ //
+ if (mRomCount >= ROM_MAX_ENTRIES) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &mRomEntry[mRomCount].PciSegment,
+ &mRomEntry[mRomCount].PciBus,
+ &mRomEntry[mRomCount].PciDevice,
+ &mRomEntry[mRomCount].PciFunction
+ );
+ mRomEntry[mRomCount].ShadowAddress = ShadowAddress;
+ mRomEntry[mRomCount].ShadowedSize = ShadowedSize;
+ mRomEntry[mRomCount].DiskStart = DiskStart;
+ mRomEntry[mRomCount].DiskEnd = DiskEnd;
+
+ mRomCount++;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
+ information represents every call to RomShadow ()
+
+ @param PciHandle PCI device to get status for
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_NOT_FOUND No Legacy ROM loaded for this device
+
+**/
+EFI_STATUS
+IsLegacyRom (
+ IN EFI_HANDLE PciHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+
+ //
+ // See if the option ROM from PciHandle has been previously posted
+ //
+ for (Index = 0; Index < mRomCount; Index++) {
+ if (mRomEntry[Index].PciSegment == Segment &&
+ mRomEntry[Index].PciBus == Bus &&
+ mRomEntry[Index].PciDevice == Device &&
+ mRomEntry[Index].PciFunction == Function
+ ) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
+ related information from the header.
+
+ @param Csm16Revision The PCI interface version of underlying CSM16
+ @param VendorId Vendor ID of the PCI device
+ @param DeviceId Device ID of the PCI device
+ @param Rom On input pointing to beginning of the raw PCI OpROM
+ On output pointing to the first legacy PCI OpROM
+ @param ImageSize On input is the size of Raw PCI Rom
+ On output is the size of the first legacy PCI ROM
+ @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3
+ @param OpRomRevision Revision of the PCI Rom
+ @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
+
+ @retval EFI_SUCCESS Successfully find the legacy PCI ROM
+ @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM
+
+**/
+EFI_STATUS
+GetPciLegacyRom (
+ IN UINT16 Csm16Revision,
+ IN UINT16 VendorId,
+ IN UINT16 DeviceId,
+ IN OUT VOID **Rom,
+ IN OUT UINTN *ImageSize,
+ OUT UINTN *MaxRuntimeImageLength, OPTIONAL
+ OUT UINT8 *OpRomRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ )
+{
+ BOOLEAN Match;
+ UINT16 *DeviceIdList;
+ EFI_PCI_ROM_HEADER RomHeader;
+ PCI_3_0_DATA_STRUCTURE *Pcir;
+ VOID *BackupImage;
+ VOID *BestImage;
+
+
+ if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {
+ return EFI_NOT_FOUND;
+ }
+
+ BestImage = NULL;
+ BackupImage = NULL;
+ RomHeader.Raw = *Rom;
+ while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ if (*ImageSize <
+ RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)
+ ) {
+ return EFI_NOT_FOUND;
+ }
+
+ Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
+
+ if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
+ Match = FALSE;
+ if (Pcir->VendorId == VendorId) {
+ if (Pcir->DeviceId == DeviceId) {
+ Match = TRUE;
+ } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {
+ DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);
+ //
+ // Checking the device list
+ //
+ while (*DeviceIdList != 0) {
+ if (*DeviceIdList == DeviceId) {
+ Match = TRUE;
+ break;
+ }
+ DeviceIdList ++;
+ }
+ }
+ }
+
+ if (Match) {
+ if (Csm16Revision >= 0x0300) {
+ //
+ // Case 1: CSM16 3.0
+ //
+ if (Pcir->Revision >= 3) {
+ //
+ // case 1.1: meets OpRom 3.0
+ // Perfect!!!
+ //
+ BestImage = RomHeader.Raw;
+ break;
+ } else {
+ //
+ // case 1.2: meets OpRom 2.x
+ // Store it and try to find the OpRom 3.0
+ //
+ BackupImage = RomHeader.Raw;
+ }
+ } else {
+ //
+ // Case 2: CSM16 2.x
+ //
+ if (Pcir->Revision >= 3) {
+ //
+ // case 2.1: meets OpRom 3.0
+ // Store it and try to find the OpRom 2.x
+ //
+ BackupImage = RomHeader.Raw;
+ } else {
+ //
+ // case 2.2: meets OpRom 2.x
+ // Perfect!!!
+ //
+ BestImage = RomHeader.Raw;
+ break;
+ }
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));
+ }
+ }
+
+ if ((Pcir->Indicator & 0x80) == 0x80) {
+ break;
+ } else {
+ RomHeader.Raw += 512 * Pcir->ImageLength;
+ }
+ }
+
+ if (BestImage == NULL) {
+ if (BackupImage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // The versions of CSM16 and OpRom don't match exactly
+ //
+ BestImage = BackupImage;
+ }
+ RomHeader.Raw = BestImage;
+ Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
+ *Rom = BestImage;
+ *ImageSize = Pcir->ImageLength * 512;
+
+ if (MaxRuntimeImageLength != NULL) {
+ if (Pcir->Revision < 3) {
+ *MaxRuntimeImageLength = 0;
+ } else {
+ *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
+ }
+ }
+
+ if (OpRomRevision != NULL) {
+ //
+ // Optional return PCI Data Structure revision
+ //
+ if (Pcir->Length >= 0x1C) {
+ *OpRomRevision = Pcir->Revision;
+ } else {
+ *OpRomRevision = 0;
+ }
+ }
+
+ if (ConfigUtilityCodeHeader != NULL) {
+ //
+ // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
+ //
+ if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {
+ *ConfigUtilityCodeHeader = NULL;
+ } else {
+ *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build a table of bridge info for PIRQ translation.
+
+ @param RoutingTable RoutingTable obtained from Platform.
+ @param RoutingTableEntries Number of RoutingTable entries.
+
+ @retval EFI_SUCCESS New Subordinate bus.
+ @retval EFI_NOT_FOUND No more Subordinate busses.
+
+**/
+EFI_STATUS
+CreateBridgeTable (
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN BridgeIndex;
+ UINTN Index;
+ UINTN Index1;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ BRIDGE_TABLE SlotBridges[MAX_BRIDGE_INDEX];
+ UINTN SlotBridgeIndex;
+
+ BridgeIndex = 0x00;
+ SlotBridgeIndex = 0x00;
+
+ //
+ // Assumption is table is built from low bus to high bus numbers.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {
+ PciIo->GetLocation (
+ PciIo,
+ &Bridges[BridgeIndex].PciSegment,
+ &Bridges[BridgeIndex].PciBus,
+ &Bridges[BridgeIndex].PciDevice,
+ &Bridges[BridgeIndex].PciFunction
+ );
+
+ Bridges[BridgeIndex].PrimaryBus = PciConfigHeader.Bridge.PrimaryBus;
+
+ Bridges[BridgeIndex].SecondaryBus = PciConfigHeader.Bridge.SecondaryBus;
+
+ Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;
+
+ for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){
+ //
+ // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
+ // Once we find one, store it in the SlotBridges[]
+ //
+ if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)
+ && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {
+ CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));
+ SlotBridgeIndex++;
+
+ break;
+ }
+ }
+
+ ++BridgeIndex;
+ }
+ }
+
+ //
+ // Pack up Bridges by removing those useless ones
+ //
+ for (Index = 0; Index < BridgeIndex;){
+ for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {
+ if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||
+ ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {
+ //
+ // We have found one that meets our criteria
+ //
+ Index++;
+ break;
+ }
+ }
+
+ //
+ // This one doesn't meet criteria, pack it
+ //
+ if (Index1 >= SlotBridgeIndex) {
+ for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {
+ CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));
+ }
+
+ BridgeIndex--;
+ }
+ }
+
+ NumberOfBridges = BridgeIndex;
+
+ //
+ // Sort bridges low to high by Secondary bus followed by subordinate bus
+ //
+ if (NumberOfBridges > 1) {
+ Index = 0;
+ do {
+ SortedBridgeIndex[Index] = Index;
+ ++Index;
+ } while (Index < NumberOfBridges);
+
+ for (Index = 0; Index < NumberOfBridges - 1; Index++) {
+ for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {
+ if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {
+ SortedBridgeIndex[Index] = Index1;
+ SortedBridgeIndex[Index1] = Index;
+ }
+
+ if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&
+ (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)
+ ) {
+ SortedBridgeIndex[Index] = Index1;
+ SortedBridgeIndex[Index1] = Index;
+ }
+ }
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find base Bridge for device.
+
+ @param Private Legacy BIOS Instance data
+ @param PciBus Input = Bus of device.
+ @param PciDevice Input = Device.
+ @param RoutingTable The platform specific routing table
+ @param RoutingTableEntries Number of entries in table
+
+ @retval EFI_SUCCESS At base bus.
+ @retval EFI_NOT_FOUND Behind a bridge.
+
+**/
+EFI_STATUS
+GetBaseBus (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN UINTN PciBus,
+ IN UINTN PciDevice,
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < RoutingTableEntries; Index++) {
+ if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Translate PIRQ through busses
+
+ @param Private Legacy BIOS Instance data
+ @param PciBus Input = Bus of device. Output = Translated Bus
+ @param PciDevice Input = Device. Output = Translated Device
+ @param PciFunction Input = Function. Output = Translated Function
+ @param PirqIndex Input = Original PIRQ index. If single function
+ device then 0, otherwise 0-3.
+ Output = Translated Index
+
+ @retval EFI_SUCCESS Pirq successfully translated.
+ @retval EFI_NOT_FOUND The device is not behind any known bridge.
+
+**/
+EFI_STATUS
+TranslateBusPirq (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN OUT UINTN *PciBus,
+ IN OUT UINTN *PciDevice,
+ IN OUT UINTN *PciFunction,
+ IN OUT UINT8 *PirqIndex
+ )
+{
+ /*
+ This routine traverses the PCI busses from base slot
+ and translates the PIRQ register to the appropriate one.
+
+ Example:
+
+ Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
+ Primary bus# = 0
+ Secondary bus # = 1
+ Subordinate bus # is highest bus # behind this bus
+ Bus 1, Device 0 is Slot 0 and is not a bridge.
+ Bus 1, Device 1 is Slot 1 and is a bridge.
+ Slot PIRQ routing is A,B,C,D.
+ Primary bus # = 1
+ Secondary bus # = 2
+ Subordinate bus # = 5
+ Bus 2, Device 6 is a bridge. It has no bridges behind it.
+ Primary bus # = 2
+ Secondary bus # = 3
+ Subordinate bus # = 3
+ Bridge PIRQ routing is C,D,A,B
+ Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
+ Primary bus # = 2
+ Secondary bus = 4 Device 6 takes bus 2.
+ Subordinate bus = 5.
+ Bridge PIRQ routing is D,A,B,C
+ Bus 4, Device 2 is a bridge. It has no bridges behind it.
+ Primary bus # = 4
+ Secondary bus # = 5
+ Subordinate bus = 5
+ Bridge PIRQ routing is B,C,D,A
+ Bus 5, Device 1 is to be programmed.
+ Device PIRQ routing is C,D,A,B
+
+
+Search busses starting from slot bus for final bus >= Secondary bus and
+final bus <= Suborninate bus. Assumption is bus entries increase in bus
+number.
+Starting PIRQ is A,B,C,D.
+Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
+ 7 modulo 4 giving (D,A,B,C).
+Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
+ (B,C,D,A).
+No other busses match criteria. Device to be programmed is Bus 5, Device 1.
+Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
+
+*/
+ UINTN LocalBus;
+ UINTN LocalDevice;
+ UINTN BaseBus;
+ UINTN BaseDevice;
+ UINTN BaseFunction;
+ UINT8 LocalPirqIndex;
+ BOOLEAN BaseIndexFlag;
+ UINTN BridgeIndex;
+ UINTN SBridgeIndex;
+ BaseIndexFlag = FALSE;
+ BridgeIndex = 0x00;
+
+ LocalPirqIndex = *PirqIndex;
+ LocalBus = *PciBus;
+ LocalDevice = *PciDevice;
+ BaseBus = *PciBus;
+ BaseDevice = *PciDevice;
+ BaseFunction = *PciFunction;
+
+ //
+ // LocalPirqIndex list PIRQs in rotated fashion
+ // = 0 A,B,C,D
+ // = 1 B,C,D,A
+ // = 2 C,D,A,B
+ // = 3 D,A,B,C
+ //
+
+ for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {
+ SBridgeIndex = SortedBridgeIndex[BridgeIndex];
+ //
+ // Check if device behind this bridge
+ //
+ if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {
+ //
+ // If BaseIndexFlag = FALSE then have found base bridge, i.e
+ // bridge in slot. Save info for use by IRQ routing table.
+ //
+ if (!BaseIndexFlag) {
+ BaseBus = Bridges[SBridgeIndex].PciBus;
+ BaseDevice = Bridges[SBridgeIndex].PciDevice;
+ BaseFunction = Bridges[SBridgeIndex].PciFunction;
+ BaseIndexFlag = TRUE;
+ } else {
+ LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);
+ }
+
+ //
+ // Check if at device. If not get new PCI location & PIRQ
+ //
+ if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {
+ //
+ // Translate PIRQ
+ //
+ LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);
+ break;
+ }
+ }
+ }
+
+ //
+ // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
+ //
+ if(BridgeIndex >= NumberOfBridges){
+ DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));
+ }
+
+ *PirqIndex = LocalPirqIndex;
+ *PciBus = BaseBus;
+ *PciDevice = BaseDevice;
+ *PciFunction = BaseFunction;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Copy the $PIR table as required.
+
+ @param Private Legacy BIOS Instance data
+ @param RoutingTable Pointer to IRQ routing table
+ @param RoutingTableEntries IRQ routing table entries
+ @param PirqTable Pointer to $PIR table
+ @param PirqTableSize Length of table
+
+**/
+VOID
+CopyPirqTable (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries,
+ IN EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable,
+ IN UINTN PirqTableSize
+ )
+{
+ EFI_IA32_REGISTER_SET Regs;
+ UINT32 Granularity;
+
+ //
+ // Copy $PIR table, if it exists.
+ //
+ if (PirqTable != NULL) {
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Private->InternalIrqRoutingTable = RoutingTable;
+ Private->NumberIrqRoutingEntries = (UINT16) (RoutingTableEntries);
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) PirqTableSize;
+ //
+ // Allocate at F segment according to PCI IRQ Routing Table Specification
+ //
+ Regs.X.BX = (UINT16) 0x1;
+ //
+ // 16-byte boundary alignment requirement according to
+ // PCI IRQ Routing Table Specification
+ //
+ Regs.X.DX = 0x10;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));
+ } else {
+ DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));
+ Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;
+ CopyMem (
+ (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,
+ PirqTable,
+ PirqTableSize
+ );
+ }
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ }
+
+ Private->PciInterruptLine = TRUE;
+ mHandleCount = 0;
+}
+
+/**
+ Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
+
+ @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
+
+**/
+VOID
+DumpPciHandle (
+ IN EFI_LEGACY_INSTALL_PCI_HANDLER *PciHandle
+ )
+{
+ DEBUG ((EFI_D_INFO, "PciBus - %02x\n", (UINTN)PciHandle->PciBus));
+ DEBUG ((EFI_D_INFO, "PciDeviceFun - %02x\n", (UINTN)PciHandle->PciDeviceFun));
+ DEBUG ((EFI_D_INFO, "PciSegment - %02x\n", (UINTN)PciHandle->PciSegment));
+ DEBUG ((EFI_D_INFO, "PciClass - %02x\n", (UINTN)PciHandle->PciClass));
+ DEBUG ((EFI_D_INFO, "PciSubclass - %02x\n", (UINTN)PciHandle->PciSubclass));
+ DEBUG ((EFI_D_INFO, "PciInterface - %02x\n", (UINTN)PciHandle->PciInterface));
+
+ DEBUG ((EFI_D_INFO, "PrimaryIrq - %02x\n", (UINTN)PciHandle->PrimaryIrq));
+ DEBUG ((EFI_D_INFO, "PrimaryReserved - %02x\n", (UINTN)PciHandle->PrimaryReserved));
+ DEBUG ((EFI_D_INFO, "PrimaryControl - %04x\n", (UINTN)PciHandle->PrimaryControl));
+ DEBUG ((EFI_D_INFO, "PrimaryBase - %04x\n", (UINTN)PciHandle->PrimaryBase));
+ DEBUG ((EFI_D_INFO, "PrimaryBusMaster - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));
+
+ DEBUG ((EFI_D_INFO, "SecondaryIrq - %02x\n", (UINTN)PciHandle->SecondaryIrq));
+ DEBUG ((EFI_D_INFO, "SecondaryReserved - %02x\n", (UINTN)PciHandle->SecondaryReserved));
+ DEBUG ((EFI_D_INFO, "SecondaryControl - %04x\n", (UINTN)PciHandle->SecondaryControl));
+ DEBUG ((EFI_D_INFO, "SecondaryBase - %04x\n", (UINTN)PciHandle->SecondaryBase));
+ DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));
+ return;
+}
+
+/**
+ Copy the $PIR table as required.
+
+ @param Private Legacy BIOS Instance data
+ @param PciIo Pointer to PCI_IO protocol
+ @param PciIrq Pci IRQ number
+ @param PciConfigHeader Type00 Pci configuration header
+
+**/
+VOID
+InstallLegacyIrqHandler (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 PciIrq,
+ IN PCI_TYPE00 *PciConfigHeader
+ )
+{
+ EFI_IA32_REGISTER_SET Regs;
+ UINT16 LegMask;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+ UINT16 PrimaryMaster;
+ UINT16 SecondaryMaster;
+ UINTN TempData;
+ UINTN RegisterAddress;
+ UINT32 Granularity;
+
+ PrimaryMaster = 0;
+ SecondaryMaster = 0;
+ Legacy8259 = Private->Legacy8259;
+ //
+ // Disable interrupt in PIC, in case shared, to prevent an
+ // interrupt from occuring.
+ //
+ Legacy8259->GetMask (
+ Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));
+
+ Legacy8259->SetMask (
+ Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ Private->IntThunk->PciHandler.PciBus = (UINT8) PciBus;
+ Private->IntThunk->PciHandler.PciDeviceFun = (UINT8) ((PciDevice << 3) + PciFunction);
+ Private->IntThunk->PciHandler.PciSegment = (UINT8) PciSegment;
+ Private->IntThunk->PciHandler.PciClass = PciConfigHeader->Hdr.ClassCode[2];
+ Private->IntThunk->PciHandler.PciSubclass = PciConfigHeader->Hdr.ClassCode[1];
+ Private->IntThunk->PciHandler.PciInterface = PciConfigHeader->Hdr.ClassCode[0];
+
+ //
+ // Use native mode base address registers in two cases:
+ // 1. Programming Interface (PI) register indicates Primary Controller is
+ // in native mode OR
+ // 2. PCI device Sub Class Code is not IDE
+ //
+ Private->IntThunk->PciHandler.PrimaryBusMaster = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);
+ if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ Private->IntThunk->PciHandler.PrimaryIrq = PciIrq;
+ Private->IntThunk->PciHandler.PrimaryBase = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);
+ Private->IntThunk->PciHandler.PrimaryControl = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);
+ } else {
+ Private->IntThunk->PciHandler.PrimaryIrq = 14;
+ Private->IntThunk->PciHandler.PrimaryBase = 0x1f0;
+ Private->IntThunk->PciHandler.PrimaryControl = 0x3f6;
+ }
+ //
+ // Secondary controller data
+ //
+ if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {
+ Private->IntThunk->PciHandler.SecondaryBusMaster = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);
+ PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);
+ SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);
+
+ //
+ // Clear pending interrupts in Bus Master registers
+ //
+ IoWrite16 (PrimaryMaster, 0x04);
+ IoWrite16 (SecondaryMaster, 0x04);
+
+ }
+
+ //
+ // Use native mode base address registers in two cases:
+ // 1. Programming Interface (PI) register indicates Secondary Controller is
+ // in native mode OR
+ // 2. PCI device Sub Class Code is not IDE
+ //
+ if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ Private->IntThunk->PciHandler.SecondaryIrq = PciIrq;
+ Private->IntThunk->PciHandler.SecondaryBase = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);
+ Private->IntThunk->PciHandler.SecondaryControl = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);
+ } else {
+
+ Private->IntThunk->PciHandler.SecondaryIrq = 15;
+ Private->IntThunk->PciHandler.SecondaryBase = 0x170;
+ Private->IntThunk->PciHandler.SecondaryControl = 0x376;
+ }
+
+ //
+ // Clear pending interrupts in IDE Command Block Status reg before we
+ // Thunk to CSM16 below. Don't want a pending Interrupt before we
+ // install the handlers as wierd corruption would occur and hang system.
+ //
+ //
+ // Read IDE CMD blk status reg to clear out any pending interrupts.
+ // Do here for Primary and Secondary IDE channels
+ //
+ RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;
+ IoRead8 (RegisterAddress);
+ RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;
+ IoRead8 (RegisterAddress);
+
+ Private->IntThunk->PciHandler.PrimaryReserved = 0;
+ Private->IntThunk->PciHandler.SecondaryReserved = 0;
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Regs.X.AX = Legacy16InstallPciHandler;
+ TempData = (UINTN) &Private->IntThunk->PciHandler;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+
+ DumpPciHandle (&Private->IntThunk->PciHandler);
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+}
+
+
+/**
+ Program the interrupt routing register in all the PCI devices. On a PC AT system
+ this register contains the 8259 IRQ vector that matches it's PCI interrupt.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_ALREADY_STARTED All PCI devices have been processed.
+
+**/
+EFI_STATUS
+PciProgramAllInterruptLineRegisters (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+ EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ UINT8 InterruptPin;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN MassStorageHandleCount;
+ EFI_HANDLE *MassStorageHandleBuffer;
+ UINTN MassStorageHandleIndex;
+ UINT8 PciIrq;
+ UINT16 Command;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
+ UINTN RoutingTableEntries;
+ UINT16 LegMask;
+ UINT16 LegEdgeLevel;
+ PCI_TYPE00 PciConfigHeader;
+ EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable;
+ UINTN PirqTableSize;
+ UINTN Flags;
+ HDD_INFO *HddInfo;
+ UINT64 Supports;
+
+ //
+ // Note - This routine use to return immediately if Private->PciInterruptLine
+ // was true. Routine changed since resets etc can cause not all
+ // PciIo protocols to be registered the first time through.
+ // New algorithm is to do the copy $PIR table on first pass and save
+ // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
+ // a larger handle count then proceed with body of function else return
+ // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
+ // If zero then function unprogrammed else skip function.
+ //
+ Legacy8259 = Private->Legacy8259;
+ LegacyInterrupt = Private->LegacyInterrupt;
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+
+ LegacyBiosPlatform->GetRoutingTable (
+ Private->LegacyBiosPlatform,
+ (VOID *) &RoutingTable,
+ &RoutingTableEntries,
+ (VOID *) &PirqTable,
+ &PirqTableSize,
+ NULL,
+ NULL
+ );
+ CreateBridgeTable (RoutingTable, RoutingTableEntries);
+
+ if (!Private->PciInterruptLine) {
+ CopyPirqTable (
+ Private,
+ RoutingTable,
+ RoutingTableEntries,
+ PirqTable,
+ PirqTableSize
+ );
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ if (HandleCount == mHandleCount) {
+ FreePool (HandleBuffer);
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (mHandleCount == 0x00) {
+ mHandleCount = HandleCount;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // If VGA then only do VGA to allow drives fore time to spin up
+ // otherwise assign PCI IRQs to all potential devices.
+ //
+ if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {
+ continue;
+ } else {
+ //
+ // Force code to go through all handles next time called if video.
+ // This will catch case where HandleCount doesn't change but want
+ // to get drive info etc.
+ //
+ mHandleCount = 0x00;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Test whether the device can be enabled or not.
+ // If it can't be enabled, then just skip it to avoid further operation.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+ Command = PciConfigHeader.Hdr.Command;
+
+ //
+ // Note PciIo->Attributes does not program the PCI command register
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ InterruptPin = PciConfigHeader.Device.InterruptPin;
+
+ if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ //
+ // Translate PIRQ index back thru busses to slot bus with InterruptPin
+ // zero based
+ //
+ InterruptPin -= 1;
+
+ Status = GetBaseBus (
+ Private,
+ PciBus,
+ PciDevice,
+ RoutingTable,
+ RoutingTableEntries
+ );
+
+ if (Status == EFI_NOT_FOUND) {
+ TranslateBusPirq (
+ Private,
+ &PciBus,
+ &PciDevice,
+ &PciFunction,
+ &InterruptPin
+ );
+ }
+ //
+ // Translate InterruptPin(0-3) into PIRQ
+ //
+ Status = LegacyBiosPlatform->TranslatePirq (
+ LegacyBiosPlatform,
+ PciBus,
+ (PciDevice << 3),
+ PciFunction,
+ &InterruptPin,
+ &PciIrq
+ );
+ //
+ // TranslatePirq() should never fail or we are in trouble
+ // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));
+ continue;
+ }
+
+ LegacyInterrupt->WritePirq (
+ LegacyInterrupt,
+ InterruptPin,
+ PciIrq
+ );
+
+ //
+ // Check if device has an OPROM associated with it.
+ // If not invoke special 16-bit function, to allow 16-bit
+ // code to install an interrupt handler.
+ //
+ Status = LegacyBiosCheckPciRom (
+ &Private->LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ NULL,
+ &Flags
+ );
+ if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {
+ //
+ // Device has no OPROM associated with it and is a mass storage
+ // device. It needs to have an PCI IRQ handler installed. To
+ // correctly install the handler we need to insure device is
+ // connected. The device may just have register itself but not
+ // been connected. Re-read PCI config space after as it can
+ // change
+ //
+ //
+ // Get IDE Handle. If matches handle then skip ConnectController
+ // since ConnectController may force native mode and we don't
+ // want that for primary IDE controller
+ //
+ MassStorageHandleCount = 0;
+ MassStorageHandleBuffer = NULL;
+ LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &MassStorageHandleBuffer,
+ &MassStorageHandleCount,
+ NULL
+ );
+
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+
+ LegacyBiosBuildIdeData (Private, &HddInfo, 0);
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {
+ if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {
+ //
+ // InstallLegacyIrqHandler according to Platform requirement
+ //
+ InstallLegacyIrqHandler (
+ Private,
+ PciIo,
+ PciIrq,
+ &PciConfigHeader
+ );
+ break;
+ }
+ }
+ }
+ //
+ // Write InterruptPin and enable 8259.
+ //
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x3c,
+ 1,
+ &PciIrq
+ );
+ Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));
+
+ Legacy8259->GetMask (
+ Legacy8259,
+ &LegMask,
+ &LegEdgeLevel,
+ NULL,
+ NULL
+ );
+
+ LegMask = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));
+ LegEdgeLevel = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));
+ Legacy8259->SetMask (
+ Legacy8259,
+ &LegMask,
+ &LegEdgeLevel,
+ NULL,
+ NULL
+ );
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find & verify PnP Expansion header in ROM image
+
+ @param Private Protocol instance pointer.
+ @param FirstHeader 1 = Find first header, 0 = Find successive headers
+ @param PnpPtr Input Rom start if FirstHeader =1, Current Header
+ otherwise Output Next header, if it exists
+
+ @retval EFI_SUCCESS Next Header found at BasePnpPtr
+ @retval EFI_NOT_FOUND No more headers
+
+**/
+EFI_STATUS
+FindNextPnpExpansionHeader (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BOOLEAN FirstHeader,
+ IN OUT LEGACY_PNP_EXPANSION_HEADER **PnpPtr
+
+ )
+{
+ UINTN TempData;
+ LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;
+ LocalPnpPtr = *PnpPtr;
+ if (FirstHeader == FIRST_INSTANCE) {
+ mBasePnpPtr = LocalPnpPtr;
+ mBbsRomSegment = (UINT16) ((UINTN) mBasePnpPtr >> 4);
+ //
+ // Offset 0x1a gives offset to PnP expansion header for the first
+ // instance, there after the structure gives the offset to the next
+ // structure
+ //
+ LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);
+ TempData = (*((UINT16 *) LocalPnpPtr));
+ } else {
+ TempData = (UINT16) LocalPnpPtr->NextHeader;
+ }
+
+ LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));
+
+ //
+ // Search for PnP table in Shadowed ROM
+ //
+ *PnpPtr = LocalPnpPtr;
+ if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+
+/**
+ Update list of Bev or BCV table entries.
+
+ @param Private Protocol instance pointer.
+ @param RomStart Table of ROM start address in RAM/ROM. PciIo _
+ Handle to PCI IO for this device
+ @param PciIo Instance of PCI I/O Protocol
+
+ @retval EFI_SUCCESS Always should succeed.
+
+**/
+EFI_STATUS
+UpdateBevBcvTable (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_LEGACY_EXPANSION_ROM_HEADER *RomStart,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ VOID *RomEnd;
+ BBS_TABLE *BbsTable;
+ UINTN BbsIndex;
+ EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;
+ LEGACY_PNP_EXPANSION_HEADER *PnpPtr;
+ BOOLEAN Instance;
+ EFI_STATUS Status;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINT8 Class;
+ UINT16 DeviceType;
+ Segment = 0;
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+ Class = 0;
+ DeviceType = BBS_UNKNOWN;
+
+ //
+ // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
+ // controller).
+ //
+ BbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+
+ BbsTable = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;
+ PnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;
+ PciPtr = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;
+
+ RomEnd = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);
+ Instance = FIRST_INSTANCE;
+ //
+ // OPROMs like PXE may not be tied to a piece of hardware and thus
+ // don't have a PciIo associated with them
+ //
+ if (PciIo != NULL) {
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x0b,
+ 1,
+ &Class
+ );
+
+ if (Class == PCI_CLASS_MASS_STORAGE) {
+ DeviceType = BBS_HARDDISK;
+ } else {
+ if (Class == PCI_CLASS_NETWORK) {
+ DeviceType = BBS_EMBED_NETWORK;
+ }
+ }
+ }
+
+ if (PciPtr >= (EFI_LEGACY_EXPANSION_ROM_HEADER *) ((UINTN) 0xc8000)) {
+ while (TRUE) {
+ Status = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);
+ Instance = NOT_FIRST_INSTANCE;
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // There can be additional $PnP headers within the OPROM.
+ // Example: SCSI can have one per drive.
+ //
+ BbsTable[BbsIndex].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ BbsTable[BbsIndex].DeviceType = DeviceType;
+ BbsTable[BbsIndex].Bus = (UINT32) Bus;
+ BbsTable[BbsIndex].Device = (UINT32) Device;
+ BbsTable[BbsIndex].Function = (UINT32) Function;
+ BbsTable[BbsIndex].StatusFlags.OldPosition = 0;
+ BbsTable[BbsIndex].StatusFlags.Reserved1 = 0;
+ BbsTable[BbsIndex].StatusFlags.Enabled = 0;
+ BbsTable[BbsIndex].StatusFlags.Failed = 0;
+ BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;
+ BbsTable[BbsIndex].StatusFlags.Reserved2 = 0;
+ BbsTable[BbsIndex].Class = PnpPtr->Class;
+ BbsTable[BbsIndex].SubClass = PnpPtr->SubClass;
+ BbsTable[BbsIndex].DescStringOffset = PnpPtr->ProductNamePointer;
+ BbsTable[BbsIndex].DescStringSegment = mBbsRomSegment;
+ BbsTable[BbsIndex].MfgStringOffset = PnpPtr->MfgPointer;
+ BbsTable[BbsIndex].MfgStringSegment = mBbsRomSegment;
+ BbsTable[BbsIndex].BootHandlerSegment = mBbsRomSegment;
+
+ //
+ // Have seen case where PXE base code have PnP expansion ROM
+ // header but no Bcv or Bev vectors.
+ //
+ if (PnpPtr->Bcv != 0) {
+ BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;
+ ++BbsIndex;
+ }
+
+ if (PnpPtr->Bev != 0) {
+ BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bev;
+ BbsTable[BbsIndex].DeviceType = BBS_BEV_DEVICE;
+ ++BbsIndex;
+ }
+
+ if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {
+ break;
+ }
+ }
+ }
+
+ BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
+ to chose the order. Skip any devices that have already have legacy
+ BIOS run.
+
+ @param Private Protocol instance pointer.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_UNSUPPORTED Cannot get VGA device handle.
+
+**/
+EFI_STATUS
+PciShadowRoms (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_HANDLE VgaHandle;
+ EFI_HANDLE FirstHandle;
+ VOID **RomStart;
+ UINTN Flags;
+ PCI_TYPE00 PciConfigHeader;
+ UINT16 *Command;
+ UINT64 Supports;
+
+ //
+ // Make the VGA device first
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ VgaHandle = HandleBuffer[0];
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Place the VGA handle as first.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ if (HandleBuffer[Index] == VgaHandle) {
+ FirstHandle = HandleBuffer[0];
+ HandleBuffer[0] = HandleBuffer[Index];
+ HandleBuffer[Index] = FirstHandle;
+ break;
+ }
+ }
+ //
+ // Allocate memory to save Command WORD from each device. We do this
+ // to restore devices to same state as EFI after switching to legacy.
+ //
+ Command = (UINT16 *) AllocatePool (
+ sizeof (UINT16) * (HandleCount + 1)
+ );
+ if (NULL == Command) {
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Disconnect all EFI devices first. This covers cases where alegacy BIOS
+ // may control multiple PCI devices.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save command register for "connect" loop
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+ Command[Index] = PciConfigHeader.Hdr.Command;
+ //
+ // Skip any device that already has a legacy ROM run
+ //
+ Status = IsLegacyRom (HandleBuffer[Index]);
+ if (!EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Stop EFI Drivers with oprom.
+ //
+ gBS->DisconnectController (
+ HandleBuffer[Index],
+ NULL,
+ NULL
+ );
+ }
+ //
+ // For every device that has not had a legacy ROM started. Start a legacy ROM.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Here make sure if one VGA have been shadowed,
+ // then wil not shadowed another one.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+
+ //
+ // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
+ // one will work in legacy mode (OPROM will be given control) and
+ // other Video devices will work in native mode (OS driver will handle these devices).
+ //
+ if (IS_PCI_DISPLAY (&Pci) && Index != 0) {
+ continue;
+ }
+ //
+ // Skip any device that already has a legacy ROM run
+ //
+ Status = IsLegacyRom (HandleBuffer[Index]);
+ if (!EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Install legacy ROM
+ //
+ Status = LegacyBiosInstallPciRom (
+ &Private->LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ &Flags,
+ NULL,
+ NULL,
+ (VOID **) &RomStart,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {
+ continue;
+ }
+ }
+ //
+ // Restore Command register so legacy has same devices enabled or disabled
+ // as EFI.
+ // If Flags = NO_ROM use command register as is. This covers the
+ // following cases:
+ // Device has no ROMs associated with it.
+ // Device has ROM associated with it but was already
+ // installed.
+ // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
+ // = ROM_FOUND and VALID_LEGACY_ROM, enable it.
+ //
+ if ((Flags & ROM_FOUND) == ROM_FOUND) {
+ if ((Flags & VALID_LEGACY_ROM) == 0) {
+ Command[Index] = 0;
+ } else {
+ //
+ // For several VGAs, only one of them can be enabled.
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ Command[Index] = 0x1f;
+ }
+ }
+ }
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x04,
+ 1,
+ &Command[Index]
+ );
+ }
+
+ FreePool (Command);
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded
+ @param RomImage Return the legacy PCI ROM for this device
+ @param RomSize Size of ROM Image
+ @param Flags Indicates if ROM found and if PC-AT.
+
+ @retval EFI_SUCCESS Legacy Option ROM availible for this device
+ @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCheckPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *Flags
+ )
+{
+ return LegacyBiosCheckPciRomEx (
+ This,
+ PciHandle,
+ RomImage,
+ RomSize,
+ NULL,
+ Flags,
+ NULL,
+ NULL
+ );
+
+}
+
+/**
+
+ Routine Description:
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
+ @param[out] RomImage Return the legacy PCI ROM for this device
+ @param[out] RomSize Size of ROM Image
+ @param[out] RuntimeImageLength Runtime size of ROM Image
+ @param[out] Flags Indicates if ROM found and if PC-AT.
+ @param[out] OpromRevision Revision of the PCI Rom
+ @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
+
+ @return EFI_SUCCESS Legacy Option ROM availible for this device
+ @return EFI_ALREADY_STARTED This device is already managed by its Oprom
+ @return EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+LegacyBiosCheckPciRomEx (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *RuntimeImageLength, OPTIONAL
+ OUT UINTN *Flags, OPTIONAL
+ OUT UINT8 *OpromRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN LocalRomSize;
+ VOID *LocalRomImage;
+ PCI_TYPE00 PciConfigHeader;
+ VOID *LocalConfigUtilityCodeHeader;
+
+ *Flags = NO_ROM;
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // See if the option ROM for PciHandle has already been executed
+ //
+ Status = IsLegacyRom (PciHandle);
+ if (!EFI_ERROR (Status)) {
+ *Flags |= (ROM_FOUND | VALID_LEGACY_ROM);
+ return EFI_SUCCESS;
+ }
+ //
+ // Check for PCI ROM Bar
+ //
+ LocalRomSize = (UINTN) PciIo->RomSize;
+ LocalRomImage = PciIo->RomImage;
+ if (LocalRomSize != 0) {
+ *Flags |= ROM_FOUND;
+ }
+
+ //
+ // PCI specification states you should check VendorId and Device Id.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Status = GetPciLegacyRom (
+ Private->Csm16PciInterfaceVersion,
+ PciConfigHeader.Hdr.VendorId,
+ PciConfigHeader.Hdr.DeviceId,
+ &LocalRomImage,
+ &LocalRomSize,
+ RuntimeImageLength,
+ OpromRevision,
+ &LocalConfigUtilityCodeHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Flags |= VALID_LEGACY_ROM;
+
+ //
+ // See if Configuration Utility Code Header valid
+ //
+ if (LocalConfigUtilityCodeHeader != NULL) {
+ *Flags |= ROM_WITH_CONFIG;
+ }
+
+ if (ConfigUtilityCodeHeader != NULL) {
+ *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;
+ }
+
+ if (RomImage != NULL) {
+ *RomImage = LocalRomImage;
+ }
+
+ if (RomSize != NULL) {
+ *RomSize = LocalRomSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_NOT_FOUND No PS2 Keyboard found
+
+**/
+EFI_STATUS
+EnablePs2Keyboard (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ UINTN Index;
+
+ //
+ // Get SimpleTextIn and find PS2 controller
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ NULL,
+ HandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Keyboard
+ // controller
+ //
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ HandleBuffer[Index]
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Load a legacy PC-AT OpROM for VGA controller.
+
+ @param Private Driver private data.
+
+ @retval EFI_SUCCESS Legacy ROM successfully installed for this device.
+ @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video
+ driver cannot be successfully disconnected, or VGA
+ thunk driver cannot be successfully connected.
+
+**/
+EFI_STATUS
+LegacyBiosInstallVgaRom (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE VgaHandle;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_HANDLE *ConnectHandleBuffer;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciConfigHeader;
+ UINT64 Supports;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ VOID *Interface;
+
+ //
+ // EfiLegacyBiosGuild attached to a device implies that there is a legacy
+ // BIOS associated with that device.
+ //
+ // There are 3 cases to consider.
+ // Case 1: No EFI driver is controlling the video.
+ // Action: Return EFI_SUCCESS from DisconnectController, search
+ // video thunk driver, and connect it.
+ // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
+ // not on the image handle.
+ // Action: Disconnect EFI driver.
+ // ConnectController for video thunk
+ // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
+ // on the image handle.
+ // Action: Do nothing and set Private->VgaInstalled = TRUE.
+ // Then this routine is not called any more.
+ //
+ //
+ // Get the VGA device.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ VgaHandle = HandleBuffer[0];
+
+ //
+ // Check whether video thunk driver already starts.
+ //
+ Status = gBS->OpenProtocolInformation (
+ VgaHandle,
+ &gEfiPciIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Status = gBS->HandleProtocol (
+ OpenInfoBuffer[Index].AgentHandle,
+ &gEfiLegacyBiosGuid,
+ (VOID **) &Interface
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // This should be video thunk driver which is managing video device
+ // So it need not start again
+ //
+ DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));
+ Private->VgaInstalled = TRUE;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Kick off the native EFI driver
+ //
+ Status = gBS->DisconnectController (
+ VgaHandle,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return Status;
+ }
+ }
+ //
+ // Find all the Thunk Driver
+ //
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));
+ ASSERT (ConnectHandleBuffer != NULL);
+
+ CopyMem (
+ ConnectHandleBuffer,
+ HandleBuffer,
+ sizeof (EFI_HANDLE) * HandleCount
+ );
+ ConnectHandleBuffer[HandleCount] = NULL;
+
+ FreePool (HandleBuffer);
+
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = gBS->HandleProtocol (
+ VgaHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (Status == EFI_SUCCESS) {
+ Private->VgaInstalled = TRUE;
+
+ //
+ // Attach the VGA thunk driver.
+ // Assume the video is installed. This prevents potential of infinite recursion.
+ //
+ Status = gBS->ConnectController (
+ VgaHandle,
+ ConnectHandleBuffer,
+ NULL,
+ TRUE
+ );
+ }
+
+ FreePool (ConnectHandleBuffer);
+
+ if (EFI_ERROR (Status)) {
+
+ Private->VgaInstalled = FALSE;
+
+ //
+ // Reconnect the EFI VGA driver.
+ //
+ gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Load a legacy PC-AT OpROM.
+
+ @param This Protocol instance pointer.
+ @param Private Driver's private data.
+ @param PciHandle The EFI handle for the PCI device. It could be
+ NULL if the OpROM image is not associated with
+ any device.
+ @param OpromRevision The revision of PCI PC-AT ROM image.
+ @param RomImage Pointer to PCI PC-AT ROM image header. It must not
+ be NULL.
+ @param ImageSize Size of the PCI PC-AT ROM image.
+ @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure
+ On output is the actual runtime image length
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_OUT_OF_RESOURCES No more space for this ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_HANDLE PciHandle,
+ IN UINT8 OpromRevision,
+ IN VOID *RomImage,
+ IN UINTN ImageSize,
+ IN OUT UINTN *RuntimeImageLength,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS PciEnableStatus;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 LocalDiskStart;
+ UINT8 LocalDiskEnd;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT8 VideoMode;
+ EFI_TIME BootTime;
+ UINT32 *BdaPtr;
+ UINT32 LocalTime;
+ UINT32 StartBbsIndex;
+ UINT32 EndBbsIndex;
+ UINTN TempData;
+ UINTN InitAddress;
+ UINTN RuntimeAddress;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT32 Granularity;
+
+ PciIo = NULL;
+ LocalDiskStart = 0;
+ LocalDiskEnd = 0;
+ Segment = 0;
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+ VideoMode = 0;
+ PhysicalAddress = 0;
+
+ PciProgramAllInterruptLineRegisters (Private);
+
+ if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {
+ //
+ // CSM16 3.0 meets PCI 3.0 OpROM
+ // first test if there is enough space for its INIT code
+ //
+ PhysicalAddress = CONVENTIONAL_MEMORY_TOP;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (ImageSize),
+ &PhysicalAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ InitAddress = (UINTN) PhysicalAddress;
+ //
+ // then test if there is enough space for its RT code
+ //
+ RuntimeAddress = Private->OptionRom;
+ if (RuntimeAddress + *RuntimeImageLength > mEndOpromShadowAddress) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ // CSM16 3.0 meets PCI 2.x OpROM
+ // CSM16 2.x meets PCI 2.x/3.0 OpROM
+ // test if there is enough space for its INIT code
+ //
+ InitAddress = PCI_START_ADDRESS (Private->OptionRom);
+ if (InitAddress + ImageSize > mEndOpromShadowAddress) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RuntimeAddress = InitAddress;
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ (UINT32) RuntimeAddress,
+ (UINT32) ImageSize,
+ &Granularity
+ );
+
+ DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));
+
+ CopyMem ((VOID *) InitAddress, RomImage, ImageSize);
+
+ //
+ // Read the highest disk number "installed: and assume a new disk will
+ // show up on the first drive past the current value.
+ // There are several considerations here:
+ // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
+ // the change until boot selection time frame.
+ // 2. BBS compliants drives will not change 40:75 until boot time.
+ // 3. Onboard IDE controllers will change 40:75
+ //
+ LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
+ if ((Private->Disk4075 + 0x80) < LocalDiskStart) {
+ //
+ // Update table since onboard IDE drives found
+ //
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = (UINT8) (Private->Disk4075 + 0x80);
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = LocalDiskStart;
+ Private->LegacyEfiHddTableIndex ++;
+ Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);
+ Private->DiskEnd = LocalDiskStart;
+ }
+
+ if (PciHandle != mVgaHandle) {
+
+ EnablePs2Keyboard ();
+
+ //
+ // Store current mode settings since PrepareToScanRom may change mode.
+ //
+ VideoMode = *(UINT8 *) ((UINTN) 0x449);
+ }
+ //
+ // Notify the platform that we are about to scan the ROM
+ //
+ Status = Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookPrepareToScanRom,
+ 0,
+ PciHandle,
+ &InitAddress,
+ NULL,
+ NULL
+ );
+
+ //
+ // If Status returned is EFI_UNSUPPORTED then abort due to platform
+ // policy.
+ //
+ if (Status == EFI_UNSUPPORTED) {
+ goto Done;
+ }
+
+ //
+ // Report corresponding status code
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)
+ );
+
+ //
+ // Generate number of ticks since midnight for BDA. Some OPROMs require
+ // this. Place result in 40:6C-6F
+ //
+ gRT->GetTime (&BootTime, NULL);
+ LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
+
+ //
+ // Multiply result by 18.2 for number of ticks since midnight.
+ // Use 182/10 to avoid floating point math.
+ //
+ LocalTime = (LocalTime * 182) / 10;
+ BdaPtr = (UINT32 *) ((UINTN) 0x46C);
+ *BdaPtr = LocalTime;
+
+ //
+ // Pass in handoff data
+ //
+ PciEnableStatus = EFI_UNSUPPORTED;
+ ZeroMem (&Regs, sizeof (Regs));
+ if (PciHandle != NULL) {
+
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Enable command register.
+ //
+ PciEnableStatus = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));
+ }
+
+ mIgnoreBbsUpdateFlag = FALSE;
+ Regs.X.AX = Legacy16DispatchOprom;
+
+ //
+ // Generate DispatchOpRomTable data
+ //
+ Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;
+ Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset = Private->Legacy16Table->PnPInstallationCheckOffset;
+ Private->IntThunk->DispatchOpromTable.OpromSegment = (UINT16) (InitAddress >> 4);
+ Private->IntThunk->DispatchOpromTable.PciBus = (UINT8) Bus;
+ Private->IntThunk->DispatchOpromTable.PciDeviceFunction = (UINT8) ((Device << 3) | Function);
+ Private->IntThunk->DispatchOpromTable.NumberBbsEntries = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ Private->IntThunk->DispatchOpromTable.BbsTablePointer = (UINT32) (UINTN) Private->BbsTablePtr;
+ Private->IntThunk->DispatchOpromTable.RuntimeSegment = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));
+ TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+ //
+ // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes
+ // Otherwise, it may cause the system to hang in some cases
+ //
+ if (!EFI_ERROR (PciEnableStatus)) {
+ DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+ } else {
+ Regs.X.BX = 0;
+ }
+
+ if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {
+ Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;
+ mIgnoreBbsUpdateFlag = TRUE;
+ }
+ //
+ // Check if non-BBS compliant drives found
+ //
+ if (Regs.X.BX != 0) {
+ LocalDiskEnd = (UINT8) (LocalDiskStart + Regs.H.BL);
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;
+ Private->DiskEnd = LocalDiskEnd;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
+ Private->LegacyEfiHddTableIndex += 1;
+ }
+ //
+ // Skip video mode set, if installing VGA
+ //
+ if (PciHandle != mVgaHandle) {
+ //
+ // Set mode settings since PrepareToScanRom may change mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = VideoMode;
+ Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);
+ }
+ //
+ // Regs.X.AX from the adapter initializion is ignored since some adapters
+ // do not follow the standard of setting AX = 0 on success.
+ //
+ //
+ // The ROM could have updated it's size so we need to read again.
+ //
+ *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) (RuntimeAddress))->Size512 * 512;
+ DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));
+
+ //
+ // If OpROM runs in 2.0 mode
+ //
+ if (PhysicalAddress == 0) {
+ if (*RuntimeImageLength < ImageSize) {
+ //
+ // Make area from end of shadowed rom to end of original rom all ffs
+ //
+ gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);
+ }
+ }
+
+ LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
+
+ //
+ // Allow platform to perform any required actions after the
+ // OPROM has been initialized.
+ //
+ Status = Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookAfterRomInit,
+ 0,
+ PciHandle,
+ &RuntimeAddress,
+ NULL,
+ NULL
+ );
+ if (PciHandle != NULL) {
+ //
+ // If no PCI Handle then no header or Bevs.
+ //
+ if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {
+ StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ TempData = RuntimeAddress;
+ UpdateBevBcvTable (
+ Private,
+ (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,
+ PciIo
+ );
+ EndBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ LocalDiskEnd = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));
+ if (LocalDiskEnd != LocalDiskStart) {
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;
+ Private->DiskEnd = LocalDiskEnd;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
+ Private->LegacyEfiHddTableIndex += 1;
+ }
+ }
+ //
+ // Mark PCI device as having a legacy BIOS ROM loaded.
+ //
+ RomShadow (
+ PciHandle,
+ (UINT32) RuntimeAddress,
+ (UINT32) *RuntimeImageLength,
+ LocalDiskStart,
+ LocalDiskEnd
+ );
+ }
+
+ //
+ // Stuff caller's OPTIONAL return parameters.
+ //
+ if (RomShadowAddress != NULL) {
+ *RomShadowAddress = (VOID *) RuntimeAddress;
+ }
+
+ if (DiskStart != NULL) {
+ *DiskStart = LocalDiskStart;
+ }
+
+ if (DiskEnd != NULL) {
+ *DiskEnd = LocalDiskEnd;
+ }
+
+ Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (PhysicalAddress != 0) {
+ //
+ // Free pages when OpROM is 3.0
+ //
+ gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
+ }
+
+ //
+ // Insure all shadowed areas are locked
+ //
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xC0000,
+ 0x40000,
+ &Granularity
+ );
+
+ return Status;
+}
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded. This value is NULL if RomImage is
+ non-NULL. This is the normal case.
+ @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
+ if there is no hardware associated with the ROM
+ and thus no PciHandle, otherwise is must be NULL.
+ Example is PXE base code.
+ @param Flags Indicates if ROM found and if PC-AT.
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+ @param RomShadowedSize Size of RomShadowAddress in bytes
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_INVALID_PARAMETER PciHandle not found
+ @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
+ ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL * This,
+ IN EFI_HANDLE PciHandle,
+ IN VOID **RomImage,
+ OUT UINTN *Flags,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINT32 *RomShadowedSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ VOID *LocalRomImage;
+ UINTN ImageSize;
+ UINTN RuntimeImageLength;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINTN LastBus;
+ UINTN Index;
+ UINT8 OpromRevision;
+ UINT32 Granularity;
+ PCI_3_0_DATA_STRUCTURE *Pcir;
+
+ OpromRevision = 0;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ if (Private->Legacy16Table->LastPciBus == 0) {
+ //
+ // Get last bus number if not already found
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ LastBus = 0;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ if (PciBus > LastBus) {
+ LastBus = PciBus;
+ }
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ Private->Legacy16Table->LastPciBus = (UINT8) LastBus;
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ }
+
+ *Flags = 0;
+ if ((PciHandle != NULL) && (RomImage == NULL)) {
+ //
+ // If PciHandle has OpRom to Execute
+ // and OpRom are all associated with Hardware
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ if (!EFI_ERROR (Status)) {
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ //
+ // if video installed & OPROM is video return
+ //
+ if (
+ (
+ ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&
+ (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))
+ ||
+ ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&
+ (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))
+ )
+ &&
+ (!Private->VgaInstalled)
+ ) {
+ mVgaInstallationInProgress = TRUE;
+
+ //
+ // return EFI_UNSUPPORTED;
+ //
+ }
+ }
+ //
+ // To run any legacy image, the VGA needs to be installed first.
+ // if installing the video, then don't need the thunk as already installed.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ mVgaHandle = HandleBuffer[0];
+ if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {
+ //
+ // A return status of EFI_NOT_FOUND is considered valid (No EFI
+ // driver is controlling video.
+ //
+ mVgaInstallationInProgress = TRUE;
+ Status = LegacyBiosInstallVgaRom (Private);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ mVgaInstallationInProgress = FALSE;
+ return Status;
+ }
+ } else {
+ mVgaInstallationInProgress = FALSE;
+ }
+ }
+ }
+ //
+ // See if the option ROM for PciHandle has already been executed
+ //
+ Status = IsLegacyRom (PciHandle);
+
+ if (!EFI_ERROR (Status)) {
+ mVgaInstallationInProgress = FALSE;
+ GetShadowedRomParameters (
+ PciHandle,
+ DiskStart,
+ DiskEnd,
+ RomShadowAddress,
+ (UINTN *) RomShadowedSize
+ );
+ return EFI_SUCCESS;
+ }
+
+ Status = LegacyBiosCheckPciRomEx (
+ &Private->LegacyBios,
+ PciHandle,
+ &LocalRomImage,
+ &ImageSize,
+ &RuntimeImageLength,
+ Flags,
+ &OpromRevision,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // There is no PCI ROM in the ROM BAR or no onboard ROM
+ //
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ if (*RomImage == NULL) {
+ //
+ // If PciHandle is NULL, and no OpRom is to be associated
+ //
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+
+ LocalRomImage = *RomImage;
+ Pcir = (PCI_3_0_DATA_STRUCTURE *)
+ ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);
+ ImageSize = Pcir->ImageLength * 512;
+ if (Pcir->Length >= 0x1C) {
+ OpromRevision = Pcir->Revision;
+ } else {
+ OpromRevision = 0;
+ }
+ if (Pcir->Revision < 3) {
+ RuntimeImageLength = 0;
+ } else {
+ RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
+ }
+ }
+ //
+ // Shadow and initialize the OpROM.
+ //
+ ASSERT (Private->TraceIndex < 0x200);
+ Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;
+ Private->TraceIndex ++;
+ Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);
+ Status = LegacyBiosInstallRom (
+ This,
+ Private,
+ PciHandle,
+ OpromRevision,
+ LocalRomImage,
+ ImageSize,
+ &RuntimeImageLength,
+ DiskStart,
+ DiskEnd,
+ RomShadowAddress
+ );
+ if (RomShadowedSize != NULL) {
+ *RomShadowedSize = (UINT32) RuntimeImageLength;
+ }
+
+ mVgaInstallationInProgress = FALSE;
+ return Status;
+}
+
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c
new file mode 100644
index 0000000..f82121c
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c
@@ -0,0 +1,234 @@
+/** @file
+ Collect Sio information from Native EFI Drivers.
+ Sio is floppy, parallel, serial, ... hardware
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+
+/**
+ Collect EFI Info about legacy devices.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ DEVICE_PRODUCER_DATA_HEADER *SioPtr;
+ DEVICE_PRODUCER_SERIAL *Sio1Ptr;
+ DEVICE_PRODUCER_PARALLEL *Sio2Ptr;
+ DEVICE_PRODUCER_FLOPPY *Sio3Ptr;
+ EFI_HANDLE IsaBusController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN ResourceIndex;
+ UINTN ChildIndex;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
+ EFI_ISA_ACPI_RESOURCE *IoResource;
+ EFI_ISA_ACPI_RESOURCE *DmaResource;
+ EFI_ISA_ACPI_RESOURCE *InterruptResource;
+ UINTN EntryCount;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // Get the pointer to the SIO data structure
+ //
+ SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData;
+
+ //
+ // Zero the data in the SIO data structure
+ //
+ gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0);
+
+ //
+ // Find the ISA Bus Controller used for legacy
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIsaBusHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ IsaBusController = HandleBuffer[0];
+ if (!EFI_ERROR (Status)) {
+ //
+ // Force ISA Bus Controller to produce all ISA devices
+ //
+ gBS->ConnectController (IsaBusController, NULL, NULL, TRUE);
+ }
+ //
+ // Get the list of ISA controllers in the system
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Collect legacy information from each of the ISA controllers in the system
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ResourceList = IsaIo->ResourceList;
+
+ if (ResourceList == NULL) {
+ continue;
+ }
+ //
+ // Collect the resource types neededto fill in the SIO data structure
+ //
+ IoResource = NULL;
+ DmaResource = NULL;
+ InterruptResource = NULL;
+ for (ResourceIndex = 0;
+ ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList;
+ ResourceIndex++
+ ) {
+ switch (ResourceList->ResourceItem[ResourceIndex].Type) {
+ case EfiIsaAcpiResourceIo:
+ IoResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceMemory:
+ break;
+
+ case EfiIsaAcpiResourceDma:
+ DmaResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceInterrupt:
+ InterruptResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ default:
+ break;
+ }
+ }
+ //
+ // See if this is an ISA serial port
+ //
+ // Ignore DMA resource since it is always returned NULL
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) {
+
+ if (ResourceList->Device.UID <= 3 &&
+ IoResource != NULL &&
+ InterruptResource != NULL
+ ) {
+ //
+ // Get the handle of the child device that has opened the ISA I/O Protocol
+ //
+ Status = gBS->OpenProtocolInformation (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // We want resource for legacy even if no 32-bit driver installed
+ //
+ for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {
+ Sio1Ptr = &SioPtr->Serial[ResourceList->Device.UID];
+ Sio1Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio1Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio1Ptr->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;
+ }
+
+ FreePool (OpenInfoBuffer);
+ }
+ }
+ //
+ // See if this is an ISA parallel port
+ //
+ // Ignore DMA resource since it is always returned NULL, port
+ // only used in output mode.
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) {
+ if (ResourceList->Device.UID <= 2 &&
+ IoResource != NULL &&
+ InterruptResource != NULL &&
+ DmaResource != NULL
+ ) {
+ Sio2Ptr = &SioPtr->Parallel[ResourceList->Device.UID];
+ Sio2Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio2Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio2Ptr->Dma = (UINT8) DmaResource->StartRange;
+ Sio2Ptr->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;
+ }
+ }
+ //
+ // See if this is an ISA floppy controller
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) {
+ if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ if (!EFI_ERROR (Status)) {
+ Sio3Ptr = &SioPtr->Floppy;
+ Sio3Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio3Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio3Ptr->Dma = (UINT8) DmaResource->StartRange;
+ Sio3Ptr->NumberOfFloppy++;
+ }
+ }
+ }
+ //
+ // See if this is a mouse
+ // Always set mouse found so USB hot plug will work
+ //
+ // Ignore lower byte of HID. Pnp0fxx is any type of mouse.
+ //
+ // Hid = ResourceList->Device.HID & 0xff00ffff;
+ // PnpId = EISA_PNP_ID(0x0f00);
+ // if (Hid == PnpId) {
+ // if (ResourceList->Device.UID == 1) {
+ // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);
+ // if (!EFI_ERROR (Status)) {
+ //
+ SioPtr->MousePresent = 0x01;
+ //
+ // }
+ // }
+ // }
+ //
+ }
+
+ FreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c
new file mode 100644
index 0000000..c33288a
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c
@@ -0,0 +1,284 @@
+/** @file
+ Call into 16-bit BIOS code, Use AsmThunk16 function of BaseLib.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+THUNK_CONTEXT mThunkContext;
+
+/**
+ Thunk to 16-bit real mode and execute a software interrupt with a vector
+ of BiosInt. Regs will contain the 16-bit register context on entry and
+ exit.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ )
+{
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 0;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+
+ return InternalLegacyBiosFarCall (
+ This,
+ (UINT16) (((UINT32 *)NULL)[BiosInt] >> 16),
+ (UINT16) ((UINT32 *)NULL)[BiosInt],
+ Regs,
+ &Regs->X.Flags,
+ sizeof (Regs->X.Flags)
+ );
+}
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in
+ the target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 1;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+
+ return InternalLegacyBiosFarCall (This, Segment, Offset, Regs, Stack, StackSize);
+}
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+InternalLegacyBiosFarCall (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ UINTN Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ IA32_REGISTER_SET ThunkRegSet;
+ BOOLEAN InterruptState;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
+ ThunkRegSet.X.DI = Regs->X.DI;
+ ThunkRegSet.X.SI = Regs->X.SI;
+ ThunkRegSet.X.BP = Regs->X.BP;
+ ThunkRegSet.X.BX = Regs->X.BX;
+ ThunkRegSet.X.DX = Regs->X.DX;
+ //
+ // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
+ // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
+ //
+ ThunkRegSet.E.ECX = Regs->E.ECX;
+ ThunkRegSet.X.AX = Regs->X.AX;
+ ThunkRegSet.E.DS = Regs->X.DS;
+ ThunkRegSet.E.ES = Regs->X.ES;
+
+ CopyMem (&(ThunkRegSet.E.EFLAGS.UintN), &(Regs->X.Flags), sizeof (Regs->X.Flags));
+
+ //
+ // Clear the error flag; thunk code may set it. Stack16 should be the high address
+ // Make Statk16 address the low 16 bit must be not zero.
+ //
+ Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));
+
+ //
+ // Save and disable interrutp of debug timer
+ //
+ InterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy Stack to low memory stack
+ //
+ Stack16 -= StackSize / sizeof (UINT16);
+ CopyMem (Stack16, Stack, StackSize);
+ }
+
+ ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);
+ ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;
+ ThunkRegSet.E.CS = Segment;
+ ThunkRegSet.E.Eip = Offset;
+
+ mThunkContext.RealModeState = &ThunkRegSet;
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ AsmThunk16 (&mThunkContext);
+
+ //
+ // OPROM may allocate EBDA range by itself and change EBDA base and EBDA size.
+ // Get the current EBDA base address, and compared with pre-allocate minimum
+ // EBDA base address, if the current EBDA base address is smaller, it indicates
+ // PcdEbdaReservedMemorySize should be adjusted to larger for more OPROMs.
+ //
+ DEBUG_CODE (
+ {
+ UINTN EbdaBaseAddress;
+ UINTN ReservedEbdaBaseAddress;
+
+ EbdaBaseAddress = (*(UINT16 *) (UINTN) 0x40E) << 4;
+ ReservedEbdaBaseAddress = CONVENTIONAL_MEMORY_TOP - PcdGet32 (PcdEbdaReservedMemorySize);
+ ASSERT (ReservedEbdaBaseAddress <= EbdaBaseAddress);
+ }
+ );
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy low memory stack to Stack
+ //
+ CopyMem (Stack, Stack16, StackSize);
+ }
+
+ //
+ // Restore protected mode interrupt state
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ mThunkContext.RealModeState = NULL;
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Restore interrutp of debug timer
+ //
+ SaveAndSetDebugTimerInterrupt (InterruptState);
+
+ Regs->E.EDI = ThunkRegSet.E.EDI;
+ Regs->E.ESI = ThunkRegSet.E.ESI;
+ Regs->E.EBP = ThunkRegSet.E.EBP;
+ Regs->E.EBX = ThunkRegSet.E.EBX;
+ Regs->E.EDX = ThunkRegSet.E.EDX;
+ Regs->E.ECX = ThunkRegSet.E.ECX;
+ Regs->E.EAX = ThunkRegSet.E.EAX;
+ Regs->X.SS = ThunkRegSet.E.SS;
+ Regs->X.CS = ThunkRegSet.E.CS;
+ Regs->X.DS = ThunkRegSet.E.DS;
+ Regs->X.ES = ThunkRegSet.E.ES;
+
+ CopyMem (&(Regs->X.Flags), &(ThunkRegSet.E.EFLAGS.UintN), sizeof (Regs->X.Flags));
+
+ return (BOOLEAN) (Regs->X.Flags.CF == 1);
+}
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+
+ MemoryAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->IntThunk;
+
+ mThunkContext.RealModeBuffer = (VOID *) (UINTN) (MemoryAddress + ((sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE);
+ mThunkContext.RealModeBufferSize = EFI_PAGE_SIZE;
+ mThunkContext.ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE | THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15;
+
+ AsmPrepareThunk16 (&mThunkContext);
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S
new file mode 100644
index 0000000..95a0888
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S
@@ -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
index 0000000..750423e
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm
@@ -0,0 +1,71 @@
+;; @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.
+;
+;----------------------------------------------------------------------------
+
+InterruptRedirectionTemplate PROC
+ int 08h
+ DB 0cfh ; IRET
+ nop
+ int 09h
+ DB 0cfh ; IRET
+ nop
+ int 0ah
+ DB 0cfh ; IRET
+ nop
+ int 0bh
+ DB 0cfh ; IRET
+ nop
+ int 0ch
+ DB 0cfh ; IRET
+ nop
+ int 0dh
+ DB 0cfh ; IRET
+ nop
+ int 0eh
+ DB 0cfh ; IRET
+ nop
+ int 0fh
+ DB 0cfh ; IRET
+ nop
+InterruptRedirectionTemplate ENDP
+
+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
index 0000000..1fcea9c
--- /dev/null
+++ b/IntelFrameworkModulePkg/Include/Guid/LegacyBios.h
@@ -0,0 +1,36 @@
+/** @file
+ Defines a Tag GUID used to mark a UEFI legacy BIOS thunk driver based
+ on legacy BIOS services and legacy option ROM. This Tag GUID must be installed on
+ the ImageHandle of any module that follows the EFI Driver Model and uses
+ the Int86() or FarCall() services of the Legacy Bios Protocol to produce
+ a standard UEFI I/O Protocol.
+
+Copyright (c) 2006 - 2010, 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.
+
+**/
+
+#ifndef _LEGACY_BIOS_H_
+#define _LEGACY_BIOS_H_
+
+///
+/// The Global ID for the Legacy BIOS GUID that must be installed onto the ImageHandle
+/// of any module follows the EFI Driver Model and uses the Int86() or FarCall()
+/// services of the Legacy BIOS Protocol to produce a standard UEFI I/O Protocol.
+///
+#define EFI_LEGACY_BIOS_GUID \
+ { \
+ 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \
+ }
+
+extern EFI_GUID gEfiLegacyBiosGuid;
+
+#endif
diff --git a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
index 6661eaf..1543489 100644
--- a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+++ b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
@@ -56,6 +56,9 @@
## Include/Guid/AcpiVariable.h
gEfiAcpiVariableCompatiblityGuid = { 0xc020489e, 0x6db2, 0x4ef2, { 0x9a, 0xa5, 0xca, 0x6, 0xfc, 0x11, 0xd3, 0x6a }}
+ ## Include/Guid/LegacyBios.h
+ gEfiLegacyBiosGuid = { 0x2E3044AC, 0x879F, 0x490F, { 0x97, 0x60, 0xBB, 0xDF, 0xAF, 0x69, 0x5F, 0x50 }}
+
[Protocols]
## Vga Mini port binding for a VGA controller
# Include/Protocol/VgaMiniPort.h
@@ -87,6 +90,10 @@
## This PCD specifies whether Serial device use half hand shake.
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010043
+ ## Indicates if CSM support is needed for ACPI S3 Save.
+ # If TRUE, CSM support is enclosed for ACPI S3 Save.
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformCsmSupport|TRUE|BOOLEAN|0x00010044
+
[PcdsFixedAtBuild]
## FFS filename to find the default BMP Logo file.
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile |{ 0x99, 0x8b, 0xB2, 0x7B, 0xBB, 0x61, 0xD5, 0x11, 0x9A, 0x5D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }|VOID*|0x40000003
@@ -113,8 +120,25 @@
# This PCD should be set as HII type PCD by platform integrator mapped to variable L"HwErrRecSupport"
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|0|UINT16|0x40000002
-
[PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx, PcdsPatchableInModule]
## I/O Base address of floppy device controller.
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdFdcBaseAddress|0x3f0|UINT16|0x30000000
+ ## If TRUE, BiosVideo will switch to 80x25 Text VGA Mode when exiting boot service.
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoSetTextVgaModeEnable|FALSE|BOOLEAN|0x30000001
+
+ ## If TRUE, BiosVideo will check for VESA BIOS Extension service support.
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVbeEnable|TRUE|BOOLEAN|0x30000002
+
+ ## If TRUE, BiosVideo will check for VGA service support.
+ # NOTE: If both PcdBiosVideoCheckVbeEnable and PcdBiosVideoCheckVgaEnable are set to FALSE,
+ # that means Graphics Output protocol will not be installed, the VGA miniport protocol will be installed instead.
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVgaEnable|TRUE|BOOLEAN|0x30000003
+
+ ## If TRUE, memory space for legacy region will be set as cacheable.
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion|TRUE|BOOLEAN|0x00000004
+
+ ## The PCD is used to specify memory size with bytes to reserve EBDA for OPROM.
+ ## The value should be a multiple of 4KB.
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize|0x8000|UINT32|0x30000005
+
diff --git a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
index fd2898e..f986b48 100644
--- a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
+++ b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
@@ -39,11 +39,14 @@
0|DEFAULT # The entry: 0|DEFAULT is reserved and always required.
[LibraryClasses]
+ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
@@ -55,6 +58,8 @@
HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
PlatformBdsLib|IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
@@ -139,6 +144,11 @@
IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.inf
IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortDxe.inf
+ IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf
+ IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
+ IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf
+ IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf
+
IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf
IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf
IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.inf
@@ -147,6 +157,9 @@
IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf
IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf
+
+[Components.IA32,Components.X64,Components.IPF]
+ IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
[Components.IA32]
IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf