Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Sergey Isakov <isakov-sl@bk.ru> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15828 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1262 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1262 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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.
 | |
| 
 | |
| Copyright (c) 2006 - 2014, 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 "Partition.h"
 | |
| 
 | |
| //
 | |
| // Partition Driver Global Variables.
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
 | |
|   PartitionDriverBindingSupported,
 | |
|   PartitionDriverBindingStart,
 | |
|   PartitionDriverBindingStop,
 | |
|   //
 | |
|   // Grub4Dos copies the BPB of the first partition to the MBR. If the 
 | |
|   // DriverBindingStart() of the Fat driver gets run before that of Partition 
 | |
|   // driver only the first partition can be recognized.
 | |
|   // Let the driver binding version of Partition driver be higher than that of
 | |
|   // Fat driver to make sure the DriverBindingStart() of the Partition driver
 | |
|   // gets run before that of Fat driver so that all the partitions can be recognized.
 | |
|   //
 | |
|   0xb,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| //
 | |
| // Prioritized function list to detect partition table. 
 | |
| //
 | |
| PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
 | |
|   PartitionInstallGptChildHandles,
 | |
|   PartitionInstallElToritoChildHandles,
 | |
|   PartitionInstallMbrChildHandles,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Test to see if this driver supports ControllerHandle. Any ControllerHandle
 | |
|   than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
 | |
|   supported.
 | |
| 
 | |
|   @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.
 | |
| 
 | |
|   @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;
 | |
| 
 | |
|   //
 | |
|   // Check RemainingDevicePath validation
 | |
|   //
 | |
|   if (RemainingDevicePath != NULL) {
 | |
|     //
 | |
|     // 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 ||
 | |
|         Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
 | |
|         DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
 | |
|         return EFI_UNSUPPORTED;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the IO Abstraction(s) needed to perform the supported test
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiDiskIoProtocolGuid,
 | |
|                   (VOID **) &DiskIo,
 | |
|                   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 (
 | |
|          ControllerHandle,
 | |
|          &gEfiDiskIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          ControllerHandle
 | |
|          );
 | |
| 
 | |
|   //
 | |
|   // Open the EFI Device Path protocol needed to perform the supported test
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &ParentDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (Status == EFI_ALREADY_STARTED) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close protocol, don't use device path protocol in the Support() function
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         ControllerHandle,
 | |
|         &gEfiDevicePathProtocolGuid,
 | |
|         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
 | |
|                   );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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.
 | |
| 
 | |
|   @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.
 | |
| 
 | |
|   @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;
 | |
|   EFI_BLOCK_IO2_PROTOCOL    *BlockIo2;
 | |
|   EFI_DISK_IO_PROTOCOL      *DiskIo;
 | |
|   EFI_DISK_IO2_PROTOCOL     *DiskIo2;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
 | |
|   PARTITION_DETECT_ROUTINE  *Routine;
 | |
|   BOOLEAN                   MediaPresent;
 | |
|   EFI_TPL                   OldTpl;
 | |
| 
 | |
|   BlockIo2 = NULL;
 | |
|   OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 
 | |
|   //
 | |
|   // Check RemainingDevicePath validation
 | |
|   //
 | |
|   if (RemainingDevicePath != NULL) {
 | |
|     //
 | |
|     // Check if RemainingDevicePath is the End of Device Path Node, 
 | |
|     // if yes, return EFI_SUCCESS
 | |
|     //
 | |
|     if (IsDevicePathEnd (RemainingDevicePath)) {
 | |
|       Status = EFI_SUCCESS;
 | |
|       goto Exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
 | |
|   // otherwise, return error.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiBlockIoProtocolGuid,
 | |
|                   (VOID **) &BlockIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiBlockIo2ProtocolGuid,
 | |
|                   (VOID **) &BlockIo2,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     BlockIo2 = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the Device Path Protocol on ControllerHandle's handle.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &ParentDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the DiskIo and DiskIo2.
 | |
|   //
 | |
|   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
 | |
|           );
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   OpenStatus = Status;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiDiskIo2ProtocolGuid,
 | |
|                   (VOID **) &DiskIo2,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | |
|     DiskIo2 = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Try to read blocks when there's media or it is removable physical partition.
 | |
|   //
 | |
|   Status       = EFI_UNSUPPORTED;
 | |
|   MediaPresent = BlockIo->Media->MediaPresent;
 | |
|   if (BlockIo->Media->MediaPresent ||
 | |
|       (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
 | |
|     //
 | |
|     // 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,
 | |
|                    DiskIo2,
 | |
|                    BlockIo,
 | |
|                    BlockIo2,
 | |
|                    ParentDevicePath
 | |
|                    );
 | |
|       if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
 | |
|         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.
 | |
|   //
 | |
|   // 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)) {
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDiskIoProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
|     //
 | |
|     // Close Parent DiskIo2 if has.
 | |
|     //    
 | |
|     gBS->CloseProtocol (
 | |
|            ControllerHandle,
 | |
|            &gEfiDiskIo2ProtocolGuid,
 | |
|            This->DriverBindingHandle,
 | |
|            ControllerHandle
 | |
|            );
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDevicePathProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Stop this driver on ControllerHandle. Support stopping any child handles
 | |
|   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;
 | |
|   EFI_BLOCK_IO2_PROTOCOL  *BlockIo2;
 | |
|   BOOLEAN                 AllChildrenStopped;
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   EFI_DISK_IO_PROTOCOL    *DiskIo;
 | |
| 
 | |
|   BlockIo  = NULL;
 | |
|   BlockIo2 = NULL;
 | |
|   Private = NULL;
 | |
| 
 | |
|   if (NumberOfChildren == 0) {
 | |
|     //
 | |
|     // Close the bus driver
 | |
|     //
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDiskIoProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
|     //
 | |
|     // Close Parent BlockIO2 if has.
 | |
|     //    
 | |
|     gBS->CloseProtocol (
 | |
|            ControllerHandle,
 | |
|            &gEfiDiskIo2ProtocolGuid,
 | |
|            This->DriverBindingHandle,
 | |
|            ControllerHandle
 | |
|            );
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDevicePathProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   AllChildrenStopped = TRUE;
 | |
|   for (Index = 0; Index < NumberOfChildren; Index++) {
 | |
|     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
 | |
|            ); 
 | |
| 
 | |
| 
 | |
|     Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
 | |
| 
 | |
|     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) {
 | |
|       BlockIo->FlushBlocks (BlockIo);
 | |
|       BlockIo2->FlushBlocksEx (BlockIo2, NULL);
 | |
|       Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                        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
 | |
|                        );
 | |
|     }
 | |
| 
 | |
|     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);
 | |
|     }
 | |
| 
 | |
|     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
 | |
|                                   );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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) {
 | |
|     return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
 | |
|   }
 | |
| 
 | |
|   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
 | |
|   if (Offset + BufferSize > Private->End) {
 | |
|     return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
 | |
|   }
 | |
|   //
 | |
|   // 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.
 | |
| 
 | |
|   @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.
 | |
| 
 | |
|   @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,
 | |
|   IN VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   UINT64                  Offset;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
 | |
| 
 | |
|   if (BufferSize % Private->BlockSize != 0) {
 | |
|     return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
 | |
|   }
 | |
| 
 | |
|   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
 | |
|   if (Offset + BufferSize > Private->End) {
 | |
|     return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
 | |
|   }
 | |
|   //
 | |
|   // 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);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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 DiskIo2            Pointer to the DiskIo2 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_DISK_IO2_PROTOCOL   *DiskIo2,
 | |
|   IN UINT32                  MediaId,
 | |
|   IN EFI_STATUS              DefaultStatus
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                 Status;
 | |
| 
 | |
|   //
 | |
|   // Read 1 byte from offset 0 but passing NULL as buffer pointer
 | |
|   //
 | |
|   Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, NULL);
 | |
|   if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
 | |
|     return Status;
 | |
|   }
 | |
|   return DefaultStatus;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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
 | |
|                                     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The general callback for the DiskIo2 interfaces.
 | |
|   @param  Event                 Event whose notification function is being invoked.
 | |
|   @param  Context               The pointer to the notification function's context,
 | |
|                                 which points to the PARTITION_ACCESS_TASK instance.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PartitionOnAccessComplete (
 | |
|   IN EFI_EVENT                 Event,
 | |
|   IN VOID                      *Context
 | |
|   )
 | |
| {
 | |
|   PARTITION_ACCESS_TASK   *Task;
 | |
| 
 | |
|   Task = (PARTITION_ACCESS_TASK *) Context;
 | |
| 
 | |
|   gBS->CloseEvent (Event);
 | |
| 
 | |
|   Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;
 | |
|   gBS->SignalEvent (Task->BlockIo2Token->Event);
 | |
| 
 | |
|   FreePool (Task);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a new PARTITION_ACCESS_TASK instance.
 | |
| 
 | |
|   @param  Token  Pointer to the EFI_BLOCK_IO2_TOKEN.
 | |
| 
 | |
|   @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
 | |
| **/
 | |
| PARTITION_ACCESS_TASK *
 | |
| PartitionCreateAccessTask (
 | |
|   IN EFI_BLOCK_IO2_TOKEN    *Token
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   PARTITION_ACCESS_TASK     *Task;
 | |
| 
 | |
|   Task = AllocatePool (sizeof (*Task));
 | |
|   if (Task == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   PartitionOnAccessComplete,
 | |
|                   Task,
 | |
|                   &Task->DiskIo2Token.Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool (Task);
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Task->BlockIo2Token = Token;
 | |
| 
 | |
|   return Task;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   UINT64                  Offset;
 | |
|   PARTITION_ACCESS_TASK   *Task;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
 | |
| 
 | |
|   if (BufferSize % Private->BlockSize != 0) {
 | |
|     return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
 | |
|   }
 | |
| 
 | |
|   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
 | |
|   if (Offset + BufferSize > Private->End) {
 | |
|     return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
 | |
|   }
 | |
| 
 | |
|   if ((Token != NULL) && (Token->Event != NULL)) {
 | |
|     Task = PartitionCreateAccessTask (Token);
 | |
|     if (Task == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       gBS->CloseEvent (Task->DiskIo2Token.Event);
 | |
|       FreePool (Task);
 | |
|     }
 | |
|   } else {
 | |
|     Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   UINT64                  Offset;
 | |
|   PARTITION_ACCESS_TASK   *Task;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
 | |
| 
 | |
|   if (BufferSize % Private->BlockSize != 0) {
 | |
|     return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
 | |
|   }
 | |
| 
 | |
|   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
 | |
|   if (Offset + BufferSize > Private->End) {
 | |
|     return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
 | |
|   }
 | |
|   
 | |
|   if ((Token != NULL) && (Token->Event != NULL)) {
 | |
|     Task = PartitionCreateAccessTask (Token);
 | |
|     if (Task == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     Status =  Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       gBS->CloseEvent (Task->DiskIo2Token.Event);
 | |
|       FreePool (Task);
 | |
|     }
 | |
|   } else {
 | |
|     Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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.
 | |
|   @param[in, out] Token    A pointer to the token associated with the transaction
 | |
| 
 | |
|   @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
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   PARTITION_ACCESS_TASK   *Task;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
 | |
| 
 | |
|   if ((Token != NULL) && (Token->Event != NULL)) {
 | |
|     Task = PartitionCreateAccessTask (Token);
 | |
|     if (Task == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       gBS->CloseEvent (Task->DiskIo2Token.Event);
 | |
|       FreePool (Task);
 | |
|     }
 | |
|   } else {
 | |
|     Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Create a child handle for a logical block device that represents the
 | |
|   bytes Start to End of the Parent Block IO device.
 | |
| 
 | |
|   @param[in]  This              Protocol instance pointer.
 | |
|   @param[in]  ParentHandle      Parent Handle for new child.
 | |
|   @param[in]  ParentDiskIo      Parent DiskIo interface.
 | |
|   @param[in]  ParentDiskIo2     Parent DiskIo2 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.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PartitionInstallChildHandle (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN  EFI_HANDLE                   ParentHandle,
 | |
|   IN  EFI_DISK_IO_PROTOCOL         *ParentDiskIo,
 | |
|   IN  EFI_DISK_IO2_PROTOCOL        *ParentDiskIo2,
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL        *ParentBlockIo,
 | |
|   IN  EFI_BLOCK_IO2_PROTOCOL       *ParentBlockIo2,
 | |
|   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;
 | |
| 
 | |
|   Status  = EFI_SUCCESS;
 | |
|   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;
 | |
|   Private->ParentBlockIo2   = ParentBlockIo2;
 | |
|   Private->DiskIo           = ParentDiskIo;
 | |
|   Private->DiskIo2          = ParentDiskIo2;
 | |
| 
 | |
|   //
 | |
|   // 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));
 | |
| 
 | |
|   Private->BlockIo.Reset        = PartitionReset;
 | |
|   Private->BlockIo.ReadBlocks   = PartitionReadBlocks;
 | |
|   Private->BlockIo.WriteBlocks  = PartitionWriteBlocks;
 | |
|   Private->BlockIo.FlushBlocks  = PartitionFlushBlocks;
 | |
| 
 | |
|   //
 | |
|   // Set the BlockIO2 into Private Data.
 | |
|   //
 | |
|   if (Private->DiskIo2 != NULL) {
 | |
|     ASSERT (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; 
 | |
|   }
 | |
| 
 | |
|   Private->Media.IoAlign   = 0;
 | |
|   Private->Media.LogicalPartition = TRUE;
 | |
|   Private->Media.LastBlock = DivU64x32 (
 | |
|                                MultU64x32 (
 | |
|                                  End - Start + 1,
 | |
|                                  ParentBlockIo->Media->BlockSize
 | |
|                                  ),
 | |
|                                 BlockSize
 | |
|                                ) - 1;
 | |
| 
 | |
|   Private->Media.BlockSize = (UINT32) BlockSize;
 | |
| 
 | |
|   Private->Media2.IoAlign   = 0;
 | |
|   Private->Media2.LogicalPartition = TRUE;
 | |
|   Private->Media2.LastBlock = Private->Media.LastBlock;
 | |
|   Private->Media2.BlockSize = (UINT32) BlockSize;
 | |
| 
 | |
|   //
 | |
|   // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
 | |
|   //  for logical partitions.
 | |
|   //
 | |
|   if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
 | |
|     Private->Media.LowestAlignedLba               = 0;
 | |
|     Private->Media.LogicalBlocksPerPhysicalBlock  = 0;
 | |
|     Private->Media2.LowestAlignedLba              = 0;
 | |
|     Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
 | |
|     if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
 | |
|       Private->Media.OptimalTransferLengthGranularity  = 0;
 | |
|       Private->Media2.OptimalTransferLengthGranularity = 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Private->DevicePath     = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create the new handle. 
 | |
|   //
 | |
|   Private->Handle = NULL;
 | |
|   if (Private->DiskIo2 != NULL) {
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &Private->Handle,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     Private->DevicePath,
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     &Private->BlockIo,
 | |
|                     &gEfiBlockIo2ProtocolGuid,
 | |
|                     &Private->BlockIo2,
 | |
|                     Private->EspGuid,
 | |
|                     NULL,
 | |
|                     NULL
 | |
|                     );
 | |
|   } else {    
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &Private->Handle,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     Private->DevicePath,
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     &Private->BlockIo,
 | |
|                     Private->EspGuid,
 | |
|                     NULL,
 | |
|                     NULL
 | |
|                     );
 | |
|   }
 | |
| 
 | |
|   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).
 | |
|   //
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gPartitionDriverBinding,
 | |
|              ImageHandle,
 | |
|              &gPartitionComponentName,
 | |
|              &gPartitionComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 |