VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/PartitionDxe/Partition.c@ 48947

Last change on this file since 48947 was 48947, checked in by vboxsync, 11 years ago

Devices: Whitespace and svn:keyword cleanups by scm.

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

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