1
/* $Id: Partition.c $ */
7
* Copyright (C) 2012 Oracle Corporation
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License (GPL) as published by the Free Software
13
* Foundation, in version 2 as it comes in the "COPYING" file of the
14
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
Partition driver that produces logical BlockIo devices from a physical
20
BlockIo device. The logical BlockIo devices are based on the format
21
of the raw block devices media. Currently "El Torito CD-ROM", Legacy
22
MBR, and GPT partition schemes are supported.
24
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
25
This program and the accompanying materials
26
are licensed and made available under the terms and conditions of the BSD License
27
which accompanies this distribution. The full text of the license may be found at
28
http://opensource.org/licenses/bsd-license.php
30
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
31
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
36
#include "Partition.h"
39
// Partition Driver Global Variables.
41
EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
42
PartitionDriverBindingSupported,
43
PartitionDriverBindingStart,
44
PartitionDriverBindingStop,
46
// Grub4Dos copies the BPB of the first partition to the MBR. If the
47
// DriverBindingStart() of the Fat driver gets run before that of Partition
48
// driver only the first partition can be recognized.
49
// Let the driver binding version of Partition driver be higher than that of
50
// Fat driver to make sure the DriverBindingStart() of the Partition driver
51
// gets run before that of Fat driver so that all the partitions can be recognized.
59
// Prioritized function list to detect partition table.
61
PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
62
PartitionInstallAppleChildHandles,
63
PartitionInstallGptChildHandles,
64
PartitionInstallElToritoChildHandles,
65
PartitionInstallMbrChildHandles,
70
Test to see if this driver supports ControllerHandle. Any ControllerHandle
71
than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
74
@param[in] This Protocol instance pointer.
75
@param[in] ControllerHandle Handle of device to test.
76
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
79
@retval EFI_SUCCESS This driver supports this device
80
@retval EFI_ALREADY_STARTED This driver is already running on this device
81
@retval other This driver does not support this device
86
PartitionDriverBindingSupported (
87
IN EFI_DRIVER_BINDING_PROTOCOL *This,
88
IN EFI_HANDLE ControllerHandle,
89
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
93
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
94
EFI_DISK_IO_PROTOCOL *DiskIo;
99
// Check RemainingDevicePath validation
101
if (RemainingDevicePath != NULL) {
103
// Check if RemainingDevicePath is the End of Device Path Node,
104
// if yes, go on checking other conditions
106
LogFlowFuncMarkDP(RemainingDevicePath);
107
if (!IsDevicePathEnd (RemainingDevicePath)) {
109
// If RemainingDevicePath isn't the End of Device Path Node,
110
// check its validation
112
Node = (EFI_DEV_PATH *) RemainingDevicePath;
113
if ( Node->DevPath.Type != MEDIA_DEVICE_PATH
114
|| Node->DevPath.SubType != MEDIA_HARDDRIVE_DP
115
|| DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)
116
|| Node->DevPath.Type != MESSAGING_DEVICE_PATH
117
|| Node->DevPath.SubType != MSG_SATA_DP) {
118
LogFlowFuncLeaveRC(EFI_UNSUPPORTED);
119
return EFI_UNSUPPORTED;
125
// Open the IO Abstraction(s) needed to perform the supported test
127
Status = gBS->OpenProtocol (
129
&gEfiDiskIoProtocolGuid,
131
This->DriverBindingHandle,
133
EFI_OPEN_PROTOCOL_BY_DRIVER
135
if (Status == EFI_ALREADY_STARTED) {
136
LogFlowFuncLeaveRC(EFI_SUCCESS);
139
if (EFI_ERROR (Status)) {
140
LogFlowFuncLeaveRC(Status);
144
// Close the I/O Abstraction(s) used to perform the supported test
148
&gEfiDiskIoProtocolGuid,
149
This->DriverBindingHandle,
154
// Open the EFI Device Path protocol needed to perform the supported test
156
Status = gBS->OpenProtocol (
158
&gEfiDevicePathProtocolGuid,
159
(VOID **) &ParentDevicePath,
160
This->DriverBindingHandle,
162
EFI_OPEN_PROTOCOL_BY_DRIVER
164
LogFlowFuncMarkDP(ParentDevicePath);
165
if (Status == EFI_ALREADY_STARTED) {
166
LogFlowFuncLeaveRC(EFI_SUCCESS);
170
if (EFI_ERROR (Status)) {
171
LogFlowFuncLeaveRC(Status);
176
// Close protocol, don't use device path protocol in the Support() function
180
&gEfiDevicePathProtocolGuid,
181
This->DriverBindingHandle,
186
// Open the IO Abstraction(s) needed to perform the supported test
188
Status = gBS->OpenProtocol (
190
&gEfiBlockIoProtocolGuid,
192
This->DriverBindingHandle,
194
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
196
if (EFI_ERROR (Status)) {
197
LogFlowFuncLeaveRC(Status);
201
LogFlowFuncLeaveRC(EFI_SUCCESS);
206
Start this driver on ControllerHandle by opening a Block IO or a Block IO2
207
or both, and Disk IO protocol, reading Device Path, and creating a child
208
handle with a Disk IO and device path protocol.
210
@param[in] This Protocol instance pointer.
211
@param[in] ControllerHandle Handle of device to bind driver to
212
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
215
@retval EFI_SUCCESS This driver is added to ControllerHandle
216
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
217
@retval other This driver does not support this device
222
PartitionDriverBindingStart (
223
IN EFI_DRIVER_BINDING_PROTOCOL *This,
224
IN EFI_HANDLE ControllerHandle,
225
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
229
EFI_STATUS OpenStatus;
230
EFI_BLOCK_IO_PROTOCOL *BlockIo;
231
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
232
EFI_DISK_IO_PROTOCOL *DiskIo;
233
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
234
PARTITION_DETECT_ROUTINE *Routine;
235
BOOLEAN MediaPresent;
241
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
243
// Check RemainingDevicePath validation
245
if (RemainingDevicePath != NULL) {
247
// Check if RemainingDevicePath is the End of Device Path Node,
248
// if yes, return EFI_SUCCESS
250
if (IsDevicePathEnd (RemainingDevicePath)) {
251
Status = EFI_SUCCESS;
257
// Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
258
// otherwise, return error.
260
Status = gBS->OpenProtocol (
262
&gEfiBlockIoProtocolGuid,
264
This->DriverBindingHandle,
266
EFI_OPEN_PROTOCOL_GET_PROTOCOL
268
if (EFI_ERROR (Status)) {
269
LogFlowFuncMarkRC(Status);
273
Status = gBS->OpenProtocol (
275
&gEfiBlockIo2ProtocolGuid,
277
This->DriverBindingHandle,
279
EFI_OPEN_PROTOCOL_BY_DRIVER
283
// Get the Device Path Protocol on ControllerHandle's handle.
285
Status = gBS->OpenProtocol (
287
&gEfiDevicePathProtocolGuid,
288
(VOID **) &ParentDevicePath,
289
This->DriverBindingHandle,
291
EFI_OPEN_PROTOCOL_BY_DRIVER
293
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
294
LogFlowFuncMarkRC(Status);
298
Status = gBS->OpenProtocol (
300
&gEfiDiskIoProtocolGuid,
302
This->DriverBindingHandle,
304
EFI_OPEN_PROTOCOL_BY_DRIVER
306
if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
309
&gEfiDevicePathProtocolGuid,
310
This->DriverBindingHandle,
313
LogFlowFuncMarkRC(Status);
320
// Try to read blocks when there's media or it is removable physical partition.
322
Status = EFI_UNSUPPORTED;
323
MediaPresent = BlockIo->Media->MediaPresent;
324
if (BlockIo->Media->MediaPresent ||
325
(BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
327
// Try for GPT, then El Torito, and then legacy MBR partition types. If the
328
// media supports a given partition type install child handles to represent
329
// the partitions described by the media.
331
Routine = &mPartitionDetectRoutineTable[0];
332
while (*Routine != NULL) {
333
Status = (*Routine) (
341
LogFlowFuncMarkRC(Status);
342
if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
343
LogFlowFuncMarkVar(idxRoutine, "%d");
351
// In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
352
// the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
353
// driver. So don't try to close them. Otherwise, we will break the dependency
354
// between the controller and the driver set up before.
356
// In the case that when the media changes on a device it will Reinstall the
357
// BlockIo interaface. This will cause a call to our Stop(), and a subsequent
358
// reentrant call to our Start() successfully. We should leave the device open
359
// when this happen. The "media change" case includes either the status is
360
// EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
362
if (EFI_ERROR (Status) &&
363
!EFI_ERROR (OpenStatus) &&
364
Status != EFI_MEDIA_CHANGED &&
365
!(MediaPresent && Status == EFI_NO_MEDIA)) {
368
&gEfiDiskIoProtocolGuid,
369
This->DriverBindingHandle,
373
// Close Parent BlockIO2 if has.
377
&gEfiBlockIo2ProtocolGuid,
378
This->DriverBindingHandle,
384
&gEfiDevicePathProtocolGuid,
385
This->DriverBindingHandle,
391
gBS->RestoreTPL (OldTpl);
392
LogFlowFuncLeaveRC(Status);
397
Stop this driver on ControllerHandle. Support stopping any child handles
398
created by this driver.
400
@param This Protocol instance pointer.
401
@param ControllerHandle Handle of device to stop driver on
402
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
403
children is zero stop the entire bus driver.
404
@param ChildHandleBuffer List of Child Handles to Stop.
406
@retval EFI_SUCCESS This driver is removed ControllerHandle
407
@retval other This driver was not removed from this device
412
PartitionDriverBindingStop (
413
IN EFI_DRIVER_BINDING_PROTOCOL *This,
414
IN EFI_HANDLE ControllerHandle,
415
IN UINTN NumberOfChildren,
416
IN EFI_HANDLE *ChildHandleBuffer
421
EFI_BLOCK_IO_PROTOCOL *BlockIo;
422
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
423
BOOLEAN AllChildrenStopped;
424
PARTITION_PRIVATE_DATA *Private;
425
EFI_DISK_IO_PROTOCOL *DiskIo;
431
if (NumberOfChildren == 0) {
433
// Close the bus driver
437
&gEfiDiskIoProtocolGuid,
438
This->DriverBindingHandle,
442
// Close Parent BlockIO2 if has.
446
&gEfiBlockIo2ProtocolGuid,
447
This->DriverBindingHandle,
453
&gEfiDevicePathProtocolGuid,
454
This->DriverBindingHandle,
460
AllChildrenStopped = TRUE;
461
for (Index = 0; Index < NumberOfChildren; Index++) {
463
ChildHandleBuffer[Index],
464
&gEfiBlockIoProtocolGuid,
466
This->DriverBindingHandle,
468
EFI_OPEN_PROTOCOL_GET_PROTOCOL
471
// Try to locate BlockIo2.
474
ChildHandleBuffer[Index],
475
&gEfiBlockIo2ProtocolGuid,
477
This->DriverBindingHandle,
479
EFI_OPEN_PROTOCOL_GET_PROTOCOL
483
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
485
Status = gBS->CloseProtocol (
487
&gEfiDiskIoProtocolGuid,
488
This->DriverBindingHandle,
489
ChildHandleBuffer[Index]
492
// All Software protocols have be freed from the handle so remove it.
493
// Remove the BlockIo Protocol if has.
494
// Remove the BlockIo2 Protocol if has.
496
if (BlockIo2 != NULL) {
497
BlockIo->FlushBlocks (BlockIo);
498
BlockIo2->FlushBlocksEx (BlockIo2, NULL);
499
Status = gBS->UninstallMultipleProtocolInterfaces (
500
ChildHandleBuffer[Index],
501
&gEfiDevicePathProtocolGuid,
503
&gEfiBlockIoProtocolGuid,
505
&gEfiBlockIo2ProtocolGuid,
512
BlockIo->FlushBlocks (BlockIo);
513
Status = gBS->UninstallMultipleProtocolInterfaces (
514
ChildHandleBuffer[Index],
515
&gEfiDevicePathProtocolGuid,
517
&gEfiBlockIoProtocolGuid,
525
if (EFI_ERROR (Status)) {
528
&gEfiDiskIoProtocolGuid,
530
This->DriverBindingHandle,
531
ChildHandleBuffer[Index],
532
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
535
FreePool (Private->DevicePath);
539
if (EFI_ERROR (Status)) {
540
AllChildrenStopped = FALSE;
544
if (!AllChildrenStopped) {
545
return EFI_DEVICE_ERROR;
553
Reset the Block Device.
555
@param This Protocol instance pointer.
556
@param ExtendedVerification Driver may perform diagnostics on reset.
558
@retval EFI_SUCCESS The device was reset.
559
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
566
IN EFI_BLOCK_IO_PROTOCOL *This,
567
IN BOOLEAN ExtendedVerification
570
PARTITION_PRIVATE_DATA *Private;
572
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
574
return Private->ParentBlockIo->Reset (
575
Private->ParentBlockIo,
581
Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
582
for no media or media change case. Otherwise DefaultStatus is returned.
584
@param DiskIo Pointer to the DiskIo instance.
585
@param MediaId Id of the media, changes every time the media is replaced.
586
@param DefaultStatus The default status to return when it's not the no media
587
or media change case.
589
@retval EFI_NO_MEDIA There is no media.
590
@retval EFI_MEDIA_CHANGED The media was changed.
591
@retval others The default status to return.
595
IN EFI_DISK_IO_PROTOCOL *DiskIo,
597
IN EFI_STATUS DefaultStatus
603
// Read 1 byte from offset 0 but passing NULL as buffer pointer
605
Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, NULL);
606
if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
609
return DefaultStatus;
613
Read by using the Disk IO protocol on the parent device. Lba addresses
614
must be converted to byte offsets.
616
@param This Protocol instance pointer.
617
@param MediaId Id of the media, changes every time the media is replaced.
618
@param Lba The starting Logical Block Address to read from
619
@param BufferSize Size of Buffer, must be a multiple of device block size.
620
@param Buffer Buffer containing read data
622
@retval EFI_SUCCESS The data was read correctly from the device.
623
@retval EFI_DEVICE_ERROR The device reported an error while performing the read.
624
@retval EFI_NO_MEDIA There is no media in the device.
625
@retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
626
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
627
@retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
628
valid for the device.
633
PartitionReadBlocks (
634
IN EFI_BLOCK_IO_PROTOCOL *This,
641
PARTITION_PRIVATE_DATA *Private;
644
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
646
if (BufferSize % Private->BlockSize != 0) {
647
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
650
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
651
if (Offset + BufferSize > Private->End) {
652
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
655
// Because some kinds of partition have different block size from their parent
656
// device, we call the Disk IO protocol on the parent device, not the Block IO
659
return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
663
Write by using the Disk IO protocol on the parent device. Lba addresses
664
must be converted to byte offsets.
666
@param[in] This Protocol instance pointer.
667
@param[in] MediaId Id of the media, changes every time the media is replaced.
668
@param[in] Lba The starting Logical Block Address to read from
669
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
670
@param[in] Buffer Buffer containing data to be written to device.
672
@retval EFI_SUCCESS The data was written correctly to the device.
673
@retval EFI_WRITE_PROTECTED The device can not be written to.
674
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
675
@retval EFI_NO_MEDIA There is no media in the device.
676
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
677
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
678
@retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
679
valid for the device.
684
PartitionWriteBlocks (
685
IN EFI_BLOCK_IO_PROTOCOL *This,
692
PARTITION_PRIVATE_DATA *Private;
695
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
697
if (BufferSize % Private->BlockSize != 0) {
698
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
701
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
702
if (Offset + BufferSize > Private->End) {
703
return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
706
// Because some kinds of partition have different block size from their parent
707
// device, we call the Disk IO protocol on the parent device, not the Block IO
710
return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
715
Flush the parent Block Device.
717
@param This Protocol instance pointer.
719
@retval EFI_SUCCESS All outstanding data was written to the device
720
@retval EFI_DEVICE_ERROR The device reported an error while writting back the data
721
@retval EFI_NO_MEDIA There is no media in the device.
726
PartitionFlushBlocks (
727
IN EFI_BLOCK_IO_PROTOCOL *This
730
PARTITION_PRIVATE_DATA *Private;
732
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
734
return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
738
Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
739
for no media or media change case. Otherwise DefaultStatus is returned.
741
@param BlockIo2 Pointer to the BlockIo2 instance.
742
@param MediaId Id of the media, changes every time the media is replaced.
743
@param DefaultStatus The default status to return when it's not the no media
744
or media change case.
746
@retval EFI_NO_MEDIA There is no media.
747
@retval EFI_MEDIA_CHANGED The media was changed.
748
@retval others The default status to return.
752
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
754
IN EFI_STATUS DefaultStatus
760
// Read from LBA 0 but passing NULL as buffer pointer to detect the media status.
762
Status = BlockIo2->ReadBlocksEx (
770
if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
773
return DefaultStatus;
777
Reset the Block Device throught Block I/O2 protocol.
779
@param This Protocol instance pointer.
780
@param ExtendedVerification Driver may perform diagnostics on reset.
782
@retval EFI_SUCCESS The device was reset.
783
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
790
IN EFI_BLOCK_IO2_PROTOCOL *This,
791
IN BOOLEAN ExtendedVerification
794
PARTITION_PRIVATE_DATA *Private;
796
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
798
return Private->ParentBlockIo2->Reset (
799
Private->ParentBlockIo2,
805
Read BufferSize bytes from Lba into Buffer.
807
This function reads the requested number of blocks from the device. All the
808
blocks are read, or an error is returned.
809
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
810
non-blocking I/O is being used, the Event associated with this request will
813
@param[in] This Indicates a pointer to the calling context.
814
@param[in] MediaId Id of the media, changes every time the media is
816
@param[in] Lba The starting Logical Block Address to read from.
817
@param[in, out] Token A pointer to the token associated with the transaction.
818
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
819
@param[out] Buffer A pointer to the destination buffer for the data. The
820
caller is responsible for either having implicit or
821
explicit ownership of the buffer.
823
@retval EFI_SUCCESS The read request was queued if Token->Event is
824
not NULL.The data was read correctly from the
825
device if the Token->Event is NULL.
826
@retval EFI_DEVICE_ERROR The device reported an error while performing
828
@retval EFI_NO_MEDIA There is no media in the device.
829
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
830
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
831
intrinsic block size of the device.
832
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
833
or the buffer is not on proper alignment.
834
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
839
PartitionReadBlocksEx (
840
IN EFI_BLOCK_IO2_PROTOCOL *This,
843
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
848
PARTITION_PRIVATE_DATA *Private;
852
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
855
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
858
if (BufferSize % Private->BlockSize != 0) {
859
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
862
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
863
if (Offset + BufferSize > Private->End) {
864
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
868
// Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
869
// be multiple of BlockSize. If the Spec will be updated the DiskIO to support
870
// BlockIO2, this limitation will be removed and call DiskIO here.
872
Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
874
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
878
// Because some partitions have different block size from their parent
879
// device, in that case the Block I/O2 couldn't be called.
881
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
882
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
885
return Private->ParentBlockIo2->ReadBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
889
Write BufferSize bytes from Lba into Buffer.
891
This function writes the requested number of blocks to the device. All blocks
892
are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
893
EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
894
being used, the Event associated with this request will not be signaled.
896
@param[in] This Indicates a pointer to the calling context.
897
@param[in] MediaId The media ID that the write request is for.
898
@param[in] Lba The starting logical block address to be written. The
899
caller is responsible for writing to only legitimate
901
@param[in, out] Token A pointer to the token associated with the transaction.
902
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
903
@param[in] Buffer A pointer to the source buffer for the data.
905
@retval EFI_SUCCESS The write request was queued if Event is not NULL.
906
The data was written correctly to the device if
908
@retval EFI_WRITE_PROTECTED The device can not be written to.
909
@retval EFI_NO_MEDIA There is no media in the device.
910
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
911
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
912
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
913
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
914
or the buffer is not on proper alignment.
915
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
921
PartitionWriteBlocksEx (
922
IN EFI_BLOCK_IO2_PROTOCOL *This,
925
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
930
PARTITION_PRIVATE_DATA *Private;
934
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
937
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
940
if (BufferSize % Private->BlockSize != 0) {
941
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
944
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
945
if (Offset + BufferSize > Private->End) {
946
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
950
// Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
951
// be multiple of BlockSize. If the Spec will be updated the DiskIO to support
952
// BlockIO2, this limitation will be removed and call DiskIO here.
954
Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
956
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
960
// Because some kinds of partition have different block size from their parent,
961
// in that case it couldn't call parent Block I/O2.
963
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
964
return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
967
return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
971
Flush the Block Device.
973
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
974
is returned and non-blocking I/O is being used, the Event associated with
975
this request will not be signaled.
977
@param[in] This Indicates a pointer to the calling context.
978
@param[in, out] Token A pointer to the token associated with the transaction
980
@retval EFI_SUCCESS The flush request was queued if Event is not NULL.
981
All outstanding data was written correctly to the
982
device if the Event is NULL.
983
@retval EFI_DEVICE_ERROR The device reported an error while writting back
985
@retval EFI_WRITE_PROTECTED The device cannot be written to.
986
@retval EFI_NO_MEDIA There is no media in the device.
987
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
988
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
994
PartitionFlushBlocksEx (
995
IN EFI_BLOCK_IO2_PROTOCOL *This,
996
IN OUT EFI_BLOCK_IO2_TOKEN *Token
999
PARTITION_PRIVATE_DATA *Private;
1001
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
1004
// Because some kinds of partition have different block size from their parent,
1005
// in that case it couldn't call parent Block I/O2.
1007
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
1008
return EFI_UNSUPPORTED;
1011
return Private->ParentBlockIo2->FlushBlocksEx (Private->ParentBlockIo2, Token);
1016
Create a child handle for a logical block device that represents the
1017
bytes Start to End of the Parent Block IO device.
1019
@param[in] This Protocol instance pointer.
1020
@param[in] ParentHandle Parent Handle for new child.
1021
@param[in] ParentDiskIo Parent DiskIo interface.
1022
@param[in] ParentBlockIo Parent BlockIo interface.
1023
@param[in] ParentBlockIo2 Parent BlockIo2 interface.
1024
@param[in] ParentDevicePath Parent Device Path.
1025
@param[in] DevicePathNode Child Device Path node.
1026
@param[in] Start Start Block.
1027
@param[in] End End Block.
1028
@param[in] BlockSize Child block size.
1029
@param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
1031
@retval EFI_SUCCESS A child handle was added.
1032
@retval other A child handle was not added.
1036
PartitionInstallChildHandle (
1037
IN EFI_DRIVER_BINDING_PROTOCOL *This,
1038
IN EFI_HANDLE ParentHandle,
1039
IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
1040
IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
1041
IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
1042
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1043
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
1046
IN UINT32 BlockSize,
1047
IN BOOLEAN InstallEspGuid
1051
PARTITION_PRIVATE_DATA *Private;
1053
Status = EFI_SUCCESS;
1054
Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
1055
if (Private == NULL) {
1056
return EFI_OUT_OF_RESOURCES;
1059
Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
1061
Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
1062
Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
1064
Private->BlockSize = BlockSize;
1065
Private->ParentBlockIo = ParentBlockIo;
1066
Private->ParentBlockIo2 = ParentBlockIo2;
1067
Private->DiskIo = ParentDiskIo;
1070
// Set the BlockIO into Private Data.
1072
Private->BlockIo.Revision = ParentBlockIo->Revision;
1074
Private->BlockIo.Media = &Private->Media;
1075
CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1077
Private->BlockIo.Reset = PartitionReset;
1078
Private->BlockIo.ReadBlocks = PartitionReadBlocks;
1079
Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
1080
Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
1083
// Set the BlockIO2 into Private Data.
1085
if (Private->ParentBlockIo2 != NULL) {
1086
Private->BlockIo2.Media = &Private->Media2;
1087
CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1089
Private->BlockIo2.Reset = PartitionResetEx;
1090
Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
1091
Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
1092
Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
1095
Private->Media.IoAlign = 0;
1096
Private->Media.LogicalPartition = TRUE;
1097
Private->Media.LastBlock = DivU64x32 (
1100
ParentBlockIo->Media->BlockSize
1105
Private->Media.BlockSize = (UINT32) BlockSize;
1108
// For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
1110
Private->Media2.LogicalPartition = TRUE;
1111
Private->Media2.LastBlock = Private->Media.LastBlock;
1112
Private->Media2.BlockSize = (UINT32) BlockSize;
1115
// Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1116
// for logical partitions.
1118
if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
1119
Private->Media.LowestAlignedLba = 0;
1120
Private->Media.LogicalBlocksPerPhysicalBlock = 0;
1121
Private->Media2.LowestAlignedLba = 0;
1122
Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
1123
if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
1124
Private->Media.OptimalTransferLengthGranularity = 0;
1125
Private->Media2.OptimalTransferLengthGranularity = 0;
1129
Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
1131
if (Private->DevicePath == NULL) {
1133
return EFI_OUT_OF_RESOURCES;
1136
if (InstallEspGuid) {
1137
Private->EspGuid = &gEfiPartTypeSystemPartGuid;
1140
// If NULL InstallMultipleProtocolInterfaces will ignore it.
1142
Private->EspGuid = NULL;
1146
// Create the new handle.
1147
// BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
1148
// is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
1149
// directly call the parent BlockIO and doesn't handle the different block size issue.
1150
// If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
1151
// DiskIO to handle the blocksize unequal issue and the limitation will be remove from
1154
Private->Handle = NULL;
1155
if ((Private->ParentBlockIo2 != NULL) &&
1156
(Private->ParentBlockIo2->Media->BlockSize == BlockSize)
1158
Status = gBS->InstallMultipleProtocolInterfaces (
1160
&gEfiDevicePathProtocolGuid,
1161
Private->DevicePath,
1162
&gEfiBlockIoProtocolGuid,
1164
&gEfiBlockIo2ProtocolGuid,
1171
Status = gBS->InstallMultipleProtocolInterfaces (
1173
&gEfiDevicePathProtocolGuid,
1174
Private->DevicePath,
1175
&gEfiBlockIoProtocolGuid,
1183
if (!EFI_ERROR (Status)) {
1185
// Open the Parent Handle for the child
1187
Status = gBS->OpenProtocol (
1189
&gEfiDiskIoProtocolGuid,
1190
(VOID **) &ParentDiskIo,
1191
This->DriverBindingHandle,
1193
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1196
FreePool (Private->DevicePath);
1205
The user Entry Point for module Partition. The user code starts with this function.
1207
@param[in] ImageHandle The firmware allocated handle for the EFI image.
1208
@param[in] SystemTable A pointer to the EFI System Table.
1210
@retval EFI_SUCCESS The entry point is executed successfully.
1211
@retval other Some error occurs when executing this entry point.
1216
InitializePartition (
1217
IN EFI_HANDLE ImageHandle,
1218
IN EFI_SYSTEM_TABLE *SystemTable
1224
// Install driver model protocol(s).
1226
Status = EfiLibInstallDriverBindingComponentName2 (
1229
&gPartitionDriverBinding,
1231
&gPartitionComponentName,
1232
&gPartitionComponentName2
1234
ASSERT_EFI_ERROR (Status);