mirror of https://github.com/acidanthera/audk.git
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 - 2011, Intel Corporation. All rights reserved.<BR>
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions
|
|
of the BSD License which accompanies this distribution. The
|
|
full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "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;
|
|
}
|