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.
26 // Include common header file for this module.
28 #include "CommonHeader.h"
30 #include "Partition.h"
33 // Partition Driver Global Variables
35 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
36 PartitionDriverBindingSupported
,
37 PartitionDriverBindingStart
,
38 PartitionDriverBindingStop
,
45 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
46 PartitionInstallGptChildHandles
,
47 PartitionInstallElToritoChildHandles
,
48 PartitionInstallMbrChildHandles
,
55 PartitionDriverBindingSupported (
56 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
57 IN EFI_HANDLE ControllerHandle
,
58 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
63 Test to see if this driver supports ControllerHandle. Any ControllerHandle
64 than contains a BlockIo and DiskIo protocol can be supported.
67 This - Protocol instance pointer.
68 ControllerHandle - Handle of device to test
69 RemainingDevicePath - Not used
72 EFI_SUCCESS - This driver supports this device
73 EFI_ALREADY_STARTED - This driver is already running on this device
74 EFI_UNSUPPORTED - This driver does not support this device
79 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
80 EFI_DISK_IO_PROTOCOL
*DiskIo
;
83 if (RemainingDevicePath
!= NULL
) {
84 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
85 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
86 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
87 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)
89 return EFI_UNSUPPORTED
;
93 // Open the IO Abstraction(s) needed to perform the supported test
95 Status
= gBS
->OpenProtocol (
97 &gEfiDevicePathProtocolGuid
,
98 (VOID
**) &ParentDevicePath
,
99 This
->DriverBindingHandle
,
101 EFI_OPEN_PROTOCOL_BY_DRIVER
103 if (Status
== EFI_ALREADY_STARTED
) {
107 if (EFI_ERROR (Status
)) {
111 // Close the I/O Abstraction(s) used to perform the supported test
115 &gEfiDevicePathProtocolGuid
,
116 This
->DriverBindingHandle
,
121 // Open the IO Abstraction(s) needed to perform the supported test
123 Status
= gBS
->OpenProtocol (
125 &gEfiDiskIoProtocolGuid
,
127 This
->DriverBindingHandle
,
129 EFI_OPEN_PROTOCOL_BY_DRIVER
131 if (Status
== EFI_ALREADY_STARTED
) {
135 if (EFI_ERROR (Status
)) {
139 // Close the I/O Abstraction(s) used to perform the supported test
143 &gEfiDiskIoProtocolGuid
,
144 This
->DriverBindingHandle
,
149 // Open the IO Abstraction(s) needed to perform the supported test
151 Status
= gBS
->OpenProtocol (
153 &gEfiBlockIoProtocolGuid
,
155 This
->DriverBindingHandle
,
157 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
165 PartitionDriverBindingStart (
166 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
167 IN EFI_HANDLE ControllerHandle
,
168 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
173 Start this driver on ControllerHandle by opening a Block IO and Disk IO
174 protocol, reading Device Path, and creating a child handle with a
175 Disk IO and device path protocol.
178 This - Protocol instance pointer.
179 ControllerHandle - Handle of device to bind driver to
180 RemainingDevicePath - Not used
183 EFI_SUCCESS - This driver is added to DeviceHandle
184 EFI_ALREADY_STARTED - This driver is already running on DeviceHandle
185 other - This driver does not support this device
190 EFI_STATUS OpenStatus
;
191 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
192 EFI_DISK_IO_PROTOCOL
*DiskIo
;
193 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
194 PARTITION_DETECT_ROUTINE
*Routine
;
196 Status
= gBS
->OpenProtocol (
198 &gEfiBlockIoProtocolGuid
,
200 This
->DriverBindingHandle
,
202 EFI_OPEN_PROTOCOL_GET_PROTOCOL
204 if (EFI_ERROR (Status
)) {
208 // Get the Device Path Protocol on ControllerHandle's handle
210 Status
= gBS
->OpenProtocol (
212 &gEfiDevicePathProtocolGuid
,
213 (VOID
**) &ParentDevicePath
,
214 This
->DriverBindingHandle
,
216 EFI_OPEN_PROTOCOL_BY_DRIVER
218 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
222 Status
= gBS
->OpenProtocol (
224 &gEfiDiskIoProtocolGuid
,
226 This
->DriverBindingHandle
,
228 EFI_OPEN_PROTOCOL_BY_DRIVER
230 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
233 &gEfiDevicePathProtocolGuid
,
234 This
->DriverBindingHandle
,
243 // If no media is present, do nothing here.
245 Status
= EFI_UNSUPPORTED
;
246 if (BlockIo
->Media
->MediaPresent
) {
248 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
249 // media supports a given partition type install child handles to represent
250 // the partitions described by the media.
252 Routine
= &mPartitionDetectRoutineTable
[0];
253 while (*Routine
!= NULL
) {
254 Status
= (*Routine
) (
261 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
) {
268 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
269 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
270 // driver. So don't try to close them. Otherwise, we will break the dependency
271 // between the controller and the driver set up before.
273 if (EFI_ERROR (Status
) && !EFI_ERROR (OpenStatus
) && Status
!= EFI_MEDIA_CHANGED
) {
276 &gEfiDiskIoProtocolGuid
,
277 This
->DriverBindingHandle
,
283 &gEfiDevicePathProtocolGuid
,
284 This
->DriverBindingHandle
,
294 PartitionDriverBindingStop (
295 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
296 IN EFI_HANDLE ControllerHandle
,
297 IN UINTN NumberOfChildren
,
298 IN EFI_HANDLE
*ChildHandleBuffer
303 Stop this driver on ControllerHandle. Support stoping any child handles
304 created by this driver.
307 This - Protocol instance pointer.
308 ControllerHandle - Handle of device to stop driver on
309 NumberOfChildren - Number of Children in the ChildHandleBuffer
310 ChildHandleBuffer - List of handles for the children we need to stop.
313 EFI_SUCCESS - This driver is removed DeviceHandle
314 EFI_DEVICE_ERROR - This driver was not removed from this device
320 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
321 BOOLEAN AllChildrenStopped
;
322 PARTITION_PRIVATE_DATA
*Private
;
323 EFI_DISK_IO_PROTOCOL
*DiskIo
;
325 if (NumberOfChildren
== 0) {
327 // Close the bus driver
331 &gEfiDiskIoProtocolGuid
,
332 This
->DriverBindingHandle
,
338 &gEfiDevicePathProtocolGuid
,
339 This
->DriverBindingHandle
,
346 AllChildrenStopped
= TRUE
;
347 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
348 Status
= gBS
->OpenProtocol (
349 ChildHandleBuffer
[Index
],
350 &gEfiBlockIoProtocolGuid
,
352 This
->DriverBindingHandle
,
354 EFI_OPEN_PROTOCOL_GET_PROTOCOL
356 if (!EFI_ERROR (Status
)) {
358 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
361 // All Software protocols have be freed from the handle so remove it.
363 BlockIo
->FlushBlocks (BlockIo
);
365 Status
= gBS
->CloseProtocol (
367 &gEfiDiskIoProtocolGuid
,
368 This
->DriverBindingHandle
,
369 ChildHandleBuffer
[Index
]
372 Status
= gBS
->UninstallMultipleProtocolInterfaces (
373 ChildHandleBuffer
[Index
],
374 &gEfiDevicePathProtocolGuid
,
376 &gEfiBlockIoProtocolGuid
,
382 if (EFI_ERROR (Status
)) {
385 &gEfiDiskIoProtocolGuid
,
387 This
->DriverBindingHandle
,
388 ChildHandleBuffer
[Index
],
389 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
392 FreePool (Private
->DevicePath
);
398 if (EFI_ERROR (Status
)) {
399 AllChildrenStopped
= FALSE
;
403 if (!AllChildrenStopped
) {
404 return EFI_DEVICE_ERROR
;
414 IN EFI_BLOCK_IO_PROTOCOL
*This
,
415 IN BOOLEAN ExtendedVerification
420 Reset the parent Block Device.
423 This - Protocol instance pointer.
424 ExtendedVerification - Driver may perform diagnostics on reset.
427 EFI_SUCCESS - The device was reset.
428 EFI_DEVICE_ERROR - The device is not functioning properly and could
433 PARTITION_PRIVATE_DATA
*Private
;
435 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
437 return Private
->ParentBlockIo
->Reset (
438 Private
->ParentBlockIo
,
446 PartitionReadBlocks (
447 IN EFI_BLOCK_IO_PROTOCOL
*This
,
456 Read by using the Disk IO protocol on the parent device. Lba addresses
457 must be converted to byte offsets.
460 This - Protocol instance pointer.
461 MediaId - Id of the media, changes every time the media is replaced.
462 Lba - The starting Logical Block Address to read from
463 BufferSize - Size of Buffer, must be a multiple of device block size.
464 Buffer - Buffer containing read data
467 EFI_SUCCESS - The data was read correctly from the device.
468 EFI_DEVICE_ERROR - The device reported an error while performing the read.
469 EFI_NO_MEDIA - There is no media in the device.
470 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
471 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
473 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
474 valid for the device.
478 PARTITION_PRIVATE_DATA
*Private
;
481 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
483 if (BufferSize
% Private
->BlockSize
!= 0) {
484 return EFI_BAD_BUFFER_SIZE
;
487 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
488 if (Offset
+ BufferSize
> Private
->End
) {
489 return EFI_INVALID_PARAMETER
;
492 // Because some kinds of partition have different block size from their parent
493 // device, we call the Disk IO protocol on the parent device, not the Block IO
496 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
502 PartitionWriteBlocks (
503 IN EFI_BLOCK_IO_PROTOCOL
*This
,
512 Write by using the Disk IO protocol on the parent device. Lba addresses
513 must be converted to byte offsets.
516 This - Protocol instance pointer.
517 MediaId - Id of the media, changes every time the media is replaced.
518 Lba - The starting Logical Block Address to read from
519 BufferSize - Size of Buffer, must be a multiple of device block size.
520 Buffer - Buffer containing read data
523 EFI_SUCCESS - The data was written correctly to the device.
524 EFI_WRITE_PROTECTED - The device can not be written to.
525 EFI_DEVICE_ERROR - The device reported an error while performing the write.
526 EFI_NO_MEDIA - There is no media in the device.
527 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
528 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
530 EFI_INVALID_PARAMETER - The write request contains a LBA that is not
531 valid for the device.
535 PARTITION_PRIVATE_DATA
*Private
;
538 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
540 if (BufferSize
% Private
->BlockSize
!= 0) {
541 return EFI_BAD_BUFFER_SIZE
;
544 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
545 if (Offset
+ BufferSize
> Private
->End
) {
546 return EFI_INVALID_PARAMETER
;
549 // Because some kinds of partition have different block size from their parent
550 // device, we call the Disk IO protocol on the parent device, not the Block IO
553 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
559 PartitionFlushBlocks (
560 IN EFI_BLOCK_IO_PROTOCOL
*This
565 Flush the parent Block Device.
568 This - Protocol instance pointer.
571 EFI_SUCCESS - All outstanding data was written to the device
572 EFI_DEVICE_ERROR - The device reported an error while writing back the data
573 EFI_NO_MEDIA - There is no media in the device.
577 PARTITION_PRIVATE_DATA
*Private
;
579 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
581 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
585 PartitionInstallChildHandle (
586 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
587 IN EFI_HANDLE ParentHandle
,
588 IN EFI_DISK_IO_PROTOCOL
*ParentDiskIo
,
589 IN EFI_BLOCK_IO_PROTOCOL
*ParentBlockIo
,
590 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
591 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
,
595 IN BOOLEAN InstallEspGuid
600 Create a child handle for a logical block device that represents the
601 bytes Start to End of the Parent Block IO device.
604 This - Calling context.
605 ParentHandle - Parent Handle for new child
606 ParentDiskIo - Parent DiskIo interface
607 ParentBlockIo - Parent BlockIo interface
608 ParentDevicePath - Parent Device Path
609 DevicePathNode - Child Device Path node
612 BlockSize - Child block size
613 InstallEspGuid - Flag to install EFI System Partition GUID on handle
616 EFI_SUCCESS - If a child handle was added
617 EFI_OUT_OF_RESOURCES - A child handle was not added
622 PARTITION_PRIVATE_DATA
*Private
;
624 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
625 if (Private
== NULL
) {
626 return EFI_OUT_OF_RESOURCES
;
629 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
631 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
632 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
634 Private
->BlockSize
= BlockSize
;
635 Private
->ParentBlockIo
= ParentBlockIo
;
636 Private
->DiskIo
= ParentDiskIo
;
638 Private
->BlockIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
640 Private
->BlockIo
.Media
= &Private
->Media
;
641 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
642 Private
->Media
.LogicalPartition
= TRUE
;
643 Private
->Media
.LastBlock
= DivU64x32 (
646 ParentBlockIo
->Media
->BlockSize
651 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
653 Private
->BlockIo
.Reset
= PartitionReset
;
654 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
655 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
656 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
658 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
660 if (Private
->DevicePath
== NULL
) {
662 return EFI_OUT_OF_RESOURCES
;
665 if (InstallEspGuid
) {
666 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
669 // If NULL InstallMultipleProtocolInterfaces will ignore it.
671 Private
->EspGuid
= NULL
;
674 // Create the new handle
676 Private
->Handle
= NULL
;
677 Status
= gBS
->InstallMultipleProtocolInterfaces (
679 &gEfiDevicePathProtocolGuid
,
681 &gEfiBlockIoProtocolGuid
,
688 if (!EFI_ERROR (Status
)) {
690 // Open the Parent Handle for the child
692 Status
= gBS
->OpenProtocol (
694 &gEfiDiskIoProtocolGuid
,
695 (VOID
**) &ParentDiskIo
,
696 This
->DriverBindingHandle
,
698 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
701 FreePool (Private
->DevicePath
);