]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
1c53bf0233fdda1a82d4078b4d80af15d9a1158b
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Partition.c
1 /** @file
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.
6
7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
8 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
12
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.
15
16 **/
17
18
19 #include "Partition.h"
20
21 //
22 // Partition Driver Global Variables.
23 //
24 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
25 PartitionDriverBindingSupported,
26 PartitionDriverBindingStart,
27 PartitionDriverBindingStop,
28 //
29 // Grub4Dos copies the BPB of the first partition to the MBR. If the
30 // DriverBindingStart() of the Fat driver gets run before that of Partition
31 // driver only the first partition can be recognized.
32 // Let the driver binding version of Partition driver be higher than that of
33 // Fat driver to make sure the DriverBindingStart() of the Partition driver
34 // gets run before that of Fat driver so that all the partitions can be recognized.
35 //
36 0xb,
37 NULL,
38 NULL
39 };
40
41 //
42 // Prioritized function list to detect partition table.
43 //
44 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
45 PartitionInstallGptChildHandles,
46 PartitionInstallElToritoChildHandles,
47 PartitionInstallMbrChildHandles,
48 NULL
49 };
50
51 /**
52 Test to see if this driver supports ControllerHandle. Any ControllerHandle
53 than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
54 supported.
55
56 @param[in] This Protocol instance pointer.
57 @param[in] ControllerHandle Handle of device to test.
58 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
59 device to start.
60
61 @retval EFI_SUCCESS This driver supports this device
62 @retval EFI_ALREADY_STARTED This driver is already running on this device
63 @retval other This driver does not support this device
64
65 **/
66 EFI_STATUS
67 EFIAPI
68 PartitionDriverBindingSupported (
69 IN EFI_DRIVER_BINDING_PROTOCOL *This,
70 IN EFI_HANDLE ControllerHandle,
71 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
72 )
73 {
74 EFI_STATUS Status;
75 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
76 EFI_DISK_IO_PROTOCOL *DiskIo;
77 EFI_DEV_PATH *Node;
78
79 //
80 // Check RemainingDevicePath validation
81 //
82 if (RemainingDevicePath != NULL) {
83 //
84 // Check if RemainingDevicePath is the End of Device Path Node,
85 // if yes, go on checking other conditions
86 //
87 if (!IsDevicePathEnd (RemainingDevicePath)) {
88 //
89 // If RemainingDevicePath isn't the End of Device Path Node,
90 // check its validation
91 //
92 Node = (EFI_DEV_PATH *) RemainingDevicePath;
93 if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
94 Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
95 DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
96 return EFI_UNSUPPORTED;
97 }
98 }
99 }
100
101 //
102 // Open the IO Abstraction(s) needed to perform the supported test
103 //
104 Status = gBS->OpenProtocol (
105 ControllerHandle,
106 &gEfiDiskIoProtocolGuid,
107 (VOID **) &DiskIo,
108 This->DriverBindingHandle,
109 ControllerHandle,
110 EFI_OPEN_PROTOCOL_BY_DRIVER
111 );
112 if (Status == EFI_ALREADY_STARTED) {
113 return EFI_SUCCESS;
114 }
115 if (EFI_ERROR (Status)) {
116 return Status;
117 }
118 //
119 // Close the I/O Abstraction(s) used to perform the supported test
120 //
121 gBS->CloseProtocol (
122 ControllerHandle,
123 &gEfiDiskIoProtocolGuid,
124 This->DriverBindingHandle,
125 ControllerHandle
126 );
127
128 //
129 // Open the EFI Device Path protocol needed to perform the supported test
130 //
131 Status = gBS->OpenProtocol (
132 ControllerHandle,
133 &gEfiDevicePathProtocolGuid,
134 (VOID **) &ParentDevicePath,
135 This->DriverBindingHandle,
136 ControllerHandle,
137 EFI_OPEN_PROTOCOL_BY_DRIVER
138 );
139 if (Status == EFI_ALREADY_STARTED) {
140 return EFI_SUCCESS;
141 }
142
143 if (EFI_ERROR (Status)) {
144 return Status;
145 }
146
147 //
148 // Close protocol, don't use device path protocol in the Support() function
149 //
150 gBS->CloseProtocol (
151 ControllerHandle,
152 &gEfiDevicePathProtocolGuid,
153 This->DriverBindingHandle,
154 ControllerHandle
155 );
156
157 //
158 // Open the IO Abstraction(s) needed to perform the supported test
159 //
160 Status = gBS->OpenProtocol (
161 ControllerHandle,
162 &gEfiBlockIoProtocolGuid,
163 NULL,
164 This->DriverBindingHandle,
165 ControllerHandle,
166 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
167 );
168
169 return Status;
170 }
171
172 /**
173 Start this driver on ControllerHandle by opening a Block IO or a Block IO2
174 or both, and Disk IO protocol, reading Device Path, and creating a child
175 handle with a Disk IO and device path protocol.
176
177 @param[in] This Protocol instance pointer.
178 @param[in] ControllerHandle Handle of device to bind driver to
179 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
180 device to start.
181
182 @retval EFI_SUCCESS This driver is added to ControllerHandle
183 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
184 @retval other This driver does not support this device
185
186 **/
187 EFI_STATUS
188 EFIAPI
189 PartitionDriverBindingStart (
190 IN EFI_DRIVER_BINDING_PROTOCOL *This,
191 IN EFI_HANDLE ControllerHandle,
192 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
193 )
194 {
195 EFI_STATUS Status;
196 EFI_STATUS OpenStatus;
197 EFI_BLOCK_IO_PROTOCOL *BlockIo;
198 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
199 EFI_DISK_IO_PROTOCOL *DiskIo;
200 EFI_DISK_IO2_PROTOCOL *DiskIo2;
201 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
202 PARTITION_DETECT_ROUTINE *Routine;
203 BOOLEAN MediaPresent;
204 EFI_TPL OldTpl;
205
206 BlockIo2 = NULL;
207 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
208 //
209 // Check RemainingDevicePath validation
210 //
211 if (RemainingDevicePath != NULL) {
212 //
213 // Check if RemainingDevicePath is the End of Device Path Node,
214 // if yes, return EFI_SUCCESS
215 //
216 if (IsDevicePathEnd (RemainingDevicePath)) {
217 Status = EFI_SUCCESS;
218 goto Exit;
219 }
220 }
221
222 //
223 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
224 // otherwise, return error.
225 //
226 Status = gBS->OpenProtocol (
227 ControllerHandle,
228 &gEfiBlockIoProtocolGuid,
229 (VOID **) &BlockIo,
230 This->DriverBindingHandle,
231 ControllerHandle,
232 EFI_OPEN_PROTOCOL_GET_PROTOCOL
233 );
234 if (EFI_ERROR (Status)) {
235 goto Exit;
236 }
237
238 Status = gBS->OpenProtocol (
239 ControllerHandle,
240 &gEfiBlockIo2ProtocolGuid,
241 (VOID **) &BlockIo2,
242 This->DriverBindingHandle,
243 ControllerHandle,
244 EFI_OPEN_PROTOCOL_GET_PROTOCOL
245 );
246 if (EFI_ERROR (Status)) {
247 BlockIo2 = NULL;
248 }
249
250 //
251 // Get the Device Path Protocol on ControllerHandle's handle.
252 //
253 Status = gBS->OpenProtocol (
254 ControllerHandle,
255 &gEfiDevicePathProtocolGuid,
256 (VOID **) &ParentDevicePath,
257 This->DriverBindingHandle,
258 ControllerHandle,
259 EFI_OPEN_PROTOCOL_BY_DRIVER
260 );
261 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
262 goto Exit;
263 }
264
265 //
266 // Get the DiskIo and DiskIo2.
267 //
268 Status = gBS->OpenProtocol (
269 ControllerHandle,
270 &gEfiDiskIoProtocolGuid,
271 (VOID **) &DiskIo,
272 This->DriverBindingHandle,
273 ControllerHandle,
274 EFI_OPEN_PROTOCOL_BY_DRIVER
275 );
276 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
277 gBS->CloseProtocol (
278 ControllerHandle,
279 &gEfiDevicePathProtocolGuid,
280 This->DriverBindingHandle,
281 ControllerHandle
282 );
283 goto Exit;
284 }
285
286 OpenStatus = Status;
287
288 Status = gBS->OpenProtocol (
289 ControllerHandle,
290 &gEfiDiskIo2ProtocolGuid,
291 (VOID **) &DiskIo2,
292 This->DriverBindingHandle,
293 ControllerHandle,
294 EFI_OPEN_PROTOCOL_BY_DRIVER
295 );
296 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
297 DiskIo2 = NULL;
298 }
299
300 //
301 // Try to read blocks when there's media or it is removable physical partition.
302 //
303 Status = EFI_UNSUPPORTED;
304 MediaPresent = BlockIo->Media->MediaPresent;
305 if (BlockIo->Media->MediaPresent ||
306 (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
307 //
308 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
309 // media supports a given partition type install child handles to represent
310 // the partitions described by the media.
311 //
312 Routine = &mPartitionDetectRoutineTable[0];
313 while (*Routine != NULL) {
314 Status = (*Routine) (
315 This,
316 ControllerHandle,
317 DiskIo,
318 DiskIo2,
319 BlockIo,
320 BlockIo2,
321 ParentDevicePath
322 );
323 if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
324 break;
325 }
326 Routine++;
327 }
328 }
329 //
330 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
331 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
332 // driver. So don't try to close them. Otherwise, we will break the dependency
333 // between the controller and the driver set up before.
334 //
335 // In the case that when the media changes on a device it will Reinstall the
336 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
337 // reentrant call to our Start() successfully. We should leave the device open
338 // when this happen. The "media change" case includes either the status is
339 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
340 //
341 if (EFI_ERROR (Status) &&
342 !EFI_ERROR (OpenStatus) &&
343 Status != EFI_MEDIA_CHANGED &&
344 !(MediaPresent && Status == EFI_NO_MEDIA)) {
345 gBS->CloseProtocol (
346 ControllerHandle,
347 &gEfiDiskIoProtocolGuid,
348 This->DriverBindingHandle,
349 ControllerHandle
350 );
351 //
352 // Close Parent DiskIo2 if has.
353 //
354 gBS->CloseProtocol (
355 ControllerHandle,
356 &gEfiDiskIo2ProtocolGuid,
357 This->DriverBindingHandle,
358 ControllerHandle
359 );
360
361 gBS->CloseProtocol (
362 ControllerHandle,
363 &gEfiDevicePathProtocolGuid,
364 This->DriverBindingHandle,
365 ControllerHandle
366 );
367 }
368
369 Exit:
370 gBS->RestoreTPL (OldTpl);
371 return Status;
372 }
373
374 /**
375 Stop this driver on ControllerHandle. Support stopping any child handles
376 created by this driver.
377
378 @param This Protocol instance pointer.
379 @param ControllerHandle Handle of device to stop driver on
380 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
381 children is zero stop the entire bus driver.
382 @param ChildHandleBuffer List of Child Handles to Stop.
383
384 @retval EFI_SUCCESS This driver is removed ControllerHandle
385 @retval other This driver was not removed from this device
386
387 **/
388 EFI_STATUS
389 EFIAPI
390 PartitionDriverBindingStop (
391 IN EFI_DRIVER_BINDING_PROTOCOL *This,
392 IN EFI_HANDLE ControllerHandle,
393 IN UINTN NumberOfChildren,
394 IN EFI_HANDLE *ChildHandleBuffer
395 )
396 {
397 EFI_STATUS Status;
398 UINTN Index;
399 EFI_BLOCK_IO_PROTOCOL *BlockIo;
400 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
401 BOOLEAN AllChildrenStopped;
402 PARTITION_PRIVATE_DATA *Private;
403 EFI_DISK_IO_PROTOCOL *DiskIo;
404
405 BlockIo = NULL;
406 BlockIo2 = NULL;
407 Private = NULL;
408
409 if (NumberOfChildren == 0) {
410 //
411 // In the case of re-entry of the PartitionDriverBindingStop, the
412 // NumberOfChildren may not reflect the actual number of children on the
413 // bus driver. Hence, additional check is needed here.
414 //
415 if (HasChildren (ControllerHandle)) {
416 DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n"));
417 return EFI_DEVICE_ERROR;
418 }
419
420 //
421 // Close the bus driver
422 //
423 gBS->CloseProtocol (
424 ControllerHandle,
425 &gEfiDiskIoProtocolGuid,
426 This->DriverBindingHandle,
427 ControllerHandle
428 );
429 //
430 // Close Parent BlockIO2 if has.
431 //
432 gBS->CloseProtocol (
433 ControllerHandle,
434 &gEfiDiskIo2ProtocolGuid,
435 This->DriverBindingHandle,
436 ControllerHandle
437 );
438
439 gBS->CloseProtocol (
440 ControllerHandle,
441 &gEfiDevicePathProtocolGuid,
442 This->DriverBindingHandle,
443 ControllerHandle
444 );
445 return EFI_SUCCESS;
446 }
447
448 AllChildrenStopped = TRUE;
449 for (Index = 0; Index < NumberOfChildren; Index++) {
450 gBS->OpenProtocol (
451 ChildHandleBuffer[Index],
452 &gEfiBlockIoProtocolGuid,
453 (VOID **) &BlockIo,
454 This->DriverBindingHandle,
455 ControllerHandle,
456 EFI_OPEN_PROTOCOL_GET_PROTOCOL
457 );
458 //
459 // Try to locate BlockIo2.
460 //
461 gBS->OpenProtocol (
462 ChildHandleBuffer[Index],
463 &gEfiBlockIo2ProtocolGuid,
464 (VOID **) &BlockIo2,
465 This->DriverBindingHandle,
466 ControllerHandle,
467 EFI_OPEN_PROTOCOL_GET_PROTOCOL
468 );
469
470
471 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
472 if (Private->InStop) {
473 //
474 // If the child handle is going to be stopped again during the re-entry
475 // of DriverBindingStop, just do nothing.
476 //
477 break;
478 }
479 Private->InStop = TRUE;
480
481 BlockIo->FlushBlocks (BlockIo);
482
483 if (BlockIo2 != NULL) {
484 Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);
485 DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));
486 } else {
487 Status = EFI_SUCCESS;
488 }
489
490 gBS->CloseProtocol (
491 ControllerHandle,
492 &gEfiDiskIoProtocolGuid,
493 This->DriverBindingHandle,
494 ChildHandleBuffer[Index]
495 );
496 //
497 // All Software protocols have be freed from the handle so remove it.
498 // Remove the BlockIo Protocol if has.
499 // Remove the BlockIo2 Protocol if has.
500 //
501 if (BlockIo2 != NULL) {
502 //
503 // Some device drivers might re-install the BlockIO(2) protocols for a
504 // media change condition. Therefore, if the FlushBlocksEx returned with
505 // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
506 // reference of already stopped child handle.
507 //
508 if (Status != EFI_MEDIA_CHANGED) {
509 Status = gBS->UninstallMultipleProtocolInterfaces (
510 ChildHandleBuffer[Index],
511 &gEfiDevicePathProtocolGuid,
512 Private->DevicePath,
513 &gEfiBlockIoProtocolGuid,
514 &Private->BlockIo,
515 &gEfiBlockIo2ProtocolGuid,
516 &Private->BlockIo2,
517 Private->EspGuid,
518 NULL,
519 NULL
520 );
521 }
522 } else {
523 Status = gBS->UninstallMultipleProtocolInterfaces (
524 ChildHandleBuffer[Index],
525 &gEfiDevicePathProtocolGuid,
526 Private->DevicePath,
527 &gEfiBlockIoProtocolGuid,
528 &Private->BlockIo,
529 Private->EspGuid,
530 NULL,
531 NULL
532 );
533 }
534
535 if (EFI_ERROR (Status)) {
536 Private->InStop = FALSE;
537 gBS->OpenProtocol (
538 ControllerHandle,
539 &gEfiDiskIoProtocolGuid,
540 (VOID **) &DiskIo,
541 This->DriverBindingHandle,
542 ChildHandleBuffer[Index],
543 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
544 );
545 } else {
546 FreePool (Private->DevicePath);
547 FreePool (Private);
548 }
549
550 if (EFI_ERROR (Status)) {
551 AllChildrenStopped = FALSE;
552 if (Status == EFI_MEDIA_CHANGED) {
553 break;
554 }
555 }
556 }
557
558 if (!AllChildrenStopped) {
559 return EFI_DEVICE_ERROR;
560 }
561
562 return EFI_SUCCESS;
563 }
564
565
566 /**
567 Reset the Block Device.
568
569 @param This Protocol instance pointer.
570 @param ExtendedVerification Driver may perform diagnostics on reset.
571
572 @retval EFI_SUCCESS The device was reset.
573 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
574 not be reset.
575
576 **/
577 EFI_STATUS
578 EFIAPI
579 PartitionReset (
580 IN EFI_BLOCK_IO_PROTOCOL *This,
581 IN BOOLEAN ExtendedVerification
582 )
583 {
584 PARTITION_PRIVATE_DATA *Private;
585
586 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
587
588 return Private->ParentBlockIo->Reset (
589 Private->ParentBlockIo,
590 ExtendedVerification
591 );
592 }
593
594 /**
595 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
596 for no media or media change case. Otherwise DefaultStatus is returned.
597
598 @param DiskIo Pointer to the DiskIo instance.
599 @param MediaId Id of the media, changes every time the media is replaced.
600 @param DefaultStatus The default status to return when it's not the no media
601 or media change case.
602
603 @retval EFI_NO_MEDIA There is no media.
604 @retval EFI_MEDIA_CHANGED The media was changed.
605 @retval others The default status to return.
606 **/
607 EFI_STATUS
608 ProbeMediaStatus (
609 IN EFI_DISK_IO_PROTOCOL *DiskIo,
610 IN UINT32 MediaId,
611 IN EFI_STATUS DefaultStatus
612 )
613 {
614 EFI_STATUS Status;
615 UINT8 Buffer[1];
616
617 //
618 // Read 1 byte from offset 0 to check if the MediaId is still valid.
619 // The reading operation is synchronious thus it is not worth it to
620 // allocate a buffer from the pool. The destination buffer for the
621 // data is in the stack.
622 //
623 Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer);
624 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
625 return Status;
626 }
627 return DefaultStatus;
628 }
629
630 /**
631 Read by using the Disk IO protocol on the parent device. Lba addresses
632 must be converted to byte offsets.
633
634 @param This Protocol instance pointer.
635 @param MediaId Id of the media, changes every time the media is replaced.
636 @param Lba The starting Logical Block Address to read from
637 @param BufferSize Size of Buffer, must be a multiple of device block size.
638 @param Buffer Buffer containing read data
639
640 @retval EFI_SUCCESS The data was read correctly from the device.
641 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
642 @retval EFI_NO_MEDIA There is no media in the device.
643 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
644 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
645 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
646 valid for the device.
647
648 **/
649 EFI_STATUS
650 EFIAPI
651 PartitionReadBlocks (
652 IN EFI_BLOCK_IO_PROTOCOL *This,
653 IN UINT32 MediaId,
654 IN EFI_LBA Lba,
655 IN UINTN BufferSize,
656 OUT VOID *Buffer
657 )
658 {
659 PARTITION_PRIVATE_DATA *Private;
660 UINT64 Offset;
661
662 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
663
664 if (BufferSize % Private->BlockSize != 0) {
665 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
666 }
667
668 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
669 if (Offset + BufferSize > Private->End) {
670 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
671 }
672 //
673 // Because some kinds of partition have different block size from their parent
674 // device, we call the Disk IO protocol on the parent device, not the Block IO
675 // protocol
676 //
677 return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
678 }
679
680 /**
681 Write by using the Disk IO protocol on the parent device. Lba addresses
682 must be converted to byte offsets.
683
684 @param[in] This Protocol instance pointer.
685 @param[in] MediaId Id of the media, changes every time the media is replaced.
686 @param[in] Lba The starting Logical Block Address to read from
687 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
688 @param[in] Buffer Buffer containing data to be written to device.
689
690 @retval EFI_SUCCESS The data was written correctly to the device.
691 @retval EFI_WRITE_PROTECTED The device can not be written to.
692 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
693 @retval EFI_NO_MEDIA There is no media in the device.
694 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
695 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
696 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
697 valid for the device.
698
699 **/
700 EFI_STATUS
701 EFIAPI
702 PartitionWriteBlocks (
703 IN EFI_BLOCK_IO_PROTOCOL *This,
704 IN UINT32 MediaId,
705 IN EFI_LBA Lba,
706 IN UINTN BufferSize,
707 IN VOID *Buffer
708 )
709 {
710 PARTITION_PRIVATE_DATA *Private;
711 UINT64 Offset;
712
713 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
714
715 if (BufferSize % Private->BlockSize != 0) {
716 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
717 }
718
719 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
720 if (Offset + BufferSize > Private->End) {
721 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
722 }
723 //
724 // Because some kinds of partition have different block size from their parent
725 // device, we call the Disk IO protocol on the parent device, not the Block IO
726 // protocol
727 //
728 return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
729 }
730
731
732 /**
733 Flush the parent Block Device.
734
735 @param This Protocol instance pointer.
736
737 @retval EFI_SUCCESS All outstanding data was written to the device
738 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
739 @retval EFI_NO_MEDIA There is no media in the device.
740
741 **/
742 EFI_STATUS
743 EFIAPI
744 PartitionFlushBlocks (
745 IN EFI_BLOCK_IO_PROTOCOL *This
746 )
747 {
748 PARTITION_PRIVATE_DATA *Private;
749
750 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
751
752 return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
753 }
754
755 /**
756 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
757 for no media or media change case. Otherwise DefaultStatus is returned.
758
759 @param DiskIo2 Pointer to the DiskIo2 instance.
760 @param MediaId Id of the media, changes every time the media is replaced.
761 @param DefaultStatus The default status to return when it's not the no media
762 or media change case.
763
764 @retval EFI_NO_MEDIA There is no media.
765 @retval EFI_MEDIA_CHANGED The media was changed.
766 @retval others The default status to return.
767 **/
768 EFI_STATUS
769 ProbeMediaStatusEx (
770 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
771 IN UINT32 MediaId,
772 IN EFI_STATUS DefaultStatus
773 )
774 {
775 EFI_STATUS Status;
776
777 //
778 // Read 1 byte from offset 0 but passing NULL as buffer pointer
779 //
780 Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, NULL);
781 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
782 return Status;
783 }
784 return DefaultStatus;
785 }
786
787 /**
788 Reset the Block Device throught Block I/O2 protocol.
789
790 @param This Protocol instance pointer.
791 @param ExtendedVerification Driver may perform diagnostics on reset.
792
793 @retval EFI_SUCCESS The device was reset.
794 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
795 not be reset.
796
797 **/
798 EFI_STATUS
799 EFIAPI
800 PartitionResetEx (
801 IN EFI_BLOCK_IO2_PROTOCOL *This,
802 IN BOOLEAN ExtendedVerification
803 )
804 {
805 PARTITION_PRIVATE_DATA *Private;
806
807 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
808
809 return Private->ParentBlockIo2->Reset (
810 Private->ParentBlockIo2,
811 ExtendedVerification
812 );
813 }
814
815 /**
816 The general callback for the DiskIo2 interfaces.
817 @param Event Event whose notification function is being invoked.
818 @param Context The pointer to the notification function's context,
819 which points to the PARTITION_ACCESS_TASK instance.
820 **/
821 VOID
822 EFIAPI
823 PartitionOnAccessComplete (
824 IN EFI_EVENT Event,
825 IN VOID *Context
826 )
827 {
828 PARTITION_ACCESS_TASK *Task;
829
830 Task = (PARTITION_ACCESS_TASK *) Context;
831
832 gBS->CloseEvent (Event);
833
834 Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;
835 gBS->SignalEvent (Task->BlockIo2Token->Event);
836
837 FreePool (Task);
838 }
839
840 /**
841 Create a new PARTITION_ACCESS_TASK instance.
842
843 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
844
845 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
846 **/
847 PARTITION_ACCESS_TASK *
848 PartitionCreateAccessTask (
849 IN EFI_BLOCK_IO2_TOKEN *Token
850 )
851 {
852 EFI_STATUS Status;
853 PARTITION_ACCESS_TASK *Task;
854
855 Task = AllocatePool (sizeof (*Task));
856 if (Task == NULL) {
857 return NULL;
858 }
859
860 Status = gBS->CreateEvent (
861 EVT_NOTIFY_SIGNAL,
862 TPL_NOTIFY,
863 PartitionOnAccessComplete,
864 Task,
865 &Task->DiskIo2Token.Event
866 );
867 if (EFI_ERROR (Status)) {
868 FreePool (Task);
869 return NULL;
870 }
871
872 Task->BlockIo2Token = Token;
873
874 return Task;
875 }
876
877 /**
878 Read BufferSize bytes from Lba into Buffer.
879
880 This function reads the requested number of blocks from the device. All the
881 blocks are read, or an error is returned.
882 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
883 non-blocking I/O is being used, the Event associated with this request will
884 not be signaled.
885
886 @param[in] This Indicates a pointer to the calling context.
887 @param[in] MediaId Id of the media, changes every time the media is
888 replaced.
889 @param[in] Lba The starting Logical Block Address to read from.
890 @param[in, out] Token A pointer to the token associated with the transaction.
891 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
892 @param[out] Buffer A pointer to the destination buffer for the data. The
893 caller is responsible for either having implicit or
894 explicit ownership of the buffer.
895
896 @retval EFI_SUCCESS The read request was queued if Token->Event is
897 not NULL.The data was read correctly from the
898 device if the Token->Event is NULL.
899 @retval EFI_DEVICE_ERROR The device reported an error while performing
900 the read.
901 @retval EFI_NO_MEDIA There is no media in the device.
902 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
903 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
904 intrinsic block size of the device.
905 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
906 or the buffer is not on proper alignment.
907 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
908 of resources.
909 **/
910 EFI_STATUS
911 EFIAPI
912 PartitionReadBlocksEx (
913 IN EFI_BLOCK_IO2_PROTOCOL *This,
914 IN UINT32 MediaId,
915 IN EFI_LBA Lba,
916 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
917 IN UINTN BufferSize,
918 OUT VOID *Buffer
919 )
920 {
921 EFI_STATUS Status;
922 PARTITION_PRIVATE_DATA *Private;
923 UINT64 Offset;
924 PARTITION_ACCESS_TASK *Task;
925
926 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
927
928 if (BufferSize % Private->BlockSize != 0) {
929 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
930 }
931
932 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
933 if (Offset + BufferSize > Private->End) {
934 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
935 }
936
937 if ((Token != NULL) && (Token->Event != NULL)) {
938 Task = PartitionCreateAccessTask (Token);
939 if (Task == NULL) {
940 return EFI_OUT_OF_RESOURCES;
941 }
942
943 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
944 if (EFI_ERROR (Status)) {
945 gBS->CloseEvent (Task->DiskIo2Token.Event);
946 FreePool (Task);
947 }
948 } else {
949 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
950 }
951
952 return Status;
953 }
954
955 /**
956 Write BufferSize bytes from Lba into Buffer.
957
958 This function writes the requested number of blocks to the device. All blocks
959 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
960 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
961 being used, the Event associated with this request will not be signaled.
962
963 @param[in] This Indicates a pointer to the calling context.
964 @param[in] MediaId The media ID that the write request is for.
965 @param[in] Lba The starting logical block address to be written. The
966 caller is responsible for writing to only legitimate
967 locations.
968 @param[in, out] Token A pointer to the token associated with the transaction.
969 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
970 @param[in] Buffer A pointer to the source buffer for the data.
971
972 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
973 The data was written correctly to the device if
974 the Event is NULL.
975 @retval EFI_WRITE_PROTECTED The device can not be written to.
976 @retval EFI_NO_MEDIA There is no media in the device.
977 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
978 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
979 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
980 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
981 or the buffer is not on proper alignment.
982 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
983 of resources.
984
985 **/
986 EFI_STATUS
987 EFIAPI
988 PartitionWriteBlocksEx (
989 IN EFI_BLOCK_IO2_PROTOCOL *This,
990 IN UINT32 MediaId,
991 IN EFI_LBA Lba,
992 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
993 IN UINTN BufferSize,
994 IN VOID *Buffer
995 )
996 {
997 EFI_STATUS Status;
998 PARTITION_PRIVATE_DATA *Private;
999 UINT64 Offset;
1000 PARTITION_ACCESS_TASK *Task;
1001
1002 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
1003
1004 if (BufferSize % Private->BlockSize != 0) {
1005 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
1006 }
1007
1008 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
1009 if (Offset + BufferSize > Private->End) {
1010 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
1011 }
1012
1013 if ((Token != NULL) && (Token->Event != NULL)) {
1014 Task = PartitionCreateAccessTask (Token);
1015 if (Task == NULL) {
1016 return EFI_OUT_OF_RESOURCES;
1017 }
1018
1019 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
1020 if (EFI_ERROR (Status)) {
1021 gBS->CloseEvent (Task->DiskIo2Token.Event);
1022 FreePool (Task);
1023 }
1024 } else {
1025 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
1026 }
1027 return Status;
1028 }
1029
1030 /**
1031 Flush the Block Device.
1032
1033 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
1034 is returned and non-blocking I/O is being used, the Event associated with
1035 this request will not be signaled.
1036
1037 @param[in] This Indicates a pointer to the calling context.
1038 @param[in, out] Token A pointer to the token associated with the transaction
1039
1040 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
1041 All outstanding data was written correctly to the
1042 device if the Event is NULL.
1043 @retval EFI_DEVICE_ERROR The device reported an error while writting back
1044 the data.
1045 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1046 @retval EFI_NO_MEDIA There is no media in the device.
1047 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1048 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1049 of resources.
1050
1051 **/
1052 EFI_STATUS
1053 EFIAPI
1054 PartitionFlushBlocksEx (
1055 IN EFI_BLOCK_IO2_PROTOCOL *This,
1056 IN OUT EFI_BLOCK_IO2_TOKEN *Token
1057 )
1058 {
1059 EFI_STATUS Status;
1060 PARTITION_PRIVATE_DATA *Private;
1061 PARTITION_ACCESS_TASK *Task;
1062
1063 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
1064
1065 if ((Token != NULL) && (Token->Event != NULL)) {
1066 Task = PartitionCreateAccessTask (Token);
1067 if (Task == NULL) {
1068 return EFI_OUT_OF_RESOURCES;
1069 }
1070
1071 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);
1072 if (EFI_ERROR (Status)) {
1073 gBS->CloseEvent (Task->DiskIo2Token.Event);
1074 FreePool (Task);
1075 }
1076 } else {
1077 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);
1078 }
1079 return Status;
1080 }
1081
1082
1083 /**
1084 Create a child handle for a logical block device that represents the
1085 bytes Start to End of the Parent Block IO device.
1086
1087 @param[in] This Protocol instance pointer.
1088 @param[in] ParentHandle Parent Handle for new child.
1089 @param[in] ParentDiskIo Parent DiskIo interface.
1090 @param[in] ParentDiskIo2 Parent DiskIo2 interface.
1091 @param[in] ParentBlockIo Parent BlockIo interface.
1092 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
1093 @param[in] ParentDevicePath Parent Device Path.
1094 @param[in] DevicePathNode Child Device Path node.
1095 @param[in] Start Start Block.
1096 @param[in] End End Block.
1097 @param[in] BlockSize Child block size.
1098 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
1099
1100 @retval EFI_SUCCESS A child handle was added.
1101 @retval other A child handle was not added.
1102
1103 **/
1104 EFI_STATUS
1105 PartitionInstallChildHandle (
1106 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1107 IN EFI_HANDLE ParentHandle,
1108 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
1109 IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
1110 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
1111 IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
1112 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1113 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
1114 IN EFI_LBA Start,
1115 IN EFI_LBA End,
1116 IN UINT32 BlockSize,
1117 IN BOOLEAN InstallEspGuid
1118 )
1119 {
1120 EFI_STATUS Status;
1121 PARTITION_PRIVATE_DATA *Private;
1122
1123 Status = EFI_SUCCESS;
1124 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
1125 if (Private == NULL) {
1126 return EFI_OUT_OF_RESOURCES;
1127 }
1128
1129 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
1130
1131 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
1132 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
1133
1134 Private->BlockSize = BlockSize;
1135 Private->ParentBlockIo = ParentBlockIo;
1136 Private->ParentBlockIo2 = ParentBlockIo2;
1137 Private->DiskIo = ParentDiskIo;
1138 Private->DiskIo2 = ParentDiskIo2;
1139
1140 //
1141 // Set the BlockIO into Private Data.
1142 //
1143 Private->BlockIo.Revision = ParentBlockIo->Revision;
1144
1145 Private->BlockIo.Media = &Private->Media;
1146 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1147
1148 Private->BlockIo.Reset = PartitionReset;
1149 Private->BlockIo.ReadBlocks = PartitionReadBlocks;
1150 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
1151 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
1152
1153 //
1154 // Set the BlockIO2 into Private Data.
1155 //
1156 if (Private->DiskIo2 != NULL) {
1157 ASSERT (Private->ParentBlockIo2 != NULL);
1158 Private->BlockIo2.Media = &Private->Media2;
1159 CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1160
1161 Private->BlockIo2.Reset = PartitionResetEx;
1162 Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
1163 Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
1164 Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
1165 }
1166
1167 Private->Media.IoAlign = 0;
1168 Private->Media.LogicalPartition = TRUE;
1169 Private->Media.LastBlock = DivU64x32 (
1170 MultU64x32 (
1171 End - Start + 1,
1172 ParentBlockIo->Media->BlockSize
1173 ),
1174 BlockSize
1175 ) - 1;
1176
1177 Private->Media.BlockSize = (UINT32) BlockSize;
1178
1179 Private->Media2.IoAlign = 0;
1180 Private->Media2.LogicalPartition = TRUE;
1181 Private->Media2.LastBlock = Private->Media.LastBlock;
1182 Private->Media2.BlockSize = (UINT32) BlockSize;
1183
1184 //
1185 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1186 // for logical partitions.
1187 //
1188 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
1189 Private->Media.LowestAlignedLba = 0;
1190 Private->Media.LogicalBlocksPerPhysicalBlock = 0;
1191 Private->Media2.LowestAlignedLba = 0;
1192 Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
1193 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
1194 Private->Media.OptimalTransferLengthGranularity = 0;
1195 Private->Media2.OptimalTransferLengthGranularity = 0;
1196 }
1197 }
1198
1199 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
1200
1201 if (Private->DevicePath == NULL) {
1202 FreePool (Private);
1203 return EFI_OUT_OF_RESOURCES;
1204 }
1205
1206 if (InstallEspGuid) {
1207 Private->EspGuid = &gEfiPartTypeSystemPartGuid;
1208 } else {
1209 //
1210 // If NULL InstallMultipleProtocolInterfaces will ignore it.
1211 //
1212 Private->EspGuid = NULL;
1213 }
1214
1215 //
1216 // Create the new handle.
1217 //
1218 Private->Handle = NULL;
1219 if (Private->DiskIo2 != NULL) {
1220 Status = gBS->InstallMultipleProtocolInterfaces (
1221 &Private->Handle,
1222 &gEfiDevicePathProtocolGuid,
1223 Private->DevicePath,
1224 &gEfiBlockIoProtocolGuid,
1225 &Private->BlockIo,
1226 &gEfiBlockIo2ProtocolGuid,
1227 &Private->BlockIo2,
1228 Private->EspGuid,
1229 NULL,
1230 NULL
1231 );
1232 } else {
1233 Status = gBS->InstallMultipleProtocolInterfaces (
1234 &Private->Handle,
1235 &gEfiDevicePathProtocolGuid,
1236 Private->DevicePath,
1237 &gEfiBlockIoProtocolGuid,
1238 &Private->BlockIo,
1239 Private->EspGuid,
1240 NULL,
1241 NULL
1242 );
1243 }
1244
1245 if (!EFI_ERROR (Status)) {
1246 //
1247 // Open the Parent Handle for the child
1248 //
1249 Status = gBS->OpenProtocol (
1250 ParentHandle,
1251 &gEfiDiskIoProtocolGuid,
1252 (VOID **) &ParentDiskIo,
1253 This->DriverBindingHandle,
1254 Private->Handle,
1255 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1256 );
1257 } else {
1258 FreePool (Private->DevicePath);
1259 FreePool (Private);
1260 }
1261
1262 return Status;
1263 }
1264
1265
1266 /**
1267 The user Entry Point for module Partition. The user code starts with this function.
1268
1269 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1270 @param[in] SystemTable A pointer to the EFI System Table.
1271
1272 @retval EFI_SUCCESS The entry point is executed successfully.
1273 @retval other Some error occurs when executing this entry point.
1274
1275 **/
1276 EFI_STATUS
1277 EFIAPI
1278 InitializePartition (
1279 IN EFI_HANDLE ImageHandle,
1280 IN EFI_SYSTEM_TABLE *SystemTable
1281 )
1282 {
1283 EFI_STATUS Status;
1284
1285 //
1286 // Install driver model protocol(s).
1287 //
1288 Status = EfiLibInstallDriverBindingComponentName2 (
1289 ImageHandle,
1290 SystemTable,
1291 &gPartitionDriverBinding,
1292 ImageHandle,
1293 &gPartitionComponentName,
1294 &gPartitionComponentName2
1295 );
1296 ASSERT_EFI_ERROR (Status);
1297
1298
1299 return Status;
1300 }
1301
1302
1303 /**
1304 Test to see if there is any child on ControllerHandle.
1305
1306 @param[in] ControllerHandle Handle of device to test.
1307
1308 @retval TRUE There are children on the ControllerHandle.
1309 @retval FALSE No child is on the ControllerHandle.
1310
1311 **/
1312 BOOLEAN
1313 HasChildren (
1314 IN EFI_HANDLE ControllerHandle
1315 )
1316 {
1317 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
1318 UINTN EntryCount;
1319 EFI_STATUS Status;
1320 UINTN Index;
1321
1322 Status = gBS->OpenProtocolInformation (
1323 ControllerHandle,
1324 &gEfiDiskIoProtocolGuid,
1325 &OpenInfoBuffer,
1326 &EntryCount
1327 );
1328 ASSERT_EFI_ERROR (Status);
1329
1330 for (Index = 0; Index < EntryCount; Index++) {
1331 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1332 break;
1333 }
1334 }
1335 FreePool (OpenInfoBuffer);
1336
1337 return (BOOLEAN) (Index < EntryCount);
1338 }
1339