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;
 | 
						|
}
 |