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