From bcecde140a561c64e297225904afebebd62336ce Mon Sep 17 00:00:00 2001 From: jljusten Date: Mon, 27 Jun 2011 23:32:56 +0000 Subject: 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 --- .../Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c | 782 +++++ .../Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h | 439 +++ .../Csm/BiosThunk/BlockIoDxe/BiosInt13.c | 1485 +++++++++ .../Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf | 58 + .../Csm/BiosThunk/BlockIoDxe/ComponentName.c | 309 ++ .../Csm/BiosThunk/BlockIoDxe/Edd.h | 209 ++ .../Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c | 2365 +++++++++++++ .../Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h | 744 +++++ .../Csm/BiosThunk/KeyboardDxe/ComponentName.c | 183 + .../Csm/BiosThunk/KeyboardDxe/ComponentName.h | 153 + .../Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf | 68 + .../Csm/BiosThunk/Snp16Dxe/BiosSnp16.c | 3507 ++++++++++++++++++++ .../Csm/BiosThunk/Snp16Dxe/BiosSnp16.h | 1655 +++++++++ .../Csm/BiosThunk/Snp16Dxe/ComponentName.c | 309 ++ .../Csm/BiosThunk/Snp16Dxe/Misc.c | 956 ++++++ .../Csm/BiosThunk/Snp16Dxe/Pxe.h | 613 ++++ .../Csm/BiosThunk/Snp16Dxe/PxeUndi.c | 1254 +++++++ .../Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf | 67 + .../Csm/BiosThunk/VideoDxe/BiosVideo.c | 3164 ++++++++++++++++++ .../Csm/BiosThunk/VideoDxe/BiosVideo.h | 532 +++ .../Csm/BiosThunk/VideoDxe/ComponentName.c | 313 ++ .../Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h | 451 +++ .../Csm/BiosThunk/VideoDxe/VideoDxe.inf | 80 + 23 files changed, 19696 insertions(+) create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h create mode 100644 IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf (limited to 'IntelFrameworkModulePkg/Csm/BiosThunk') diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c new file mode 100644 index 0000000000..309cf1a9ed --- /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.
+ +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 0000000000..de3c8d3518 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h @@ -0,0 +1,439 @@ +/** @file + +Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.
+ +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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 0000000000..c53490b0e3 --- /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.
+ +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 0000000000..3fcaa2723c --- /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.
+# +# 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 0000000000..88bca13d5f --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c @@ -0,0 +1,309 @@ +/** @file + +Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.
+ +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 0000000000..be4d8302cf --- /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.
+ +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 0000000000..06ef9d3345 --- /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.
+ +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 0000000000..c9f86a1dbd --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h @@ -0,0 +1,744 @@ +/** @file + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ +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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Driver Binding Externs +// +extern EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gBiosKeyboardComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2; + + +#include + +// +// 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 0000000000..caeecf70a7 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c @@ -0,0 +1,183 @@ +/** @file + +Copyright (c) 2006, Intel Corporation. All rights reserved.
+ +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 0000000000..a20061b753 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h @@ -0,0 +1,153 @@ +/** @file + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +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 0000000000..6166ba3ec3 --- /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.
+# +# 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 0000000000..2ae8daca73 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c @@ -0,0 +1,3507 @@ +/** @file + +Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.
+ +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 0000000000..b29059f685 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h @@ -0,0 +1,1655 @@ +/** @file + +Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.
+ +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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 0000000000..a95d83459d --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c @@ -0,0 +1,309 @@ +/** @file + +Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.
+ +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 0000000000..0b3543e12c --- /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.
+ +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 0000000000..54503a840f --- /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.
+ +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 0000000000..d35fc3f430 --- /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.
+ +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 0000000000..c37c4abb86 --- /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.
+# +# 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 0000000000..76591e7a47 --- /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.
+ +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 0000000000..45a75b9cd0 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h @@ -0,0 +1,532 @@ +/** @file + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 0000000000..1d70e5c4a3 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c @@ -0,0 +1,313 @@ +/** @file + +Copyright (c) 2006, Intel Corporation. All rights reserved.
+ +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 0000000000..dcda3fcd5a --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h @@ -0,0 +1,451 @@ +/** @file + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +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 0000000000..bf5f255dcf --- /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.
+# +# 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 -- cgit v1.2.3