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