3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Partition driver that produces logical BlockIo devices from a physical
19 BlockIo device. The logical BlockIo devices are based on the format
20 of the raw block devices media. Currently "El Torito CD-ROM", Legacy
21 MBR, and GPT partition schemes are supported.
25 #include "Partition.h"
28 // Partition Driver Global Variables
30 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
31 PartitionDriverBindingSupported
,
32 PartitionDriverBindingStart
,
33 PartitionDriverBindingStop
,
40 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
41 PartitionInstallGptChildHandles
,
42 PartitionInstallElToritoChildHandles
,
43 PartitionInstallMbrChildHandles
,
50 PartitionDriverBindingSupported (
51 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
52 IN EFI_HANDLE ControllerHandle
,
53 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
58 Test to see if this driver supports ControllerHandle. Any ControllerHandle
59 than contains a BlockIo and DiskIo protocol can be supported.
62 This - Protocol instance pointer.
63 ControllerHandle - Handle of device to test
64 RemainingDevicePath - Not used
67 EFI_SUCCESS - This driver supports this device
68 EFI_ALREADY_STARTED - This driver is already running on this device
69 EFI_UNSUPPORTED - This driver does not support this device
74 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
75 EFI_DISK_IO_PROTOCOL
*DiskIo
;
78 if (RemainingDevicePath
!= NULL
) {
79 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
80 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
81 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
82 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)
84 return EFI_UNSUPPORTED
;
88 // Open the IO Abstraction(s) needed to perform the supported test
90 Status
= gBS
->OpenProtocol (
92 &gEfiDevicePathProtocolGuid
,
93 (VOID
**) &ParentDevicePath
,
94 This
->DriverBindingHandle
,
96 EFI_OPEN_PROTOCOL_BY_DRIVER
98 if (Status
== EFI_ALREADY_STARTED
) {
102 if (EFI_ERROR (Status
)) {
106 // Close the I/O Abstraction(s) used to perform the supported test
110 &gEfiDevicePathProtocolGuid
,
111 This
->DriverBindingHandle
,
116 // Open the IO Abstraction(s) needed to perform the supported test
118 Status
= gBS
->OpenProtocol (
120 &gEfiDiskIoProtocolGuid
,
122 This
->DriverBindingHandle
,
124 EFI_OPEN_PROTOCOL_BY_DRIVER
126 if (Status
== EFI_ALREADY_STARTED
) {
130 if (EFI_ERROR (Status
)) {
134 // Close the I/O Abstraction(s) used to perform the supported test
138 &gEfiDiskIoProtocolGuid
,
139 This
->DriverBindingHandle
,
144 // Open the IO Abstraction(s) needed to perform the supported test
146 Status
= gBS
->OpenProtocol (
148 &gEfiBlockIoProtocolGuid
,
150 This
->DriverBindingHandle
,
152 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
160 PartitionDriverBindingStart (
161 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
162 IN EFI_HANDLE ControllerHandle
,
163 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
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.
173 This - Protocol instance pointer.
174 ControllerHandle - Handle of device to bind driver to
175 RemainingDevicePath - Not used
178 EFI_SUCCESS - This driver is added to DeviceHandle
179 EFI_ALREADY_STARTED - This driver is already running on DeviceHandle
180 other - This driver does not support this device
185 EFI_STATUS OpenStatus
;
186 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
187 EFI_DISK_IO_PROTOCOL
*DiskIo
;
188 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
189 PARTITION_DETECT_ROUTINE
*Routine
;
191 Status
= gBS
->OpenProtocol (
193 &gEfiBlockIoProtocolGuid
,
195 This
->DriverBindingHandle
,
197 EFI_OPEN_PROTOCOL_GET_PROTOCOL
199 if (EFI_ERROR (Status
)) {
203 // Get the Device Path Protocol on ControllerHandle's handle
205 Status
= gBS
->OpenProtocol (
207 &gEfiDevicePathProtocolGuid
,
208 (VOID
**) &ParentDevicePath
,
209 This
->DriverBindingHandle
,
211 EFI_OPEN_PROTOCOL_BY_DRIVER
213 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
217 Status
= gBS
->OpenProtocol (
219 &gEfiDiskIoProtocolGuid
,
221 This
->DriverBindingHandle
,
223 EFI_OPEN_PROTOCOL_BY_DRIVER
225 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
228 &gEfiDevicePathProtocolGuid
,
229 This
->DriverBindingHandle
,
238 // If no media is present, do nothing here.
240 Status
= EFI_UNSUPPORTED
;
241 if (BlockIo
->Media
->MediaPresent
) {
243 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
244 // media supports a given partition type install child handles to represent
245 // the partitions described by the media.
247 Routine
= &mPartitionDetectRoutineTable
[0];
248 while (*Routine
!= NULL
) {
249 Status
= (*Routine
) (
256 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
) {
263 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
264 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
265 // driver. So don't try to close them. Otherwise, we will break the dependency
266 // between the controller and the driver set up before.
268 if (EFI_ERROR (Status
) && !EFI_ERROR (OpenStatus
) && Status
!= EFI_MEDIA_CHANGED
) {
271 &gEfiDiskIoProtocolGuid
,
272 This
->DriverBindingHandle
,
278 &gEfiDevicePathProtocolGuid
,
279 This
->DriverBindingHandle
,
289 PartitionDriverBindingStop (
290 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
291 IN EFI_HANDLE ControllerHandle
,
292 IN UINTN NumberOfChildren
,
293 IN EFI_HANDLE
*ChildHandleBuffer
298 Stop this driver on ControllerHandle. Support stoping any child handles
299 created by this driver.
302 This - Protocol instance pointer.
303 ControllerHandle - Handle of device to stop driver on
304 NumberOfChildren - Number of Children in the ChildHandleBuffer
305 ChildHandleBuffer - List of handles for the children we need to stop.
308 EFI_SUCCESS - This driver is removed DeviceHandle
309 EFI_DEVICE_ERROR - This driver was not removed from this device
315 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
316 BOOLEAN AllChildrenStopped
;
317 PARTITION_PRIVATE_DATA
*Private
;
318 EFI_DISK_IO_PROTOCOL
*DiskIo
;
320 if (NumberOfChildren
== 0) {
322 // Close the bus driver
326 &gEfiDiskIoProtocolGuid
,
327 This
->DriverBindingHandle
,
333 &gEfiDevicePathProtocolGuid
,
334 This
->DriverBindingHandle
,
341 AllChildrenStopped
= TRUE
;
342 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
343 Status
= gBS
->OpenProtocol (
344 ChildHandleBuffer
[Index
],
345 &gEfiBlockIoProtocolGuid
,
347 This
->DriverBindingHandle
,
349 EFI_OPEN_PROTOCOL_GET_PROTOCOL
351 if (!EFI_ERROR (Status
)) {
353 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
356 // All Software protocols have be freed from the handle so remove it.
358 BlockIo
->FlushBlocks (BlockIo
);
360 Status
= gBS
->CloseProtocol (
362 &gEfiDiskIoProtocolGuid
,
363 This
->DriverBindingHandle
,
364 ChildHandleBuffer
[Index
]
367 Status
= gBS
->UninstallMultipleProtocolInterfaces (
368 ChildHandleBuffer
[Index
],
369 &gEfiDevicePathProtocolGuid
,
371 &gEfiBlockIoProtocolGuid
,
377 if (EFI_ERROR (Status
)) {
380 &gEfiDiskIoProtocolGuid
,
382 This
->DriverBindingHandle
,
383 ChildHandleBuffer
[Index
],
384 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
387 gBS
->FreePool (Private
->DevicePath
);
388 gBS
->FreePool (Private
);
393 if (EFI_ERROR (Status
)) {
394 AllChildrenStopped
= FALSE
;
398 if (!AllChildrenStopped
) {
399 return EFI_DEVICE_ERROR
;
409 IN EFI_BLOCK_IO_PROTOCOL
*This
,
410 IN BOOLEAN ExtendedVerification
415 Reset the parent Block Device.
418 This - Protocol instance pointer.
419 ExtendedVerification - Driver may perform diagnostics on reset.
422 EFI_SUCCESS - The device was reset.
423 EFI_DEVICE_ERROR - The device is not functioning properly and could
428 PARTITION_PRIVATE_DATA
*Private
;
430 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
432 return Private
->ParentBlockIo
->Reset (
433 Private
->ParentBlockIo
,
441 PartitionReadBlocks (
442 IN EFI_BLOCK_IO_PROTOCOL
*This
,
451 Read by using the Disk IO protocol on the parent device. Lba addresses
452 must be converted to byte offsets.
455 This - Protocol instance pointer.
456 MediaId - Id of the media, changes every time the media is replaced.
457 Lba - The starting Logical Block Address to read from
458 BufferSize - Size of Buffer, must be a multiple of device block size.
459 Buffer - Buffer containing read data
462 EFI_SUCCESS - The data was read correctly from the device.
463 EFI_DEVICE_ERROR - The device reported an error while performing the read.
464 EFI_NO_MEDIA - There is no media in the device.
465 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
466 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
468 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
469 valid for the device.
473 PARTITION_PRIVATE_DATA
*Private
;
476 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
478 if (BufferSize
% Private
->BlockSize
!= 0) {
479 return EFI_BAD_BUFFER_SIZE
;
482 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
483 if (Offset
+ BufferSize
> Private
->End
) {
484 return EFI_INVALID_PARAMETER
;
487 // Because some kinds of partition have different block size from their parent
488 // device, we call the Disk IO protocol on the parent device, not the Block IO
491 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
497 PartitionWriteBlocks (
498 IN EFI_BLOCK_IO_PROTOCOL
*This
,
507 Write by using the Disk IO protocol on the parent device. Lba addresses
508 must be converted to byte offsets.
511 This - Protocol instance pointer.
512 MediaId - Id of the media, changes every time the media is replaced.
513 Lba - The starting Logical Block Address to read from
514 BufferSize - Size of Buffer, must be a multiple of device block size.
515 Buffer - Buffer containing read data
518 EFI_SUCCESS - The data was written correctly to the device.
519 EFI_WRITE_PROTECTED - The device can not be written to.
520 EFI_DEVICE_ERROR - The device reported an error while performing the write.
521 EFI_NO_MEDIA - There is no media in the device.
522 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
523 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
525 EFI_INVALID_PARAMETER - The write request contains a LBA that is not
526 valid for the device.
530 PARTITION_PRIVATE_DATA
*Private
;
533 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
535 if (BufferSize
% Private
->BlockSize
!= 0) {
536 return EFI_BAD_BUFFER_SIZE
;
539 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
540 if (Offset
+ BufferSize
> Private
->End
) {
541 return EFI_INVALID_PARAMETER
;
544 // Because some kinds of partition have different block size from their parent
545 // device, we call the Disk IO protocol on the parent device, not the Block IO
548 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
554 PartitionFlushBlocks (
555 IN EFI_BLOCK_IO_PROTOCOL
*This
560 Flush the parent Block Device.
563 This - Protocol instance pointer.
566 EFI_SUCCESS - All outstanding data was written to the device
567 EFI_DEVICE_ERROR - The device reported an error while writing back the data
568 EFI_NO_MEDIA - There is no media in the device.
572 PARTITION_PRIVATE_DATA
*Private
;
574 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
576 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
580 PartitionInstallChildHandle (
581 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
582 IN EFI_HANDLE ParentHandle
,
583 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
584 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
585 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
586 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
590 IN BOOLEAN InstallEspGuid
595 Create a child handle for a logical block device that represents the
596 bytes Start to End of the Parent Block IO device.
599 This - Calling context.
600 ParentHandle - Parent Handle for new child
601 ParentDiskIo - Parent DiskIo interface
602 ParentBlockIo - Parent BlockIo interface
603 ParentDevicePath - Parent Device Path
604 DevicePathNode - Child Device Path node
607 BlockSize - Child block size
608 InstallEspGuid - Flag to install EFI System Partition GUID on handle
611 EFI_SUCCESS - If a child handle was added
612 EFI_OUT_OF_RESOURCES - A child handle was not added
617 PARTITION_PRIVATE_DATA
*Private
;
619 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
620 if (Private
== NULL
) {
621 return EFI_OUT_OF_RESOURCES
;
624 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
626 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
627 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
629 Private
->BlockSize
= BlockSize
;
630 Private
->ParentBlockIo
= ParentBlockIo
;
631 Private
->DiskIo
= ParentDiskIo
;
633 Private
->BlockIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
635 Private
->BlockIo
.Media
= &Private
->Media
;
636 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
637 Private
->Media
.LogicalPartition
= TRUE
;
638 Private
->Media
.LastBlock
= DivU64x32 (
641 ParentBlockIo
->Media
->BlockSize
646 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
648 Private
->BlockIo
.Reset
= PartitionReset
;
649 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
650 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
651 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
653 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
655 if (Private
->DevicePath
== NULL
) {
656 gBS
->FreePool (Private
);
657 return EFI_OUT_OF_RESOURCES
;
660 if (InstallEspGuid
) {
661 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
664 // If NULL InstallMultipleProtocolInterfaces will ignore it.
666 Private
->EspGuid
= NULL
;
669 // Create the new handle
671 Private
->Handle
= NULL
;
672 Status
= gBS
->InstallMultipleProtocolInterfaces (
674 &gEfiDevicePathProtocolGuid
,
676 &gEfiBlockIoProtocolGuid
,
683 if (!EFI_ERROR (Status
)) {
685 // Open the Parent Handle for the child
687 Status
= gBS
->OpenProtocol (
689 &gEfiDiskIoProtocolGuid
,
690 (VOID
**) &ParentDiskIo
,
691 This
->DriverBindingHandle
,
693 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
696 gBS
->FreePool (Private
->DevicePath
);
697 gBS
->FreePool (Private
);