]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
Fix Smbios table checksum error, by zero IntermediateChecksum and EntryPointStructure...
[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
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 BlockIo2 Pointer to the BlockIo2 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_BLOCK_IO2_PROTOCOL *BlockIo2,
731 IN UINT32 MediaId,
732 IN EFI_STATUS DefaultStatus
733 )
734 {
735 EFI_STATUS Status;
736
737 //
738 // Read from LBA 0 but passing NULL as buffer pointer to detect the media status.
739 //
740 Status = BlockIo2->ReadBlocksEx (
741 BlockIo2,
742 MediaId,
743 0,
744 NULL,
745 0,
746 NULL
747 );
748 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
749 return Status;
750 }
751 return DefaultStatus;
752 }
753
754 /**
755 Reset the Block Device throught Block I/O2 protocol.
756
757 @param This Protocol instance pointer.
758 @param ExtendedVerification Driver may perform diagnostics on reset.
759
760 @retval EFI_SUCCESS The device was reset.
761 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
762 not be reset.
763
764 **/
765 EFI_STATUS
766 EFIAPI
767 PartitionResetEx (
768 IN EFI_BLOCK_IO2_PROTOCOL *This,
769 IN BOOLEAN ExtendedVerification
770 )
771 {
772 PARTITION_PRIVATE_DATA *Private;
773
774 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
775
776 return Private->ParentBlockIo2->Reset (
777 Private->ParentBlockIo2,
778 ExtendedVerification
779 );
780 }
781
782 /**
783 Read BufferSize bytes from Lba into Buffer.
784
785 This function reads the requested number of blocks from the device. All the
786 blocks are read, or an error is returned.
787 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
788 non-blocking I/O is being used, the Event associated with this request will
789 not be signaled.
790
791 @param[in] This Indicates a pointer to the calling context.
792 @param[in] MediaId Id of the media, changes every time the media is
793 replaced.
794 @param[in] Lba The starting Logical Block Address to read from.
795 @param[in, out] Token A pointer to the token associated with the transaction.
796 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
797 @param[out] Buffer A pointer to the destination buffer for the data. The
798 caller is responsible for either having implicit or
799 explicit ownership of the buffer.
800
801 @retval EFI_SUCCESS The read request was queued if Token->Event is
802 not NULL.The data was read correctly from the
803 device if the Token->Event is NULL.
804 @retval EFI_DEVICE_ERROR The device reported an error while performing
805 the read.
806 @retval EFI_NO_MEDIA There is no media in the device.
807 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
808 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
809 intrinsic block size of the device.
810 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
811 or the buffer is not on proper alignment.
812 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
813 of resources.
814 **/
815 EFI_STATUS
816 EFIAPI
817 PartitionReadBlocksEx (
818 IN EFI_BLOCK_IO2_PROTOCOL *This,
819 IN UINT32 MediaId,
820 IN EFI_LBA Lba,
821 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
822 IN UINTN BufferSize,
823 OUT VOID *Buffer
824 )
825 {
826 PARTITION_PRIVATE_DATA *Private;
827 UINT64 Offset;
828 UINT32 UnderRun;
829
830 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
831
832 if (Token == NULL) {
833 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
834 }
835
836 if (BufferSize % Private->BlockSize != 0) {
837 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
838 }
839
840 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
841 if (Offset + BufferSize > Private->End) {
842 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
843 }
844
845 //
846 // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
847 // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
848 // BlockIO2, this limitation will be removed and call DiskIO here.
849 //
850 Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
851 if (UnderRun != 0) {
852 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
853 }
854
855 //
856 // Because some partitions have different block size from their parent
857 // device, in that case the Block I/O2 couldn't be called.
858 //
859 if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
860 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
861 }
862
863 return Private->ParentBlockIo2->ReadBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
864 }
865
866 /**
867 Write BufferSize bytes from Lba into Buffer.
868
869 This function writes the requested number of blocks to the device. All blocks
870 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
871 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
872 being used, the Event associated with this request will not be signaled.
873
874 @param[in] This Indicates a pointer to the calling context.
875 @param[in] MediaId The media ID that the write request is for.
876 @param[in] Lba The starting logical block address to be written. The
877 caller is responsible for writing to only legitimate
878 locations.
879 @param[in, out] Token A pointer to the token associated with the transaction.
880 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
881 @param[in] Buffer A pointer to the source buffer for the data.
882
883 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
884 The data was written correctly to the device if
885 the Event is NULL.
886 @retval EFI_WRITE_PROTECTED The device can not be written to.
887 @retval EFI_NO_MEDIA There is no media in the device.
888 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
889 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
890 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
891 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
892 or the buffer is not on proper alignment.
893 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
894 of resources.
895
896 **/
897 EFI_STATUS
898 EFIAPI
899 PartitionWriteBlocksEx (
900 IN EFI_BLOCK_IO2_PROTOCOL *This,
901 IN UINT32 MediaId,
902 IN EFI_LBA Lba,
903 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
904 IN UINTN BufferSize,
905 IN VOID *Buffer
906 )
907 {
908 PARTITION_PRIVATE_DATA *Private;
909 UINT64 Offset;
910 UINT32 UnderRun;
911
912 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
913
914 if (Token == NULL) {
915 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
916 }
917
918 if (BufferSize % Private->BlockSize != 0) {
919 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
920 }
921
922 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
923 if (Offset + BufferSize > Private->End) {
924 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
925 }
926
927 //
928 // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
929 // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
930 // BlockIO2, this limitation will be removed and call DiskIO here.
931 //
932 Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
933 if (UnderRun != 0) {
934 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
935 }
936
937 //
938 // Because some kinds of partition have different block size from their parent,
939 // in that case it couldn't call parent Block I/O2.
940 //
941 if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
942 return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
943 }
944
945 return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
946 }
947
948 /**
949 Flush the Block Device.
950
951 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
952 is returned and non-blocking I/O is being used, the Event associated with
953 this request will not be signaled.
954
955 @param[in] This Indicates a pointer to the calling context.
956 @param[in, out] Token A pointer to the token associated with the transaction
957
958 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
959 All outstanding data was written correctly to the
960 device if the Event is NULL.
961 @retval EFI_DEVICE_ERROR The device reported an error while writting back
962 the data.
963 @retval EFI_WRITE_PROTECTED The device cannot be written to.
964 @retval EFI_NO_MEDIA There is no media in the device.
965 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
966 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
967 of resources.
968
969 **/
970 EFI_STATUS
971 EFIAPI
972 PartitionFlushBlocksEx (
973 IN EFI_BLOCK_IO2_PROTOCOL *This,
974 IN OUT EFI_BLOCK_IO2_TOKEN *Token
975 )
976 {
977 PARTITION_PRIVATE_DATA *Private;
978
979 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
980
981 //
982 // Because some kinds of partition have different block size from their parent,
983 // in that case it couldn't call parent Block I/O2.
984 //
985 if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
986 return EFI_UNSUPPORTED;
987 }
988
989 return Private->ParentBlockIo2->FlushBlocksEx (Private->ParentBlockIo2, Token);
990 }
991
992
993 /**
994 Create a child handle for a logical block device that represents the
995 bytes Start to End of the Parent Block IO device.
996
997 @param[in] This Protocol instance pointer.
998 @param[in] ParentHandle Parent Handle for new child.
999 @param[in] ParentDiskIo Parent DiskIo interface.
1000 @param[in] ParentBlockIo Parent BlockIo interface.
1001 @param[in] ParentBlockIo2 Parent BlockIo2 interface.
1002 @param[in] ParentDevicePath Parent Device Path.
1003 @param[in] DevicePathNode Child Device Path node.
1004 @param[in] Start Start Block.
1005 @param[in] End End Block.
1006 @param[in] BlockSize Child block size.
1007 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
1008
1009 @retval EFI_SUCCESS A child handle was added.
1010 @retval other A child handle was not added.
1011
1012 **/
1013 EFI_STATUS
1014 PartitionInstallChildHandle (
1015 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1016 IN EFI_HANDLE ParentHandle,
1017 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
1018 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
1019 IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
1020 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1021 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
1022 IN EFI_LBA Start,
1023 IN EFI_LBA End,
1024 IN UINT32 BlockSize,
1025 IN BOOLEAN InstallEspGuid
1026 )
1027 {
1028 EFI_STATUS Status;
1029 PARTITION_PRIVATE_DATA *Private;
1030
1031 Status = EFI_SUCCESS;
1032 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
1033 if (Private == NULL) {
1034 return EFI_OUT_OF_RESOURCES;
1035 }
1036
1037 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
1038
1039 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
1040 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
1041
1042 Private->BlockSize = BlockSize;
1043 Private->ParentBlockIo = ParentBlockIo;
1044 Private->ParentBlockIo2 = ParentBlockIo2;
1045 Private->DiskIo = ParentDiskIo;
1046
1047 //
1048 // Set the BlockIO into Private Data.
1049 //
1050 Private->BlockIo.Revision = ParentBlockIo->Revision;
1051
1052 Private->BlockIo.Media = &Private->Media;
1053 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1054
1055 Private->BlockIo.Reset = PartitionReset;
1056 Private->BlockIo.ReadBlocks = PartitionReadBlocks;
1057 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
1058 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
1059
1060 //
1061 // Set the BlockIO2 into Private Data.
1062 //
1063 if (Private->ParentBlockIo2 != NULL) {
1064 Private->BlockIo2.Media = &Private->Media2;
1065 CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
1066
1067 Private->BlockIo2.Reset = PartitionResetEx;
1068 Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
1069 Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
1070 Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
1071 }
1072
1073 Private->Media.IoAlign = 0;
1074 Private->Media.LogicalPartition = TRUE;
1075 Private->Media.LastBlock = DivU64x32 (
1076 MultU64x32 (
1077 End - Start + 1,
1078 ParentBlockIo->Media->BlockSize
1079 ),
1080 BlockSize
1081 ) - 1;
1082
1083 Private->Media.BlockSize = (UINT32) BlockSize;
1084
1085 //
1086 // For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
1087 //
1088 Private->Media2.LogicalPartition = TRUE;
1089 Private->Media2.LastBlock = Private->Media.LastBlock;
1090 Private->Media2.BlockSize = (UINT32) BlockSize;
1091
1092 //
1093 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
1094 // for logical partitions.
1095 //
1096 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
1097 Private->Media.LowestAlignedLba = 0;
1098 Private->Media.LogicalBlocksPerPhysicalBlock = 0;
1099 Private->Media2.LowestAlignedLba = 0;
1100 Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
1101 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
1102 Private->Media.OptimalTransferLengthGranularity = 0;
1103 Private->Media2.OptimalTransferLengthGranularity = 0;
1104 }
1105 }
1106
1107 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
1108
1109 if (Private->DevicePath == NULL) {
1110 FreePool (Private);
1111 return EFI_OUT_OF_RESOURCES;
1112 }
1113
1114 if (InstallEspGuid) {
1115 Private->EspGuid = &gEfiPartTypeSystemPartGuid;
1116 } else {
1117 //
1118 // If NULL InstallMultipleProtocolInterfaces will ignore it.
1119 //
1120 Private->EspGuid = NULL;
1121 }
1122
1123 //
1124 // Create the new handle.
1125 // BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
1126 // is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
1127 // directly call the parent BlockIO and doesn't handle the different block size issue.
1128 // If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
1129 // DiskIO to handle the blocksize unequal issue and the limitation will be remove from
1130 // here.
1131 //
1132 Private->Handle = NULL;
1133 if ((Private->ParentBlockIo2 != NULL) &&
1134 (Private->ParentBlockIo2->Media->BlockSize == BlockSize)
1135 ) {
1136 Status = gBS->InstallMultipleProtocolInterfaces (
1137 &Private->Handle,
1138 &gEfiDevicePathProtocolGuid,
1139 Private->DevicePath,
1140 &gEfiBlockIoProtocolGuid,
1141 &Private->BlockIo,
1142 &gEfiBlockIo2ProtocolGuid,
1143 &Private->BlockIo2,
1144 Private->EspGuid,
1145 NULL,
1146 NULL
1147 );
1148 } else {
1149 Status = gBS->InstallMultipleProtocolInterfaces (
1150 &Private->Handle,
1151 &gEfiDevicePathProtocolGuid,
1152 Private->DevicePath,
1153 &gEfiBlockIoProtocolGuid,
1154 &Private->BlockIo,
1155 Private->EspGuid,
1156 NULL,
1157 NULL
1158 );
1159 }
1160
1161 if (!EFI_ERROR (Status)) {
1162 //
1163 // Open the Parent Handle for the child
1164 //
1165 Status = gBS->OpenProtocol (
1166 ParentHandle,
1167 &gEfiDiskIoProtocolGuid,
1168 (VOID **) &ParentDiskIo,
1169 This->DriverBindingHandle,
1170 Private->Handle,
1171 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1172 );
1173 } else {
1174 FreePool (Private->DevicePath);
1175 FreePool (Private);
1176 }
1177
1178 return Status;
1179 }
1180
1181
1182 /**
1183 The user Entry Point for module Partition. The user code starts with this function.
1184
1185 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1186 @param[in] SystemTable A pointer to the EFI System Table.
1187
1188 @retval EFI_SUCCESS The entry point is executed successfully.
1189 @retval other Some error occurs when executing this entry point.
1190
1191 **/
1192 EFI_STATUS
1193 EFIAPI
1194 InitializePartition (
1195 IN EFI_HANDLE ImageHandle,
1196 IN EFI_SYSTEM_TABLE *SystemTable
1197 )
1198 {
1199 EFI_STATUS Status;
1200
1201 //
1202 // Install driver model protocol(s).
1203 //
1204 Status = EfiLibInstallDriverBindingComponentName2 (
1205 ImageHandle,
1206 SystemTable,
1207 &gPartitionDriverBinding,
1208 ImageHandle,
1209 &gPartitionComponentName,
1210 &gPartitionComponentName2
1211 );
1212 ASSERT_EFI_ERROR (Status);
1213
1214
1215 return Status;
1216 }
1217