]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
MdeModulePkg/PartitionDxe: Put the UDF check ahead of MBR
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Partition.c
... / ...
CommitLineData
1/** @file\r
2 Partition driver that produces logical BlockIo devices from a physical\r
3 BlockIo device. The logical BlockIo devices are based on the format\r
4 of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy\r
5 MBR, and GPT partition schemes are supported.\r
6\r
7Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.\r
8Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9SPDX-License-Identifier: BSD-2-Clause-Patent\r
10\r
11**/\r
12\r
13\r
14#include "Partition.h"\r
15\r
16//\r
17// Partition Driver Global Variables.\r
18//\r
19EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {\r
20 PartitionDriverBindingSupported,\r
21 PartitionDriverBindingStart,\r
22 PartitionDriverBindingStop,\r
23 //\r
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
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
32 NULL,\r
33 NULL\r
34};\r
35\r
36//\r
37// Prioritized function list to detect partition table.\r
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
46//\r
47PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {\r
48 PartitionInstallGptChildHandles,\r
49 PartitionInstallUdfChildHandles,\r
50 PartitionInstallMbrChildHandles,\r
51 NULL\r
52};\r
53\r
54/**\r
55 Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
56 than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be\r
57 supported.\r
58\r
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
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
82 //\r
83 // Check RemainingDevicePath validation\r
84 //\r
85 if (RemainingDevicePath != NULL) {\r
86 //\r
87 // Check if RemainingDevicePath is the End of Device Path Node,\r
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
97 Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||\r
98 DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {\r
99 return EFI_UNSUPPORTED;\r
100 }\r
101 }\r
102 }\r
103\r
104 //\r
105 // Open the IO Abstraction(s) needed to perform the supported test\r
106 //\r
107 Status = gBS->OpenProtocol (\r
108 ControllerHandle,\r
109 &gEfiDiskIoProtocolGuid,\r
110 (VOID **) &DiskIo,\r
111 This->DriverBindingHandle,\r
112 ControllerHandle,\r
113 EFI_OPEN_PROTOCOL_BY_DRIVER\r
114 );\r
115 if (Status == EFI_ALREADY_STARTED) {\r
116 return EFI_SUCCESS;\r
117 }\r
118 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
125 ControllerHandle,\r
126 &gEfiDiskIoProtocolGuid,\r
127 This->DriverBindingHandle,\r
128 ControllerHandle\r
129 );\r
130\r
131 //\r
132 // Open the EFI Device Path protocol needed to perform the supported test\r
133 //\r
134 Status = gBS->OpenProtocol (\r
135 ControllerHandle,\r
136 &gEfiDevicePathProtocolGuid,\r
137 (VOID **) &ParentDevicePath,\r
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
149\r
150 //\r
151 // Close protocol, don't use device path protocol in the Support() function\r
152 //\r
153 gBS->CloseProtocol (\r
154 ControllerHandle,\r
155 &gEfiDevicePathProtocolGuid,\r
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
171\r
172 return Status;\r
173}\r
174\r
175/**\r
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
179\r
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
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
201 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
202 EFI_DISK_IO_PROTOCOL *DiskIo;\r
203 EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
204 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
205 PARTITION_DETECT_ROUTINE *Routine;\r
206 BOOLEAN MediaPresent;\r
207 EFI_TPL OldTpl;\r
208\r
209 BlockIo2 = NULL;\r
210 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
211 //\r
212 // Check RemainingDevicePath validation\r
213 //\r
214 if (RemainingDevicePath != NULL) {\r
215 //\r
216 // Check if RemainingDevicePath is the End of Device Path Node,\r
217 // if yes, return EFI_SUCCESS\r
218 //\r
219 if (IsDevicePathEnd (RemainingDevicePath)) {\r
220 Status = EFI_SUCCESS;\r
221 goto Exit;\r
222 }\r
223 }\r
224\r
225 //\r
226 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,\r
227 // otherwise, return error.\r
228 //\r
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
238 goto Exit;\r
239 }\r
240\r
241 Status = gBS->OpenProtocol (\r
242 ControllerHandle,\r
243 &gEfiBlockIo2ProtocolGuid,\r
244 (VOID **) &BlockIo2,\r
245 This->DriverBindingHandle,\r
246 ControllerHandle,\r
247 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
248 );\r
249 if (EFI_ERROR (Status)) {\r
250 BlockIo2 = NULL;\r
251 }\r
252\r
253 //\r
254 // Get the Device Path Protocol on ControllerHandle's handle.\r
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
265 goto Exit;\r
266 }\r
267\r
268 //\r
269 // Get the DiskIo and DiskIo2.\r
270 //\r
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
286 goto Exit;\r
287 }\r
288\r
289 OpenStatus = Status;\r
290\r
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
303 //\r
304 // Try to read blocks when there's media or it is removable physical partition.\r
305 //\r
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
310 //\r
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
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
321 DiskIo2,\r
322 BlockIo,\r
323 BlockIo2,\r
324 ParentDevicePath\r
325 );\r
326 if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {\r
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
338 // In the case that when the media changes on a device it will Reinstall the\r
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
342 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.\r
343 //\r
344 if (EFI_ERROR (Status) &&\r
345 !EFI_ERROR (OpenStatus) &&\r
346 Status != EFI_MEDIA_CHANGED &&\r
347 !(MediaPresent && Status == EFI_NO_MEDIA)) {\r
348 gBS->CloseProtocol (\r
349 ControllerHandle,\r
350 &gEfiDiskIoProtocolGuid,\r
351 This->DriverBindingHandle,\r
352 ControllerHandle\r
353 );\r
354 //\r
355 // Close Parent DiskIo2 if has.\r
356 //\r
357 gBS->CloseProtocol (\r
358 ControllerHandle,\r
359 &gEfiDiskIo2ProtocolGuid,\r
360 This->DriverBindingHandle,\r
361 ControllerHandle\r
362 );\r
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
372Exit:\r
373 gBS->RestoreTPL (OldTpl);\r
374 return Status;\r
375}\r
376\r
377/**\r
378 Stop this driver on ControllerHandle. Support stopping any child handles\r
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
403 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
404 BOOLEAN AllChildrenStopped;\r
405 PARTITION_PRIVATE_DATA *Private;\r
406 EFI_DISK_IO_PROTOCOL *DiskIo;\r
407 EFI_GUID *TypeGuid;\r
408\r
409 BlockIo = NULL;\r
410 BlockIo2 = NULL;\r
411 Private = NULL;\r
412\r
413 if (NumberOfChildren == 0) {\r
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
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
433 //\r
434 // Close Parent BlockIO2 if has.\r
435 //\r
436 gBS->CloseProtocol (\r
437 ControllerHandle,\r
438 &gEfiDiskIo2ProtocolGuid,\r
439 This->DriverBindingHandle,\r
440 ControllerHandle\r
441 );\r
442\r
443 gBS->CloseProtocol (\r
444 ControllerHandle,\r
445 &gEfiDevicePathProtocolGuid,\r
446 This->DriverBindingHandle,\r
447 ControllerHandle\r
448 );\r
449 return EFI_SUCCESS;\r
450 }\r
451\r
452 AllChildrenStopped = TRUE;\r
453 for (Index = 0; Index < NumberOfChildren; Index++) {\r
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
472 );\r
473\r
474\r
475 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);\r
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
484\r
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
500\r
501 if (IsZeroGuid (&Private->TypeGuid)) {\r
502 TypeGuid = NULL;\r
503 } else {\r
504 TypeGuid = &Private->TypeGuid;\r
505 }\r
506\r
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
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
528 &gEfiPartitionInfoProtocolGuid,\r
529 &Private->PartitionInfo,\r
530 TypeGuid,\r
531 NULL,\r
532 NULL\r
533 );\r
534 }\r
535 } else {\r
536 Status = gBS->UninstallMultipleProtocolInterfaces (\r
537 ChildHandleBuffer[Index],\r
538 &gEfiDevicePathProtocolGuid,\r
539 Private->DevicePath,\r
540 &gEfiBlockIoProtocolGuid,\r
541 &Private->BlockIo,\r
542 &gEfiPartitionInfoProtocolGuid,\r
543 &Private->PartitionInfo,\r
544 TypeGuid,\r
545 NULL,\r
546 NULL\r
547 );\r
548 }\r
549\r
550 if (EFI_ERROR (Status)) {\r
551 Private->InStop = FALSE;\r
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
563 }\r
564\r
565 if (EFI_ERROR (Status)) {\r
566 AllChildrenStopped = FALSE;\r
567 if (Status == EFI_MEDIA_CHANGED) {\r
568 break;\r
569 }\r
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
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
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
630 UINT8 Buffer[1];\r
631\r
632 //\r
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
637 //\r
638 Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer);\r
639 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
640 return Status;\r
641 }\r
642 return DefaultStatus;\r
643}\r
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
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
680 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
681 }\r
682\r
683 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
684 if (Offset + BufferSize > Private->End) {\r
685 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
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
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
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
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
722 IN VOID *Buffer\r
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
731 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
732 }\r
733\r
734 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
735 if (Offset + BufferSize > Private->End) {\r
736 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
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
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
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
774 @param DiskIo2 Pointer to the DiskIo2 instance.\r
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
785 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
786 IN UINT32 MediaId,\r
787 IN EFI_STATUS DefaultStatus\r
788 )\r
789{\r
790 EFI_STATUS Status;\r
791 UINT8 Buffer[1];\r
792\r
793 //\r
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
798 //\r
799 Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID*)Buffer);\r
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
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
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
881 TPL_NOTIFY,\r
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
896/**\r
897 Read BufferSize bytes from Lba into Buffer.\r
898\r
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
906 @param[in] MediaId Id of the media, changes every time the media is\r
907 replaced.\r
908 @param[in] Lba The starting Logical Block Address to read from.\r
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
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
924 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
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
940 EFI_STATUS Status;\r
941 PARTITION_PRIVATE_DATA *Private;\r
942 UINT64 Offset;\r
943 PARTITION_ACCESS_TASK *Task;\r
944\r
945 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
946\r
947 if (BufferSize % Private->BlockSize != 0) {\r
948 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
949 }\r
950\r
951 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
952 if (Offset + BufferSize > Private->End) {\r
953 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
954 }\r
955\r
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
961\r
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
969 }\r
970\r
971 return Status;\r
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
999 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
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
1016 EFI_STATUS Status;\r
1017 PARTITION_PRIVATE_DATA *Private;\r
1018 UINT64 Offset;\r
1019 PARTITION_ACCESS_TASK *Task;\r
1020\r
1021 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
1022\r
1023 if (BufferSize % Private->BlockSize != 0) {\r
1024 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
1025 }\r
1026\r
1027 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
1028 if (Offset + BufferSize > Private->End) {\r
1029 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
1030 }\r
1031\r
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
1037\r
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
1045 }\r
1046 return Status;\r
1047}\r
1048\r
1049/**\r
1050 Flush the Block Device.\r
1051\r
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
1054 this request will not be signaled.\r
1055\r
1056 @param[in] This Indicates a pointer to the calling context.\r
1057 @param[in, out] Token A pointer to the token associated with the transaction\r
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
1078 EFI_STATUS Status;\r
1079 PARTITION_PRIVATE_DATA *Private;\r
1080 PARTITION_ACCESS_TASK *Task;\r
1081\r
1082 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
1083\r
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
1089\r
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
1099}\r
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
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
1109 @param[in] ParentDiskIo2 Parent DiskIo2 interface.\r
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
1114 @param[in] PartitionInfo Child Partition Information interface.\r
1115 @param[in] Start Start Block.\r
1116 @param[in] End End Block.\r
1117 @param[in] BlockSize Child block size.\r
1118 @param[in] TypeGuid Partition GUID Type.\r
1119\r
1120 @retval EFI_SUCCESS A child handle was added.\r
1121 @retval other A child handle was not added.\r
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
1129 IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,\r
1130 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,\r
1131 IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,\r
1132 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1133 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,\r
1134 IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,\r
1135 IN EFI_LBA Start,\r
1136 IN EFI_LBA End,\r
1137 IN UINT32 BlockSize,\r
1138 IN EFI_GUID *TypeGuid\r
1139 )\r
1140{\r
1141 EFI_STATUS Status;\r
1142 PARTITION_PRIVATE_DATA *Private;\r
1143\r
1144 Status = EFI_SUCCESS;\r
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
1152 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);\r
1153 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);\r
1154\r
1155 Private->BlockSize = BlockSize;\r
1156 Private->ParentBlockIo = ParentBlockIo;\r
1157 Private->ParentBlockIo2 = ParentBlockIo2;\r
1158 Private->DiskIo = ParentDiskIo;\r
1159 Private->DiskIo2 = ParentDiskIo2;\r
1160\r
1161 //\r
1162 // Set the BlockIO into Private Data.\r
1163 //\r
1164 Private->BlockIo.Revision = ParentBlockIo->Revision;\r
1165\r
1166 Private->BlockIo.Media = &Private->Media;\r
1167 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
1168\r
1169 Private->BlockIo.Reset = PartitionReset;\r
1170 Private->BlockIo.ReadBlocks = PartitionReadBlocks;\r
1171 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;\r
1172 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;\r
1173\r
1174 //\r
1175 // Set the BlockIO2 into Private Data.\r
1176 //\r
1177 if (Private->DiskIo2 != NULL) {\r
1178 ASSERT (Private->ParentBlockIo2 != NULL);\r
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
1185 Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;\r
1186 }\r
1187\r
1188 Private->Media.IoAlign = 0;\r
1189 Private->Media.LogicalPartition = TRUE;\r
1190 Private->Media.LastBlock = DivU64x32 (\r
1191 MultU64x32 (\r
1192 End - Start + 1,\r
1193 ParentBlockIo->Media->BlockSize\r
1194 ),\r
1195 BlockSize\r
1196 ) - 1;\r
1197\r
1198 Private->Media.BlockSize = (UINT32) BlockSize;\r
1199\r
1200 Private->Media2.IoAlign = 0;\r
1201 Private->Media2.LogicalPartition = TRUE;\r
1202 Private->Media2.LastBlock = Private->Media.LastBlock;\r
1203 Private->Media2.BlockSize = (UINT32) BlockSize;\r
1204\r
1205 //\r
1206 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0\r
1207 // for logical partitions.\r
1208 //\r
1209 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {\r
1210 Private->Media.LowestAlignedLba = 0;\r
1211 Private->Media.LogicalBlocksPerPhysicalBlock = 0;\r
1212 Private->Media2.LowestAlignedLba = 0;\r
1213 Private->Media2.LogicalBlocksPerPhysicalBlock = 0;\r
1214 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {\r
1215 Private->Media.OptimalTransferLengthGranularity = 0;\r
1216 Private->Media2.OptimalTransferLengthGranularity = 0;\r
1217 }\r
1218 }\r
1219\r
1220 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);\r
1221\r
1222 if (Private->DevicePath == NULL) {\r
1223 FreePool (Private);\r
1224 return EFI_OUT_OF_RESOURCES;\r
1225 }\r
1226\r
1227 //\r
1228 // Set the PartitionInfo into Private Data.\r
1229 //\r
1230 CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));\r
1231\r
1232 if (TypeGuid != NULL) {\r
1233 CopyGuid(&(Private->TypeGuid), TypeGuid);\r
1234 } else {\r
1235 ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));\r
1236 }\r
1237\r
1238 //\r
1239 // Create the new handle.\r
1240 //\r
1241 Private->Handle = NULL;\r
1242 if (Private->DiskIo2 != NULL) {\r
1243 Status = gBS->InstallMultipleProtocolInterfaces (\r
1244 &Private->Handle,\r
1245 &gEfiDevicePathProtocolGuid,\r
1246 Private->DevicePath,\r
1247 &gEfiBlockIoProtocolGuid,\r
1248 &Private->BlockIo,\r
1249 &gEfiBlockIo2ProtocolGuid,\r
1250 &Private->BlockIo2,\r
1251 &gEfiPartitionInfoProtocolGuid,\r
1252 &Private->PartitionInfo,\r
1253 TypeGuid,\r
1254 NULL,\r
1255 NULL\r
1256 );\r
1257 } else {\r
1258 Status = gBS->InstallMultipleProtocolInterfaces (\r
1259 &Private->Handle,\r
1260 &gEfiDevicePathProtocolGuid,\r
1261 Private->DevicePath,\r
1262 &gEfiBlockIoProtocolGuid,\r
1263 &Private->BlockIo,\r
1264 &gEfiPartitionInfoProtocolGuid,\r
1265 &Private->PartitionInfo,\r
1266 TypeGuid,\r
1267 NULL,\r
1268 NULL\r
1269 );\r
1270 }\r
1271\r
1272 if (!EFI_ERROR (Status)) {\r
1273 //\r
1274 // Open the Parent Handle for the child\r
1275 //\r
1276 Status = gBS->OpenProtocol (\r
1277 ParentHandle,\r
1278 &gEfiDiskIoProtocolGuid,\r
1279 (VOID **) &ParentDiskIo,\r
1280 This->DriverBindingHandle,\r
1281 Private->Handle,\r
1282 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1283 );\r
1284 } else {\r
1285 FreePool (Private->DevicePath);\r
1286 FreePool (Private);\r
1287\r
1288 //\r
1289 // if the Status == EFI_ALREADY_STARTED, it means the child handles\r
1290 // are already installed. So return EFI_SUCCESS to avoid do the next\r
1291 // partition type check.\r
1292 //\r
1293 if (Status == EFI_ALREADY_STARTED) {\r
1294 Status = EFI_SUCCESS;\r
1295 }\r
1296 }\r
1297\r
1298 return Status;\r
1299}\r
1300\r
1301\r
1302/**\r
1303 The user Entry Point for module Partition. The user code starts with this function.\r
1304\r
1305 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1306 @param[in] SystemTable A pointer to the EFI System Table.\r
1307\r
1308 @retval EFI_SUCCESS The entry point is executed successfully.\r
1309 @retval other Some error occurs when executing this entry point.\r
1310\r
1311**/\r
1312EFI_STATUS\r
1313EFIAPI\r
1314InitializePartition (\r
1315 IN EFI_HANDLE ImageHandle,\r
1316 IN EFI_SYSTEM_TABLE *SystemTable\r
1317 )\r
1318{\r
1319 EFI_STATUS Status;\r
1320\r
1321 //\r
1322 // Install driver model protocol(s).\r
1323 //\r
1324 Status = EfiLibInstallDriverBindingComponentName2 (\r
1325 ImageHandle,\r
1326 SystemTable,\r
1327 &gPartitionDriverBinding,\r
1328 ImageHandle,\r
1329 &gPartitionComponentName,\r
1330 &gPartitionComponentName2\r
1331 );\r
1332 ASSERT_EFI_ERROR (Status);\r
1333\r
1334\r
1335 return Status;\r
1336}\r
1337\r
1338\r
1339/**\r
1340 Test to see if there is any child on ControllerHandle.\r
1341\r
1342 @param[in] ControllerHandle Handle of device to test.\r
1343\r
1344 @retval TRUE There are children on the ControllerHandle.\r
1345 @retval FALSE No child is on the ControllerHandle.\r
1346\r
1347**/\r
1348BOOLEAN\r
1349HasChildren (\r
1350 IN EFI_HANDLE ControllerHandle\r
1351 )\r
1352{\r
1353 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
1354 UINTN EntryCount;\r
1355 EFI_STATUS Status;\r
1356 UINTN Index;\r
1357\r
1358 Status = gBS->OpenProtocolInformation (\r
1359 ControllerHandle,\r
1360 &gEfiDiskIoProtocolGuid,\r
1361 &OpenInfoBuffer,\r
1362 &EntryCount\r
1363 );\r
1364 ASSERT_EFI_ERROR (Status);\r
1365\r
1366 for (Index = 0; Index < EntryCount; Index++) {\r
1367 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
1368 break;\r
1369 }\r
1370 }\r
1371 FreePool (OpenInfoBuffer);\r
1372\r
1373 return (BOOLEAN) (Index < EntryCount);\r
1374}\r
1375\r