2 Partition driver that produces logical BlockIo devices from a physical
3 BlockIo device. The logical BlockIo devices are based on the format
4 of the raw block devices media. Currently "El Torito CD-ROM", Legacy
5 MBR, and GPT partition schemes are supported.
7 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include "Partition.h"
22 // Partition Driver Global Variables.
24 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
25 PartitionDriverBindingSupported
,
26 PartitionDriverBindingStart
,
27 PartitionDriverBindingStop
,
34 // Prioritized function list to detect partition table.
36 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
37 PartitionInstallGptChildHandles
,
38 PartitionInstallElToritoChildHandles
,
39 PartitionInstallMbrChildHandles
,
46 Test to see if this driver supports ControllerHandle. Any ControllerHandle
47 than contains a BlockIo and DiskIo protocol can be supported.
49 @param This Protocol instance pointer.
50 @param ControllerHandle Handle of device to test
51 @param RemainingDevicePath Optional parameter use to pick a specific child
54 @retval EFI_SUCCESS This driver supports this device
55 @retval EFI_ALREADY_STARTED This driver is already running on this device
56 @retval other This driver does not support this device
61 PartitionDriverBindingSupported (
62 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
63 IN EFI_HANDLE ControllerHandle
,
64 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
68 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
69 EFI_DISK_IO_PROTOCOL
*DiskIo
;
73 // Check RemainingDevicePath validation
75 if (RemainingDevicePath
!= NULL
) {
77 // Check if RemainingDevicePath is the End of Device Path Node,
78 // if yes, go on checking other conditions
80 if (!IsDevicePathEnd (RemainingDevicePath
)) {
82 // If RemainingDevicePath isn't the End of Device Path Node,
83 // check its validation
85 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
86 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
87 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
88 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)) {
89 return EFI_UNSUPPORTED
;
95 // Open the IO Abstraction(s) needed to perform the supported test
97 Status
= gBS
->OpenProtocol (
99 &gEfiDiskIoProtocolGuid
,
101 This
->DriverBindingHandle
,
103 EFI_OPEN_PROTOCOL_BY_DRIVER
105 if (Status
== EFI_ALREADY_STARTED
) {
109 if (EFI_ERROR (Status
)) {
113 // Close the I/O Abstraction(s) used to perform the supported test
117 &gEfiDiskIoProtocolGuid
,
118 This
->DriverBindingHandle
,
123 // Open the EFI Device Path protocol needed to perform the supported test
125 Status
= gBS
->OpenProtocol (
127 &gEfiDevicePathProtocolGuid
,
128 (VOID
**) &ParentDevicePath
,
129 This
->DriverBindingHandle
,
131 EFI_OPEN_PROTOCOL_BY_DRIVER
133 if (Status
== EFI_ALREADY_STARTED
) {
137 if (EFI_ERROR (Status
)) {
142 // Close protocol, don't use device path protocol in the Support() function
146 &gEfiDevicePathProtocolGuid
,
147 This
->DriverBindingHandle
,
152 // Open the IO Abstraction(s) needed to perform the supported test
154 Status
= gBS
->OpenProtocol (
156 &gEfiBlockIoProtocolGuid
,
158 This
->DriverBindingHandle
,
160 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
168 Start this driver on ControllerHandle by opening a Block IO and Disk IO
169 protocol, reading Device Path, and creating a child handle with a
170 Disk IO and device path protocol.
172 @param This Protocol instance pointer.
173 @param ControllerHandle Handle of device to bind driver to
174 @param RemainingDevicePath Optional parameter use to pick a specific child
177 @retval EFI_SUCCESS This driver is added to ControllerHandle
178 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
179 @retval other This driver does not support this device
184 PartitionDriverBindingStart (
185 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
186 IN EFI_HANDLE ControllerHandle
,
187 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
191 EFI_STATUS OpenStatus
;
192 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
193 EFI_DISK_IO_PROTOCOL
*DiskIo
;
194 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
195 PARTITION_DETECT_ROUTINE
*Routine
;
196 BOOLEAN MediaPresent
;
199 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
201 // Check RemainingDevicePath validation
203 if (RemainingDevicePath
!= NULL
) {
205 // Check if RemainingDevicePath is the End of Device Path Node,
206 // if yes, return EFI_SUCCESS
208 if (IsDevicePathEnd (RemainingDevicePath
)) {
209 Status
= EFI_SUCCESS
;
214 Status
= gBS
->OpenProtocol (
216 &gEfiBlockIoProtocolGuid
,
218 This
->DriverBindingHandle
,
220 EFI_OPEN_PROTOCOL_GET_PROTOCOL
222 if (EFI_ERROR (Status
)) {
226 // Get the Device Path Protocol on ControllerHandle's handle
228 Status
= gBS
->OpenProtocol (
230 &gEfiDevicePathProtocolGuid
,
231 (VOID
**) &ParentDevicePath
,
232 This
->DriverBindingHandle
,
234 EFI_OPEN_PROTOCOL_BY_DRIVER
236 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
240 Status
= gBS
->OpenProtocol (
242 &gEfiDiskIoProtocolGuid
,
244 This
->DriverBindingHandle
,
246 EFI_OPEN_PROTOCOL_BY_DRIVER
248 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
251 &gEfiDevicePathProtocolGuid
,
252 This
->DriverBindingHandle
,
261 // Try to read blocks when there's media or it is removable physical partition.
263 Status
= EFI_UNSUPPORTED
;
264 MediaPresent
= BlockIo
->Media
->MediaPresent
;
265 if (BlockIo
->Media
->MediaPresent
||
266 (BlockIo
->Media
->RemovableMedia
&& !BlockIo
->Media
->LogicalPartition
)) {
268 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
269 // media supports a given partition type install child handles to represent
270 // the partitions described by the media.
272 Routine
= &mPartitionDetectRoutineTable
[0];
273 while (*Routine
!= NULL
) {
274 Status
= (*Routine
) (
281 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
|| Status
== EFI_NO_MEDIA
) {
288 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
289 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
290 // driver. So don't try to close them. Otherwise, we will break the dependency
291 // between the controller and the driver set up before.
293 // In the case that when the media changes on a device it will Reinstall the
294 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
295 // reentrant call to our Start() successfully. We should leave the device open
296 // when this happen. The "media change" case includes either the status is
297 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
299 if (EFI_ERROR (Status
) &&
300 !EFI_ERROR (OpenStatus
) &&
301 Status
!= EFI_MEDIA_CHANGED
&&
302 !(MediaPresent
&& Status
== EFI_NO_MEDIA
)) {
305 &gEfiDiskIoProtocolGuid
,
306 This
->DriverBindingHandle
,
312 &gEfiDevicePathProtocolGuid
,
313 This
->DriverBindingHandle
,
319 gBS
->RestoreTPL (OldTpl
);
325 Stop this driver on ControllerHandle. Support stopping any child handles
326 created by this driver.
328 @param This Protocol instance pointer.
329 @param ControllerHandle Handle of device to stop driver on
330 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
331 children is zero stop the entire bus driver.
332 @param ChildHandleBuffer List of Child Handles to Stop.
334 @retval EFI_SUCCESS This driver is removed ControllerHandle
335 @retval other This driver was not removed from this device
340 PartitionDriverBindingStop (
341 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
342 IN EFI_HANDLE ControllerHandle
,
343 IN UINTN NumberOfChildren
,
344 IN EFI_HANDLE
*ChildHandleBuffer
349 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
350 BOOLEAN AllChildrenStopped
;
351 PARTITION_PRIVATE_DATA
*Private
;
352 EFI_DISK_IO_PROTOCOL
*DiskIo
;
354 if (NumberOfChildren
== 0) {
356 // Close the bus driver
360 &gEfiDiskIoProtocolGuid
,
361 This
->DriverBindingHandle
,
367 &gEfiDevicePathProtocolGuid
,
368 This
->DriverBindingHandle
,
375 AllChildrenStopped
= TRUE
;
376 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
377 Status
= gBS
->OpenProtocol (
378 ChildHandleBuffer
[Index
],
379 &gEfiBlockIoProtocolGuid
,
381 This
->DriverBindingHandle
,
383 EFI_OPEN_PROTOCOL_GET_PROTOCOL
385 if (!EFI_ERROR (Status
)) {
387 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
390 // All Software protocols have be freed from the handle so remove it.
392 BlockIo
->FlushBlocks (BlockIo
);
394 Status
= gBS
->CloseProtocol (
396 &gEfiDiskIoProtocolGuid
,
397 This
->DriverBindingHandle
,
398 ChildHandleBuffer
[Index
]
401 Status
= gBS
->UninstallMultipleProtocolInterfaces (
402 ChildHandleBuffer
[Index
],
403 &gEfiDevicePathProtocolGuid
,
405 &gEfiBlockIoProtocolGuid
,
411 if (EFI_ERROR (Status
)) {
414 &gEfiDiskIoProtocolGuid
,
416 This
->DriverBindingHandle
,
417 ChildHandleBuffer
[Index
],
418 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
421 FreePool (Private
->DevicePath
);
427 if (EFI_ERROR (Status
)) {
428 AllChildrenStopped
= FALSE
;
432 if (!AllChildrenStopped
) {
433 return EFI_DEVICE_ERROR
;
441 Reset the Block Device.
443 @param This Protocol instance pointer.
444 @param ExtendedVerification Driver may perform diagnostics on reset.
446 @retval EFI_SUCCESS The device was reset.
447 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
454 IN EFI_BLOCK_IO_PROTOCOL
*This
,
455 IN BOOLEAN ExtendedVerification
458 PARTITION_PRIVATE_DATA
*Private
;
460 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
462 return Private
->ParentBlockIo
->Reset (
463 Private
->ParentBlockIo
,
470 Read by using the Disk IO protocol on the parent device. Lba addresses
471 must be converted to byte offsets.
473 @param This Protocol instance pointer.
474 @param MediaId Id of the media, changes every time the media is replaced.
475 @param Lba The starting Logical Block Address to read from
476 @param BufferSize Size of Buffer, must be a multiple of device block size.
477 @param Buffer Buffer containing read data
479 @retval EFI_SUCCESS The data was read correctly from the device.
480 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
481 @retval EFI_NO_MEDIA There is no media in the device.
482 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
483 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
484 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
485 valid for the device.
490 PartitionReadBlocks (
491 IN EFI_BLOCK_IO_PROTOCOL
*This
,
498 PARTITION_PRIVATE_DATA
*Private
;
501 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
503 if (BufferSize
% Private
->BlockSize
!= 0) {
504 return EFI_BAD_BUFFER_SIZE
;
507 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
508 if (Offset
+ BufferSize
> Private
->End
) {
509 return EFI_INVALID_PARAMETER
;
512 // Because some kinds of partition have different block size from their parent
513 // device, we call the Disk IO protocol on the parent device, not the Block IO
516 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
520 Write by using the Disk IO protocol on the parent device. Lba addresses
521 must be converted to byte offsets.
523 @param This Protocol instance pointer.
524 @param MediaId Id of the media, changes every time the media is replaced.
525 @param Lba The starting Logical Block Address to read from
526 @param BufferSize Size of Buffer, must be a multiple of device block size.
527 @param Buffer Buffer containing read data
529 @retval EFI_SUCCESS The data was written correctly to the device.
530 @retval EFI_WRITE_PROTECTED The device can not be written to.
531 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
532 @retval EFI_NO_MEDIA There is no media in the device.
533 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
534 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
535 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
536 valid for the device.
541 PartitionWriteBlocks (
542 IN EFI_BLOCK_IO_PROTOCOL
*This
,
549 PARTITION_PRIVATE_DATA
*Private
;
552 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
554 if (BufferSize
% Private
->BlockSize
!= 0) {
555 return EFI_BAD_BUFFER_SIZE
;
558 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
559 if (Offset
+ BufferSize
> Private
->End
) {
560 return EFI_INVALID_PARAMETER
;
563 // Because some kinds of partition have different block size from their parent
564 // device, we call the Disk IO protocol on the parent device, not the Block IO
567 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
572 Flush the parent Block Device.
574 @param This Protocol instance pointer.
576 @retval EFI_SUCCESS All outstanding data was written to the device
577 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
578 @retval EFI_NO_MEDIA There is no media in the device.
583 PartitionFlushBlocks (
584 IN EFI_BLOCK_IO_PROTOCOL
*This
587 PARTITION_PRIVATE_DATA
*Private
;
589 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
591 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
597 Create a child handle for a logical block device that represents the
598 bytes Start to End of the Parent Block IO device.
600 @param[in] This Protocol instance pointer
601 @param[in] ParentHandle Parent Handle for new child
602 @param[in] ParentDiskIo Parent DiskIo interface
603 @param[in] ParentBlockIo Parent BlockIo interface
604 @param[in] ParentDevicePath Parent Device Path
605 @param[in] DevicePathNode Child Device Path node
606 @param[in] Start Start Block
607 @param[in] End End Block
608 @param[in] BlockSize Child block size
609 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle
611 @retval EFI_SUCCESS A child handle was added
612 @retval other A child handle was not added
616 PartitionInstallChildHandle (
617 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
618 IN EFI_HANDLE ParentHandle
,
619 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
620 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
621 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
622 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
626 IN BOOLEAN InstallEspGuid
630 PARTITION_PRIVATE_DATA
*Private
;
632 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
633 if (Private
== NULL
) {
634 return EFI_OUT_OF_RESOURCES
;
637 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
639 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
640 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
642 Private
->BlockSize
= BlockSize
;
643 Private
->ParentBlockIo
= ParentBlockIo
;
644 Private
->DiskIo
= ParentDiskIo
;
646 Private
->BlockIo
.Revision
= ParentBlockIo
->Revision
;
648 Private
->BlockIo
.Media
= &Private
->Media
;
649 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
650 Private
->Media
.LogicalPartition
= TRUE
;
653 // Logical BlockIo instance doesn't have IoAlign restriction because it implements block io operation based on DiskIo
655 Private
->Media
.IoAlign
= 0;
656 Private
->Media
.LastBlock
= DivU64x32 (
659 ParentBlockIo
->Media
->BlockSize
664 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
667 // Per UEFI Spec, LowestAlignedLba and LogicalBlocksPerPhysicalBlock must be 0
668 // for logical partitions.
670 if (Private
->BlockIo
.Revision
>= EFI_BLOCK_IO_PROTOCOL_REVISION2
) {
671 Private
->BlockIo
.Media
->LowestAlignedLba
= 0;
672 Private
->BlockIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
675 Private
->BlockIo
.Reset
= PartitionReset
;
676 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
677 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
678 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
680 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
682 if (Private
->DevicePath
== NULL
) {
684 return EFI_OUT_OF_RESOURCES
;
687 if (InstallEspGuid
) {
688 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
691 // If NULL InstallMultipleProtocolInterfaces will ignore it.
693 Private
->EspGuid
= NULL
;
696 // Create the new handle
698 Private
->Handle
= NULL
;
699 Status
= gBS
->InstallMultipleProtocolInterfaces (
701 &gEfiDevicePathProtocolGuid
,
703 &gEfiBlockIoProtocolGuid
,
710 if (!EFI_ERROR (Status
)) {
712 // Open the Parent Handle for the child
714 Status
= gBS
->OpenProtocol (
716 &gEfiDiskIoProtocolGuid
,
717 (VOID
**) &ParentDiskIo
,
718 This
->DriverBindingHandle
,
720 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
723 FreePool (Private
->DevicePath
);
732 The user Entry Point for module Partition. The user code starts with this function.
734 @param[in] ImageHandle The firmware allocated handle for the EFI image.
735 @param[in] SystemTable A pointer to the EFI System Table.
737 @retval EFI_SUCCESS The entry point is executed successfully.
738 @retval other Some error occurs when executing this entry point.
743 InitializePartition (
744 IN EFI_HANDLE ImageHandle
,
745 IN EFI_SYSTEM_TABLE
*SystemTable
751 // Install driver model protocol(s).
753 Status
= EfiLibInstallDriverBindingComponentName2 (
756 &gPartitionDriverBinding
,
758 &gPartitionComponentName
,
759 &gPartitionComponentName2
761 ASSERT_EFI_ERROR (Status
);