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