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