--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Partition.c\r
+\r
+Abstract:\r
+\r
+ Partition driver that produces logical BlockIo devices from a physical\r
+ BlockIo device. The logical BlockIo devices are based on the format\r
+ of the raw block devices media. Currently "El Torito CD-ROM", Legacy\r
+ MBR, and GPT partition schemes are supported.\r
+\r
+--*/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "Partition.h"\r
+\r
+//\r
+// Partition Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {\r
+ PartitionDriverBindingSupported,\r
+ PartitionDriverBindingStart,\r
+ PartitionDriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+STATIC \r
+PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {\r
+ PartitionInstallGptChildHandles,\r
+ PartitionInstallElToritoChildHandles,\r
+ PartitionInstallMbrChildHandles,\r
+ NULL\r
+};\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
+ than contains a BlockIo and DiskIo protocol can be supported.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ ControllerHandle - Handle of device to test\r
+ RemainingDevicePath - Not used\r
+\r
+ Returns:\r
+ EFI_SUCCESS - This driver supports this device\r
+ EFI_ALREADY_STARTED - This driver is already running on this device\r
+ EFI_UNSUPPORTED - This driver does not support this device\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ EFI_DEV_PATH *Node;\r
+\r
+ if (RemainingDevicePath != NULL) {\r
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
+ if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||\r
+ Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||\r
+ DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ (VOID **) &DiskIo,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO\r
+ protocol, reading Device Path, and creating a child handle with a\r
+ Disk IO and device path protocol.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ ControllerHandle - Handle of device to bind driver to\r
+ RemainingDevicePath - Not used\r
+\r
+ Returns:\r
+ EFI_SUCCESS - This driver is added to DeviceHandle\r
+ EFI_ALREADY_STARTED - This driver is already running on DeviceHandle\r
+ other - This driver does not support this device\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS OpenStatus;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ PARTITION_DETECT_ROUTINE *Routine;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the Device Path Protocol on ControllerHandle's handle\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ (VOID **) &DiskIo,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ OpenStatus = Status;\r
+\r
+ //\r
+ // If no media is present, do nothing here.\r
+ //\r
+ Status = EFI_UNSUPPORTED;\r
+ if (BlockIo->Media->MediaPresent) {\r
+ //\r
+ // Try for GPT, then El Torito, and then legacy MBR partition types. If the\r
+ // media supports a given partition type install child handles to represent\r
+ // the partitions described by the media.\r
+ //\r
+ Routine = &mPartitionDetectRoutineTable[0];\r
+ while (*Routine != NULL) {\r
+ Status = (*Routine) (\r
+ This,\r
+ ControllerHandle,\r
+ DiskIo,\r
+ BlockIo,\r
+ ParentDevicePath\r
+ );\r
+ if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED) {\r
+ break;\r
+ }\r
+ Routine++;\r
+ }\r
+ }\r
+ //\r
+ // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),\r
+ // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the\r
+ // driver. So don't try to close them. Otherwise, we will break the dependency\r
+ // between the controller and the driver set up before.\r
+ //\r
+ if (EFI_ERROR (Status) && !EFI_ERROR (OpenStatus) && Status != EFI_MEDIA_CHANGED) {\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ ControllerHandle - Handle of device to stop driver on\r
+ NumberOfChildren - Number of Children in the ChildHandleBuffer\r
+ ChildHandleBuffer - List of handles for the children we need to stop.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - This driver is removed DeviceHandle\r
+ EFI_DEVICE_ERROR - This driver was not removed from this device\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ BOOLEAN AllChildrenStopped;\r
+ PARTITION_PRIVATE_DATA *Private;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+\r
+ if (NumberOfChildren == 0) {\r
+ //\r
+ // Close the bus driver\r
+ //\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AllChildrenStopped = TRUE;\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);\r
+\r
+ //\r
+ // All Software protocols have be freed from the handle so remove it.\r
+ //\r
+ BlockIo->FlushBlocks (BlockIo);\r
+\r
+ Status = gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ Private->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Private->BlockIo,\r
+ Private->EspGuid,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ (VOID **) &DiskIo,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ FreePool (Private->DevicePath);\r
+ FreePool (Private);\r
+ }\r
+\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ }\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Reset the parent Block Device.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ ExtendedVerification - Driver may perform diagnostics on reset.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The device was reset.\r
+ EFI_DEVICE_ERROR - The device is not functioning properly and could\r
+ not be reset.\r
+\r
+--*/\r
+{\r
+ PARTITION_PRIVATE_DATA *Private;\r
+\r
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
+\r
+ return Private->ParentBlockIo->Reset (\r
+ Private->ParentBlockIo,\r
+ ExtendedVerification\r
+ );\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Read by using the Disk IO protocol on the parent device. Lba addresses\r
+ must be converted to byte offsets.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ MediaId - Id of the media, changes every time the media is replaced.\r
+ Lba - The starting Logical Block Address to read from\r
+ BufferSize - Size of Buffer, must be a multiple of device block size.\r
+ Buffer - Buffer containing read data\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The data was read correctly from the device.\r
+ EFI_DEVICE_ERROR - The device reported an error while performing the read.\r
+ EFI_NO_MEDIA - There is no media in the device.\r
+ EFI_MEDIA_CHANGED - The MediaId does not matched the current device.\r
+ EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the\r
+ device.\r
+ EFI_INVALID_PARAMETER - The read request contains device addresses that are not\r
+ valid for the device.\r
+\r
+--*/\r
+{\r
+ PARTITION_PRIVATE_DATA *Private;\r
+ UINT64 Offset;\r
+\r
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
+\r
+ if (BufferSize % Private->BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
+ if (Offset + BufferSize > Private->End) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Because some kinds of partition have different block size from their parent\r
+ // device, we call the Disk IO protocol on the parent device, not the Block IO\r
+ // protocol\r
+ //\r
+ return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Write by using the Disk IO protocol on the parent device. Lba addresses\r
+ must be converted to byte offsets.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ MediaId - Id of the media, changes every time the media is replaced.\r
+ Lba - The starting Logical Block Address to read from\r
+ BufferSize - Size of Buffer, must be a multiple of device block size.\r
+ Buffer - Buffer containing read data\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The data was written correctly to the device.\r
+ EFI_WRITE_PROTECTED - The device can not be written to.\r
+ EFI_DEVICE_ERROR - The device reported an error while performing the write.\r
+ EFI_NO_MEDIA - There is no media in the device.\r
+ EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.\r
+ EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the\r
+ device.\r
+ EFI_INVALID_PARAMETER - The write request contains a LBA that is not\r
+ valid for the device.\r
+\r
+--*/\r
+{\r
+ PARTITION_PRIVATE_DATA *Private;\r
+ UINT64 Offset;\r
+\r
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
+\r
+ if (BufferSize % Private->BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
+ if (Offset + BufferSize > Private->End) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Because some kinds of partition have different block size from their parent\r
+ // device, we call the Disk IO protocol on the parent device, not the Block IO\r
+ // protocol\r
+ //\r
+ return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+PartitionFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Flush the parent Block Device.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - All outstanding data was written to the device\r
+ EFI_DEVICE_ERROR - The device reported an error while writing back the data\r
+ EFI_NO_MEDIA - There is no media in the device.\r
+\r
+--*/\r
+{\r
+ PARTITION_PRIVATE_DATA *Private;\r
+\r
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
+\r
+ return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);\r
+}\r
+\r
+EFI_STATUS\r
+PartitionInstallChildHandle (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ParentHandle,\r
+ IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,\r
+ IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,\r
+ IN EFI_LBA Start,\r
+ IN EFI_LBA End,\r
+ IN UINT32 BlockSize,\r
+ IN BOOLEAN InstallEspGuid\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Create a child handle for a logical block device that represents the\r
+ bytes Start to End of the Parent Block IO device.\r
+\r
+Arguments:\r
+ This - Calling context.\r
+ ParentHandle - Parent Handle for new child\r
+ ParentDiskIo - Parent DiskIo interface\r
+ ParentBlockIo - Parent BlockIo interface\r
+ ParentDevicePath - Parent Device Path\r
+ DevicePathNode - Child Device Path node\r
+ Start - Start Block\r
+ End - End Block\r
+ BlockSize - Child block size\r
+ InstallEspGuid - Flag to install EFI System Partition GUID on handle\r
+\r
+Returns:\r
+ EFI_SUCCESS - If a child handle was added\r
+ EFI_OUT_OF_RESOURCES - A child handle was not added\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ PARTITION_PRIVATE_DATA *Private;\r
+\r
+ Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;\r
+\r
+ Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);\r
+ Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);\r
+\r
+ Private->BlockSize = BlockSize;\r
+ Private->ParentBlockIo = ParentBlockIo;\r
+ Private->DiskIo = ParentDiskIo;\r
+\r
+ Private->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+\r
+ Private->BlockIo.Media = &Private->Media;\r
+ CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
+ Private->Media.LogicalPartition = TRUE;\r
+ Private->Media.LastBlock = DivU64x32 (\r
+ MultU64x32 (\r
+ End - Start + 1,\r
+ ParentBlockIo->Media->BlockSize\r
+ ),\r
+ BlockSize\r
+ ) - 1;\r
+\r
+ Private->Media.BlockSize = (UINT32) BlockSize;\r
+\r
+ Private->BlockIo.Reset = PartitionReset;\r
+ Private->BlockIo.ReadBlocks = PartitionReadBlocks;\r
+ Private->BlockIo.WriteBlocks = PartitionWriteBlocks;\r
+ Private->BlockIo.FlushBlocks = PartitionFlushBlocks;\r
+\r
+ Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);\r
+\r
+ if (Private->DevicePath == NULL) {\r
+ FreePool (Private);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (InstallEspGuid) {\r
+ Private->EspGuid = &gEfiPartTypeSystemPartGuid;\r
+ } else {\r
+ //\r
+ // If NULL InstallMultipleProtocolInterfaces will ignore it.\r
+ //\r
+ Private->EspGuid = NULL;\r
+ }\r
+ //\r
+ // Create the new handle\r
+ //\r
+ Private->Handle = NULL;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Private->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Private->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Private->BlockIo,\r
+ Private->EspGuid,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Open the Parent Handle for the child\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ParentHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ (VOID **) &ParentDiskIo,\r
+ This->DriverBindingHandle,\r
+ Private->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ FreePool (Private->DevicePath);\r
+ FreePool (Private);\r
+ }\r
+\r
+ return Status;\r
+}\r