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