2 Partition driver that produces logical BlockIo devices from a physical
3 BlockIo device. The logical BlockIo devices are based on the format
4 of the raw block devices media. Currently "El Torito CD-ROM", Legacy
5 MBR, and GPT partition schemes are supported.
7 Copyright (c) 2006 - 2007, Intel Corporation
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 // Include common header file for this module.
22 #include "CommonHeader.h"
24 #include "Partition.h"
27 // Partition Driver Global Variables
29 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding
= {
30 PartitionDriverBindingSupported
,
31 PartitionDriverBindingStart
,
32 PartitionDriverBindingStop
,
39 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable
[] = {
40 PartitionInstallGptChildHandles
,
41 PartitionInstallElToritoChildHandles
,
42 PartitionInstallMbrChildHandles
,
49 Test to see if this driver supports ControllerHandle. Any ControllerHandle
50 than contains a BlockIo and DiskIo protocol can be supported.
52 @param This Protocol instance pointer.
53 @param ControllerHandle Handle of device to test
54 @param RemainingDevicePath Optional parameter use to pick a specific child
57 @retval EFI_SUCCESS This driver supports this device
58 @retval EFI_ALREADY_STARTED This driver is already running on this device
59 @retval other This driver does not support this device
64 PartitionDriverBindingSupported (
65 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
66 IN EFI_HANDLE ControllerHandle
,
67 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
71 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
72 EFI_DISK_IO_PROTOCOL
*DiskIo
;
75 if (RemainingDevicePath
!= NULL
) {
76 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
77 if (Node
->DevPath
.Type
!= MEDIA_DEVICE_PATH
||
78 Node
->DevPath
.SubType
!= MEDIA_HARDDRIVE_DP
||
79 DevicePathNodeLength (&Node
->DevPath
) != sizeof (HARDDRIVE_DEVICE_PATH
)
81 return EFI_UNSUPPORTED
;
85 // Open the IO Abstraction(s) needed to perform the supported test
87 Status
= gBS
->OpenProtocol (
89 &gEfiDevicePathProtocolGuid
,
90 (VOID
**) &ParentDevicePath
,
91 This
->DriverBindingHandle
,
93 EFI_OPEN_PROTOCOL_BY_DRIVER
95 if (Status
== EFI_ALREADY_STARTED
) {
99 if (EFI_ERROR (Status
)) {
103 // Close the I/O Abstraction(s) used to perform the supported test
107 &gEfiDevicePathProtocolGuid
,
108 This
->DriverBindingHandle
,
113 // Open the IO Abstraction(s) needed to perform the supported test
115 Status
= gBS
->OpenProtocol (
117 &gEfiDiskIoProtocolGuid
,
119 This
->DriverBindingHandle
,
121 EFI_OPEN_PROTOCOL_BY_DRIVER
123 if (Status
== EFI_ALREADY_STARTED
) {
127 if (EFI_ERROR (Status
)) {
131 // Close the I/O Abstraction(s) used to perform the supported test
135 &gEfiDiskIoProtocolGuid
,
136 This
->DriverBindingHandle
,
141 // Open the IO Abstraction(s) needed to perform the supported test
143 Status
= gBS
->OpenProtocol (
145 &gEfiBlockIoProtocolGuid
,
147 This
->DriverBindingHandle
,
149 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
157 Start this driver on ControllerHandle by opening a Block IO and Disk IO
158 protocol, reading Device Path, and creating a child handle with a
159 Disk IO and device path protocol.
161 @param This Protocol instance pointer.
162 @param ControllerHandle Handle of device to bind driver to
163 @param RemainingDevicePath Optional parameter use to pick a specific child
166 @retval EFI_SUCCESS This driver is added to ControllerHandle
167 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
168 @retval other This driver does not support this device
173 PartitionDriverBindingStart (
174 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
175 IN EFI_HANDLE ControllerHandle
,
176 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
180 EFI_STATUS OpenStatus
;
181 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
182 EFI_DISK_IO_PROTOCOL
*DiskIo
;
183 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
184 PARTITION_DETECT_ROUTINE
*Routine
;
186 Status
= gBS
->OpenProtocol (
188 &gEfiBlockIoProtocolGuid
,
190 This
->DriverBindingHandle
,
192 EFI_OPEN_PROTOCOL_GET_PROTOCOL
194 if (EFI_ERROR (Status
)) {
198 // Get the Device Path Protocol on ControllerHandle's handle
200 Status
= gBS
->OpenProtocol (
202 &gEfiDevicePathProtocolGuid
,
203 (VOID
**) &ParentDevicePath
,
204 This
->DriverBindingHandle
,
206 EFI_OPEN_PROTOCOL_BY_DRIVER
208 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
212 Status
= gBS
->OpenProtocol (
214 &gEfiDiskIoProtocolGuid
,
216 This
->DriverBindingHandle
,
218 EFI_OPEN_PROTOCOL_BY_DRIVER
220 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
223 &gEfiDevicePathProtocolGuid
,
224 This
->DriverBindingHandle
,
233 // If no media is present, do nothing here.
235 Status
= EFI_UNSUPPORTED
;
236 if (BlockIo
->Media
->MediaPresent
) {
238 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
239 // media supports a given partition type install child handles to represent
240 // the partitions described by the media.
242 Routine
= &mPartitionDetectRoutineTable
[0];
243 while (*Routine
!= NULL
) {
244 Status
= (*Routine
) (
251 if (!EFI_ERROR (Status
) || Status
== EFI_MEDIA_CHANGED
) {
258 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
259 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
260 // driver. So don't try to close them. Otherwise, we will break the dependency
261 // between the controller and the driver set up before.
263 if (EFI_ERROR (Status
) && !EFI_ERROR (OpenStatus
) && Status
!= EFI_MEDIA_CHANGED
) {
266 &gEfiDiskIoProtocolGuid
,
267 This
->DriverBindingHandle
,
273 &gEfiDevicePathProtocolGuid
,
274 This
->DriverBindingHandle
,
284 Stop this driver on ControllerHandle. Support stoping any child handles
285 created by this driver.
287 @param This Protocol instance pointer.
288 @param ControllerHandle Handle of device to stop driver on
289 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
290 children is zero stop the entire bus driver.
291 @param ChildHandleBuffer List of Child Handles to Stop.
293 @retval EFI_SUCCESS This driver is removed ControllerHandle
294 @retval other This driver was not removed from this device
299 PartitionDriverBindingStop (
300 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
301 IN EFI_HANDLE ControllerHandle
,
302 IN UINTN NumberOfChildren
,
303 IN EFI_HANDLE
*ChildHandleBuffer
308 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
309 BOOLEAN AllChildrenStopped
;
310 PARTITION_PRIVATE_DATA
*Private
;
311 EFI_DISK_IO_PROTOCOL
*DiskIo
;
313 if (NumberOfChildren
== 0) {
315 // Close the bus driver
319 &gEfiDiskIoProtocolGuid
,
320 This
->DriverBindingHandle
,
326 &gEfiDevicePathProtocolGuid
,
327 This
->DriverBindingHandle
,
334 AllChildrenStopped
= TRUE
;
335 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
336 Status
= gBS
->OpenProtocol (
337 ChildHandleBuffer
[Index
],
338 &gEfiBlockIoProtocolGuid
,
340 This
->DriverBindingHandle
,
342 EFI_OPEN_PROTOCOL_GET_PROTOCOL
344 if (!EFI_ERROR (Status
)) {
346 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo
);
349 // All Software protocols have be freed from the handle so remove it.
351 BlockIo
->FlushBlocks (BlockIo
);
353 Status
= gBS
->CloseProtocol (
355 &gEfiDiskIoProtocolGuid
,
356 This
->DriverBindingHandle
,
357 ChildHandleBuffer
[Index
]
360 Status
= gBS
->UninstallMultipleProtocolInterfaces (
361 ChildHandleBuffer
[Index
],
362 &gEfiDevicePathProtocolGuid
,
364 &gEfiBlockIoProtocolGuid
,
370 if (EFI_ERROR (Status
)) {
373 &gEfiDiskIoProtocolGuid
,
375 This
->DriverBindingHandle
,
376 ChildHandleBuffer
[Index
],
377 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
380 FreePool (Private
->DevicePath
);
386 if (EFI_ERROR (Status
)) {
387 AllChildrenStopped
= FALSE
;
391 if (!AllChildrenStopped
) {
392 return EFI_DEVICE_ERROR
;
400 Reset the Block Device.
402 @param This Protocol instance pointer.
403 @param ExtendedVerification Driver may perform diagnostics on reset.
405 @retval EFI_SUCCESS The device was reset.
406 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
414 IN EFI_BLOCK_IO_PROTOCOL
*This
,
415 IN BOOLEAN ExtendedVerification
418 PARTITION_PRIVATE_DATA
*Private
;
420 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
422 return Private
->ParentBlockIo
->Reset (
423 Private
->ParentBlockIo
,
430 Read by using the Disk IO protocol on the parent device. Lba addresses
431 must be converted to byte offsets.
433 @param This Protocol instance pointer.
434 @param MediaId Id of the media, changes every time the media is replaced.
435 @param Lba The starting Logical Block Address to read from
436 @param BufferSize Size of Buffer, must be a multiple of device block size.
437 @param Buffer Buffer containing read data
439 @retval EFI_SUCCESS The data was read correctly from the device.
440 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
441 @retval EFI_NO_MEDIA There is no media in the device.
442 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
443 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
444 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
445 valid for the device.
451 PartitionReadBlocks (
452 IN EFI_BLOCK_IO_PROTOCOL
*This
,
459 PARTITION_PRIVATE_DATA
*Private
;
462 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
464 if (BufferSize
% Private
->BlockSize
!= 0) {
465 return EFI_BAD_BUFFER_SIZE
;
468 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
469 if (Offset
+ BufferSize
> Private
->End
) {
470 return EFI_INVALID_PARAMETER
;
473 // Because some kinds of partition have different block size from their parent
474 // device, we call the Disk IO protocol on the parent device, not the Block IO
477 return Private
->DiskIo
->ReadDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
481 Write by using the Disk IO protocol on the parent device. Lba addresses
482 must be converted to byte offsets.
484 @param This Protocol instance pointer.
485 @param MediaId Id of the media, changes every time the media is replaced.
486 @param Lba The starting Logical Block Address to read from
487 @param BufferSize Size of Buffer, must be a multiple of device block size.
488 @param Buffer Buffer containing read data
490 @retval EFI_SUCCESS The data was written correctly to the device.
491 @retval EFI_WRITE_PROTECTED The device can not be written to.
492 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
493 @retval EFI_NO_MEDIA There is no media in the device.
494 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
495 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
496 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
497 valid for the device.
503 PartitionWriteBlocks (
504 IN EFI_BLOCK_IO_PROTOCOL
*This
,
511 PARTITION_PRIVATE_DATA
*Private
;
514 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
516 if (BufferSize
% Private
->BlockSize
!= 0) {
517 return EFI_BAD_BUFFER_SIZE
;
520 Offset
= MultU64x32 (Lba
, Private
->BlockSize
) + Private
->Start
;
521 if (Offset
+ BufferSize
> Private
->End
) {
522 return EFI_INVALID_PARAMETER
;
525 // Because some kinds of partition have different block size from their parent
526 // device, we call the Disk IO protocol on the parent device, not the Block IO
529 return Private
->DiskIo
->WriteDisk (Private
->DiskIo
, MediaId
, Offset
, BufferSize
, Buffer
);
534 Flush the parent Block Device.
536 @param This Protocol instance pointer.
538 @retval EFI_SUCCESS All outstanding data was written to the device
539 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
540 @retval EFI_NO_MEDIA There is no media in the device.
546 PartitionFlushBlocks (
547 IN EFI_BLOCK_IO_PROTOCOL
*This
550 PARTITION_PRIVATE_DATA
*Private
;
552 Private
= PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This
);
554 return Private
->ParentBlockIo
->FlushBlocks (Private
->ParentBlockIo
);
560 Create a child handle for a logical block device that represents the
561 bytes Start to End of the Parent Block IO device.
563 @param[in] This Protocol instance pointer.
564 @param[in] This Calling context.
565 @param[in] ParentHandle Parent Handle for new child
566 @param[in] ParentDiskIo Parent DiskIo interface
567 @param[in] ParentBlockIo Parent BlockIo interface
568 @param[in] ParentDevicePath Parent Device Path
569 @param[in] DevicePathNode Child Device Path node
570 @param[in] Start Start Block
571 @param[in] End End Block
572 @param[in] BlockSize Child block size
573 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle
575 @retval EFI_SUCCESS A child handle was added
576 @retval other A child handle was not added
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
594 PARTITION_PRIVATE_DATA
*Private
;
596 Private
= AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA
));
597 if (Private
== NULL
) {
598 return EFI_OUT_OF_RESOURCES
;
601 Private
->Signature
= PARTITION_PRIVATE_DATA_SIGNATURE
;
603 Private
->Start
= MultU64x32 (Start
, ParentBlockIo
->Media
->BlockSize
);
604 Private
->End
= MultU64x32 (End
+ 1, ParentBlockIo
->Media
->BlockSize
);
606 Private
->BlockSize
= BlockSize
;
607 Private
->ParentBlockIo
= ParentBlockIo
;
608 Private
->DiskIo
= ParentDiskIo
;
610 Private
->BlockIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
612 Private
->BlockIo
.Media
= &Private
->Media
;
613 CopyMem (Private
->BlockIo
.Media
, ParentBlockIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
614 Private
->Media
.LogicalPartition
= TRUE
;
615 Private
->Media
.LastBlock
= DivU64x32 (
618 ParentBlockIo
->Media
->BlockSize
623 Private
->Media
.BlockSize
= (UINT32
) BlockSize
;
625 Private
->BlockIo
.Reset
= PartitionReset
;
626 Private
->BlockIo
.ReadBlocks
= PartitionReadBlocks
;
627 Private
->BlockIo
.WriteBlocks
= PartitionWriteBlocks
;
628 Private
->BlockIo
.FlushBlocks
= PartitionFlushBlocks
;
630 Private
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, DevicePathNode
);
632 if (Private
->DevicePath
== NULL
) {
634 return EFI_OUT_OF_RESOURCES
;
637 if (InstallEspGuid
) {
638 Private
->EspGuid
= &gEfiPartTypeSystemPartGuid
;
641 // If NULL InstallMultipleProtocolInterfaces will ignore it.
643 Private
->EspGuid
= NULL
;
646 // Create the new handle
648 Private
->Handle
= NULL
;
649 Status
= gBS
->InstallMultipleProtocolInterfaces (
651 &gEfiDevicePathProtocolGuid
,
653 &gEfiBlockIoProtocolGuid
,
660 if (!EFI_ERROR (Status
)) {
662 // Open the Parent Handle for the child
664 Status
= gBS
->OpenProtocol (
666 &gEfiDiskIoProtocolGuid
,
667 (VOID
**) &ParentDiskIo
,
668 This
->DriverBindingHandle
,
670 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
673 FreePool (Private
->DevicePath
);
682 The user Entry Point for module Partition. The user code starts with this function.
684 @param[in] ImageHandle The firmware allocated handle for the EFI image.
685 @param[in] SystemTable A pointer to the EFI System Table.
687 @retval EFI_SUCCESS The entry point is executed successfully.
688 @retval other Some error occurs when executing this entry point.
693 InitializePartition (
694 IN EFI_HANDLE ImageHandle
,
695 IN EFI_SYSTEM_TABLE
*SystemTable
701 // Install driver model protocol(s).
703 Status
= EfiLibInstallAllDriverProtocols (
706 &gPartitionDriverBinding
,
708 &gPartitionComponentName
,
712 ASSERT_EFI_ERROR (Status
);