]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
Add DiskIo2 protocol definition to MdePkg.
[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 - 2013, 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_DISK_IO2_PROTOCOL *DiskIo2;
204 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
205 PARTITION_DETECT_ROUTINE *Routine;
206 BOOLEAN MediaPresent;
207 EFI_TPL OldTpl;
208
209 BlockIo2 = NULL;
210 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
211 //
212 // Check RemainingDevicePath validation
213 //
214 if (RemainingDevicePath != NULL) {
215 //
216 // Check if RemainingDevicePath is the End of Device Path Node,
217 // if yes, return EFI_SUCCESS
218 //
219 if (IsDevicePathEnd (RemainingDevicePath)) {
220 Status = EFI_SUCCESS;
221 goto Exit;
222 }
223 }
224
225 //
226 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
227 // otherwise, return error.
228 //
229 Status = gBS->OpenProtocol (
230 ControllerHandle,
231 &gEfiBlockIoProtocolGuid,
232 (VOID **) &BlockIo,
233 This->DriverBindingHandle,
234 ControllerHandle,
235 EFI_OPEN_PROTOCOL_GET_PROTOCOL
236 );
237 if (EFI_ERROR (Status)) {
238 goto Exit;
239 }
240
241 Status = gBS->OpenProtocol (
242 ControllerHandle,
243 &gEfiBlockIo2ProtocolGuid,
244 (VOID **) &BlockIo2,
245 This->DriverBindingHandle,
246 ControllerHandle,
247 EFI_OPEN_PROTOCOL_GET_PROTOCOL
248 );
249 if (EFI_ERROR (Status)) {
250 BlockIo2 = NULL;
251 }
252
253 //
254 // Get the Device Path Protocol on ControllerHandle's handle.
255 //
256 Status = gBS->OpenProtocol (
257 ControllerHandle,
258 &gEfiDevicePathProtocolGuid,
259 (VOID **) &ParentDevicePath,
260 This->DriverBindingHandle,
261 ControllerHandle,
262 EFI_OPEN_PROTOCOL_BY_DRIVER
263 );
264 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
265 goto Exit;
266 }
267
268 //
269 // Get the DiskIo and DiskIo2.
270 //
271 Status = gBS->OpenProtocol (
272 ControllerHandle,
273 &gEfiDiskIoProtocolGuid,
274 (VOID **) &DiskIo,
275 This->DriverBindingHandle,
276 ControllerHandle,
277 EFI_OPEN_PROTOCOL_BY_DRIVER
278 );
279 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
280 gBS->CloseProtocol (
281 ControllerHandle,
282 &gEfiDevicePathProtocolGuid,
283 This->DriverBindingHandle,
284 ControllerHandle
285 );
286 goto Exit;
287 }
288
289 OpenStatus = Status;
290
291 Status = gBS->OpenProtocol (
292 ControllerHandle,
293 &gEfiDiskIo2ProtocolGuid,
294 (VOID **) &DiskIo2,
295 This->DriverBindingHandle,
296 ControllerHandle,
297 EFI_OPEN_PROTOCOL_BY_DRIVER
298 );
299 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
300 DiskIo2 = NULL;
301 }
302
303 //
304 // Try to read blocks when there's media or it is removable physical partition.
305 //
306 Status = EFI_UNSUPPORTED;
307 MediaPresent = BlockIo->Media->MediaPresent;
308 if (BlockIo->Media->MediaPresent ||
309 (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
310 //
311 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
312 // media supports a given partition type install child handles to represent
313 // the partitions described by the media.
314 //
315 Routine = &mPartitionDetectRoutineTable[0];
316 while (*Routine != NULL) {
317 Status = (*Routine) (
318 This,
319 ControllerHandle,
320 DiskIo,
321 DiskIo2,
322 BlockIo,
323 BlockIo2,
324 ParentDevicePath
325 );
326 if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
327 break;
328 }
329 Routine++;
330 }
331 }
332 //
333 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
334 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
335 // driver. So don't try to close them. Otherwise, we will break the dependency
336 // between the controller and the driver set up before.
337 //
338 // In the case that when the media changes on a device it will Reinstall the
339 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
340 // reentrant call to our Start() successfully. We should leave the device open
341 // when this happen. The "media change" case includes either the status is
342 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
343 //
344 if (EFI_ERROR (Status) &&
345 !EFI_ERROR (OpenStatus) &&
346 Status != EFI_MEDIA_CHANGED &&
347 !(MediaPresent && Status == EFI_NO_MEDIA)) {
348 gBS->CloseProtocol (
349 ControllerHandle,
350 &gEfiDiskIoProtocolGuid,
351 This->DriverBindingHandle,
352 ControllerHandle
353 );
354 //
355 // Close Parent BlockIO2 if has.
356 //
357 gBS->CloseProtocol (
358 ControllerHandle,
359 &gEfiBlockIo2ProtocolGuid,
360 This->DriverBindingHandle,
361 ControllerHandle
362 );
363
364 gBS->CloseProtocol (
365 ControllerHandle,
366 &gEfiDevicePathProtocolGuid,
367 This->DriverBindingHandle,
368 ControllerHandle
369 );
370 }
371
372 Exit:
373 gBS->RestoreTPL (OldTpl);
374 return Status;
375 }
376
377 /**
378 Stop this driver on ControllerHandle. Support stopping any child handles
379 created by this driver.
380
381 @param This Protocol instance pointer.
382 @param ControllerHandle Handle of device to stop driver on
383 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
384 children is zero stop the entire bus driver.
385 @param ChildHandleBuffer List of Child Handles to Stop.
386
387 @retval EFI_SUCCESS This driver is removed ControllerHandle
388 @retval other This driver was not removed from this device
389
390 **/
391 EFI_STATUS
392 EFIAPI
393 PartitionDriverBindingStop (
394 IN EFI_DRIVER_BINDING_PROTOCOL *This,
395 IN EFI_HANDLE ControllerHandle,
396 IN UINTN NumberOfChildren,
397 IN EFI_HANDLE *ChildHandleBuffer
398 )
399 {
400 EFI_STATUS Status;
401 UINTN Index;
402 EFI_BLOCK_IO_PROTOCOL *BlockIo;
403 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
404 BOOLEAN AllChildrenStopped;
405 PARTITION_PRIVATE_DATA *Private;
406 EFI_DISK_IO_PROTOCOL *DiskIo;
407
408 BlockIo = NULL;
409 BlockIo2 = NULL;
410 Private = NULL;
411
412 if (NumberOfChildren == 0) {
413 //
414 // Close the bus driver
415 //
416 gBS->CloseProtocol (
417 ControllerHandle,
418 &gEfiDiskIoProtocolGuid,
419 This->DriverBindingHandle,
420 ControllerHandle
421 );
422 //
423 // Close Parent BlockIO2 if has.
424 //
425 gBS->CloseProtocol (
426 ControllerHandle,
427 &gEfiDiskIo2ProtocolGuid,
428 This->DriverBindingHandle,
429 ControllerHandle
430 );
431
432 gBS->CloseProtocol (
433 ControllerHandle,
434 &gEfiDevicePathProtocolGuid,
435 This->DriverBindingHandle,
436 ControllerHandle
437 );
438 return EFI_SUCCESS;
439 }
440
441 AllChildrenStopped = TRUE;
442 for (Index = 0; Index < NumberOfChildren; Index++) {
443 gBS->OpenProtocol (
444 ChildHandleBuffer[Index],
445 &gEfiBlockIoProtocolGuid,
446 (VOID **) &BlockIo,
447 This->DriverBindingHandle,
448 ControllerHandle,
449 EFI_OPEN_PROTOCOL_GET_PROTOCOL
450 );
451 //
452 // Try to locate BlockIo2.
453 //
454 gBS->OpenProtocol (
455 ChildHandleBuffer[Index],
456 &gEfiBlockIo2ProtocolGuid,
457 (VOID **) &BlockIo2,
458 This->DriverBindingHandle,
459 ControllerHandle,
460 EFI_OPEN_PROTOCOL_GET_PROTOCOL
461 );
462
463
464 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
465
466 Status = gBS->CloseProtocol (
467 ControllerHandle,
468 &gEfiDiskIoProtocolGuid,
469 This->DriverBindingHandle,
470 ChildHandleBuffer[Index]
471 );
472 //
473 // All Software protocols have be freed from the handle so remove it.
474 // Remove the BlockIo Protocol if has.
475 // Remove the BlockIo2 Protocol if has.
476 //
477 if (BlockIo2 != NULL) {
478 BlockIo->FlushBlocks (BlockIo);
479 BlockIo2->FlushBlocksEx (BlockIo2, NULL);
480 Status = gBS->UninstallMultipleProtocolInterfaces (
481 ChildHandleBuffer[Index],
482 &gEfiDevicePathProtocolGuid,
483 Private->DevicePath,
484 &gEfiBlockIoProtocolGuid,
485 &Private->BlockIo,
486 &gEfiBlockIo2ProtocolGuid,
487 &Private->BlockIo2,
488 Private->EspGuid,
489 NULL,
490 NULL
491 );
492 } else {
493 BlockIo->FlushBlocks (BlockIo);
494 Status = gBS->UninstallMultipleProtocolInterfaces (
495 ChildHandleBuffer[Index],
496 &gEfiDevicePathProtocolGuid,
497 Private->DevicePath,
498 &gEfiBlockIoProtocolGuid,
499 &Private->BlockIo,
500 Private->EspGuid,
501 NULL,
502 NULL
503 );
504 }
505
506 if (EFI_ERROR (Status)) {
507 gBS->OpenProtocol (
508 ControllerHandle,
509 &gEfiDiskIoProtocolGuid,
510 (VOID **) &DiskIo,
511 This->DriverBindingHandle,
512 ChildHandleBuffer[Index],
513 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
514 );
515 } else {
516 FreePool (Private->DevicePath);
517 FreePool (Private);
518 }
519
520 if (EFI_ERROR (Status)) {
521 AllChildrenStopped = FALSE;
522 }
523 }
524
525 if (!AllChildrenStopped) {
526 return EFI_DEVICE_ERROR;
527 }
528
529 return EFI_SUCCESS;
530 }
531
532
533 /**
534 Reset the Block Device.
535
536 @param This Protocol instance pointer.
537 @param ExtendedVerification Driver may perform diagnostics on reset.
538
539 @retval EFI_SUCCESS The device was reset.
540 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
541 not be reset.
542
543 **/
544 EFI_STATUS
545 EFIAPI
546 PartitionReset (
547 IN EFI_BLOCK_IO_PROTOCOL *This,
548 IN BOOLEAN ExtendedVerification
549 )
550 {
551 PARTITION_PRIVATE_DATA *Private;
552
553 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
554
555 return Private->ParentBlockIo->Reset (
556 Private->ParentBlockIo,
557 ExtendedVerification
558 );
559 }
560
561 /**
562 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
563 for no media or media change case. Otherwise DefaultStatus is returned.
564
565 @param DiskIo Pointer to the DiskIo instance.
566 @param MediaId Id of the media, changes every time the media is replaced.
567 @param DefaultStatus The default status to return when it's not the no media
568 or media change case.
569
570 @retval EFI_NO_MEDIA There is no media.
571 @retval EFI_MEDIA_CHANGED The media was changed.
572 @retval others The default status to return.
573 **/
574 EFI_STATUS
575 ProbeMediaStatus (
576 IN EFI_DISK_IO_PROTOCOL *DiskIo,
577 IN UINT32 MediaId,
578 IN EFI_STATUS DefaultStatus
579 )
580 {
581 EFI_STATUS Status;
582
583 //
584 // Read 1 byte from offset 0 but passing NULL as buffer pointer
585 //
586 Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, NULL);
587 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
588 return Status;
589 }
590 return DefaultStatus;
591 }
592
593 /**
594 Read by using the Disk IO protocol on the parent device. Lba addresses
595 must be converted to byte offsets.
596
597 @param This Protocol instance pointer.
598 @param MediaId Id of the media, changes every time the media is replaced.
599 @param Lba The starting Logical Block Address to read from
600 @param BufferSize Size of Buffer, must be a multiple of device block size.
601 @param Buffer Buffer containing read data
602
603 @retval EFI_SUCCESS The data was read correctly from the device.
604 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
605 @retval EFI_NO_MEDIA There is no media in the device.
606 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
607 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
608 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
609 valid for the device.
610
611 **/
612 EFI_STATUS
613 EFIAPI
614 PartitionReadBlocks (
615 IN EFI_BLOCK_IO_PROTOCOL *This,
616 IN UINT32 MediaId,
617 IN EFI_LBA Lba,
618 IN UINTN BufferSize,
619 OUT VOID *Buffer
620 )
621 {
622 PARTITION_PRIVATE_DATA *Private;
623 UINT64 Offset;
624
625 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
626
627 if (BufferSize % Private->BlockSize != 0) {
628 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
629 }
630
631 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
632 if (Offset + BufferSize > Private->End) {
633 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
634 }
635 //
636 // Because some kinds of partition have different block size from their parent
637 // device, we call the Disk IO protocol on the parent device, not the Block IO
638 // protocol
639 //
640 return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
641 }
642
643 /**
644 Write by using the Disk IO protocol on the parent device. Lba addresses
645 must be converted to byte offsets.
646
647 @param[in] This Protocol instance pointer.
648 @param[in] MediaId Id of the media, changes every time the media is replaced.
649 @param[in] Lba The starting Logical Block Address to read from
650 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
651 @param[in] Buffer Buffer containing data to be written to device.
652
653 @retval EFI_SUCCESS The data was written correctly to the device.
654 @retval EFI_WRITE_PROTECTED The device can not be written to.
655 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
656 @retval EFI_NO_MEDIA There is no media in the device.
657 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
658 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
659 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
660 valid for the device.
661
662 **/
663 EFI_STATUS
664 EFIAPI
665 PartitionWriteBlocks (
666 IN EFI_BLOCK_IO_PROTOCOL *This,
667 IN UINT32 MediaId,
668 IN EFI_LBA Lba,
669 IN UINTN BufferSize,
670 IN VOID *Buffer
671 )
672 {
673 PARTITION_PRIVATE_DATA *Private;
674 UINT64 Offset;
675
676 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
677
678 if (BufferSize % Private->BlockSize != 0) {
679 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
680 }
681
682 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
683 if (Offset + BufferSize > Private->End) {
684 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
685 }
686 //
687 // Because some kinds of partition have different block size from their parent
688 // device, we call the Disk IO protocol on the parent device, not the Block IO
689 // protocol
690 //
691 return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
692 }
693
694
695 /**
696 Flush the parent Block Device.
697
698 @param This Protocol instance pointer.
699
700 @retval EFI_SUCCESS All outstanding data was written to the device
701 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
702 @retval EFI_NO_MEDIA There is no media in the device.
703
704 **/
705 EFI_STATUS
706 EFIAPI
707 PartitionFlushBlocks (
708 IN EFI_BLOCK_IO_PROTOCOL *This
709 )
710 {
711 PARTITION_PRIVATE_DATA *Private;
712
713 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
714
715 return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
716 }
717
718 /**
719 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
720 for no media or media change case. Otherwise DefaultStatus is returned.
721
722 @param DiskIo2 Pointer to the DiskIo2 instance.
723 @param MediaId Id of the media, changes every time the media is replaced.
724 @param DefaultStatus The default status to return when it's not the no media
725 or media change case.
726
727 @retval EFI_NO_MEDIA There is no media.
728 @retval EFI_MEDIA_CHANGED The media was changed.
729 @retval others The default status to return.
730 **/
731 EFI_STATUS
732 ProbeMediaStatusEx (
733 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
734 IN UINT32 MediaId,
735 IN EFI_STATUS DefaultStatus
736 )
737 {
738 EFI_STATUS Status;
739
740 //
741 // Read 1 byte from offset 0 but passing NULL as buffer pointer
742 //
743 Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, NULL);
744 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
745 return Status;
746 }
747 return DefaultStatus;
748 }
749
750 /**
751 Reset the Block Device throught Block I/O2 protocol.
752
753 @param This Protocol instance pointer.
754 @param ExtendedVerification Driver may perform diagnostics on reset.
755
756 @retval EFI_SUCCESS The device was reset.
757 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
758 not be reset.
759
760 **/
761 EFI_STATUS
762 EFIAPI
763 PartitionResetEx (
764 IN EFI_BLOCK_IO2_PROTOCOL *This,
765 IN BOOLEAN ExtendedVerification
766 )
767 {
768 PARTITION_PRIVATE_DATA *Private;
769
770 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
771
772 return Private->ParentBlockIo2->Reset (
773 Private->ParentBlockIo2,
774 ExtendedVerification
775 );
776 }
777
778 /**
779 The general callback for the DiskIo2 interfaces.
780 @param Event Event whose notification function is being invoked.
781 @param Context The pointer to the notification function's context,
782 which points to the PARTITION_ACCESS_TASK instance.
783 **/
784 VOID
785 EFIAPI
786 PartitionOnAccessComplete (
787 IN EFI_EVENT Event,
788 IN VOID *Context
789 )
790 {
791 PARTITION_ACCESS_TASK *Task;
792
793 Task = (PARTITION_ACCESS_TASK *) Context;
794
795 gBS->CloseEvent (Event);
796
797 Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;
798 gBS->SignalEvent (Task->BlockIo2Token->Event);
799
800 FreePool (Task);
801 }
802
803 /**
804 Create a new PARTITION_ACCESS_TASK instance.
805
806 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
807
808 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
809 **/
810 PARTITION_ACCESS_TASK *
811 PartitionCreateAccessTask (
812 IN EFI_BLOCK_IO2_TOKEN *Token
813 )
814 {
815 EFI_STATUS Status;
816 PARTITION_ACCESS_TASK *Task;
817
818 Task = AllocatePool (sizeof (*Task));
819 if (Task == NULL) {
820 return NULL;
821 }
822
823 Status = gBS->CreateEvent (
824 EVT_NOTIFY_SIGNAL,
825 TPL_CALLBACK,
826 PartitionOnAccessComplete,
827 Task,
828 &Task->DiskIo2Token.Event
829 );
830 if (EFI_ERROR (Status)) {
831 FreePool (Task);
832 return NULL;
833 }
834
835 Task->BlockIo2Token = Token;
836
837 return Task;
838 }
839
840 /**
841 Read BufferSize bytes from Lba into Buffer.
842
843 This function reads the requested number of blocks from the device. All the
844 blocks are read, or an error is returned.
845 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
846 non-blocking I/O is being used, the Event associated with this request will
847 not be signaled.
848
849 @param[in] This Indicates a pointer to the calling context.
850 @param[in] MediaId Id of the media, changes every time the media is
851 replaced.
852 @param[in] Lba The starting Logical Block Address to read from.
853 @param[in, out] Token A pointer to the token associated with the transaction.
854 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
855 @param[out] Buffer A pointer to the destination buffer for the data. The
856 caller is responsible for either having implicit or
857 explicit ownership of the buffer.
858
859 @retval EFI_SUCCESS The read request was queued if Token->Event is
860 not NULL.The data was read correctly from the
861 device if the Token->Event is NULL.
862 @retval EFI_DEVICE_ERROR The device reported an error while performing
863 the read.
864 @retval EFI_NO_MEDIA There is no media in the device.
865 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
866 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
867 intrinsic block size of the device.
868 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
869 or the buffer is not on proper alignment.
870 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
871 of resources.
872 **/
873 EFI_STATUS
874 EFIAPI
875 PartitionReadBlocksEx (
876 IN EFI_BLOCK_IO2_PROTOCOL *This,
877 IN UINT32 MediaId,
878 IN EFI_LBA Lba,
879 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
880 IN UINTN BufferSize,
881 OUT VOID *Buffer
882 )
883 {
884 EFI_STATUS Status;
885 PARTITION_PRIVATE_DATA *Private;
886 UINT64 Offset;
887 PARTITION_ACCESS_TASK *Task;
888
889 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
890
891 if (BufferSize % Private->BlockSize != 0) {
892 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
893 }
894
895 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
896 if (Offset + BufferSize > Private->End) {
897 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
898 }
899
900 if ((Token != NULL) && (Token->Event != NULL)) {
901 Task = PartitionCreateAccessTask (Token);
902 if (Task == NULL) {
903 return EFI_OUT_OF_RESOURCES;
904 }
905
906 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
907 if (EFI_ERROR (Status)) {
908 gBS->CloseEvent (Task->DiskIo2Token.Event);
909 FreePool (Task);
910 }
911 } else {
912 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
913 }
914
915 return Status;
916 }
917
918 /**
919 Write BufferSize bytes from Lba into Buffer.
920
921 This function writes the requested number of blocks to the device. All blocks
922 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
923 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
924 being used, the Event associated with this request will not be signaled.
925
926 @param[in] This Indicates a pointer to the calling context.
927 @param[in] MediaId The media ID that the write request is for.
928 @param[in] Lba The starting logical block address to be written. The
929 caller is responsible for writing to only legitimate
930 locations.
931 @param[in, out] Token A pointer to the token associated with the transaction.
932 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
933 @param[in] Buffer A pointer to the source buffer for the data.
934
935 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
936 The data was written correctly to the device if
937 the Event is NULL.
938 @retval EFI_WRITE_PROTECTED The device can not be written to.
939 @retval EFI_NO_MEDIA There is no media in the device.
940 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
941 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
942 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
943 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
944 or the buffer is not on proper alignment.
945 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
946 of resources.
947
948 **/
949 EFI_STATUS
950 EFIAPI
951 PartitionWriteBlocksEx (
952 IN EFI_BLOCK_IO2_PROTOCOL *This,
953 IN UINT32 MediaId,
954 IN EFI_LBA Lba,
955 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
956 IN UINTN BufferSize,
957 IN VOID *Buffer
958 )
959 {
960 EFI_STATUS Status;
961 PARTITION_PRIVATE_DATA *Private;
962 UINT64 Offset;
963 PARTITION_ACCESS_TASK *Task;
964
965 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
966
967 if (BufferSize % Private->BlockSize != 0) {
968 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
969 }
970
971 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
972 if (Offset + BufferSize > Private->End) {
973 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
974 }
975
976 if ((Token != NULL) && (Token->Event != NULL)) {
977 Task = PartitionCreateAccessTask (Token);
978 if (Task == NULL) {
979 return EFI_OUT_OF_RESOURCES;
980 }
981
982 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
983 if (EFI_ERROR (Status)) {
984 gBS->CloseEvent (Task->DiskIo2Token.Event);
985 FreePool (Task);
986 }
987 } else {
988 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
989 }
990 return Status;
991 }
992
993 /**
994 Flush the Block Device.
995
996 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
997 is returned and non-blocking I/O is being used, the Event associated with
998 this request will not be signaled.
999
1000 @param[in] This Indicates a pointer to the calling context.
1001 @param[in, out] Token A pointer to the token associated with the transaction
1002
1003 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
1004 All outstanding data was written correctly to the
1005 device if the Event is NULL.
1006 @retval EFI_DEVICE_ERROR The device reported an error while writting back
1007 the data.
1008 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1009 @retval EFI_NO_MEDIA There is no media in the device.
1010 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1011 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1012 of resources.
1013
1014 **/
1015 EFI_STATUS
1016 EFIAPI
1017 PartitionFlushBlocksEx (
1018 IN EFI_BLOCK_IO2_PROTOCOL *This,
1019 IN OUT EFI_BLOCK_IO2_TOKEN *Token
1020 )
1021 {
1022 EFI_STATUS Status;
1023 PARTITION_PRIVATE_DATA *Private;
1024 PARTITION_ACCESS_TASK *Task;
1025
1026 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
1027
1028 if ((Token != NULL) && (Token->Event != NULL)) {
1029 Task = PartitionCreateAccessTask (Token);
1030 if (Task == NULL) {
1031 return EFI_OUT_OF_RESOURCES;
1032 }
1033
1034 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);
1035 if (EFI_ERROR (Status)) {
1036 gBS->CloseEvent (Task->DiskIo2Token.Event);
1037 FreePool (Task);
1038 }
1039 } else {
1040 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);
1041 }
1042 return Status;
1043 }
1044
1045
1046 /**
1047 Create a child handle for a logical block device that represents the
1048 bytes Start to End of the Parent Block IO device.
1049
1050 @param[in] This Protocol instance pointer.
1051 @param[in] ParentHandle Parent Handle for new child.
1052 @param[in] ParentDiskIo Parent DiskIo interface.
1053 @param[in] ParentDiskIo2 Parent DiskIo2 interface.
1054 @param[in] ParentBlockIo Parent BlockIo interface.
1055 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
1056 @param[in] ParentDevicePath Parent Device Path.
1057 @param[in] DevicePathNode Child Device Path node.
1058 @param[in] Start Start Block.
1059 @param[in] End End Block.
1060 @param[in] BlockSize Child block size.
1061 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
1062
1063 @retval EFI_SUCCESS A child handle was added.
1064 @retval other A child handle was not added.
1065
1066 **/
1067 EFI_STATUS
1068 PartitionInstallChildHandle (
1069 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1070 IN EFI_HANDLE ParentHandle,
1071 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
1072 IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
1073 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
1074 IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
1075 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1076 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
1077 IN EFI_LBA Start,
1078 IN EFI_LBA End,
1079 IN UINT32 BlockSize,
1080 IN BOOLEAN InstallEspGuid
1081 )
1082 {
1083 EFI_STATUS Status;
1084 PARTITION_PRIVATE_DATA *Private;
1085
1086 Status = EFI_SUCCESS;
1087 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
1088 if (Private == NULL) {
1089 return EFI_OUT_OF_RESOURCES;
1090 }
1091
1092 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
1093
1094 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
1095 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
1096
1097 Private->BlockSize = BlockSize;
1098 Private->ParentBlockIo = ParentBlockIo;
1099 Private->ParentBlockIo2 = ParentBlockIo2;
1100 Private->DiskIo = ParentDiskIo;
1101 Private->DiskIo2 = ParentDiskIo2;
1102
1103 //
1104 // Set the BlockIO into Private Data.
1105 //
1106 Private->BlockIo.Revision = ParentBlockIo->Revision;
1107
1108 Private->BlockIo.Media = &Private->Media;
1109 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1110
1111 Private->BlockIo.Reset = PartitionReset;
1112 Private->BlockIo.ReadBlocks = PartitionReadBlocks;
1113 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
1114 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
1115
1116 //
1117 // Set the BlockIO2 into Private Data.
1118 //
1119 if (Private->DiskIo2 != NULL) {
1120 ASSERT (Private->ParentBlockIo2 != NULL);
1121 Private->BlockIo2.Media = &Private->Media2;
1122 CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1123
1124 Private->BlockIo2.Reset = PartitionResetEx;
1125 Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
1126 Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
1127 Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
1128 }
1129
1130 Private->Media.IoAlign = 0;
1131 Private->Media.LogicalPartition = TRUE;
1132 Private->Media.LastBlock = DivU64x32 (
1133 MultU64x32 (
1134 End - Start + 1,
1135 ParentBlockIo->Media->BlockSize
1136 ),
1137 BlockSize
1138 ) - 1;
1139
1140 Private->Media.BlockSize = (UINT32) BlockSize;
1141
1142 Private->Media2.IoAlign = 0;
1143 Private->Media2.LogicalPartition = TRUE;
1144 Private->Media2.LastBlock = Private->Media.LastBlock;
1145 Private->Media2.BlockSize = (UINT32) BlockSize;
1146
1147 //
1148 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1149 // for logical partitions.
1150 //
1151 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
1152 Private->Media.LowestAlignedLba = 0;
1153 Private->Media.LogicalBlocksPerPhysicalBlock = 0;
1154 Private->Media2.LowestAlignedLba = 0;
1155 Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
1156 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
1157 Private->Media.OptimalTransferLengthGranularity = 0;
1158 Private->Media2.OptimalTransferLengthGranularity = 0;
1159 }
1160 }
1161
1162 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
1163
1164 if (Private->DevicePath == NULL) {
1165 FreePool (Private);
1166 return EFI_OUT_OF_RESOURCES;
1167 }
1168
1169 if (InstallEspGuid) {
1170 Private->EspGuid = &gEfiPartTypeSystemPartGuid;
1171 } else {
1172 //
1173 // If NULL InstallMultipleProtocolInterfaces will ignore it.
1174 //
1175 Private->EspGuid = NULL;
1176 }
1177
1178 //
1179 // Create the new handle.
1180 //
1181 Private->Handle = NULL;
1182 if (Private->DiskIo2 != NULL) {
1183 Status = gBS->InstallMultipleProtocolInterfaces (
1184 &Private->Handle,
1185 &gEfiDevicePathProtocolGuid,
1186 Private->DevicePath,
1187 &gEfiBlockIoProtocolGuid,
1188 &Private->BlockIo,
1189 &gEfiBlockIo2ProtocolGuid,
1190 &Private->BlockIo2,
1191 Private->EspGuid,
1192 NULL,
1193 NULL
1194 );
1195 } else {
1196 Status = gBS->InstallMultipleProtocolInterfaces (
1197 &Private->Handle,
1198 &gEfiDevicePathProtocolGuid,
1199 Private->DevicePath,
1200 &gEfiBlockIoProtocolGuid,
1201 &Private->BlockIo,
1202 Private->EspGuid,
1203 NULL,
1204 NULL
1205 );
1206 }
1207
1208 if (!EFI_ERROR (Status)) {
1209 //
1210 // Open the Parent Handle for the child
1211 //
1212 Status = gBS->OpenProtocol (
1213 ParentHandle,
1214 &gEfiDiskIoProtocolGuid,
1215 (VOID **) &ParentDiskIo,
1216 This->DriverBindingHandle,
1217 Private->Handle,
1218 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1219 );
1220 } else {
1221 FreePool (Private->DevicePath);
1222 FreePool (Private);
1223 }
1224
1225 return Status;
1226 }
1227
1228
1229 /**
1230 The user Entry Point for module Partition. The user code starts with this function.
1231
1232 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1233 @param[in] SystemTable A pointer to the EFI System Table.
1234
1235 @retval EFI_SUCCESS The entry point is executed successfully.
1236 @retval other Some error occurs when executing this entry point.
1237
1238 **/
1239 EFI_STATUS
1240 EFIAPI
1241 InitializePartition (
1242 IN EFI_HANDLE ImageHandle,
1243 IN EFI_SYSTEM_TABLE *SystemTable
1244 )
1245 {
1246 EFI_STATUS Status;
1247
1248 //
1249 // Install driver model protocol(s).
1250 //
1251 Status = EfiLibInstallDriverBindingComponentName2 (
1252 ImageHandle,
1253 SystemTable,
1254 &gPartitionDriverBinding,
1255 ImageHandle,
1256 &gPartitionComponentName,
1257 &gPartitionComponentName2
1258 );
1259 ASSERT_EFI_ERROR (Status);
1260
1261
1262 return Status;
1263 }
1264