add ia32 and x64 direcotry for EdkFvbServiceLib
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / Partition / Dxe / 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 - 2007, Intel Corporation
8 All rights reserved. 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 STATIC
34 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
35 PartitionInstallGptChildHandles,
36 PartitionInstallElToritoChildHandles,
37 PartitionInstallMbrChildHandles,
38 NULL
39 };
40
41
42
43 /**
44 Test to see if this driver supports ControllerHandle. Any ControllerHandle
45 than contains a BlockIo and DiskIo protocol can be supported.
46
47 @param This Protocol instance pointer.
48 @param ControllerHandle Handle of device to test
49 @param RemainingDevicePath Optional parameter use to pick a specific child
50 device to start.
51
52 @retval EFI_SUCCESS This driver supports this device
53 @retval EFI_ALREADY_STARTED This driver is already running on this device
54 @retval other This driver does not support this device
55
56 **/
57 EFI_STATUS
58 EFIAPI
59 PartitionDriverBindingSupported (
60 IN EFI_DRIVER_BINDING_PROTOCOL *This,
61 IN EFI_HANDLE ControllerHandle,
62 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
63 )
64 {
65 EFI_STATUS Status;
66 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
67 EFI_DISK_IO_PROTOCOL *DiskIo;
68 EFI_DEV_PATH *Node;
69
70 if (RemainingDevicePath != NULL) {
71 Node = (EFI_DEV_PATH *) RemainingDevicePath;
72 if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
73 Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
74 DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)
75 ) {
76 return EFI_UNSUPPORTED;
77 }
78 }
79 //
80 // Open the IO Abstraction(s) needed to perform the supported test
81 //
82 Status = gBS->OpenProtocol (
83 ControllerHandle,
84 &gEfiDevicePathProtocolGuid,
85 (VOID **) &ParentDevicePath,
86 This->DriverBindingHandle,
87 ControllerHandle,
88 EFI_OPEN_PROTOCOL_BY_DRIVER
89 );
90 if (Status == EFI_ALREADY_STARTED) {
91 return EFI_SUCCESS;
92 }
93
94 if (EFI_ERROR (Status)) {
95 return Status;
96 }
97 //
98 // Close the I/O Abstraction(s) used to perform the supported test
99 //
100 gBS->CloseProtocol (
101 ControllerHandle,
102 &gEfiDevicePathProtocolGuid,
103 This->DriverBindingHandle,
104 ControllerHandle
105 );
106
107 //
108 // Open the IO Abstraction(s) needed to perform the supported test
109 //
110 Status = gBS->OpenProtocol (
111 ControllerHandle,
112 &gEfiDiskIoProtocolGuid,
113 (VOID **) &DiskIo,
114 This->DriverBindingHandle,
115 ControllerHandle,
116 EFI_OPEN_PROTOCOL_BY_DRIVER
117 );
118 if (Status == EFI_ALREADY_STARTED) {
119 return EFI_SUCCESS;
120 }
121
122 if (EFI_ERROR (Status)) {
123 return Status;
124 }
125 //
126 // Close the I/O Abstraction(s) used to perform the supported test
127 //
128 gBS->CloseProtocol (
129 ControllerHandle,
130 &gEfiDiskIoProtocolGuid,
131 This->DriverBindingHandle,
132 ControllerHandle
133 );
134
135 //
136 // Open the IO Abstraction(s) needed to perform the supported test
137 //
138 Status = gBS->OpenProtocol (
139 ControllerHandle,
140 &gEfiBlockIoProtocolGuid,
141 NULL,
142 This->DriverBindingHandle,
143 ControllerHandle,
144 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
145 );
146
147 return Status;
148 }
149
150
151 /**
152 Start this driver on ControllerHandle by opening a Block IO and Disk IO
153 protocol, reading Device Path, and creating a child handle with a
154 Disk IO and device path protocol.
155
156 @param This Protocol instance pointer.
157 @param ControllerHandle Handle of device to bind driver to
158 @param RemainingDevicePath Optional parameter use to pick a specific child
159 device to start.
160
161 @retval EFI_SUCCESS This driver is added to ControllerHandle
162 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
163 @retval other This driver does not support this device
164
165 **/
166 EFI_STATUS
167 EFIAPI
168 PartitionDriverBindingStart (
169 IN EFI_DRIVER_BINDING_PROTOCOL *This,
170 IN EFI_HANDLE ControllerHandle,
171 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
172 )
173 {
174 EFI_STATUS Status;
175 EFI_STATUS OpenStatus;
176 EFI_BLOCK_IO_PROTOCOL *BlockIo;
177 EFI_DISK_IO_PROTOCOL *DiskIo;
178 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
179 PARTITION_DETECT_ROUTINE *Routine;
180
181 Status = gBS->OpenProtocol (
182 ControllerHandle,
183 &gEfiBlockIoProtocolGuid,
184 (VOID **) &BlockIo,
185 This->DriverBindingHandle,
186 ControllerHandle,
187 EFI_OPEN_PROTOCOL_GET_PROTOCOL
188 );
189 if (EFI_ERROR (Status)) {
190 return Status;
191 }
192 //
193 // Get the Device Path Protocol on ControllerHandle's handle
194 //
195 Status = gBS->OpenProtocol (
196 ControllerHandle,
197 &gEfiDevicePathProtocolGuid,
198 (VOID **) &ParentDevicePath,
199 This->DriverBindingHandle,
200 ControllerHandle,
201 EFI_OPEN_PROTOCOL_BY_DRIVER
202 );
203 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
204 return Status;
205 }
206
207 Status = gBS->OpenProtocol (
208 ControllerHandle,
209 &gEfiDiskIoProtocolGuid,
210 (VOID **) &DiskIo,
211 This->DriverBindingHandle,
212 ControllerHandle,
213 EFI_OPEN_PROTOCOL_BY_DRIVER
214 );
215 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
216 gBS->CloseProtocol (
217 ControllerHandle,
218 &gEfiDevicePathProtocolGuid,
219 This->DriverBindingHandle,
220 ControllerHandle
221 );
222 return Status;
223 }
224
225 OpenStatus = Status;
226
227 //
228 // If no media is present, do nothing here.
229 //
230 Status = EFI_UNSUPPORTED;
231 if (BlockIo->Media->MediaPresent) {
232 //
233 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
234 // media supports a given partition type install child handles to represent
235 // the partitions described by the media.
236 //
237 Routine = &mPartitionDetectRoutineTable[0];
238 while (*Routine != NULL) {
239 Status = (*Routine) (
240 This,
241 ControllerHandle,
242 DiskIo,
243 BlockIo,
244 ParentDevicePath
245 );
246 if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED) {
247 break;
248 }
249 Routine++;
250 }
251 }
252 //
253 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
254 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
255 // driver. So don't try to close them. Otherwise, we will break the dependency
256 // between the controller and the driver set up before.
257 //
258 if (EFI_ERROR (Status) && !EFI_ERROR (OpenStatus) && Status != EFI_MEDIA_CHANGED) {
259 gBS->CloseProtocol (
260 ControllerHandle,
261 &gEfiDiskIoProtocolGuid,
262 This->DriverBindingHandle,
263 ControllerHandle
264 );
265
266 gBS->CloseProtocol (
267 ControllerHandle,
268 &gEfiDevicePathProtocolGuid,
269 This->DriverBindingHandle,
270 ControllerHandle
271 );
272 }
273
274 return Status;
275 }
276
277
278 /**
279 Stop this driver on ControllerHandle. Support stoping any child handles
280 created by this driver.
281
282 @param This Protocol instance pointer.
283 @param ControllerHandle Handle of device to stop driver on
284 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
285 children is zero stop the entire bus driver.
286 @param ChildHandleBuffer List of Child Handles to Stop.
287
288 @retval EFI_SUCCESS This driver is removed ControllerHandle
289 @retval other This driver was not removed from this device
290
291 **/
292 EFI_STATUS
293 EFIAPI
294 PartitionDriverBindingStop (
295 IN EFI_DRIVER_BINDING_PROTOCOL *This,
296 IN EFI_HANDLE ControllerHandle,
297 IN UINTN NumberOfChildren,
298 IN EFI_HANDLE *ChildHandleBuffer
299 )
300 {
301 EFI_STATUS Status;
302 UINTN Index;
303 EFI_BLOCK_IO_PROTOCOL *BlockIo;
304 BOOLEAN AllChildrenStopped;
305 PARTITION_PRIVATE_DATA *Private;
306 EFI_DISK_IO_PROTOCOL *DiskIo;
307
308 if (NumberOfChildren == 0) {
309 //
310 // Close the bus driver
311 //
312 gBS->CloseProtocol (
313 ControllerHandle,
314 &gEfiDiskIoProtocolGuid,
315 This->DriverBindingHandle,
316 ControllerHandle
317 );
318
319 gBS->CloseProtocol (
320 ControllerHandle,
321 &gEfiDevicePathProtocolGuid,
322 This->DriverBindingHandle,
323 ControllerHandle
324 );
325
326 return EFI_SUCCESS;
327 }
328
329 AllChildrenStopped = TRUE;
330 for (Index = 0; Index < NumberOfChildren; Index++) {
331 Status = gBS->OpenProtocol (
332 ChildHandleBuffer[Index],
333 &gEfiBlockIoProtocolGuid,
334 (VOID **) &BlockIo,
335 This->DriverBindingHandle,
336 ControllerHandle,
337 EFI_OPEN_PROTOCOL_GET_PROTOCOL
338 );
339 if (!EFI_ERROR (Status)) {
340
341 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
342
343 //
344 // All Software protocols have be freed from the handle so remove it.
345 //
346 BlockIo->FlushBlocks (BlockIo);
347
348 Status = gBS->CloseProtocol (
349 ControllerHandle,
350 &gEfiDiskIoProtocolGuid,
351 This->DriverBindingHandle,
352 ChildHandleBuffer[Index]
353 );
354
355 Status = gBS->UninstallMultipleProtocolInterfaces (
356 ChildHandleBuffer[Index],
357 &gEfiDevicePathProtocolGuid,
358 Private->DevicePath,
359 &gEfiBlockIoProtocolGuid,
360 &Private->BlockIo,
361 Private->EspGuid,
362 NULL,
363 NULL
364 );
365 if (EFI_ERROR (Status)) {
366 gBS->OpenProtocol (
367 ControllerHandle,
368 &gEfiDiskIoProtocolGuid,
369 (VOID **) &DiskIo,
370 This->DriverBindingHandle,
371 ChildHandleBuffer[Index],
372 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
373 );
374 } else {
375 FreePool (Private->DevicePath);
376 FreePool (Private);
377 }
378
379 }
380
381 if (EFI_ERROR (Status)) {
382 AllChildrenStopped = FALSE;
383 }
384 }
385
386 if (!AllChildrenStopped) {
387 return EFI_DEVICE_ERROR;
388 }
389
390 return EFI_SUCCESS;
391 }
392
393
394 /**
395 Reset the Block Device.
396
397 @param This Protocol instance pointer.
398 @param ExtendedVerification Driver may perform diagnostics on reset.
399
400 @retval EFI_SUCCESS The device was reset.
401 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
402 not be reset.
403
404 **/
405 STATIC
406 EFI_STATUS
407 EFIAPI
408 PartitionReset (
409 IN EFI_BLOCK_IO_PROTOCOL *This,
410 IN BOOLEAN ExtendedVerification
411 )
412 {
413 PARTITION_PRIVATE_DATA *Private;
414
415 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
416
417 return Private->ParentBlockIo->Reset (
418 Private->ParentBlockIo,
419 ExtendedVerification
420 );
421 }
422
423
424 /**
425 Read by using the Disk IO protocol on the parent device. Lba addresses
426 must be converted to byte offsets.
427
428 @param This Protocol instance pointer.
429 @param MediaId Id of the media, changes every time the media is replaced.
430 @param Lba The starting Logical Block Address to read from
431 @param BufferSize Size of Buffer, must be a multiple of device block size.
432 @param Buffer Buffer containing read data
433
434 @retval EFI_SUCCESS The data was read correctly from the device.
435 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
436 @retval EFI_NO_MEDIA There is no media in the device.
437 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
438 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
439 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
440 valid for the device.
441
442 **/
443 STATIC
444 EFI_STATUS
445 EFIAPI
446 PartitionReadBlocks (
447 IN EFI_BLOCK_IO_PROTOCOL *This,
448 IN UINT32 MediaId,
449 IN EFI_LBA Lba,
450 IN UINTN BufferSize,
451 OUT VOID *Buffer
452 )
453 {
454 PARTITION_PRIVATE_DATA *Private;
455 UINT64 Offset;
456
457 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
458
459 if (BufferSize % Private->BlockSize != 0) {
460 return EFI_BAD_BUFFER_SIZE;
461 }
462
463 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
464 if (Offset + BufferSize > Private->End) {
465 return EFI_INVALID_PARAMETER;
466 }
467 //
468 // Because some kinds of partition have different block size from their parent
469 // device, we call the Disk IO protocol on the parent device, not the Block IO
470 // protocol
471 //
472 return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
473 }
474
475 /**
476 Write by using the Disk IO protocol on the parent device. Lba addresses
477 must be converted to byte offsets.
478
479 @param This Protocol instance pointer.
480 @param MediaId Id of the media, changes every time the media is replaced.
481 @param Lba The starting Logical Block Address to read from
482 @param BufferSize Size of Buffer, must be a multiple of device block size.
483 @param Buffer Buffer containing read data
484
485 @retval EFI_SUCCESS The data was written correctly to the device.
486 @retval EFI_WRITE_PROTECTED The device can not be written to.
487 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
488 @retval EFI_NO_MEDIA There is no media in the device.
489 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
490 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
491 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
492 valid for the device.
493
494 **/
495 STATIC
496 EFI_STATUS
497 EFIAPI
498 PartitionWriteBlocks (
499 IN EFI_BLOCK_IO_PROTOCOL *This,
500 IN UINT32 MediaId,
501 IN EFI_LBA Lba,
502 IN UINTN BufferSize,
503 OUT VOID *Buffer
504 )
505 {
506 PARTITION_PRIVATE_DATA *Private;
507 UINT64 Offset;
508
509 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
510
511 if (BufferSize % Private->BlockSize != 0) {
512 return EFI_BAD_BUFFER_SIZE;
513 }
514
515 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
516 if (Offset + BufferSize > Private->End) {
517 return EFI_INVALID_PARAMETER;
518 }
519 //
520 // Because some kinds of partition have different block size from their parent
521 // device, we call the Disk IO protocol on the parent device, not the Block IO
522 // protocol
523 //
524 return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
525 }
526
527
528 /**
529 Flush the parent Block Device.
530
531 @param This Protocol instance pointer.
532
533 @retval EFI_SUCCESS All outstanding data was written to the device
534 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
535 @retval EFI_NO_MEDIA There is no media in the device.
536
537 **/
538 STATIC
539 EFI_STATUS
540 EFIAPI
541 PartitionFlushBlocks (
542 IN EFI_BLOCK_IO_PROTOCOL *This
543 )
544 {
545 PARTITION_PRIVATE_DATA *Private;
546
547 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
548
549 return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
550 }
551
552
553
554 /**
555 Create a child handle for a logical block device that represents the
556 bytes Start to End of the Parent Block IO device.
557
558 @param[in] This Protocol instance pointer.
559 @param[in] This Calling context.
560 @param[in] ParentHandle Parent Handle for new child
561 @param[in] ParentDiskIo Parent DiskIo interface
562 @param[in] ParentBlockIo Parent BlockIo interface
563 @param[in] ParentDevicePath Parent Device Path
564 @param[in] DevicePathNode Child Device Path node
565 @param[in] Start Start Block
566 @param[in] End End Block
567 @param[in] BlockSize Child block size
568 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle
569
570 @retval EFI_SUCCESS A child handle was added
571 @retval other A child handle was not added
572
573 **/
574 EFI_STATUS
575 PartitionInstallChildHandle (
576 IN EFI_DRIVER_BINDING_PROTOCOL *This,
577 IN EFI_HANDLE ParentHandle,
578 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
579 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
580 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
581 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
582 IN EFI_LBA Start,
583 IN EFI_LBA End,
584 IN UINT32 BlockSize,
585 IN BOOLEAN InstallEspGuid
586 )
587 {
588 EFI_STATUS Status;
589 PARTITION_PRIVATE_DATA *Private;
590
591 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
592 if (Private == NULL) {
593 return EFI_OUT_OF_RESOURCES;
594 }
595
596 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
597
598 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
599 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
600
601 Private->BlockSize = BlockSize;
602 Private->ParentBlockIo = ParentBlockIo;
603 Private->DiskIo = ParentDiskIo;
604
605 Private->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
606
607 Private->BlockIo.Media = &Private->Media;
608 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
609 Private->Media.LogicalPartition = TRUE;
610 Private->Media.LastBlock = DivU64x32 (
611 MultU64x32 (
612 End - Start + 1,
613 ParentBlockIo->Media->BlockSize
614 ),
615 BlockSize
616 ) - 1;
617
618 Private->Media.BlockSize = (UINT32) BlockSize;
619
620 Private->BlockIo.Reset = PartitionReset;
621 Private->BlockIo.ReadBlocks = PartitionReadBlocks;
622 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
623 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
624
625 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
626
627 if (Private->DevicePath == NULL) {
628 FreePool (Private);
629 return EFI_OUT_OF_RESOURCES;
630 }
631
632 if (InstallEspGuid) {
633 Private->EspGuid = &gEfiPartTypeSystemPartGuid;
634 } else {
635 //
636 // If NULL InstallMultipleProtocolInterfaces will ignore it.
637 //
638 Private->EspGuid = NULL;
639 }
640 //
641 // Create the new handle
642 //
643 Private->Handle = NULL;
644 Status = gBS->InstallMultipleProtocolInterfaces (
645 &Private->Handle,
646 &gEfiDevicePathProtocolGuid,
647 Private->DevicePath,
648 &gEfiBlockIoProtocolGuid,
649 &Private->BlockIo,
650 Private->EspGuid,
651 NULL,
652 NULL
653 );
654
655 if (!EFI_ERROR (Status)) {
656 //
657 // Open the Parent Handle for the child
658 //
659 Status = gBS->OpenProtocol (
660 ParentHandle,
661 &gEfiDiskIoProtocolGuid,
662 (VOID **) &ParentDiskIo,
663 This->DriverBindingHandle,
664 Private->Handle,
665 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
666 );
667 } else {
668 FreePool (Private->DevicePath);
669 FreePool (Private);
670 }
671
672 return Status;
673 }
674
675
676 /**
677 The user Entry Point for module Partition. The user code starts with this function.
678
679 @param[in] ImageHandle The firmware allocated handle for the EFI image.
680 @param[in] SystemTable A pointer to the EFI System Table.
681
682 @retval EFI_SUCCESS The entry point is executed successfully.
683 @retval other Some error occurs when executing this entry point.
684
685 **/
686 EFI_STATUS
687 EFIAPI
688 InitializePartition (
689 IN EFI_HANDLE ImageHandle,
690 IN EFI_SYSTEM_TABLE *SystemTable
691 )
692 {
693 EFI_STATUS Status;
694
695 //
696 // Install driver model protocol(s).
697 //
698 Status = EfiLibInstallAllDriverProtocols (
699 ImageHandle,
700 SystemTable,
701 &gPartitionDriverBinding,
702 ImageHandle,
703 &gPartitionComponentName,
704 NULL,
705 NULL
706 );
707 ASSERT_EFI_ERROR (Status);
708
709
710 return Status;
711 }
712