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