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
;
443 IN EFI_BLOCK_IO_PROTOCOL
*This
,
444 IN BOOLEAN ExtendedVerification
449 Reset the parent Block Device.
452 This - Protocol instance pointer.
453 ExtendedVerification - Driver may perform diagnostics on reset.
456 EFI_SUCCESS - The device was reset.
457 EFI_DEVICE_ERROR - The device is not functioning properly and could
462 PARTITION_PRIVATE_DATA
*Private
;
464 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
466 return Private
->ParentBlockIo
->Reset (
467 Private
->ParentBlockIo
,
474 PartitionReadBlocks (
475 IN EFI_BLOCK_IO_PROTOCOL
*This
,
484 Read by using the Disk IO protocol on the parent device. Lba addresses
485 must be converted to byte offsets.
488 This - Protocol instance pointer.
489 MediaId - Id of the media, changes every time the media is replaced.
490 Lba - The starting Logical Block Address to read from
491 BufferSize - Size of Buffer, must be a multiple of device block size.
492 Buffer - Buffer containing read data
495 EFI_SUCCESS - The data was read correctly from the device.
496 EFI_DEVICE_ERROR - The device reported an error while performing the read.
497 EFI_NO_MEDIA - There is no media in the device.
498 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
499 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
501 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
502 valid for the device.
506 PARTITION_PRIVATE_DATA
*Private
;
509 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
511 if (BufferSize
% Private
->BlockSize
!= 0) {
512 return EFI_BAD_BUFFER_SIZE
;
515 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
516 if (Offset
+ BufferSize
> Private
->End
) {
517 return EFI_INVALID_PARAMETER
;
520 // Because some kinds of partition have different block size from their parent
521 // device, we call the Disk IO protocol on the parent device, not the Block IO
524 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
529 PartitionWriteBlocks (
530 IN EFI_BLOCK_IO_PROTOCOL
*This
,
539 Write by using the Disk IO protocol on the parent device. Lba addresses
540 must be converted to byte offsets.
543 This - Protocol instance pointer.
544 MediaId - Id of the media, changes every time the media is replaced.
545 Lba - The starting Logical Block Address to read from
546 BufferSize - Size of Buffer, must be a multiple of device block size.
547 Buffer - Buffer containing read data
550 EFI_SUCCESS - The data was written correctly to the device.
551 EFI_WRITE_PROTECTED - The device can not be written to.
552 EFI_DEVICE_ERROR - The device reported an error while performing the write.
553 EFI_NO_MEDIA - There is no media in the device.
554 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
555 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
557 EFI_INVALID_PARAMETER - The write request contains a LBA that is not
558 valid for the device.
562 PARTITION_PRIVATE_DATA
*Private
;
565 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
567 if (BufferSize
% Private
->BlockSize
!= 0) {
568 return EFI_BAD_BUFFER_SIZE
;
571 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
572 if (Offset
+ BufferSize
> Private
->End
) {
573 return EFI_INVALID_PARAMETER
;
576 // Because some kinds of partition have different block size from their parent
577 // device, we call the Disk IO protocol on the parent device, not the Block IO
580 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
585 PartitionFlushBlocks (
586 IN EFI_BLOCK_IO_PROTOCOL
*This
591 Flush the parent Block Device.
594 This - Protocol instance pointer.
597 EFI_SUCCESS - All outstanding data was written to the device
598 EFI_DEVICE_ERROR - The device reported an error while writing back the data
599 EFI_NO_MEDIA - There is no media in the device.
603 PARTITION_PRIVATE_DATA
*Private
;
605 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
607 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
611 PartitionInstallChildHandle (
612 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
613 IN EFI_HANDLE ParentHandle
,
614 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
615 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
616 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
617 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
621 IN BOOLEAN InstallEspGuid
626 Create a child handle for a logical block device that represents the
627 bytes Start to End of the Parent Block IO device.
630 This - Calling context.
631 ParentHandle - Parent Handle for new child
632 ParentDiskIo - Parent DiskIo interface
633 ParentBlockIo - Parent BlockIo interface
634 ParentDevicePath - Parent Device Path
635 DevicePathNode - Child Device Path node
638 BlockSize - Child block size
639 InstallEspGuid - Flag to install EFI System Partition GUID on handle
642 EFI_SUCCESS - If a child handle was added
643 EFI_OUT_OF_RESOURCES - A child handle was not added
648 PARTITION_PRIVATE_DATA
*Private
;
650 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
651 if (Private
== NULL
) {
652 return EFI_OUT_OF_RESOURCES
;
655 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
657 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
658 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
660 Private
->BlockSize
= BlockSize
;
661 Private
->ParentBlockIo
= ParentBlockIo
;
662 Private
->DiskIo
= ParentDiskIo
;
664 Private
->BlockIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
666 Private
->BlockIo
.Media
= &Private
->Media
;
667 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
668 Private
->Media
.LogicalPartition
= TRUE
;
669 Private
->Media
.LastBlock
= DivU64x32 (
672 ParentBlockIo
->Media
->BlockSize
677 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
679 Private
->BlockIo
.Reset
= PartitionReset
;
680 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
681 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
682 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
684 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
686 if (Private
->DevicePath
== NULL
) {
687 gBS
->FreePool (Private
);
688 return EFI_OUT_OF_RESOURCES
;
691 if (InstallEspGuid
) {
692 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
695 // If NULL InstallMultipleProtocolInterfaces will ignore it.
697 Private
->EspGuid
= NULL
;
700 // Create the new handle
702 Private
->Handle
= NULL
;
703 Status
= gBS
->InstallMultipleProtocolInterfaces (
705 &gEfiDevicePathProtocolGuid
,
707 &gEfiBlockIoProtocolGuid
,
714 if (!EFI_ERROR (Status
)) {
716 // Open the Parent Handle for the child
718 Status
= gBS
->OpenProtocol (
720 &gEfiDiskIoProtocolGuid
,
721 (VOID
**) &ParentDiskIo
,
722 This
->DriverBindingHandle
,
724 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
727 gBS
->FreePool (Private
->DevicePath
);
728 gBS
->FreePool (Private
);