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