]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
MdeModulePkg/PartitionDxe: Add partition type guid to installed handle
[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
709c9fd5 7Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.\r
68599525 8Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 9This program and the accompanying materials\r
f42be642 10are licensed and made available under the terms and conditions of the BSD License\r
11which accompanies this distribution. The full text of the license may be found at\r
12http://opensource.org/licenses/bsd-license.php\r
adbcbf8f 13\r
f42be642 14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
adbcbf8f 16\r
17**/\r
18\r
19\r
20#include "Partition.h"\r
21\r
22//\r
ff61847d 23// Partition Driver Global Variables.\r
adbcbf8f 24//\r
25EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {\r
26 PartitionDriverBindingSupported,\r
27 PartitionDriverBindingStart,\r
28 PartitionDriverBindingStop,\r
c86b273d
RN
29 //\r
30 // Grub4Dos copies the BPB of the first partition to the MBR. If the \r
31 // DriverBindingStart() of the Fat driver gets run before that of Partition \r
32 // driver only the first partition can be recognized.\r
33 // Let the driver binding version of Partition driver be higher than that of\r
34 // Fat driver to make sure the DriverBindingStart() of the Partition driver\r
35 // gets run before that of Fat driver so that all the partitions can be recognized.\r
36 //\r
37 0xb,\r
adbcbf8f 38 NULL,\r
39 NULL\r
40};\r
41\r
ff61847d 42//\r
48557c65 43// Prioritized function list to detect partition table. \r
ff61847d 44//\r
adbcbf8f 45PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {\r
46 PartitionInstallGptChildHandles,\r
adbcbf8f 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
01a68fd3
HW
309 // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.\r
310 // If the media supports a given partition type install child handles to\r
311 // 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
709c9fd5 405 EFI_GUID *TypeGuid;\r
adbcbf8f 406\r
490b5ea1 407 BlockIo = NULL;\r
408 BlockIo2 = NULL;\r
409 Private = NULL;\r
410\r
adbcbf8f 411 if (NumberOfChildren == 0) {\r
e3325721
HW
412 //\r
413 // In the case of re-entry of the PartitionDriverBindingStop, the\r
414 // NumberOfChildren may not reflect the actual number of children on the\r
415 // bus driver. Hence, additional check is needed here.\r
416 //\r
417 if (HasChildren (ControllerHandle)) {\r
418 DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n"));\r
419 return EFI_DEVICE_ERROR;\r
420 }\r
421\r
adbcbf8f 422 //\r
423 // Close the bus driver\r
424 //\r
425 gBS->CloseProtocol (\r
426 ControllerHandle,\r
427 &gEfiDiskIoProtocolGuid,\r
428 This->DriverBindingHandle,\r
429 ControllerHandle\r
430 );\r
490b5ea1 431 //\r
432 // Close Parent BlockIO2 if has.\r
433 // \r
434 gBS->CloseProtocol (\r
435 ControllerHandle,\r
493d8e3a 436 &gEfiDiskIo2ProtocolGuid,\r
490b5ea1 437 This->DriverBindingHandle,\r
438 ControllerHandle\r
439 );\r
adbcbf8f 440\r
441 gBS->CloseProtocol (\r
442 ControllerHandle,\r
443 &gEfiDevicePathProtocolGuid,\r
444 This->DriverBindingHandle,\r
445 ControllerHandle\r
446 );\r
adbcbf8f 447 return EFI_SUCCESS;\r
448 }\r
449\r
450 AllChildrenStopped = TRUE;\r
451 for (Index = 0; Index < NumberOfChildren; Index++) {\r
490b5ea1 452 gBS->OpenProtocol (\r
453 ChildHandleBuffer[Index],\r
454 &gEfiBlockIoProtocolGuid,\r
455 (VOID **) &BlockIo,\r
456 This->DriverBindingHandle,\r
457 ControllerHandle,\r
458 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
459 );\r
460 //\r
461 // Try to locate BlockIo2.\r
462 //\r
463 gBS->OpenProtocol (\r
464 ChildHandleBuffer[Index],\r
465 &gEfiBlockIo2ProtocolGuid,\r
466 (VOID **) &BlockIo2,\r
467 This->DriverBindingHandle,\r
468 ControllerHandle,\r
469 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
470 ); \r
471\r
d0844d13 472\r
473 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);\r
e3325721
HW
474 if (Private->InStop) {\r
475 //\r
476 // If the child handle is going to be stopped again during the re-entry\r
477 // of DriverBindingStop, just do nothing.\r
478 //\r
479 break;\r
480 }\r
481 Private->InStop = TRUE;\r
adbcbf8f 482\r
e3325721
HW
483 BlockIo->FlushBlocks (BlockIo);\r
484\r
485 if (BlockIo2 != NULL) {\r
486 Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);\r
487 DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));\r
488 } else {\r
489 Status = EFI_SUCCESS;\r
490 }\r
491\r
492 gBS->CloseProtocol (\r
493 ControllerHandle,\r
494 &gEfiDiskIoProtocolGuid,\r
495 This->DriverBindingHandle,\r
496 ChildHandleBuffer[Index]\r
497 );\r
709c9fd5
JB
498\r
499 if (IsZeroGuid (&Private->TypeGuid)) {\r
500 TypeGuid = NULL;\r
501 } else {\r
502 TypeGuid = &Private->TypeGuid;\r
503 }\r
504\r
490b5ea1 505 //\r
506 // All Software protocols have be freed from the handle so remove it.\r
507 // Remove the BlockIo Protocol if has.\r
508 // Remove the BlockIo2 Protocol if has.\r
509 //\r
510 if (BlockIo2 != NULL) {\r
e3325721
HW
511 //\r
512 // Some device drivers might re-install the BlockIO(2) protocols for a\r
513 // media change condition. Therefore, if the FlushBlocksEx returned with\r
514 // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential\r
515 // reference of already stopped child handle.\r
516 //\r
517 if (Status != EFI_MEDIA_CHANGED) {\r
518 Status = gBS->UninstallMultipleProtocolInterfaces (\r
519 ChildHandleBuffer[Index],\r
520 &gEfiDevicePathProtocolGuid,\r
521 Private->DevicePath,\r
522 &gEfiBlockIoProtocolGuid,\r
523 &Private->BlockIo,\r
524 &gEfiBlockIo2ProtocolGuid,\r
525 &Private->BlockIo2,\r
3a3d62d2
HW
526 &gEfiPartitionInfoProtocolGuid,\r
527 &Private->PartitionInfo,\r
709c9fd5 528 TypeGuid,\r
e3325721
HW
529 NULL,\r
530 NULL\r
531 );\r
532 }\r
490b5ea1 533 } else {\r
490b5ea1 534 Status = gBS->UninstallMultipleProtocolInterfaces (\r
535 ChildHandleBuffer[Index],\r
536 &gEfiDevicePathProtocolGuid,\r
537 Private->DevicePath,\r
538 &gEfiBlockIoProtocolGuid,\r
539 &Private->BlockIo,\r
3a3d62d2
HW
540 &gEfiPartitionInfoProtocolGuid,\r
541 &Private->PartitionInfo,\r
709c9fd5 542 TypeGuid,\r
490b5ea1 543 NULL,\r
544 NULL\r
545 );\r
546 }\r
adbcbf8f 547\r
490b5ea1 548 if (EFI_ERROR (Status)) {\r
e3325721 549 Private->InStop = FALSE;\r
490b5ea1 550 gBS->OpenProtocol (\r
551 ControllerHandle,\r
552 &gEfiDiskIoProtocolGuid,\r
553 (VOID **) &DiskIo,\r
554 This->DriverBindingHandle,\r
555 ChildHandleBuffer[Index],\r
556 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
557 );\r
558 } else {\r
559 FreePool (Private->DevicePath);\r
560 FreePool (Private);\r
adbcbf8f 561 }\r
562\r
563 if (EFI_ERROR (Status)) {\r
564 AllChildrenStopped = FALSE;\r
e3325721
HW
565 if (Status == EFI_MEDIA_CHANGED) {\r
566 break;\r
567 }\r
adbcbf8f 568 }\r
569 }\r
570\r
571 if (!AllChildrenStopped) {\r
572 return EFI_DEVICE_ERROR;\r
573 }\r
574\r
575 return EFI_SUCCESS;\r
576}\r
577\r
578\r
579/**\r
580 Reset the Block Device.\r
581\r
582 @param This Protocol instance pointer.\r
583 @param ExtendedVerification Driver may perform diagnostics on reset.\r
584\r
585 @retval EFI_SUCCESS The device was reset.\r
586 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
587 not be reset.\r
588\r
589**/\r
adbcbf8f 590EFI_STATUS\r
591EFIAPI\r
592PartitionReset (\r
593 IN EFI_BLOCK_IO_PROTOCOL *This,\r
594 IN BOOLEAN ExtendedVerification\r
595 )\r
596{\r
597 PARTITION_PRIVATE_DATA *Private;\r
598\r
599 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
600\r
601 return Private->ParentBlockIo->Reset (\r
602 Private->ParentBlockIo,\r
603 ExtendedVerification\r
604 );\r
605}\r
606\r
fcf5e49d
RN
607/**\r
608 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED\r
609 for no media or media change case. Otherwise DefaultStatus is returned.\r
610\r
611 @param DiskIo Pointer to the DiskIo instance.\r
612 @param MediaId Id of the media, changes every time the media is replaced.\r
613 @param DefaultStatus The default status to return when it's not the no media\r
614 or media change case.\r
615\r
616 @retval EFI_NO_MEDIA There is no media.\r
617 @retval EFI_MEDIA_CHANGED The media was changed.\r
618 @retval others The default status to return.\r
619**/\r
620EFI_STATUS\r
621ProbeMediaStatus (\r
622 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
623 IN UINT32 MediaId,\r
624 IN EFI_STATUS DefaultStatus\r
625 )\r
626{\r
627 EFI_STATUS Status;\r
df473cc1 628 UINT8 Buffer[1];\r
fcf5e49d
RN
629\r
630 //\r
df473cc1
RC
631 // Read 1 byte from offset 0 to check if the MediaId is still valid.\r
632 // The reading operation is synchronious thus it is not worth it to\r
633 // allocate a buffer from the pool. The destination buffer for the\r
634 // data is in the stack.\r
fcf5e49d 635 //\r
df473cc1 636 Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer);\r
fcf5e49d
RN
637 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
638 return Status;\r
639 }\r
640 return DefaultStatus;\r
641}\r
adbcbf8f 642\r
643/**\r
644 Read by using the Disk IO protocol on the parent device. Lba addresses\r
645 must be converted to byte offsets.\r
646\r
647 @param This Protocol instance pointer.\r
648 @param MediaId Id of the media, changes every time the media is replaced.\r
649 @param Lba The starting Logical Block Address to read from\r
650 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
651 @param Buffer Buffer containing read data\r
652\r
653 @retval EFI_SUCCESS The data was read correctly from the device.\r
654 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
655 @retval EFI_NO_MEDIA There is no media in the device.\r
656 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
657 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
658 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not\r
659 valid for the device.\r
660\r
661**/\r
adbcbf8f 662EFI_STATUS\r
663EFIAPI\r
664PartitionReadBlocks (\r
665 IN EFI_BLOCK_IO_PROTOCOL *This,\r
666 IN UINT32 MediaId,\r
667 IN EFI_LBA Lba,\r
668 IN UINTN BufferSize,\r
669 OUT VOID *Buffer\r
670 )\r
671{\r
672 PARTITION_PRIVATE_DATA *Private;\r
673 UINT64 Offset;\r
674\r
675 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
676\r
677 if (BufferSize % Private->BlockSize != 0) {\r
fcf5e49d 678 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
adbcbf8f 679 }\r
680\r
681 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
682 if (Offset + BufferSize > Private->End) {\r
fcf5e49d 683 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
adbcbf8f 684 }\r
685 //\r
686 // Because some kinds of partition have different block size from their parent\r
687 // device, we call the Disk IO protocol on the parent device, not the Block IO\r
688 // protocol\r
689 //\r
690 return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);\r
691}\r
692\r
693/**\r
694 Write by using the Disk IO protocol on the parent device. Lba addresses\r
695 must be converted to byte offsets.\r
696\r
490b5ea1 697 @param[in] This Protocol instance pointer.\r
698 @param[in] MediaId Id of the media, changes every time the media is replaced.\r
699 @param[in] Lba The starting Logical Block Address to read from\r
700 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
701 @param[in] Buffer Buffer containing data to be written to device.\r
adbcbf8f 702\r
703 @retval EFI_SUCCESS The data was written correctly to the device.\r
704 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
705 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
706 @retval EFI_NO_MEDIA There is no media in the device.\r
707 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
708 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
709 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not\r
710 valid for the device.\r
711\r
712**/\r
adbcbf8f 713EFI_STATUS\r
714EFIAPI\r
715PartitionWriteBlocks (\r
716 IN EFI_BLOCK_IO_PROTOCOL *This,\r
717 IN UINT32 MediaId,\r
718 IN EFI_LBA Lba,\r
719 IN UINTN BufferSize,\r
490b5ea1 720 IN VOID *Buffer\r
adbcbf8f 721 )\r
722{\r
723 PARTITION_PRIVATE_DATA *Private;\r
724 UINT64 Offset;\r
725\r
726 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
727\r
728 if (BufferSize % Private->BlockSize != 0) {\r
fcf5e49d 729 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
adbcbf8f 730 }\r
731\r
732 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
733 if (Offset + BufferSize > Private->End) {\r
fcf5e49d 734 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
adbcbf8f 735 }\r
736 //\r
737 // Because some kinds of partition have different block size from their parent\r
738 // device, we call the Disk IO protocol on the parent device, not the Block IO\r
739 // protocol\r
740 //\r
741 return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);\r
742}\r
743\r
744\r
745/**\r
746 Flush the parent Block Device.\r
747\r
748 @param This Protocol instance pointer.\r
749\r
750 @retval EFI_SUCCESS All outstanding data was written to the device\r
751 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data\r
752 @retval EFI_NO_MEDIA There is no media in the device.\r
753\r
754**/\r
adbcbf8f 755EFI_STATUS\r
756EFIAPI\r
757PartitionFlushBlocks (\r
758 IN EFI_BLOCK_IO_PROTOCOL *This\r
759 )\r
760{\r
761 PARTITION_PRIVATE_DATA *Private;\r
762\r
763 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
764\r
765 return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);\r
766}\r
767\r
65fd3952
RN
768/**\r
769 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED\r
770 for no media or media change case. Otherwise DefaultStatus is returned.\r
771\r
493d8e3a 772 @param DiskIo2 Pointer to the DiskIo2 instance.\r
65fd3952
RN
773 @param MediaId Id of the media, changes every time the media is replaced.\r
774 @param DefaultStatus The default status to return when it's not the no media\r
775 or media change case.\r
776\r
777 @retval EFI_NO_MEDIA There is no media.\r
778 @retval EFI_MEDIA_CHANGED The media was changed.\r
779 @retval others The default status to return.\r
780**/\r
781EFI_STATUS\r
782ProbeMediaStatusEx (\r
493d8e3a 783 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
65fd3952
RN
784 IN UINT32 MediaId,\r
785 IN EFI_STATUS DefaultStatus\r
786 )\r
787{\r
788 EFI_STATUS Status;\r
68599525 789 UINT8 Buffer[1];\r
65fd3952
RN
790\r
791 //\r
68599525
RN
792 // Read 1 byte from offset 0 to check if the MediaId is still valid.\r
793 // The reading operation is synchronious thus it is not worth it to\r
794 // allocate a buffer from the pool. The destination buffer for the\r
795 // data is in the stack.\r
65fd3952 796 //\r
68599525 797 Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID*)Buffer);\r
65fd3952
RN
798 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
799 return Status;\r
800 }\r
801 return DefaultStatus;\r
802}\r
803\r
490b5ea1 804/**\r
805 Reset the Block Device throught Block I/O2 protocol.\r
806\r
807 @param This Protocol instance pointer.\r
808 @param ExtendedVerification Driver may perform diagnostics on reset.\r
809\r
810 @retval EFI_SUCCESS The device was reset.\r
811 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
812 not be reset.\r
813\r
814**/\r
815EFI_STATUS\r
816EFIAPI\r
817PartitionResetEx (\r
818 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
819 IN BOOLEAN ExtendedVerification\r
820 )\r
821{\r
822 PARTITION_PRIVATE_DATA *Private;\r
823\r
824 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
825\r
826 return Private->ParentBlockIo2->Reset (\r
827 Private->ParentBlockIo2,\r
828 ExtendedVerification\r
829 );\r
830}\r
831\r
493d8e3a
RN
832/**\r
833 The general callback for the DiskIo2 interfaces.\r
834 @param Event Event whose notification function is being invoked.\r
835 @param Context The pointer to the notification function's context,\r
836 which points to the PARTITION_ACCESS_TASK instance.\r
837**/\r
838VOID\r
839EFIAPI\r
840PartitionOnAccessComplete (\r
841 IN EFI_EVENT Event,\r
842 IN VOID *Context\r
843 )\r
844{\r
845 PARTITION_ACCESS_TASK *Task;\r
846\r
847 Task = (PARTITION_ACCESS_TASK *) Context;\r
848\r
849 gBS->CloseEvent (Event);\r
850\r
851 Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;\r
852 gBS->SignalEvent (Task->BlockIo2Token->Event);\r
853\r
854 FreePool (Task);\r
855}\r
856\r
857/**\r
858 Create a new PARTITION_ACCESS_TASK instance.\r
859\r
860 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.\r
861\r
862 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.\r
863**/\r
864PARTITION_ACCESS_TASK *\r
865PartitionCreateAccessTask (\r
866 IN EFI_BLOCK_IO2_TOKEN *Token\r
867 )\r
868{\r
869 EFI_STATUS Status;\r
870 PARTITION_ACCESS_TASK *Task;\r
871\r
872 Task = AllocatePool (sizeof (*Task));\r
873 if (Task == NULL) {\r
874 return NULL;\r
875 }\r
876\r
877 Status = gBS->CreateEvent (\r
878 EVT_NOTIFY_SIGNAL,\r
80c83a69 879 TPL_NOTIFY,\r
493d8e3a
RN
880 PartitionOnAccessComplete,\r
881 Task,\r
882 &Task->DiskIo2Token.Event\r
883 );\r
884 if (EFI_ERROR (Status)) {\r
885 FreePool (Task);\r
886 return NULL;\r
887 }\r
888\r
889 Task->BlockIo2Token = Token;\r
890\r
891 return Task;\r
892}\r
893\r
490b5ea1 894/**\r
895 Read BufferSize bytes from Lba into Buffer.\r
896 \r
897 This function reads the requested number of blocks from the device. All the\r
898 blocks are read, or an error is returned.\r
899 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r
900 non-blocking I/O is being used, the Event associated with this request will\r
901 not be signaled.\r
902\r
903 @param[in] This Indicates a pointer to the calling context.\r
904 @param[in] MediaId Id of the media, changes every time the media is \r
905 replaced.\r
906 @param[in] Lba The starting Logical Block Address to read from.\r
907 @param[in, out] Token A pointer to the token associated with the transaction.\r
908 @param[in] BufferSize Size of Buffer, must be a multiple of device block size. \r
909 @param[out] Buffer A pointer to the destination buffer for the data. The \r
910 caller is responsible for either having implicit or \r
911 explicit ownership of the buffer.\r
912\r
913 @retval EFI_SUCCESS The read request was queued if Token->Event is\r
914 not NULL.The data was read correctly from the\r
915 device if the Token->Event is NULL.\r
916 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
917 the read.\r
918 @retval EFI_NO_MEDIA There is no media in the device.\r
919 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
920 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
921 intrinsic block size of the device.\r
922 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
923 or the buffer is not on proper alignment.\r
924 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
925 of resources.\r
926**/\r
927EFI_STATUS\r
928EFIAPI\r
929PartitionReadBlocksEx (\r
930 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
931 IN UINT32 MediaId,\r
932 IN EFI_LBA Lba,\r
933 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
934 IN UINTN BufferSize,\r
935 OUT VOID *Buffer\r
936 )\r
937{\r
493d8e3a 938 EFI_STATUS Status;\r
490b5ea1 939 PARTITION_PRIVATE_DATA *Private;\r
940 UINT64 Offset;\r
493d8e3a 941 PARTITION_ACCESS_TASK *Task;\r
490b5ea1 942\r
65fd3952
RN
943 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
944\r
490b5ea1 945 if (BufferSize % Private->BlockSize != 0) {\r
493d8e3a 946 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
490b5ea1 947 }\r
948\r
949 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
950 if (Offset + BufferSize > Private->End) {\r
493d8e3a 951 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
490b5ea1 952 }\r
953\r
493d8e3a
RN
954 if ((Token != NULL) && (Token->Event != NULL)) {\r
955 Task = PartitionCreateAccessTask (Token);\r
956 if (Task == NULL) {\r
957 return EFI_OUT_OF_RESOURCES;\r
958 }\r
490b5ea1 959\r
493d8e3a
RN
960 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);\r
961 if (EFI_ERROR (Status)) {\r
962 gBS->CloseEvent (Task->DiskIo2Token.Event);\r
963 FreePool (Task);\r
964 }\r
965 } else {\r
966 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);\r
490b5ea1 967 }\r
968\r
493d8e3a 969 return Status;\r
490b5ea1 970}\r
971\r
972/**\r
973 Write BufferSize bytes from Lba into Buffer.\r
974\r
975 This function writes the requested number of blocks to the device. All blocks\r
976 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r
977 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r
978 being used, the Event associated with this request will not be signaled.\r
979\r
980 @param[in] This Indicates a pointer to the calling context.\r
981 @param[in] MediaId The media ID that the write request is for.\r
982 @param[in] Lba The starting logical block address to be written. The\r
983 caller is responsible for writing to only legitimate\r
984 locations.\r
985 @param[in, out] Token A pointer to the token associated with the transaction.\r
986 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
987 @param[in] Buffer A pointer to the source buffer for the data.\r
988\r
989 @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r
990 The data was written correctly to the device if\r
991 the Event is NULL.\r
992 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
993 @retval EFI_NO_MEDIA There is no media in the device.\r
994 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
995 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
996 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
997 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
998 or the buffer is not on proper alignment.\r
999 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
1000 of resources.\r
1001\r
1002**/\r
1003EFI_STATUS\r
1004EFIAPI\r
1005PartitionWriteBlocksEx (\r
1006 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
1007 IN UINT32 MediaId,\r
1008 IN EFI_LBA Lba,\r
1009 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
1010 IN UINTN BufferSize,\r
1011 IN VOID *Buffer\r
1012 )\r
1013{\r
493d8e3a 1014 EFI_STATUS Status;\r
490b5ea1 1015 PARTITION_PRIVATE_DATA *Private;\r
1016 UINT64 Offset;\r
493d8e3a 1017 PARTITION_ACCESS_TASK *Task;\r
490b5ea1 1018\r
65fd3952
RN
1019 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
1020\r
490b5ea1 1021 if (BufferSize % Private->BlockSize != 0) {\r
493d8e3a 1022 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
490b5ea1 1023 }\r
1024\r
1025 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
1026 if (Offset + BufferSize > Private->End) {\r
493d8e3a 1027 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
490b5ea1 1028 }\r
493d8e3a
RN
1029 \r
1030 if ((Token != NULL) && (Token->Event != NULL)) {\r
1031 Task = PartitionCreateAccessTask (Token);\r
1032 if (Task == NULL) {\r
1033 return EFI_OUT_OF_RESOURCES;\r
1034 }\r
490b5ea1 1035\r
493d8e3a
RN
1036 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);\r
1037 if (EFI_ERROR (Status)) {\r
1038 gBS->CloseEvent (Task->DiskIo2Token.Event);\r
1039 FreePool (Task);\r
1040 }\r
1041 } else {\r
1042 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);\r
490b5ea1 1043 }\r
493d8e3a 1044 return Status;\r
490b5ea1 1045}\r
1046\r
1047/**\r
1048 Flush the Block Device.\r
1049 \r
1050 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r
1051 is returned and non-blocking I/O is being used, the Event associated with\r
1052 this request will not be signaled. \r
1053\r
1054 @param[in] This Indicates a pointer to the calling context.\r
86d8e199 1055 @param[in, out] Token A pointer to the token associated with the transaction\r
490b5ea1 1056\r
1057 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r
1058 All outstanding data was written correctly to the\r
1059 device if the Event is NULL.\r
1060 @retval EFI_DEVICE_ERROR The device reported an error while writting back\r
1061 the data.\r
1062 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1063 @retval EFI_NO_MEDIA There is no media in the device.\r
1064 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1065 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
1066 of resources.\r
1067\r
1068**/\r
1069EFI_STATUS\r
1070EFIAPI\r
1071PartitionFlushBlocksEx (\r
1072 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
1073 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
1074 )\r
1075{\r
493d8e3a 1076 EFI_STATUS Status;\r
490b5ea1 1077 PARTITION_PRIVATE_DATA *Private;\r
493d8e3a 1078 PARTITION_ACCESS_TASK *Task;\r
490b5ea1 1079\r
1080 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
1081\r
493d8e3a
RN
1082 if ((Token != NULL) && (Token->Event != NULL)) {\r
1083 Task = PartitionCreateAccessTask (Token);\r
1084 if (Task == NULL) {\r
1085 return EFI_OUT_OF_RESOURCES;\r
1086 }\r
490b5ea1 1087\r
493d8e3a
RN
1088 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);\r
1089 if (EFI_ERROR (Status)) {\r
1090 gBS->CloseEvent (Task->DiskIo2Token.Event);\r
1091 FreePool (Task);\r
1092 }\r
1093 } else {\r
1094 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);\r
1095 }\r
1096 return Status;\r
490b5ea1 1097}\r
adbcbf8f 1098\r
1099\r
1100/**\r
1101 Create a child handle for a logical block device that represents the\r
1102 bytes Start to End of the Parent Block IO device.\r
1103\r
490b5ea1 1104 @param[in] This Protocol instance pointer.\r
1105 @param[in] ParentHandle Parent Handle for new child.\r
1106 @param[in] ParentDiskIo Parent DiskIo interface.\r
493d8e3a 1107 @param[in] ParentDiskIo2 Parent DiskIo2 interface.\r
490b5ea1 1108 @param[in] ParentBlockIo Parent BlockIo interface.\r
1109 @param[in] ParentBlockIo2 Parent BlockIo2 interface.\r
1110 @param[in] ParentDevicePath Parent Device Path.\r
1111 @param[in] DevicePathNode Child Device Path node.\r
3a3d62d2 1112 @param[in] PartitionInfo Child Partition Information interface.\r
490b5ea1 1113 @param[in] Start Start Block.\r
1114 @param[in] End End Block.\r
1115 @param[in] BlockSize Child block size.\r
709c9fd5 1116 @param[in] TypeGuid Partition GUID Type.\r
490b5ea1 1117\r
1118 @retval EFI_SUCCESS A child handle was added.\r
1119 @retval other A child handle was not added.\r
adbcbf8f 1120\r
1121**/\r
1122EFI_STATUS\r
1123PartitionInstallChildHandle (\r
1124 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1125 IN EFI_HANDLE ParentHandle,\r
1126 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,\r
493d8e3a 1127 IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,\r
adbcbf8f 1128 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,\r
490b5ea1 1129 IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,\r
adbcbf8f 1130 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1131 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,\r
3a3d62d2 1132 IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,\r
adbcbf8f 1133 IN EFI_LBA Start,\r
1134 IN EFI_LBA End,\r
709c9fd5
JB
1135 IN UINT32 BlockSize,\r
1136 IN EFI_GUID *TypeGuid\r
adbcbf8f 1137 )\r
1138{\r
1139 EFI_STATUS Status;\r
1140 PARTITION_PRIVATE_DATA *Private;\r
1141\r
490b5ea1 1142 Status = EFI_SUCCESS;\r
adbcbf8f 1143 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));\r
1144 if (Private == NULL) {\r
1145 return EFI_OUT_OF_RESOURCES;\r
1146 }\r
1147\r
1148 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;\r
1149\r
1150 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);\r
1151 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);\r
1152\r
1153 Private->BlockSize = BlockSize;\r
1154 Private->ParentBlockIo = ParentBlockIo;\r
490b5ea1 1155 Private->ParentBlockIo2 = ParentBlockIo2;\r
adbcbf8f 1156 Private->DiskIo = ParentDiskIo;\r
493d8e3a 1157 Private->DiskIo2 = ParentDiskIo2;\r
adbcbf8f 1158\r
d0844d13 1159 //\r
1160 // Set the BlockIO into Private Data.\r
1161 //\r
1162 Private->BlockIo.Revision = ParentBlockIo->Revision;\r
1163 \r
1164 Private->BlockIo.Media = &Private->Media;\r
1165 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
490b5ea1 1166\r
d0844d13 1167 Private->BlockIo.Reset = PartitionReset;\r
1168 Private->BlockIo.ReadBlocks = PartitionReadBlocks;\r
1169 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;\r
1170 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;\r
490b5ea1 1171\r
d0844d13 1172 //\r
1173 // Set the BlockIO2 into Private Data.\r
1174 //\r
493d8e3a
RN
1175 if (Private->DiskIo2 != NULL) {\r
1176 ASSERT (Private->ParentBlockIo2 != NULL);\r
490b5ea1 1177 Private->BlockIo2.Media = &Private->Media2;\r
1178 CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
1179\r
1180 Private->BlockIo2.Reset = PartitionResetEx;\r
1181 Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;\r
1182 Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;\r
1183 Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx; \r
1184 }\r
67f802ed 1185\r
67f802ed 1186 Private->Media.IoAlign = 0;\r
490b5ea1 1187 Private->Media.LogicalPartition = TRUE;\r
adbcbf8f 1188 Private->Media.LastBlock = DivU64x32 (\r
1189 MultU64x32 (\r
1190 End - Start + 1,\r
d0844d13 1191 ParentBlockIo->Media->BlockSize\r
adbcbf8f 1192 ),\r
490b5ea1 1193 BlockSize\r
adbcbf8f 1194 ) - 1;\r
1195\r
67f802ed 1196 Private->Media.BlockSize = (UINT32) BlockSize;\r
adbcbf8f 1197\r
493d8e3a 1198 Private->Media2.IoAlign = 0;\r
490b5ea1 1199 Private->Media2.LogicalPartition = TRUE;\r
1200 Private->Media2.LastBlock = Private->Media.LastBlock;\r
1201 Private->Media2.BlockSize = (UINT32) BlockSize;\r
1202\r
fe3b68bb 1203 //\r
0e87144e 1204 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0\r
fe3b68bb
RN
1205 // for logical partitions.\r
1206 //\r
1207 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {\r
c582ad45
EB
1208 Private->Media.LowestAlignedLba = 0;\r
1209 Private->Media.LogicalBlocksPerPhysicalBlock = 0;\r
1210 Private->Media2.LowestAlignedLba = 0;\r
1211 Private->Media2.LogicalBlocksPerPhysicalBlock = 0;\r
0e87144e 1212 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {\r
c582ad45
EB
1213 Private->Media.OptimalTransferLengthGranularity = 0;\r
1214 Private->Media2.OptimalTransferLengthGranularity = 0;\r
0e87144e 1215 }\r
fe3b68bb
RN
1216 }\r
1217\r
490b5ea1 1218 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);\r
adbcbf8f 1219\r
1220 if (Private->DevicePath == NULL) {\r
1221 FreePool (Private);\r
1222 return EFI_OUT_OF_RESOURCES;\r
1223 }\r
1224\r
3a3d62d2
HW
1225 //\r
1226 // Set the PartitionInfo into Private Data.\r
1227 //\r
1228 CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));\r
1229\r
709c9fd5
JB
1230 if (TypeGuid != NULL) {\r
1231 CopyGuid(&(Private->TypeGuid), TypeGuid);\r
adbcbf8f 1232 } else {\r
709c9fd5 1233 ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));\r
adbcbf8f 1234 }\r
490b5ea1 1235\r
adbcbf8f 1236 //\r
490b5ea1 1237 // Create the new handle. \r
adbcbf8f 1238 //\r
1239 Private->Handle = NULL;\r
493d8e3a 1240 if (Private->DiskIo2 != NULL) {\r
490b5ea1 1241 Status = gBS->InstallMultipleProtocolInterfaces (\r
1242 &Private->Handle,\r
1243 &gEfiDevicePathProtocolGuid,\r
1244 Private->DevicePath,\r
1245 &gEfiBlockIoProtocolGuid,\r
1246 &Private->BlockIo,\r
1247 &gEfiBlockIo2ProtocolGuid,\r
1248 &Private->BlockIo2,\r
3a3d62d2
HW
1249 &gEfiPartitionInfoProtocolGuid,\r
1250 &Private->PartitionInfo,\r
709c9fd5 1251 TypeGuid,\r
490b5ea1 1252 NULL,\r
1253 NULL\r
1254 );\r
d0844d13 1255 } else { \r
1256 Status = gBS->InstallMultipleProtocolInterfaces (\r
1257 &Private->Handle,\r
1258 &gEfiDevicePathProtocolGuid,\r
1259 Private->DevicePath,\r
1260 &gEfiBlockIoProtocolGuid,\r
1261 &Private->BlockIo,\r
3a3d62d2
HW
1262 &gEfiPartitionInfoProtocolGuid,\r
1263 &Private->PartitionInfo,\r
709c9fd5 1264 TypeGuid,\r
d0844d13 1265 NULL,\r
1266 NULL\r
1267 );\r
490b5ea1 1268 }\r
adbcbf8f 1269\r
1270 if (!EFI_ERROR (Status)) {\r
1271 //\r
1272 // Open the Parent Handle for the child\r
1273 //\r
1274 Status = gBS->OpenProtocol (\r
1275 ParentHandle,\r
1276 &gEfiDiskIoProtocolGuid,\r
1277 (VOID **) &ParentDiskIo,\r
1278 This->DriverBindingHandle,\r
1279 Private->Handle,\r
1280 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1281 );\r
1282 } else {\r
1283 FreePool (Private->DevicePath);\r
1284 FreePool (Private);\r
1285 }\r
1286\r
1287 return Status;\r
1288}\r
1289\r
1290\r
1291/**\r
1292 The user Entry Point for module Partition. The user code starts with this function.\r
1293\r
1294 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
1295 @param[in] SystemTable A pointer to the EFI System Table.\r
1296 \r
1297 @retval EFI_SUCCESS The entry point is executed successfully.\r
1298 @retval other Some error occurs when executing this entry point.\r
1299\r
1300**/\r
1301EFI_STATUS\r
1302EFIAPI\r
1303InitializePartition (\r
1304 IN EFI_HANDLE ImageHandle,\r
1305 IN EFI_SYSTEM_TABLE *SystemTable\r
1306 )\r
1307{\r
1308 EFI_STATUS Status;\r
1309\r
1310 //\r
1311 // Install driver model protocol(s).\r
1312 //\r
d38a0f44 1313 Status = EfiLibInstallDriverBindingComponentName2 (\r
adbcbf8f 1314 ImageHandle,\r
1315 SystemTable,\r
1316 &gPartitionDriverBinding,\r
1317 ImageHandle,\r
1318 &gPartitionComponentName,\r
d38a0f44 1319 &gPartitionComponentName2\r
adbcbf8f 1320 );\r
1321 ASSERT_EFI_ERROR (Status);\r
1322\r
1323\r
1324 return Status;\r
1325}\r
1326\r
e3325721
HW
1327\r
1328/**\r
1329 Test to see if there is any child on ControllerHandle.\r
1330\r
1331 @param[in] ControllerHandle Handle of device to test.\r
1332\r
1333 @retval TRUE There are children on the ControllerHandle.\r
1334 @retval FALSE No child is on the ControllerHandle.\r
1335\r
1336**/\r
1337BOOLEAN\r
1338HasChildren (\r
1339 IN EFI_HANDLE ControllerHandle\r
1340 )\r
1341{\r
1342 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
1343 UINTN EntryCount;\r
1344 EFI_STATUS Status;\r
1345 UINTN Index;\r
1346\r
1347 Status = gBS->OpenProtocolInformation (\r
1348 ControllerHandle,\r
1349 &gEfiDiskIoProtocolGuid,\r
1350 &OpenInfoBuffer,\r
1351 &EntryCount\r
1352 );\r
1353 ASSERT_EFI_ERROR (Status);\r
1354\r
1355 for (Index = 0; Index < EntryCount; Index++) {\r
1356 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
1357 break;\r
1358 }\r
1359 }\r
1360 FreePool (OpenInfoBuffer);\r
1361\r
1362 return (BOOLEAN) (Index < EntryCount);\r
1363}\r
1364\r