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