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
,
75 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
76 PartitionInstallGptChildHandles
,
77 PartitionInstallElToritoChildHandles
,
78 PartitionInstallMbrChildHandles
,
85 PartitionDriverBindingSupported (
86 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
87 IN EFI_HANDLE ControllerHandle
,
88 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
93 Test to see if this driver supports ControllerHandle. Any ControllerHandle
94 than contains a BlockIo and DiskIo protocol can be supported.
97 This - Protocol instance pointer.
98 ControllerHandle - Handle of device to test
99 RemainingDevicePath - Not used
102 EFI_SUCCESS - This driver supports this device
103 EFI_ALREADY_STARTED - This driver is already running on this device
104 EFI_UNSUPPORTED - This driver does not support this device
109 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
110 EFI_DISK_IO_PROTOCOL
*DiskIo
;
113 if (RemainingDevicePath
!= NULL
) {
114 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
115 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
116 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
117 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)
119 return EFI_UNSUPPORTED
;
123 // Open the IO Abstraction(s) 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
)) {
141 // Close the I/O Abstraction(s) used to perform the supported test
145 &gEfiDevicePathProtocolGuid
,
146 This
->DriverBindingHandle
,
151 // Open the IO Abstraction(s) needed to perform the supported test
153 Status
= gBS
->OpenProtocol (
155 &gEfiDiskIoProtocolGuid
,
157 This
->DriverBindingHandle
,
159 EFI_OPEN_PROTOCOL_BY_DRIVER
161 if (Status
== EFI_ALREADY_STARTED
) {
165 if (EFI_ERROR (Status
)) {
169 // Close the I/O Abstraction(s) used to perform the supported test
173 &gEfiDiskIoProtocolGuid
,
174 This
->DriverBindingHandle
,
179 // Open the IO Abstraction(s) needed to perform the supported test
181 Status
= gBS
->OpenProtocol (
183 &gEfiBlockIoProtocolGuid
,
185 This
->DriverBindingHandle
,
187 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
195 PartitionDriverBindingStart (
196 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
197 IN EFI_HANDLE ControllerHandle
,
198 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
203 Start this driver on ControllerHandle by opening a Block IO and Disk IO
204 protocol, reading Device Path, and creating a child handle with a
205 Disk IO and device path protocol.
208 This - Protocol instance pointer.
209 ControllerHandle - Handle of device to bind driver to
210 RemainingDevicePath - Not used
213 EFI_SUCCESS - This driver is added to DeviceHandle
214 EFI_ALREADY_STARTED - This driver is already running on DeviceHandle
215 other - This driver does not support this device
220 EFI_STATUS OpenStatus
;
221 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
222 EFI_DISK_IO_PROTOCOL
*DiskIo
;
223 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
224 PARTITION_DETECT_ROUTINE
*Routine
;
226 Status
= gBS
->OpenProtocol (
228 &gEfiBlockIoProtocolGuid
,
230 This
->DriverBindingHandle
,
232 EFI_OPEN_PROTOCOL_GET_PROTOCOL
234 if (EFI_ERROR (Status
)) {
238 // Get the Device Path Protocol on ControllerHandle's handle
240 Status
= gBS
->OpenProtocol (
242 &gEfiDevicePathProtocolGuid
,
243 (VOID
**) &ParentDevicePath
,
244 This
->DriverBindingHandle
,
246 EFI_OPEN_PROTOCOL_BY_DRIVER
248 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
252 Status
= gBS
->OpenProtocol (
254 &gEfiDiskIoProtocolGuid
,
256 This
->DriverBindingHandle
,
258 EFI_OPEN_PROTOCOL_BY_DRIVER
260 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
263 &gEfiDevicePathProtocolGuid
,
264 This
->DriverBindingHandle
,
273 // If no media is present, do nothing here.
275 Status
= EFI_UNSUPPORTED
;
276 if (BlockIo
->Media
->MediaPresent
) {
278 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
279 // media supports a given partition type install child handles to represent
280 // the partitions described by the media.
282 Routine
= &mPartitionDetectRoutineTable
[0];
283 while (*Routine
!= NULL
) {
284 Status
= (*Routine
) (
291 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
) {
298 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
299 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
300 // driver. So don't try to close them. Otherwise, we will break the dependency
301 // between the controller and the driver set up before.
303 if (EFI_ERROR (Status
) && !EFI_ERROR (OpenStatus
) && Status
!= EFI_MEDIA_CHANGED
) {
306 &gEfiDiskIoProtocolGuid
,
307 This
->DriverBindingHandle
,
313 &gEfiDevicePathProtocolGuid
,
314 This
->DriverBindingHandle
,
324 PartitionDriverBindingStop (
325 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
326 IN EFI_HANDLE ControllerHandle
,
327 IN UINTN NumberOfChildren
,
328 IN EFI_HANDLE
*ChildHandleBuffer
333 Stop this driver on ControllerHandle. Support stoping any child handles
334 created by this driver.
337 This - Protocol instance pointer.
338 ControllerHandle - Handle of device to stop driver on
339 NumberOfChildren - Number of Children in the ChildHandleBuffer
340 ChildHandleBuffer - List of handles for the children we need to stop.
343 EFI_SUCCESS - This driver is removed DeviceHandle
344 EFI_DEVICE_ERROR - This driver was not removed from this device
350 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
351 BOOLEAN AllChildrenStopped
;
352 PARTITION_PRIVATE_DATA
*Private
;
353 EFI_DISK_IO_PROTOCOL
*DiskIo
;
355 if (NumberOfChildren
== 0) {
357 // Close the bus driver
361 &gEfiDiskIoProtocolGuid
,
362 This
->DriverBindingHandle
,
368 &gEfiDevicePathProtocolGuid
,
369 This
->DriverBindingHandle
,
376 AllChildrenStopped
= TRUE
;
377 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
378 Status
= gBS
->OpenProtocol (
379 ChildHandleBuffer
[Index
],
380 &gEfiBlockIoProtocolGuid
,
382 This
->DriverBindingHandle
,
384 EFI_OPEN_PROTOCOL_GET_PROTOCOL
386 if (!EFI_ERROR (Status
)) {
388 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
391 // All Software protocols have be freed from the handle so remove it.
393 BlockIo
->FlushBlocks (BlockIo
);
395 Status
= gBS
->CloseProtocol (
397 &gEfiDiskIoProtocolGuid
,
398 This
->DriverBindingHandle
,
399 ChildHandleBuffer
[Index
]
402 Status
= gBS
->UninstallMultipleProtocolInterfaces (
403 ChildHandleBuffer
[Index
],
404 &gEfiDevicePathProtocolGuid
,
406 &gEfiBlockIoProtocolGuid
,
412 if (EFI_ERROR (Status
)) {
415 &gEfiDiskIoProtocolGuid
,
417 This
->DriverBindingHandle
,
418 ChildHandleBuffer
[Index
],
419 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
422 gBS
->FreePool (Private
->DevicePath
);
423 gBS
->FreePool (Private
);
428 if (EFI_ERROR (Status
)) {
429 AllChildrenStopped
= FALSE
;
433 if (!AllChildrenStopped
) {
434 return EFI_DEVICE_ERROR
;
444 IN EFI_BLOCK_IO_PROTOCOL
*This
,
445 IN BOOLEAN ExtendedVerification
450 Reset the parent Block Device.
453 This - Protocol instance pointer.
454 ExtendedVerification - Driver may perform diagnostics on reset.
457 EFI_SUCCESS - The device was reset.
458 EFI_DEVICE_ERROR - The device is not functioning properly and could
463 PARTITION_PRIVATE_DATA
*Private
;
465 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
467 return Private
->ParentBlockIo
->Reset (
468 Private
->ParentBlockIo
,
476 PartitionReadBlocks (
477 IN EFI_BLOCK_IO_PROTOCOL
*This
,
486 Read by using the Disk IO protocol on the parent device. Lba addresses
487 must be converted to byte offsets.
490 This - Protocol instance pointer.
491 MediaId - Id of the media, changes every time the media is replaced.
492 Lba - The starting Logical Block Address to read from
493 BufferSize - Size of Buffer, must be a multiple of device block size.
494 Buffer - Buffer containing read data
497 EFI_SUCCESS - The data was read correctly from the device.
498 EFI_DEVICE_ERROR - The device reported an error while performing the read.
499 EFI_NO_MEDIA - There is no media in the device.
500 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
501 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
503 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
504 valid for the device.
508 PARTITION_PRIVATE_DATA
*Private
;
511 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
513 if (BufferSize
% Private
->BlockSize
!= 0) {
514 return EFI_BAD_BUFFER_SIZE
;
517 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
518 if (Offset
+ BufferSize
> Private
->End
) {
519 return EFI_INVALID_PARAMETER
;
522 // Because some kinds of partition have different block size from their parent
523 // device, we call the Disk IO protocol on the parent device, not the Block IO
526 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
);
589 PartitionFlushBlocks (
590 IN EFI_BLOCK_IO_PROTOCOL
*This
595 Flush the parent Block Device.
598 This - Protocol instance pointer.
601 EFI_SUCCESS - All outstanding data was written to the device
602 EFI_DEVICE_ERROR - The device reported an error while writing back the data
603 EFI_NO_MEDIA - There is no media in the device.
607 PARTITION_PRIVATE_DATA
*Private
;
609 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
611 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
615 PartitionInstallChildHandle (
616 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
617 IN EFI_HANDLE ParentHandle
,
618 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
619 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
620 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
621 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
625 IN BOOLEAN InstallEspGuid
630 Create a child handle for a logical block device that represents the
631 bytes Start to End of the Parent Block IO device.
634 This - Calling context.
635 ParentHandle - Parent Handle for new child
636 ParentDiskIo - Parent DiskIo interface
637 ParentBlockIo - Parent BlockIo interface
638 ParentDevicePath - Parent Device Path
639 DevicePathNode - Child Device Path node
642 BlockSize - Child block size
643 InstallEspGuid - Flag to install EFI System Partition GUID on handle
646 EFI_SUCCESS - If a child handle was added
647 EFI_OUT_OF_RESOURCES - A child handle was not added
652 PARTITION_PRIVATE_DATA
*Private
;
654 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
655 if (Private
== NULL
) {
656 return EFI_OUT_OF_RESOURCES
;
659 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
661 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
662 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
664 Private
->BlockSize
= BlockSize
;
665 Private
->ParentBlockIo
= ParentBlockIo
;
666 Private
->DiskIo
= ParentDiskIo
;
668 Private
->BlockIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
670 Private
->BlockIo
.Media
= &Private
->Media
;
671 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
672 Private
->Media
.LogicalPartition
= TRUE
;
673 Private
->Media
.LastBlock
= DivU64x32 (
676 ParentBlockIo
->Media
->BlockSize
681 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
683 Private
->BlockIo
.Reset
= PartitionReset
;
684 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
685 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
686 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
688 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
690 if (Private
->DevicePath
== NULL
) {
691 gBS
->FreePool (Private
);
692 return EFI_OUT_OF_RESOURCES
;
695 if (InstallEspGuid
) {
696 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
699 // If NULL InstallMultipleProtocolInterfaces will ignore it.
701 Private
->EspGuid
= NULL
;
704 // Create the new handle
706 Private
->Handle
= NULL
;
707 Status
= gBS
->InstallMultipleProtocolInterfaces (
709 &gEfiDevicePathProtocolGuid
,
711 &gEfiBlockIoProtocolGuid
,
718 if (!EFI_ERROR (Status
)) {
720 // Open the Parent Handle for the child
722 Status
= gBS
->OpenProtocol (
724 &gEfiDiskIoProtocolGuid
,
725 (VOID
**) &ParentDiskIo
,
726 This
->DriverBindingHandle
,
728 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
731 gBS
->FreePool (Private
->DevicePath
);
732 gBS
->FreePool (Private
);