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