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