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 - 2008, Intel Corporation. <BR>
8 All rights reserved. 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
;
72 if (RemainingDevicePath
!= NULL
) {
73 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
74 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
75 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
76 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)
78 return EFI_UNSUPPORTED
;
82 // Open the IO Abstraction(s) needed to perform the supported test
84 Status
= gBS
->OpenProtocol (
86 &gEfiDevicePathProtocolGuid
,
87 (VOID
**) &ParentDevicePath
,
88 This
->DriverBindingHandle
,
90 EFI_OPEN_PROTOCOL_BY_DRIVER
92 if (Status
== EFI_ALREADY_STARTED
) {
96 if (EFI_ERROR (Status
)) {
100 // Close the I/O Abstraction(s) used to perform the supported test
104 &gEfiDevicePathProtocolGuid
,
105 This
->DriverBindingHandle
,
110 // Open the IO Abstraction(s) needed to perform the supported test
112 Status
= gBS
->OpenProtocol (
114 &gEfiDiskIoProtocolGuid
,
116 This
->DriverBindingHandle
,
118 EFI_OPEN_PROTOCOL_BY_DRIVER
120 if (Status
== EFI_ALREADY_STARTED
) {
124 if (EFI_ERROR (Status
)) {
128 // Close the I/O Abstraction(s) used to perform the supported test
132 &gEfiDiskIoProtocolGuid
,
133 This
->DriverBindingHandle
,
138 // Open the IO Abstraction(s) needed to perform the supported test
140 Status
= gBS
->OpenProtocol (
142 &gEfiBlockIoProtocolGuid
,
144 This
->DriverBindingHandle
,
146 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
154 Start this driver on ControllerHandle by opening a Block IO and Disk IO
155 protocol, reading Device Path, and creating a child handle with a
156 Disk IO and device path protocol.
158 @param This Protocol instance pointer.
159 @param ControllerHandle Handle of device to bind driver to
160 @param RemainingDevicePath Optional parameter use to pick a specific child
163 @retval EFI_SUCCESS This driver is added to ControllerHandle
164 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
165 @retval other This driver does not support this device
170 PartitionDriverBindingStart (
171 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
172 IN EFI_HANDLE ControllerHandle
,
173 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
177 EFI_STATUS OpenStatus
;
178 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
179 EFI_DISK_IO_PROTOCOL
*DiskIo
;
180 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
181 PARTITION_DETECT_ROUTINE
*Routine
;
183 Status
= gBS
->OpenProtocol (
185 &gEfiBlockIoProtocolGuid
,
187 This
->DriverBindingHandle
,
189 EFI_OPEN_PROTOCOL_GET_PROTOCOL
191 if (EFI_ERROR (Status
)) {
195 // Get the Device Path Protocol on ControllerHandle's handle
197 Status
= gBS
->OpenProtocol (
199 &gEfiDevicePathProtocolGuid
,
200 (VOID
**) &ParentDevicePath
,
201 This
->DriverBindingHandle
,
203 EFI_OPEN_PROTOCOL_BY_DRIVER
205 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
209 Status
= gBS
->OpenProtocol (
211 &gEfiDiskIoProtocolGuid
,
213 This
->DriverBindingHandle
,
215 EFI_OPEN_PROTOCOL_BY_DRIVER
217 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
220 &gEfiDevicePathProtocolGuid
,
221 This
->DriverBindingHandle
,
230 // If no media is present, do nothing here.
232 Status
= EFI_UNSUPPORTED
;
233 if (BlockIo
->Media
->MediaPresent
) {
235 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
236 // media supports a given partition type install child handles to represent
237 // the partitions described by the media.
239 Routine
= &mPartitionDetectRoutineTable
[0];
240 while (*Routine
!= NULL
) {
241 Status
= (*Routine
) (
248 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
) {
255 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
256 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
257 // driver. So don't try to close them. Otherwise, we will break the dependency
258 // between the controller and the driver set up before.
260 if (EFI_ERROR (Status
) && !EFI_ERROR (OpenStatus
) && Status
!= EFI_MEDIA_CHANGED
) {
263 &gEfiDiskIoProtocolGuid
,
264 This
->DriverBindingHandle
,
270 &gEfiDevicePathProtocolGuid
,
271 This
->DriverBindingHandle
,
281 Stop this driver on ControllerHandle. Support stopping any child handles
282 created by this driver.
284 @param This Protocol instance pointer.
285 @param ControllerHandle Handle of device to stop driver on
286 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
287 children is zero stop the entire bus driver.
288 @param ChildHandleBuffer List of Child Handles to Stop.
290 @retval EFI_SUCCESS This driver is removed ControllerHandle
291 @retval other This driver was not removed from this device
296 PartitionDriverBindingStop (
297 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
298 IN EFI_HANDLE ControllerHandle
,
299 IN UINTN NumberOfChildren
,
300 IN EFI_HANDLE
*ChildHandleBuffer
305 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
306 BOOLEAN AllChildrenStopped
;
307 PARTITION_PRIVATE_DATA
*Private
;
308 EFI_DISK_IO_PROTOCOL
*DiskIo
;
310 if (NumberOfChildren
== 0) {
312 // Close the bus driver
316 &gEfiDiskIoProtocolGuid
,
317 This
->DriverBindingHandle
,
323 &gEfiDevicePathProtocolGuid
,
324 This
->DriverBindingHandle
,
331 AllChildrenStopped
= TRUE
;
332 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
333 Status
= gBS
->OpenProtocol (
334 ChildHandleBuffer
[Index
],
335 &gEfiBlockIoProtocolGuid
,
337 This
->DriverBindingHandle
,
339 EFI_OPEN_PROTOCOL_GET_PROTOCOL
341 if (!EFI_ERROR (Status
)) {
343 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
346 // All Software protocols have be freed from the handle so remove it.
348 BlockIo
->FlushBlocks (BlockIo
);
350 Status
= gBS
->CloseProtocol (
352 &gEfiDiskIoProtocolGuid
,
353 This
->DriverBindingHandle
,
354 ChildHandleBuffer
[Index
]
357 Status
= gBS
->UninstallMultipleProtocolInterfaces (
358 ChildHandleBuffer
[Index
],
359 &gEfiDevicePathProtocolGuid
,
361 &gEfiBlockIoProtocolGuid
,
367 if (EFI_ERROR (Status
)) {
370 &gEfiDiskIoProtocolGuid
,
372 This
->DriverBindingHandle
,
373 ChildHandleBuffer
[Index
],
374 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
377 FreePool (Private
->DevicePath
);
383 if (EFI_ERROR (Status
)) {
384 AllChildrenStopped
= FALSE
;
388 if (!AllChildrenStopped
) {
389 return EFI_DEVICE_ERROR
;
397 Reset the Block Device.
399 @param This Protocol instance pointer.
400 @param ExtendedVerification Driver may perform diagnostics on reset.
402 @retval EFI_SUCCESS The device was reset.
403 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
410 IN EFI_BLOCK_IO_PROTOCOL
*This
,
411 IN BOOLEAN ExtendedVerification
414 PARTITION_PRIVATE_DATA
*Private
;
416 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
418 return Private
->ParentBlockIo
->Reset (
419 Private
->ParentBlockIo
,
426 Read by using the Disk IO protocol on the parent device. Lba addresses
427 must be converted to byte offsets.
429 @param This Protocol instance pointer.
430 @param MediaId Id of the media, changes every time the media is replaced.
431 @param Lba The starting Logical Block Address to read from
432 @param BufferSize Size of Buffer, must be a multiple of device block size.
433 @param Buffer Buffer containing read data
435 @retval EFI_SUCCESS The data was read correctly from the device.
436 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
437 @retval EFI_NO_MEDIA There is no media in the device.
438 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
439 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
440 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
441 valid for the device.
446 PartitionReadBlocks (
447 IN EFI_BLOCK_IO_PROTOCOL
*This
,
454 PARTITION_PRIVATE_DATA
*Private
;
457 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
459 if (BufferSize
% Private
->BlockSize
!= 0) {
460 return EFI_BAD_BUFFER_SIZE
;
463 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
464 if (Offset
+ BufferSize
> Private
->End
) {
465 return EFI_INVALID_PARAMETER
;
468 // Because some kinds of partition have different block size from their parent
469 // device, we call the Disk IO protocol on the parent device, not the Block IO
472 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
476 Write by using the Disk IO protocol on the parent device. Lba addresses
477 must be converted to byte offsets.
479 @param This Protocol instance pointer.
480 @param MediaId Id of the media, changes every time the media is replaced.
481 @param Lba The starting Logical Block Address to read from
482 @param BufferSize Size of Buffer, must be a multiple of device block size.
483 @param Buffer Buffer containing read data
485 @retval EFI_SUCCESS The data was written correctly to the device.
486 @retval EFI_WRITE_PROTECTED The device can not be written to.
487 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
488 @retval EFI_NO_MEDIA There is no media in the device.
489 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
490 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
491 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
492 valid for the device.
497 PartitionWriteBlocks (
498 IN EFI_BLOCK_IO_PROTOCOL
*This
,
505 PARTITION_PRIVATE_DATA
*Private
;
508 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
510 if (BufferSize
% Private
->BlockSize
!= 0) {
511 return EFI_BAD_BUFFER_SIZE
;
514 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
515 if (Offset
+ BufferSize
> Private
->End
) {
516 return EFI_INVALID_PARAMETER
;
519 // Because some kinds of partition have different block size from their parent
520 // device, we call the Disk IO protocol on the parent device, not the Block IO
523 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
528 Flush the parent Block Device.
530 @param This Protocol instance pointer.
532 @retval EFI_SUCCESS All outstanding data was written to the device
533 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
534 @retval EFI_NO_MEDIA There is no media in the device.
539 PartitionFlushBlocks (
540 IN EFI_BLOCK_IO_PROTOCOL
*This
543 PARTITION_PRIVATE_DATA
*Private
;
545 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
547 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
553 Create a child handle for a logical block device that represents the
554 bytes Start to End of the Parent Block IO device.
556 @param[in] This Protocol instance pointer
557 @param[in] ParentHandle Parent Handle for new child
558 @param[in] ParentDiskIo Parent DiskIo interface
559 @param[in] ParentBlockIo Parent BlockIo interface
560 @param[in] ParentDevicePath Parent Device Path
561 @param[in] DevicePathNode Child Device Path node
562 @param[in] Start Start Block
563 @param[in] End End Block
564 @param[in] BlockSize Child block size
565 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle
567 @retval EFI_SUCCESS A child handle was added
568 @retval other A child handle was not added
572 PartitionInstallChildHandle (
573 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
574 IN EFI_HANDLE ParentHandle
,
575 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
576 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
577 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
578 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
582 IN BOOLEAN InstallEspGuid
586 PARTITION_PRIVATE_DATA
*Private
;
588 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
589 if (Private
== NULL
) {
590 return EFI_OUT_OF_RESOURCES
;
593 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
595 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
596 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
598 Private
->BlockSize
= BlockSize
;
599 Private
->ParentBlockIo
= ParentBlockIo
;
600 Private
->DiskIo
= ParentDiskIo
;
602 Private
->BlockIo
.Revision
= ParentBlockIo
->Revision
;
604 Private
->BlockIo
.Media
= &Private
->Media
;
605 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
606 Private
->Media
.LogicalPartition
= TRUE
;
607 Private
->Media
.LastBlock
= DivU64x32 (
610 ParentBlockIo
->Media
->BlockSize
615 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
617 Private
->BlockIo
.Reset
= PartitionReset
;
618 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
619 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
620 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
622 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
624 if (Private
->DevicePath
== NULL
) {
626 return EFI_OUT_OF_RESOURCES
;
629 if (InstallEspGuid
) {
630 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
633 // If NULL InstallMultipleProtocolInterfaces will ignore it.
635 Private
->EspGuid
= NULL
;
638 // Create the new handle
640 Private
->Handle
= NULL
;
641 Status
= gBS
->InstallMultipleProtocolInterfaces (
643 &gEfiDevicePathProtocolGuid
,
645 &gEfiBlockIoProtocolGuid
,
652 if (!EFI_ERROR (Status
)) {
654 // Open the Parent Handle for the child
656 Status
= gBS
->OpenProtocol (
658 &gEfiDiskIoProtocolGuid
,
659 (VOID
**) &ParentDiskIo
,
660 This
->DriverBindingHandle
,
662 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
665 FreePool (Private
->DevicePath
);
674 The user Entry Point for module Partition. The user code starts with this function.
676 @param[in] ImageHandle The firmware allocated handle for the EFI image.
677 @param[in] SystemTable A pointer to the EFI System Table.
679 @retval EFI_SUCCESS The entry point is executed successfully.
680 @retval other Some error occurs when executing this entry point.
685 InitializePartition (
686 IN EFI_HANDLE ImageHandle
,
687 IN EFI_SYSTEM_TABLE
*SystemTable
693 // Install driver model protocol(s).
695 Status
= EfiLibInstallDriverBindingComponentName2 (
698 &gPartitionDriverBinding
,
700 &gPartitionComponentName
,
701 &gPartitionComponentName2
703 ASSERT_EFI_ERROR (Status
);