1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			781 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			781 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions
 | 
						|
of the BSD License which accompanies this distribution.  The
 | 
						|
full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "BiosBlkIo.h"
 | 
						|
 | 
						|
//
 | 
						|
// Global data declaration
 | 
						|
//
 | 
						|
//
 | 
						|
// EFI Driver Binding Protocol Instance
 | 
						|
//
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding = {
 | 
						|
  BiosBlockIoDriverBindingSupported,
 | 
						|
  BiosBlockIoDriverBindingStart,
 | 
						|
  BiosBlockIoDriverBindingStop,
 | 
						|
  0x3,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb
 | 
						|
//
 | 
						|
EFI_LOCK                    mGlobalDataLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION);
 | 
						|
 | 
						|
//
 | 
						|
// Number of active instances of this protocol.  This is used to allocate/free
 | 
						|
// the shared buffer.  You must acquire the semaphore to modify.
 | 
						|
//
 | 
						|
UINTN                       mActiveInstances = 0;
 | 
						|
 | 
						|
//
 | 
						|
// Pointer to the beginning of the buffer used for real mode thunk
 | 
						|
// You must acquire the semaphore to modify.
 | 
						|
//
 | 
						|
EFI_PHYSICAL_ADDRESS        mBufferUnder1Mb = 0;
 | 
						|
 | 
						|
//
 | 
						|
// Address packet is a buffer under 1 MB for all version EDD calls
 | 
						|
//
 | 
						|
EDD_DEVICE_ADDRESS_PACKET   *mEddBufferUnder1Mb;
 | 
						|
 | 
						|
//
 | 
						|
// This is a buffer for INT 13h func 48 information
 | 
						|
//
 | 
						|
BIOS_LEGACY_DRIVE           *mLegacyDriverUnder1Mb;
 | 
						|
 | 
						|
//
 | 
						|
// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
 | 
						|
//  0xFE00 bytes is the max transfer size supported.
 | 
						|
//
 | 
						|
VOID                        *mEdd11Buffer;
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
  BLOCKIO_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, &gBlockIoVendorGuid, 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;
 | 
						|
}
 |