Coverage Report

Created: 2026-02-26 06:11

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