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