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