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