git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			736 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			736 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006, Intel Corporation
 | |
| All rights reserved. This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   Partition.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   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.
 | |
| 
 | |
| --*/
 | |
| 
 | |
| #include "Partition.h"
 | |
| 
 | |
| //
 | |
| // Function Prototypes
 | |
| //
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionEntryPoint (
 | |
|   IN EFI_HANDLE         ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE   *SystemTable
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionDriverBindingSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN EFI_HANDLE                   ControllerHandle,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionDriverBindingStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN EFI_HANDLE                   ControllerHandle,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN  EFI_HANDLE                   ControllerHandle,
 | |
|   IN  UINTN                        NumberOfChildren,
 | |
|   IN  EFI_HANDLE                   *ChildHandleBuffer
 | |
|   );
 | |
| 
 | |
| //
 | |
| // Partition Driver Global Variables
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
 | |
|   PartitionDriverBindingSupported,
 | |
|   PartitionDriverBindingStart,
 | |
|   PartitionDriverBindingStop,
 | |
|   0x10,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionDriverBindingSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN EFI_HANDLE                   ControllerHandle,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Test to see if this driver supports ControllerHandle. Any ControllerHandle
 | |
|     than contains a BlockIo and DiskIo protocol can be supported.
 | |
| 
 | |
|   Arguments:
 | |
|     This                - Protocol instance pointer.
 | |
|     ControllerHandle    - Handle of device to test
 | |
|     RemainingDevicePath - Not used
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS         - This driver supports this device
 | |
|     EFI_ALREADY_STARTED - This driver is already running on this device
 | |
|     EFI_UNSUPPORTED     - This driver does not support this device
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
 | |
|   EFI_DISK_IO_PROTOCOL      *DiskIo;
 | |
|   EFI_DEV_PATH              *Node;
 | |
| 
 | |
|   if (RemainingDevicePath != NULL) {
 | |
|     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,
 | |
|                   &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 the I/O Abstraction(s) used to perform the supported test
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         ControllerHandle,
 | |
|         &gEfiDevicePathProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         ControllerHandle
 | |
|         );
 | |
| 
 | |
|   //
 | |
|   // 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 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;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionDriverBindingStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | |
|   IN EFI_HANDLE                   ControllerHandle,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Start this driver on ControllerHandle by opening a Block IO and Disk IO
 | |
|     protocol, reading Device Path, and creating a child handle with a
 | |
|     Disk IO and device path protocol.
 | |
| 
 | |
|   Arguments:
 | |
|     This                - Protocol instance pointer.
 | |
|     ControllerHandle    - Handle of device to bind driver to
 | |
|     RemainingDevicePath - Not used
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS         - This driver is added to DeviceHandle
 | |
|     EFI_ALREADY_STARTED - This driver is already running on DeviceHandle
 | |
|     other               - This driver does not support this device
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_STATUS                OpenStatus;
 | |
|   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
 | |
|   EFI_DISK_IO_PROTOCOL      *DiskIo;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiBlockIoProtocolGuid,
 | |
|                   (VOID **) &BlockIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // 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) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   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
 | |
|           );
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   OpenStatus = Status;
 | |
| 
 | |
|   //
 | |
|   // If no media is present, do nothing here.
 | |
|   //
 | |
|   Status = EFI_UNSUPPORTED;
 | |
|   if (BlockIo->Media->MediaPresent) {
 | |
|     //
 | |
|     // 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.
 | |
|     //
 | |
|     if (PartitionInstallGptChildHandles (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           DiskIo,
 | |
|           BlockIo,
 | |
|           ParentDevicePath
 | |
|           ) ||
 | |
| 
 | |
|     PartitionInstallElToritoChildHandles (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           DiskIo,
 | |
|           BlockIo,
 | |
|           ParentDevicePath
 | |
|           ) ||
 | |
| 
 | |
|     PartitionInstallMbrChildHandles (
 | |
|           This,
 | |
|           ControllerHandle,
 | |
|           DiskIo,
 | |
|           BlockIo,
 | |
|           ParentDevicePath
 | |
|           )) {
 | |
|       Status = EFI_SUCCESS;
 | |
|     } else {
 | |
|       Status = EFI_NOT_FOUND;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // 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.
 | |
|   //
 | |
|   if (EFI_ERROR (Status) && !EFI_ERROR (OpenStatus)) {
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDiskIoProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDevicePathProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   IN  EFI_HANDLE                    ControllerHandle,
 | |
|   IN  UINTN                         NumberOfChildren,
 | |
|   IN  EFI_HANDLE                    *ChildHandleBuffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Stop this driver on ControllerHandle. Support stoping any child handles
 | |
|     created by this driver.
 | |
| 
 | |
|   Arguments:
 | |
|     This              - Protocol instance pointer.
 | |
|     ControllerHandle  - Handle of device to stop driver on
 | |
|     NumberOfChildren  - Number of Children in the ChildHandleBuffer
 | |
|     ChildHandleBuffer - List of handles for the children we need to stop.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS         - This driver is removed DeviceHandle
 | |
|     EFI_DEVICE_ERROR    - This driver was not removed from this device
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   UINTN                   Index;
 | |
|   EFI_BLOCK_IO_PROTOCOL   *BlockIo;
 | |
|   BOOLEAN                 AllChildrenStopped;
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   EFI_DISK_IO_PROTOCOL    *DiskIo;
 | |
| 
 | |
|   if (NumberOfChildren == 0) {
 | |
|     //
 | |
|     // Close the bus driver
 | |
|     //
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDiskIoProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiDevicePathProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   AllChildrenStopped = TRUE;
 | |
|   for (Index = 0; Index < NumberOfChildren; Index++) {
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     ChildHandleBuffer[Index],
 | |
|                     &gEfiBlockIoProtocolGuid,
 | |
|                     (VOID **) &BlockIo,
 | |
|                     This->DriverBindingHandle,
 | |
|                     ControllerHandle,
 | |
|                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
| 
 | |
|       Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
 | |
| 
 | |
|       //
 | |
|       // All Software protocols have be freed from the handle so remove it.
 | |
|       //
 | |
|       BlockIo->FlushBlocks (BlockIo);
 | |
| 
 | |
|       Status = gBS->CloseProtocol (
 | |
|                       ControllerHandle,
 | |
|                       &gEfiDiskIoProtocolGuid,
 | |
|                       This->DriverBindingHandle,
 | |
|                       ChildHandleBuffer[Index]
 | |
|                       );
 | |
| 
 | |
|       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 {
 | |
|         gBS->FreePool (Private->DevicePath);
 | |
|         gBS->FreePool (Private);
 | |
|       }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       AllChildrenStopped = FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!AllChildrenStopped) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionReset (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL  *This,
 | |
|   IN BOOLEAN                ExtendedVerification
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Reset the parent Block Device.
 | |
| 
 | |
|   Arguments:
 | |
|     This                 - Protocol instance pointer.
 | |
|     ExtendedVerification - Driver may perform diagnostics on reset.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - The device was reset.
 | |
|     EFI_DEVICE_ERROR      - The device is not functioning properly and could
 | |
|                             not be reset.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
 | |
| 
 | |
|   return Private->ParentBlockIo->Reset (
 | |
|                                   Private->ParentBlockIo,
 | |
|                                   ExtendedVerification
 | |
|                                   );
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionReadBlocks (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL  *This,
 | |
|   IN UINT32                 MediaId,
 | |
|   IN EFI_LBA                Lba,
 | |
|   IN UINTN                  BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Read by using the Disk IO protocol on the parent device. Lba addresses
 | |
|     must be converted to byte offsets.
 | |
| 
 | |
|   Arguments:
 | |
|     This       - Protocol instance pointer.
 | |
|     MediaId    - Id of the media, changes every time the media is replaced.
 | |
|     Lba        - The starting Logical Block Address to read from
 | |
|     BufferSize - Size of Buffer, must be a multiple of device block size.
 | |
|     Buffer     - Buffer containing read data
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - The data was read correctly from the device.
 | |
|     EFI_DEVICE_ERROR      - The device reported an error while performing the read.
 | |
|     EFI_NO_MEDIA          - There is no media in the device.
 | |
|     EFI_MEDIA_CHANGED     - The MediaId does not matched the current device.
 | |
|     EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the
 | |
|                             device.
 | |
|     EFI_INVALID_PARAMETER - The read request contains device addresses that are not
 | |
|                             valid for the device.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   UINT64                  Offset;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
 | |
| 
 | |
|   if (BufferSize % Private->BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
 | |
|   if (Offset + BufferSize > Private->End) {
 | |
|     return 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);
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionWriteBlocks (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL  *This,
 | |
|   IN UINT32                 MediaId,
 | |
|   IN EFI_LBA                Lba,
 | |
|   IN UINTN                  BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Write by using the Disk IO protocol on the parent device. Lba addresses
 | |
|     must be converted to byte offsets.
 | |
| 
 | |
|   Arguments:
 | |
|     This       - Protocol instance pointer.
 | |
|     MediaId    - Id of the media, changes every time the media is replaced.
 | |
|     Lba        - The starting Logical Block Address to read from
 | |
|     BufferSize - Size of Buffer, must be a multiple of device block size.
 | |
|     Buffer     - Buffer containing read data
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - The data was written correctly to the device.
 | |
|     EFI_WRITE_PROTECTED   - The device can not be written to.
 | |
|     EFI_DEVICE_ERROR      - The device reported an error while performing the write.
 | |
|     EFI_NO_MEDIA          - There is no media in the device.
 | |
|     EFI_MEDIA_CHNAGED     - The MediaId does not matched the current device.
 | |
|     EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the
 | |
|                             device.
 | |
|     EFI_INVALID_PARAMETER - The write request contains a LBA that is not
 | |
|                             valid for the device.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
|   UINT64                  Offset;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
 | |
| 
 | |
|   if (BufferSize % Private->BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
 | |
|   if (Offset + BufferSize > Private->End) {
 | |
|     return 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);
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PartitionFlushBlocks (
 | |
|   IN EFI_BLOCK_IO_PROTOCOL  *This
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Flush the parent Block Device.
 | |
| 
 | |
|   Arguments:
 | |
|     This             - Protocol instance pointer.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS      - All outstanding data was written to the device
 | |
|     EFI_DEVICE_ERROR - The device reported an error while writing back the data
 | |
|     EFI_NO_MEDIA     - There is no media in the device.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
| 
 | |
|   Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
 | |
| 
 | |
|   return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
 | |
| }
 | |
| 
 | |
| 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,
 | |
|   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
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Create a child handle for a logical block device that represents the
 | |
|   bytes Start to End of the Parent Block IO device.
 | |
| 
 | |
| Arguments:
 | |
|   This             - Calling context.
 | |
|   ParentHandle     - Parent Handle for new child
 | |
|   ParentDiskIo     - Parent DiskIo interface
 | |
|   ParentBlockIo    - Parent BlockIo interface
 | |
|   ParentDevicePath - Parent Device Path
 | |
|   DevicePathNode   - Child Device Path node
 | |
|   Start            - Start Block
 | |
|   End              - End Block
 | |
|   BlockSize        - Child block size
 | |
|   InstallEspGuid   - Flag to install EFI System Partition GUID on handle
 | |
| 
 | |
| Returns:
 | |
|   EFI_SUCCESS - If a child handle was added
 | |
|   EFI_OUT_OF_RESOURCES  - A child handle was not added
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   PARTITION_PRIVATE_DATA  *Private;
 | |
| 
 | |
|   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->DiskIo           = ParentDiskIo;
 | |
| 
 | |
|   Private->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
 | |
| 
 | |
|   Private->BlockIo.Media    = &Private->Media;
 | |
|   CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
 | |
|   Private->Media.LogicalPartition = TRUE;
 | |
|   Private->Media.LastBlock = DivU64x32 (
 | |
|                                MultU64x32 (
 | |
|                                  End - Start + 1,
 | |
|                                  ParentBlockIo->Media->BlockSize
 | |
|                                  ),
 | |
|                                BlockSize
 | |
|                                ) - 1;
 | |
| 
 | |
|   Private->Media.BlockSize      = (UINT32) BlockSize;
 | |
| 
 | |
|   Private->BlockIo.Reset        = PartitionReset;
 | |
|   Private->BlockIo.ReadBlocks   = PartitionReadBlocks;
 | |
|   Private->BlockIo.WriteBlocks  = PartitionWriteBlocks;
 | |
|   Private->BlockIo.FlushBlocks  = PartitionFlushBlocks;
 | |
| 
 | |
|   Private->DevicePath           = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
 | |
| 
 | |
|   if (Private->DevicePath == NULL) {
 | |
|     gBS->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;
 | |
|   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 {
 | |
|     gBS->FreePool (Private->DevicePath);
 | |
|     gBS->FreePool (Private);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 |