2007-07-16 07:48:11 +02:00
|
|
|
/** @file
|
|
|
|
Partition driver that produces logical BlockIo devices from a physical
|
|
|
|
BlockIo device. The logical BlockIo devices are based on the format
|
|
|
|
of the raw block devices media. Currently "El Torito CD-ROM", Legacy
|
|
|
|
MBR, and GPT partition schemes are supported.
|
|
|
|
|
2011-04-01 05:07:38 +02:00
|
|
|
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
|
2010-04-24 11:33:45 +02:00
|
|
|
This program and the accompanying materials
|
2008-04-08 06:46:45 +02:00
|
|
|
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
|
2007-07-16 07:48:11 +02:00
|
|
|
|
2008-04-08 06:46:45 +02:00
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
|
|
#include "Partition.h"
|
|
|
|
|
|
|
|
//
|
2008-07-18 11:49:25 +02:00
|
|
|
// Partition Driver Global Variables.
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
|
|
|
|
PartitionDriverBindingSupported,
|
|
|
|
PartitionDriverBindingStart,
|
|
|
|
PartitionDriverBindingStop,
|
|
|
|
0xa,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2008-07-18 11:49:25 +02:00
|
|
|
//
|
2008-12-23 17:20:43 +01:00
|
|
|
// Prioritized function list to detect partition table.
|
2008-07-18 11:49:25 +02:00
|
|
|
//
|
2007-07-16 07:48:11 +02:00
|
|
|
PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
|
|
|
|
PartitionInstallGptChildHandles,
|
|
|
|
PartitionInstallElToritoChildHandles,
|
|
|
|
PartitionInstallMbrChildHandles,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
Test to see if this driver supports ControllerHandle. Any ControllerHandle
|
2011-05-03 12:31:41 +02:00
|
|
|
than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
|
|
|
|
supported.
|
2007-07-16 07:48:11 +02:00
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
@param[in] This Protocol instance pointer.
|
|
|
|
@param[in] ControllerHandle Handle of device to test.
|
|
|
|
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
|
|
|
|
device to start.
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
@retval EFI_SUCCESS This driver supports this device
|
|
|
|
@retval EFI_ALREADY_STARTED This driver is already running on this device
|
|
|
|
@retval other This driver does not support this device
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionDriverBindingSupported (
|
|
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
|
|
IN EFI_HANDLE ControllerHandle,
|
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
|
|
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
|
|
|
EFI_DEV_PATH *Node;
|
|
|
|
|
2009-09-16 05:05:46 +02:00
|
|
|
//
|
|
|
|
// Check RemainingDevicePath validation
|
|
|
|
//
|
2007-07-16 07:48:11 +02:00
|
|
|
if (RemainingDevicePath != NULL) {
|
2009-09-16 05:05:46 +02:00
|
|
|
//
|
|
|
|
// Check if RemainingDevicePath is the End of Device Path Node,
|
|
|
|
// if yes, go on checking other conditions
|
|
|
|
//
|
|
|
|
if (!IsDevicePathEnd (RemainingDevicePath)) {
|
|
|
|
//
|
|
|
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
|
|
|
// check its validation
|
|
|
|
//
|
|
|
|
Node = (EFI_DEV_PATH *) RemainingDevicePath;
|
|
|
|
if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
|
2007-07-16 07:48:11 +02:00
|
|
|
Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
|
2009-09-16 05:05:46 +02:00
|
|
|
DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
|
2011-05-03 12:31:41 +02:00
|
|
|
return EFI_UNSUPPORTED;
|
2009-09-16 05:05:46 +02:00
|
|
|
}
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
}
|
2009-09-16 05:05:46 +02:00
|
|
|
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
|
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
|
|
//
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
2009-09-16 05:05:46 +02:00
|
|
|
&gEfiDiskIoProtocolGuid,
|
|
|
|
(VOID **) &DiskIo,
|
2007-07-16 07:48:11 +02:00
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
|
|
);
|
|
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Close the I/O Abstraction(s) used to perform the supported test
|
|
|
|
//
|
|
|
|
gBS->CloseProtocol (
|
2008-07-18 11:49:25 +02:00
|
|
|
ControllerHandle,
|
2009-09-16 05:05:46 +02:00
|
|
|
&gEfiDiskIoProtocolGuid,
|
2008-07-18 11:49:25 +02:00
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
//
|
2009-09-16 05:05:46 +02:00
|
|
|
// Open the EFI Device Path protocol needed to perform the supported test
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
2009-09-16 05:05:46 +02:00
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
(VOID **) &ParentDevicePath,
|
2007-07-16 07:48:11 +02:00
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
|
|
);
|
|
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
2009-09-16 05:05:46 +02:00
|
|
|
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
2009-09-16 05:05:46 +02:00
|
|
|
// Close protocol, don't use device path protocol in the Support() function
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
2009-09-16 05:05:46 +02:00
|
|
|
&gEfiDevicePathProtocolGuid,
|
2007-07-16 07:48:11 +02:00
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
|
|
//
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiBlockIoProtocolGuid,
|
|
|
|
NULL,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
|
|
);
|
2011-05-03 12:31:41 +02:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
|
|
NULL,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// According to UEFI Spec 2.3.1, if a driver is written for a disk device,
|
|
|
|
// then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
|
|
|
|
// Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
|
|
|
|
// not be updated until the non blocking SCSI Pass Thru Protocol is provided.
|
|
|
|
// If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
|
|
|
|
//
|
|
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-05-03 12:31:41 +02:00
|
|
|
Start this driver on ControllerHandle by opening a Block IO or a Block IO2
|
|
|
|
or both, and Disk IO protocol, reading Device Path, and creating a child
|
|
|
|
handle with a Disk IO and device path protocol.
|
2007-07-16 07:48:11 +02:00
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
@param[in] This Protocol instance pointer.
|
|
|
|
@param[in] ControllerHandle Handle of device to bind driver to
|
|
|
|
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
|
|
|
|
device to start.
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
@retval EFI_SUCCESS This driver is added to ControllerHandle
|
|
|
|
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
|
|
|
|
@retval other This driver does not support this device
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionDriverBindingStart (
|
|
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
|
|
IN EFI_HANDLE ControllerHandle,
|
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_STATUS OpenStatus;
|
|
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
2011-05-03 12:31:41 +02:00
|
|
|
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
|
2007-07-16 07:48:11 +02:00
|
|
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
|
|
|
PARTITION_DETECT_ROUTINE *Routine;
|
2009-08-14 07:41:10 +02:00
|
|
|
BOOLEAN MediaPresent;
|
2010-05-05 07:21:38 +02:00
|
|
|
EFI_TPL OldTpl;
|
2007-07-16 07:48:11 +02:00
|
|
|
|
2010-05-05 07:21:38 +02:00
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
2009-09-16 05:05:46 +02:00
|
|
|
//
|
|
|
|
// Check RemainingDevicePath validation
|
|
|
|
//
|
|
|
|
if (RemainingDevicePath != NULL) {
|
|
|
|
//
|
|
|
|
// Check if RemainingDevicePath is the End of Device Path Node,
|
|
|
|
// if yes, return EFI_SUCCESS
|
|
|
|
//
|
|
|
|
if (IsDevicePathEnd (RemainingDevicePath)) {
|
2010-05-05 07:21:38 +02:00
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
goto Exit;
|
2009-09-16 05:05:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
//
|
|
|
|
// Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
|
|
|
|
// otherwise, return error.
|
|
|
|
//
|
2007-07-16 07:48:11 +02:00
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiBlockIoProtocolGuid,
|
|
|
|
(VOID **) &BlockIo,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
2010-05-05 07:21:38 +02:00
|
|
|
goto Exit;
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
2011-05-03 12:31:41 +02:00
|
|
|
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
|
|
(VOID **) &BlockIo2,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// According to UEFI Spec 2.3.1, if a driver is written for a disk device,
|
|
|
|
// then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
|
|
|
|
// Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
|
|
|
|
// not be updated until the non blocking SCSI Pass Thru Protocol is provided.
|
|
|
|
// If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
2011-05-03 12:31:41 +02:00
|
|
|
// Get the Device Path Protocol on ControllerHandle's handle.
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
(VOID **) &ParentDevicePath,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
|
2010-05-05 07:21:38 +02:00
|
|
|
goto Exit;
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDiskIoProtocolGuid,
|
|
|
|
(VOID **) &DiskIo,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
2010-05-05 07:21:38 +02:00
|
|
|
goto Exit;
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
OpenStatus = Status;
|
|
|
|
|
|
|
|
//
|
2009-08-14 07:41:10 +02:00
|
|
|
// Try to read blocks when there's media or it is removable physical partition.
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
2009-08-14 07:41:10 +02:00
|
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
MediaPresent = BlockIo->Media->MediaPresent;
|
|
|
|
if (BlockIo->Media->MediaPresent ||
|
|
|
|
(BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
|
|
|
// Try for GPT, then El Torito, and then legacy MBR partition types. If the
|
|
|
|
// media supports a given partition type install child handles to represent
|
|
|
|
// the partitions described by the media.
|
|
|
|
//
|
|
|
|
Routine = &mPartitionDetectRoutineTable[0];
|
|
|
|
while (*Routine != NULL) {
|
|
|
|
Status = (*Routine) (
|
|
|
|
This,
|
|
|
|
ControllerHandle,
|
|
|
|
DiskIo,
|
|
|
|
BlockIo,
|
2011-05-03 12:31:41 +02:00
|
|
|
BlockIo2,
|
2007-07-16 07:48:11 +02:00
|
|
|
ParentDevicePath
|
|
|
|
);
|
2009-08-14 07:41:10 +02:00
|
|
|
if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
|
2007-07-16 07:48:11 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Routine++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
|
|
|
|
// the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
|
|
|
|
// driver. So don't try to close them. Otherwise, we will break the dependency
|
|
|
|
// between the controller and the driver set up before.
|
|
|
|
//
|
2009-08-14 07:41:10 +02:00
|
|
|
// In the case that when the media changes on a device it will Reinstall the
|
|
|
|
// BlockIo interaface. This will cause a call to our Stop(), and a subsequent
|
|
|
|
// reentrant call to our Start() successfully. We should leave the device open
|
|
|
|
// when this happen. The "media change" case includes either the status is
|
|
|
|
// EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
|
|
|
|
//
|
|
|
|
if (EFI_ERROR (Status) &&
|
|
|
|
!EFI_ERROR (OpenStatus) &&
|
|
|
|
Status != EFI_MEDIA_CHANGED &&
|
|
|
|
!(MediaPresent && Status == EFI_NO_MEDIA)) {
|
2007-07-16 07:48:11 +02:00
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDiskIoProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
2011-05-03 12:31:41 +02:00
|
|
|
//
|
|
|
|
// Close Parent BlockIO2 if has.
|
|
|
|
//
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2010-05-05 07:21:38 +02:00
|
|
|
Exit:
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
2007-07-16 07:48:11 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-12-23 17:20:43 +01:00
|
|
|
Stop this driver on ControllerHandle. Support stopping any child handles
|
2007-07-16 07:48:11 +02:00
|
|
|
created by this driver.
|
|
|
|
|
|
|
|
@param This Protocol instance pointer.
|
|
|
|
@param ControllerHandle Handle of device to stop driver on
|
|
|
|
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
|
|
|
|
children is zero stop the entire bus driver.
|
|
|
|
@param ChildHandleBuffer List of Child Handles to Stop.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS This driver is removed ControllerHandle
|
|
|
|
@retval other This driver was not removed from this device
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionDriverBindingStop (
|
|
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
|
|
IN EFI_HANDLE ControllerHandle,
|
|
|
|
IN UINTN NumberOfChildren,
|
|
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN Index;
|
|
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
2011-05-03 12:31:41 +02:00
|
|
|
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
|
2007-07-16 07:48:11 +02:00
|
|
|
BOOLEAN AllChildrenStopped;
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
BlockIo = NULL;
|
|
|
|
BlockIo2 = NULL;
|
|
|
|
Private = NULL;
|
|
|
|
|
2007-07-16 07:48:11 +02:00
|
|
|
if (NumberOfChildren == 0) {
|
|
|
|
//
|
|
|
|
// Close the bus driver
|
|
|
|
//
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDiskIoProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
2011-05-03 12:31:41 +02:00
|
|
|
//
|
|
|
|
// Close Parent BlockIO2 if has.
|
|
|
|
//
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle
|
|
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
AllChildrenStopped = TRUE;
|
|
|
|
for (Index = 0; Index < NumberOfChildren; Index++) {
|
2011-05-03 12:31:41 +02:00
|
|
|
gBS->OpenProtocol (
|
|
|
|
ChildHandleBuffer[Index],
|
|
|
|
&gEfiBlockIoProtocolGuid,
|
|
|
|
(VOID **) &BlockIo,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
|
|
);
|
|
|
|
//
|
|
|
|
// Try to locate BlockIo2.
|
|
|
|
//
|
|
|
|
gBS->OpenProtocol (
|
|
|
|
ChildHandleBuffer[Index],
|
|
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
|
|
(VOID **) &BlockIo2,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ControllerHandle,
|
|
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
|
|
);
|
|
|
|
|
2011-05-06 09:15:41 +02:00
|
|
|
|
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
|
2007-07-16 07:48:11 +02:00
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
Status = gBS->CloseProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDiskIoProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ChildHandleBuffer[Index]
|
|
|
|
);
|
|
|
|
//
|
|
|
|
// All Software protocols have be freed from the handle so remove it.
|
|
|
|
// Remove the BlockIo Protocol if has.
|
|
|
|
// Remove the BlockIo2 Protocol if has.
|
|
|
|
//
|
|
|
|
if (BlockIo2 != NULL) {
|
2007-07-16 07:48:11 +02:00
|
|
|
BlockIo->FlushBlocks (BlockIo);
|
2011-05-03 12:31:41 +02:00
|
|
|
BlockIo2->FlushBlocksEx (BlockIo2, NULL);
|
2007-07-16 07:48:11 +02:00
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
2011-05-03 12:31:41 +02:00
|
|
|
ChildHandleBuffer[Index],
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
Private->DevicePath,
|
|
|
|
&gEfiBlockIoProtocolGuid,
|
|
|
|
&Private->BlockIo,
|
|
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
|
|
&Private->BlockIo2,
|
|
|
|
Private->EspGuid,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
BlockIo->FlushBlocks (BlockIo);
|
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
|
|
ChildHandleBuffer[Index],
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
Private->DevicePath,
|
|
|
|
&gEfiBlockIoProtocolGuid,
|
|
|
|
&Private->BlockIo,
|
|
|
|
Private->EspGuid,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
}
|
2007-07-16 07:48:11 +02:00
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
gBS->OpenProtocol (
|
|
|
|
ControllerHandle,
|
|
|
|
&gEfiDiskIoProtocolGuid,
|
|
|
|
(VOID **) &DiskIo,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
ChildHandleBuffer[Index],
|
|
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
FreePool (Private->DevicePath);
|
|
|
|
FreePool (Private);
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
AllChildrenStopped = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AllChildrenStopped) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Reset the Block Device.
|
|
|
|
|
|
|
|
@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
|
|
|
|
PartitionReset (
|
|
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
|
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
|
|
|
|
|
|
|
|
return Private->ParentBlockIo->Reset (
|
|
|
|
Private->ParentBlockIo,
|
|
|
|
ExtendedVerification
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2011-04-25 11:31:57 +02:00
|
|
|
/**
|
|
|
|
Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
|
|
|
|
for no media or media change case. Otherwise DefaultStatus is returned.
|
|
|
|
|
|
|
|
@param DiskIo Pointer to the DiskIo instance.
|
|
|
|
@param MediaId Id of the media, changes every time the media is replaced.
|
|
|
|
@param DefaultStatus The default status to return when it's not the no media
|
|
|
|
or media change case.
|
|
|
|
|
|
|
|
@retval EFI_NO_MEDIA There is no media.
|
|
|
|
@retval EFI_MEDIA_CHANGED The media was changed.
|
|
|
|
@retval others The default status to return.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
ProbeMediaStatus (
|
|
|
|
IN EFI_DISK_IO_PROTOCOL *DiskIo,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_STATUS DefaultStatus
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Read 1 byte from offset 0 but passing NULL as buffer pointer
|
|
|
|
//
|
|
|
|
Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, NULL);
|
|
|
|
if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
return DefaultStatus;
|
|
|
|
}
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Read by using the Disk IO protocol on the parent device. Lba addresses
|
|
|
|
must be converted to byte offsets.
|
|
|
|
|
|
|
|
@param This Protocol instance pointer.
|
|
|
|
@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 Buffer containing read data
|
|
|
|
|
|
|
|
@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 device addresses that are not
|
|
|
|
valid for the device.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionReadBlocks (
|
|
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_LBA Lba,
|
|
|
|
IN UINTN BufferSize,
|
|
|
|
OUT VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
UINT64 Offset;
|
|
|
|
|
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
|
|
|
|
|
|
|
|
if (BufferSize % Private->BlockSize != 0) {
|
2011-04-25 11:31:57 +02:00
|
|
|
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
|
|
|
|
if (Offset + BufferSize > Private->End) {
|
2011-04-25 11:31:57 +02:00
|
|
|
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
//
|
|
|
|
// Because some kinds of partition have different block size from their parent
|
|
|
|
// device, we call the Disk IO protocol on the parent device, not the Block IO
|
|
|
|
// protocol
|
|
|
|
//
|
|
|
|
return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Write by using the Disk IO protocol on the parent device. Lba addresses
|
|
|
|
must be converted to byte offsets.
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
@param[in] This Protocol instance pointer.
|
|
|
|
@param[in] MediaId Id of the media, changes every time the media is replaced.
|
|
|
|
@param[in] Lba The starting Logical Block Address to read from
|
|
|
|
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
|
|
|
|
@param[in] Buffer Buffer containing data to be written to device.
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
@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 a LBA that is not
|
|
|
|
valid for the device.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionWriteBlocks (
|
|
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_LBA Lba,
|
|
|
|
IN UINTN BufferSize,
|
2011-05-03 12:31:41 +02:00
|
|
|
IN VOID *Buffer
|
2007-07-16 07:48:11 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
UINT64 Offset;
|
|
|
|
|
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
|
|
|
|
|
|
|
|
if (BufferSize % Private->BlockSize != 0) {
|
2011-04-25 11:31:57 +02:00
|
|
|
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
|
|
|
|
if (Offset + BufferSize > Private->End) {
|
2011-04-25 11:31:57 +02:00
|
|
|
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
|
2007-07-16 07:48:11 +02:00
|
|
|
}
|
|
|
|
//
|
|
|
|
// Because some kinds of partition have different block size from their parent
|
|
|
|
// device, we call the Disk IO protocol on the parent device, not the Block IO
|
|
|
|
// protocol
|
|
|
|
//
|
|
|
|
return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Flush the parent Block Device.
|
|
|
|
|
|
|
|
@param This Protocol instance pointer.
|
|
|
|
|
|
|
|
@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
|
|
|
|
PartitionFlushBlocks (
|
|
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
|
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
|
|
|
|
|
|
|
|
return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
|
|
|
|
}
|
|
|
|
|
2011-09-19 08:24:50 +02:00
|
|
|
/**
|
|
|
|
Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
|
|
|
|
for no media or media change case. Otherwise DefaultStatus is returned.
|
|
|
|
|
|
|
|
@param BlockIo2 Pointer to the BlockIo2 instance.
|
|
|
|
@param MediaId Id of the media, changes every time the media is replaced.
|
|
|
|
@param DefaultStatus The default status to return when it's not the no media
|
|
|
|
or media change case.
|
|
|
|
|
|
|
|
@retval EFI_NO_MEDIA There is no media.
|
|
|
|
@retval EFI_MEDIA_CHANGED The media was changed.
|
|
|
|
@retval others The default status to return.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
ProbeMediaStatusEx (
|
|
|
|
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_STATUS DefaultStatus
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Read from LBA 0 but passing NULL as buffer pointer to detect the media status.
|
|
|
|
//
|
|
|
|
Status = BlockIo2->ReadBlocksEx (
|
|
|
|
BlockIo2,
|
|
|
|
MediaId,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
return DefaultStatus;
|
|
|
|
}
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
/**
|
|
|
|
Reset the Block Device throught Block I/O2 protocol.
|
|
|
|
|
|
|
|
@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
|
|
|
|
PartitionResetEx (
|
|
|
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
|
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
|
|
|
|
|
|
|
return Private->ParentBlockIo2->Reset (
|
|
|
|
Private->ParentBlockIo2,
|
|
|
|
ExtendedVerification
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Read BufferSize bytes from Lba into Buffer.
|
|
|
|
|
|
|
|
This function reads the requested number of blocks from the device. All the
|
|
|
|
blocks are read, or an error is returned.
|
|
|
|
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
|
|
|
|
non-blocking I/O is being used, the Event associated with this request will
|
|
|
|
not be signaled.
|
|
|
|
|
|
|
|
@param[in] This Indicates a pointer to the calling context.
|
|
|
|
@param[in] MediaId Id of the media, changes every time the media is
|
|
|
|
replaced.
|
|
|
|
@param[in] Lba The starting Logical Block Address to read from.
|
|
|
|
@param[in, out] Token A pointer to the token associated with the transaction.
|
|
|
|
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
|
|
|
|
@param[out] 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 read request was queued if Token->Event is
|
|
|
|
not NULL.The data was read correctly from the
|
|
|
|
device if the Token->Event is NULL.
|
|
|
|
@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 is not for the current media.
|
|
|
|
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
|
|
|
|
intrinsic 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.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
|
|
|
of resources.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionReadBlocksEx (
|
|
|
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_LBA Lba,
|
|
|
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
|
|
|
IN UINTN BufferSize,
|
|
|
|
OUT VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
UINT64 Offset;
|
|
|
|
UINT32 UnderRun;
|
|
|
|
|
2011-09-19 08:24:50 +02:00
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
if (Token == NULL) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (BufferSize % Private->BlockSize != 0) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
|
|
|
|
if (Offset + BufferSize > Private->End) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
|
|
|
|
// be multiple of BlockSize. If the Spec will be updated the DiskIO to support
|
|
|
|
// BlockIO2, this limitation will be removed and call DiskIO here.
|
|
|
|
//
|
|
|
|
Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
|
|
|
|
if (UnderRun != 0) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Because some partitions have different block size from their parent
|
|
|
|
// device, in that case the Block I/O2 couldn't be called.
|
|
|
|
//
|
|
|
|
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return Private->ParentBlockIo2->ReadBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Write BufferSize bytes from Lba into Buffer.
|
|
|
|
|
|
|
|
This function writes the requested number of blocks to the device. All blocks
|
|
|
|
are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
|
|
|
|
EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
|
|
|
|
being used, the Event associated with this request will not be signaled.
|
|
|
|
|
|
|
|
@param[in] This Indicates a pointer to the calling context.
|
|
|
|
@param[in] MediaId The media ID that the write request is for.
|
|
|
|
@param[in] Lba The starting logical block address to be written. The
|
|
|
|
caller is responsible for writing to only legitimate
|
|
|
|
locations.
|
|
|
|
@param[in, out] Token A pointer to the token associated with the transaction.
|
|
|
|
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
|
|
|
|
@param[in] Buffer A pointer to the source buffer for the data.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The write request was queued if Event is not NULL.
|
|
|
|
The data was written correctly to the device if
|
|
|
|
the Event is NULL.
|
|
|
|
@retval EFI_WRITE_PROTECTED The device can not be written to.
|
|
|
|
@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_DEVICE_ERROR The device reported an error while performing the write.
|
|
|
|
@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.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
|
|
|
of resources.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionWriteBlocksEx (
|
|
|
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_LBA Lba,
|
|
|
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
|
|
|
IN UINTN BufferSize,
|
|
|
|
IN VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
UINT64 Offset;
|
|
|
|
UINT32 UnderRun;
|
|
|
|
|
2011-09-19 08:24:50 +02:00
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
if (Token == NULL) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (BufferSize % Private->BlockSize != 0) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
|
|
|
|
if (Offset + BufferSize > Private->End) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
|
|
|
|
// be multiple of BlockSize. If the Spec will be updated the DiskIO to support
|
|
|
|
// BlockIO2, this limitation will be removed and call DiskIO here.
|
|
|
|
//
|
|
|
|
Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
|
|
|
|
if (UnderRun != 0) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Because some kinds of partition have different block size from their parent,
|
|
|
|
// in that case it couldn't call parent Block I/O2.
|
|
|
|
//
|
|
|
|
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
|
2011-09-19 08:24:50 +02:00
|
|
|
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Flush the Block Device.
|
|
|
|
|
|
|
|
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
|
|
|
|
is returned and non-blocking I/O is being used, the Event associated with
|
|
|
|
this request will not be signaled.
|
|
|
|
|
|
|
|
@param[in] This Indicates a pointer to the calling context.
|
2011-05-19 08:12:58 +02:00
|
|
|
@param[in, out] Token A pointer to the token associated with the transaction
|
2011-05-03 12:31:41 +02:00
|
|
|
|
|
|
|
@retval EFI_SUCCESS The flush request was queued if Event is not NULL.
|
|
|
|
All outstanding data was written correctly to the
|
|
|
|
device if the Event is NULL.
|
|
|
|
@retval EFI_DEVICE_ERROR The device reported an error while writting back
|
|
|
|
the data.
|
|
|
|
@retval EFI_WRITE_PROTECTED The device cannot be written to.
|
|
|
|
@retval EFI_NO_MEDIA There is no media in the device.
|
|
|
|
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
|
|
|
of resources.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
PartitionFlushBlocksEx (
|
|
|
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
|
|
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
|
|
|
|
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Because some kinds of partition have different block size from their parent,
|
|
|
|
// in that case it couldn't call parent Block I/O2.
|
|
|
|
//
|
|
|
|
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Private->ParentBlockIo2->FlushBlocksEx (Private->ParentBlockIo2, Token);
|
|
|
|
}
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Create a child handle for a logical block device that represents the
|
|
|
|
bytes Start to End of the Parent Block IO device.
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
@param[in] This Protocol instance pointer.
|
|
|
|
@param[in] ParentHandle Parent Handle for new child.
|
|
|
|
@param[in] ParentDiskIo Parent DiskIo interface.
|
|
|
|
@param[in] ParentBlockIo Parent BlockIo interface.
|
|
|
|
@param[in] ParentBlockIo2 Parent BlockIo2 interface.
|
|
|
|
@param[in] ParentDevicePath Parent Device Path.
|
|
|
|
@param[in] DevicePathNode Child Device Path node.
|
|
|
|
@param[in] Start Start Block.
|
|
|
|
@param[in] End End Block.
|
|
|
|
@param[in] BlockSize Child block size.
|
|
|
|
@param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS A child handle was added.
|
|
|
|
@retval other A child handle was not added.
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PartitionInstallChildHandle (
|
|
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
|
|
IN EFI_HANDLE ParentHandle,
|
|
|
|
IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
|
|
|
|
IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
|
2011-05-03 12:31:41 +02:00
|
|
|
IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
|
2007-07-16 07:48:11 +02:00
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
|
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
|
|
|
|
IN EFI_LBA Start,
|
|
|
|
IN EFI_LBA End,
|
|
|
|
IN UINT32 BlockSize,
|
|
|
|
IN BOOLEAN InstallEspGuid
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
PARTITION_PRIVATE_DATA *Private;
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
Status = EFI_SUCCESS;
|
2007-07-16 07:48:11 +02:00
|
|
|
Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
|
|
|
|
if (Private == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
|
|
|
|
|
|
|
|
Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
|
|
|
|
Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
|
|
|
|
|
|
|
|
Private->BlockSize = BlockSize;
|
|
|
|
Private->ParentBlockIo = ParentBlockIo;
|
2011-05-03 12:31:41 +02:00
|
|
|
Private->ParentBlockIo2 = ParentBlockIo2;
|
2007-07-16 07:48:11 +02:00
|
|
|
Private->DiskIo = ParentDiskIo;
|
|
|
|
|
2011-05-06 09:15:41 +02:00
|
|
|
//
|
|
|
|
// Set the BlockIO into Private Data.
|
|
|
|
//
|
|
|
|
Private->BlockIo.Revision = ParentBlockIo->Revision;
|
|
|
|
|
|
|
|
Private->BlockIo.Media = &Private->Media;
|
|
|
|
CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
|
2011-05-03 12:31:41 +02:00
|
|
|
|
2011-05-06 09:15:41 +02:00
|
|
|
Private->BlockIo.Reset = PartitionReset;
|
|
|
|
Private->BlockIo.ReadBlocks = PartitionReadBlocks;
|
|
|
|
Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
|
|
|
|
Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
|
2011-05-03 12:31:41 +02:00
|
|
|
|
2011-05-06 09:15:41 +02:00
|
|
|
//
|
|
|
|
// Set the BlockIO2 into Private Data.
|
|
|
|
//
|
2011-05-03 12:31:41 +02:00
|
|
|
if (Private->ParentBlockIo2 != NULL) {
|
|
|
|
Private->BlockIo2.Media = &Private->Media2;
|
|
|
|
CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
|
|
|
|
|
|
|
|
Private->BlockIo2.Reset = PartitionResetEx;
|
|
|
|
Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
|
|
|
|
Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
|
|
|
|
Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
|
|
|
|
}
|
2011-04-01 05:07:38 +02:00
|
|
|
|
|
|
|
Private->Media.IoAlign = 0;
|
2011-05-03 12:31:41 +02:00
|
|
|
Private->Media.LogicalPartition = TRUE;
|
2007-07-16 07:48:11 +02:00
|
|
|
Private->Media.LastBlock = DivU64x32 (
|
|
|
|
MultU64x32 (
|
|
|
|
End - Start + 1,
|
2011-05-06 09:15:41 +02:00
|
|
|
ParentBlockIo->Media->BlockSize
|
2007-07-16 07:48:11 +02:00
|
|
|
),
|
2011-05-03 12:31:41 +02:00
|
|
|
BlockSize
|
2007-07-16 07:48:11 +02:00
|
|
|
) - 1;
|
|
|
|
|
2011-04-01 05:07:38 +02:00
|
|
|
Private->Media.BlockSize = (UINT32) BlockSize;
|
2007-07-16 07:48:11 +02:00
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
//
|
|
|
|
// For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
|
|
|
|
//
|
|
|
|
Private->Media2.LogicalPartition = TRUE;
|
|
|
|
Private->Media2.LastBlock = Private->Media.LastBlock;
|
|
|
|
Private->Media2.BlockSize = (UINT32) BlockSize;
|
|
|
|
|
2010-07-20 05:11:58 +02:00
|
|
|
//
|
2011-05-23 09:47:19 +02:00
|
|
|
// Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
|
2010-07-20 05:11:58 +02:00
|
|
|
// for logical partitions.
|
|
|
|
//
|
|
|
|
if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
|
2011-05-27 22:04:45 +02:00
|
|
|
Private->Media.LowestAlignedLba = 0;
|
|
|
|
Private->Media.LogicalBlocksPerPhysicalBlock = 0;
|
|
|
|
Private->Media2.LowestAlignedLba = 0;
|
|
|
|
Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
|
2011-05-23 09:47:19 +02:00
|
|
|
if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
|
2011-05-27 22:04:45 +02:00
|
|
|
Private->Media.OptimalTransferLengthGranularity = 0;
|
|
|
|
Private->Media2.OptimalTransferLengthGranularity = 0;
|
2011-05-23 09:47:19 +02:00
|
|
|
}
|
2010-07-20 05:11:58 +02:00
|
|
|
}
|
|
|
|
|
2011-05-03 12:31:41 +02:00
|
|
|
Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
if (Private->DevicePath == NULL) {
|
|
|
|
FreePool (Private);
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InstallEspGuid) {
|
|
|
|
Private->EspGuid = &gEfiPartTypeSystemPartGuid;
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// If NULL InstallMultipleProtocolInterfaces will ignore it.
|
|
|
|
//
|
|
|
|
Private->EspGuid = NULL;
|
|
|
|
}
|
2011-05-03 12:31:41 +02:00
|
|
|
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
2011-05-03 12:31:41 +02:00
|
|
|
// Create the new handle.
|
|
|
|
// BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
|
|
|
|
// is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
|
|
|
|
// directly call the parent BlockIO and doesn't handle the different block size issue.
|
|
|
|
// If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
|
|
|
|
// DiskIO to handle the blocksize unequal issue and the limitation will be remove from
|
|
|
|
// here.
|
2007-07-16 07:48:11 +02:00
|
|
|
//
|
|
|
|
Private->Handle = NULL;
|
2011-05-06 09:15:41 +02:00
|
|
|
if ((Private->ParentBlockIo2 != NULL) &&
|
2011-05-03 12:31:41 +02:00
|
|
|
(Private->ParentBlockIo2->Media->BlockSize == BlockSize)
|
|
|
|
) {
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&Private->Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
Private->DevicePath,
|
|
|
|
&gEfiBlockIoProtocolGuid,
|
|
|
|
&Private->BlockIo,
|
|
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
|
|
&Private->BlockIo2,
|
|
|
|
Private->EspGuid,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
);
|
2011-05-06 09:15:41 +02:00
|
|
|
} else {
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&Private->Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
Private->DevicePath,
|
|
|
|
&gEfiBlockIoProtocolGuid,
|
|
|
|
&Private->BlockIo,
|
|
|
|
Private->EspGuid,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
);
|
2011-05-03 12:31:41 +02:00
|
|
|
}
|
2007-07-16 07:48:11 +02:00
|
|
|
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// Open the Parent Handle for the child
|
|
|
|
//
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
ParentHandle,
|
|
|
|
&gEfiDiskIoProtocolGuid,
|
|
|
|
(VOID **) &ParentDiskIo,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
Private->Handle,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
FreePool (Private->DevicePath);
|
|
|
|
FreePool (Private);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
The user Entry Point for module Partition. 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
|
|
|
|
InitializePartition (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Install driver model protocol(s).
|
|
|
|
//
|
2007-09-30 05:01:48 +02:00
|
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
2007-07-16 07:48:11 +02:00
|
|
|
ImageHandle,
|
|
|
|
SystemTable,
|
|
|
|
&gPartitionDriverBinding,
|
|
|
|
ImageHandle,
|
|
|
|
&gPartitionComponentName,
|
2007-09-30 05:01:48 +02:00
|
|
|
&gPartitionComponentName2
|
2007-07-16 07:48:11 +02:00
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|