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 // Function Prototypes
33 IN EFI_HANDLE ImageHandle
,
34 IN EFI_SYSTEM_TABLE
*SystemTable
39 PartitionDriverBindingSupported (
40 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
41 IN EFI_HANDLE ControllerHandle
,
42 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
47 PartitionDriverBindingStart (
48 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
49 IN EFI_HANDLE ControllerHandle
,
50 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
55 PartitionDriverBindingStop (
56 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
57 IN EFI_HANDLE ControllerHandle
,
58 IN UINTN NumberOfChildren
,
59 IN EFI_HANDLE
*ChildHandleBuffer
63 // Partition Driver Global Variables
65 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
66 PartitionDriverBindingSupported
,
67 PartitionDriverBindingStart
,
68 PartitionDriverBindingStop
,
76 PartitionDriverBindingSupported (
77 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
78 IN EFI_HANDLE ControllerHandle
,
79 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
84 Test to see if this driver supports ControllerHandle. Any ControllerHandle
85 than contains a BlockIo and DiskIo protocol can be supported.
88 This - Protocol instance pointer.
89 ControllerHandle - Handle of device to test
90 RemainingDevicePath - Not used
93 EFI_SUCCESS - This driver supports this device
94 EFI_ALREADY_STARTED - This driver is already running on this device
95 EFI_UNSUPPORTED - This driver does not support this device
100 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
101 EFI_DISK_IO_PROTOCOL
*DiskIo
;
104 if (RemainingDevicePath
!= NULL
) {
105 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
106 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
107 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
108 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)
110 return EFI_UNSUPPORTED
;
114 // Open the IO Abstraction(s) needed to perform the supported test
116 Status
= gBS
->OpenProtocol (
118 &gEfiDevicePathProtocolGuid
,
119 (VOID
**) &ParentDevicePath
,
120 This
->DriverBindingHandle
,
122 EFI_OPEN_PROTOCOL_BY_DRIVER
124 if (Status
== EFI_ALREADY_STARTED
) {
128 if (EFI_ERROR (Status
)) {
132 // Close the I/O Abstraction(s) used to perform the supported test
136 &gEfiDevicePathProtocolGuid
,
137 This
->DriverBindingHandle
,
142 // Open the IO Abstraction(s) needed to perform the supported test
144 Status
= gBS
->OpenProtocol (
146 &gEfiDiskIoProtocolGuid
,
148 This
->DriverBindingHandle
,
150 EFI_OPEN_PROTOCOL_BY_DRIVER
152 if (Status
== EFI_ALREADY_STARTED
) {
156 if (EFI_ERROR (Status
)) {
160 // Close the I/O Abstraction(s) used to perform the supported test
164 &gEfiDiskIoProtocolGuid
,
165 This
->DriverBindingHandle
,
170 // Open the IO Abstraction(s) needed to perform the supported test
172 Status
= gBS
->OpenProtocol (
174 &gEfiBlockIoProtocolGuid
,
176 This
->DriverBindingHandle
,
178 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
186 PartitionDriverBindingStart (
187 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
188 IN EFI_HANDLE ControllerHandle
,
189 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
194 Start this driver on ControllerHandle by opening a Block IO and Disk IO
195 protocol, reading Device Path, and creating a child handle with a
196 Disk IO and device path protocol.
199 This - Protocol instance pointer.
200 ControllerHandle - Handle of device to bind driver to
201 RemainingDevicePath - Not used
204 EFI_SUCCESS - This driver is added to DeviceHandle
205 EFI_ALREADY_STARTED - This driver is already running on DeviceHandle
206 other - This driver does not support this device
211 EFI_STATUS OpenStatus
;
212 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
213 EFI_DISK_IO_PROTOCOL
*DiskIo
;
214 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
216 Status
= gBS
->OpenProtocol (
218 &gEfiBlockIoProtocolGuid
,
220 This
->DriverBindingHandle
,
222 EFI_OPEN_PROTOCOL_GET_PROTOCOL
224 if (EFI_ERROR (Status
)) {
228 // Get the Device Path Protocol on ControllerHandle's handle
230 Status
= gBS
->OpenProtocol (
232 &gEfiDevicePathProtocolGuid
,
233 (VOID
**) &ParentDevicePath
,
234 This
->DriverBindingHandle
,
236 EFI_OPEN_PROTOCOL_BY_DRIVER
238 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
242 Status
= gBS
->OpenProtocol (
244 &gEfiDiskIoProtocolGuid
,
246 This
->DriverBindingHandle
,
248 EFI_OPEN_PROTOCOL_BY_DRIVER
250 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
253 &gEfiDevicePathProtocolGuid
,
254 This
->DriverBindingHandle
,
263 // If no media is present, do nothing here.
265 Status
= EFI_UNSUPPORTED
;
266 if (BlockIo
->Media
->MediaPresent
) {
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 if (PartitionInstallGptChildHandles (
280 PartitionInstallElToritoChildHandles (
288 PartitionInstallMbrChildHandles (
295 Status
= EFI_SUCCESS
;
297 Status
= EFI_NOT_FOUND
;
301 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
302 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
303 // driver. So don't try to close them. Otherwise, we will break the dependency
304 // between the controller and the driver set up before.
306 if (EFI_ERROR (Status
) && !EFI_ERROR (OpenStatus
)) {
309 &gEfiDiskIoProtocolGuid
,
310 This
->DriverBindingHandle
,
316 &gEfiDevicePathProtocolGuid
,
317 This
->DriverBindingHandle
,
327 PartitionDriverBindingStop (
328 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
329 IN EFI_HANDLE ControllerHandle
,
330 IN UINTN NumberOfChildren
,
331 IN EFI_HANDLE
*ChildHandleBuffer
336 Stop this driver on ControllerHandle. Support stoping any child handles
337 created by this driver.
340 This - Protocol instance pointer.
341 ControllerHandle - Handle of device to stop driver on
342 NumberOfChildren - Number of Children in the ChildHandleBuffer
343 ChildHandleBuffer - List of handles for the children we need to stop.
346 EFI_SUCCESS - This driver is removed DeviceHandle
347 EFI_DEVICE_ERROR - This driver was not removed from this device
353 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
354 BOOLEAN AllChildrenStopped
;
355 PARTITION_PRIVATE_DATA
*Private
;
356 EFI_DISK_IO_PROTOCOL
*DiskIo
;
358 if (NumberOfChildren
== 0) {
360 // Close the bus driver
364 &gEfiDiskIoProtocolGuid
,
365 This
->DriverBindingHandle
,
371 &gEfiDevicePathProtocolGuid
,
372 This
->DriverBindingHandle
,
379 AllChildrenStopped
= TRUE
;
380 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
381 Status
= gBS
->OpenProtocol (
382 ChildHandleBuffer
[Index
],
383 &gEfiBlockIoProtocolGuid
,
385 This
->DriverBindingHandle
,
387 EFI_OPEN_PROTOCOL_GET_PROTOCOL
389 if (!EFI_ERROR (Status
)) {
391 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
394 // All Software protocols have be freed from the handle so remove it.
396 BlockIo
->FlushBlocks (BlockIo
);
398 Status
= gBS
->CloseProtocol (
400 &gEfiDiskIoProtocolGuid
,
401 This
->DriverBindingHandle
,
402 ChildHandleBuffer
[Index
]
405 Status
= gBS
->UninstallMultipleProtocolInterfaces (
406 ChildHandleBuffer
[Index
],
407 &gEfiDevicePathProtocolGuid
,
409 &gEfiBlockIoProtocolGuid
,
415 if (EFI_ERROR (Status
)) {
418 &gEfiDiskIoProtocolGuid
,
420 This
->DriverBindingHandle
,
421 ChildHandleBuffer
[Index
],
422 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
425 gBS
->FreePool (Private
->DevicePath
);
426 gBS
->FreePool (Private
);
431 if (EFI_ERROR (Status
)) {
432 AllChildrenStopped
= FALSE
;
436 if (!AllChildrenStopped
) {
437 return EFI_DEVICE_ERROR
;
446 IN EFI_BLOCK_IO_PROTOCOL
*This
,
447 IN BOOLEAN ExtendedVerification
452 Reset the parent Block Device.
455 This - Protocol instance pointer.
456 ExtendedVerification - Driver may perform diagnostics on reset.
459 EFI_SUCCESS - The device was reset.
460 EFI_DEVICE_ERROR - The device is not functioning properly and could
465 PARTITION_PRIVATE_DATA
*Private
;
467 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
469 return Private
->ParentBlockIo
->Reset (
470 Private
->ParentBlockIo
,
477 PartitionReadBlocks (
478 IN EFI_BLOCK_IO_PROTOCOL
*This
,
487 Read by using the Disk IO protocol on the parent device. Lba addresses
488 must be converted to byte offsets.
491 This - Protocol instance pointer.
492 MediaId - Id of the media, changes every time the media is replaced.
493 Lba - The starting Logical Block Address to read from
494 BufferSize - Size of Buffer, must be a multiple of device block size.
495 Buffer - Buffer containing read data
498 EFI_SUCCESS - The data was read correctly from the device.
499 EFI_DEVICE_ERROR - The device reported an error while performing the read.
500 EFI_NO_MEDIA - There is no media in the device.
501 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
502 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
504 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
505 valid for the device.
509 PARTITION_PRIVATE_DATA
*Private
;
512 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
514 if (BufferSize
% Private
->BlockSize
!= 0) {
515 return EFI_BAD_BUFFER_SIZE
;
518 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
519 if (Offset
+ BufferSize
> Private
->End
) {
520 return EFI_INVALID_PARAMETER
;
523 // Because some kinds of partition have different block size from their parent
524 // device, we call the Disk IO protocol on the parent device, not the Block IO
527 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
532 PartitionWriteBlocks (
533 IN EFI_BLOCK_IO_PROTOCOL
*This
,
542 Write by using the Disk IO protocol on the parent device. Lba addresses
543 must be converted to byte offsets.
546 This - Protocol instance pointer.
547 MediaId - Id of the media, changes every time the media is replaced.
548 Lba - The starting Logical Block Address to read from
549 BufferSize - Size of Buffer, must be a multiple of device block size.
550 Buffer - Buffer containing read data
553 EFI_SUCCESS - The data was written correctly to the device.
554 EFI_WRITE_PROTECTED - The device can not be written to.
555 EFI_DEVICE_ERROR - The device reported an error while performing the write.
556 EFI_NO_MEDIA - There is no media in the device.
557 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
558 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
560 EFI_INVALID_PARAMETER - The write request contains a LBA that is not
561 valid for the device.
565 PARTITION_PRIVATE_DATA
*Private
;
568 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
570 if (BufferSize
% Private
->BlockSize
!= 0) {
571 return EFI_BAD_BUFFER_SIZE
;
574 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
575 if (Offset
+ BufferSize
> Private
->End
) {
576 return EFI_INVALID_PARAMETER
;
579 // Because some kinds of partition have different block size from their parent
580 // device, we call the Disk IO protocol on the parent device, not the Block IO
583 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
588 PartitionFlushBlocks (
589 IN EFI_BLOCK_IO_PROTOCOL
*This
594 Flush the parent Block Device.
597 This - Protocol instance pointer.
600 EFI_SUCCESS - All outstanding data was written to the device
601 EFI_DEVICE_ERROR - The device reported an error while writing back the data
602 EFI_NO_MEDIA - There is no media in the device.
606 PARTITION_PRIVATE_DATA
*Private
;
608 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
610 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
614 PartitionInstallChildHandle (
615 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
616 IN EFI_HANDLE ParentHandle
,
617 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
618 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
619 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
620 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
624 IN BOOLEAN InstallEspGuid
629 Create a child handle for a logical block device that represents the
630 bytes Start to End of the Parent Block IO device.
633 This - Calling context.
634 ParentHandle - Parent Handle for new child
635 ParentDiskIo - Parent DiskIo interface
636 ParentBlockIo - Parent BlockIo interface
637 ParentDevicePath - Parent Device Path
638 DevicePathNode - Child Device Path node
641 BlockSize - Child block size
642 InstallEspGuid - Flag to install EFI System Partition GUID on handle
645 EFI_SUCCESS - If a child handle was added
646 EFI_OUT_OF_RESOURCES - A child handle was not added
651 PARTITION_PRIVATE_DATA
*Private
;
653 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
654 if (Private
== NULL
) {
655 return EFI_OUT_OF_RESOURCES
;
658 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
660 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
661 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
663 Private
->BlockSize
= BlockSize
;
664 Private
->ParentBlockIo
= ParentBlockIo
;
665 Private
->DiskIo
= ParentDiskIo
;
667 Private
->BlockIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
669 Private
->BlockIo
.Media
= &Private
->Media
;
670 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
671 Private
->Media
.LogicalPartition
= TRUE
;
672 Private
->Media
.LastBlock
= DivU64x32 (
675 ParentBlockIo
->Media
->BlockSize
680 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
682 Private
->BlockIo
.Reset
= PartitionReset
;
683 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
684 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
685 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
687 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
689 if (Private
->DevicePath
== NULL
) {
690 gBS
->FreePool (Private
);
691 return EFI_OUT_OF_RESOURCES
;
694 if (InstallEspGuid
) {
695 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
698 // If NULL InstallMultipleProtocolInterfaces will ignore it.
700 Private
->EspGuid
= NULL
;
703 // Create the new handle
705 Private
->Handle
= NULL
;
706 Status
= gBS
->InstallMultipleProtocolInterfaces (
708 &gEfiDevicePathProtocolGuid
,
710 &gEfiBlockIoProtocolGuid
,
717 if (!EFI_ERROR (Status
)) {
719 // Open the Parent Handle for the child
721 Status
= gBS
->OpenProtocol (
723 &gEfiDiskIoProtocolGuid
,
724 (VOID
**) &ParentDiskIo
,
725 This
->DriverBindingHandle
,
727 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
730 gBS
->FreePool (Private
->DevicePath
);
731 gBS
->FreePool (Private
);