VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/PartitionDxe/Partition.c@ 48661

Last change on this file since 48661 was 42653, checked in by vboxsync, 13 years ago

EFI/OvmfPkg: import PartitionDxe from OvmfPkg.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette