]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
MdeModulePkg/UfsPassThruDxe: Use BaseLib linked list iteration macros
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / RamDiskDxe / RamDiskProtocol.c
CommitLineData
20752cb8
HW
1/** @file\r
2 The realization of EFI_RAM_DISK_PROTOCOL.\r
3\r
38c9fbdc 4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
5eae4ff0 5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
9d510e61 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
20752cb8
HW
7\r
8**/\r
9\r
10#include "RamDiskImpl.h"\r
11\r
12RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = {\r
13 RAM_DISK_PRIVATE_DATA_SIGNATURE,\r
14 NULL\r
15};\r
16\r
17MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = {\r
18 {\r
19 MEDIA_DEVICE_PATH,\r
20 MEDIA_RAM_DISK_DP,\r
21 {\r
22 (UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)),\r
23 (UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8)\r
24 }\r
25 }\r
26};\r
27\r
07a3fecd
HW
28BOOLEAN mRamDiskSsdtTableKeyValid = FALSE;\r
29UINTN mRamDiskSsdtTableKey;\r
30\r
20752cb8
HW
31\r
32/**\r
33 Initialize the RAM disk device node.\r
34\r
35 @param[in] PrivateData Points to RAM disk private data.\r
36 @param[in, out] RamDiskDevNode Points to the RAM disk device node.\r
37\r
38**/\r
39VOID\r
40RamDiskInitDeviceNode (\r
41 IN RAM_DISK_PRIVATE_DATA *PrivateData,\r
42 IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode\r
43 )\r
44{\r
45 WriteUnaligned64 (\r
46 (UINT64 *) &(RamDiskDevNode->StartingAddr[0]),\r
47 (UINT64) PrivateData->StartingAddr\r
48 );\r
49 WriteUnaligned64 (\r
50 (UINT64 *) &(RamDiskDevNode->EndingAddr[0]),\r
5eae4ff0 51 (UINT64) PrivateData->StartingAddr + PrivateData->Size - 1\r
20752cb8
HW
52 );\r
53 CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid);\r
54 RamDiskDevNode->Instance = PrivateData->InstanceNumber;\r
55}\r
56\r
57\r
07a3fecd
HW
58/**\r
59 Initialize and publish NVDIMM root device SSDT in ACPI table.\r
60\r
61 @retval EFI_SUCCESS The NVDIMM root device SSDT is published.\r
62 @retval Others The NVDIMM root device SSDT is not published.\r
63\r
64**/\r
65EFI_STATUS\r
66RamDiskPublishSsdt (\r
67 VOID\r
68 )\r
69{\r
70 EFI_STATUS Status;\r
71 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
6558fd73 72 UINTN SectionInstance;\r
07a3fecd
HW
73 UINTN TableSize;\r
74\r
6558fd73
HW
75 Status = EFI_SUCCESS;\r
76 SectionInstance = 0;\r
77\r
78 //\r
79 // Scan all the EFI raw section instances in FV to find the NVDIMM root\r
80 // device SSDT.\r
81 //\r
82 while (TRUE) {\r
83 Status = GetSectionFromFv (\r
84 &gEfiCallerIdGuid,\r
85 EFI_SECTION_RAW,\r
86 SectionInstance,\r
87 (VOID **) &Table,\r
88 &TableSize\r
89 );\r
90 if (EFI_ERROR (Status)) {\r
91 break;\r
92 }\r
07a3fecd 93\r
6558fd73
HW
94 if (Table->OemTableId == SIGNATURE_64 ('R', 'a', 'm', 'D', 'i', 's', 'k', ' ')) {\r
95 Status = mAcpiTableProtocol->InstallAcpiTable (\r
96 mAcpiTableProtocol,\r
97 Table,\r
98 TableSize,\r
99 &mRamDiskSsdtTableKey\r
100 );\r
101 ASSERT_EFI_ERROR (Status);\r
102\r
103 if (!EFI_ERROR (Status)) {\r
104 mRamDiskSsdtTableKeyValid = TRUE;\r
105 }\r
106\r
107 FreePool (Table);\r
108 return Status;\r
109 } else {\r
110 FreePool (Table);\r
111 SectionInstance++;\r
112 }\r
113 }\r
07a3fecd
HW
114\r
115 return Status;\r
116}\r
117\r
118\r
119/**\r
120 Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI\r
121 table.\r
122\r
123 @param[in] PrivateData Points to RAM disk private data.\r
124\r
125 @retval EFI_SUCCESS The RAM disk NFIT has been published.\r
126 @retval others The RAM disk NFIT has not been published.\r
127\r
128**/\r
129EFI_STATUS\r
130RamDiskPublishNfit (\r
131 IN RAM_DISK_PRIVATE_DATA *PrivateData\r
132 )\r
133{\r
134 EFI_STATUS Status;\r
135 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
136 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
137 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
138 UINTN TableIndex;\r
139 VOID *TableHeader;\r
140 EFI_ACPI_TABLE_VERSION TableVersion;\r
141 UINTN TableKey;\r
142 EFI_ACPI_DESCRIPTION_HEADER *NfitHeader;\r
143 EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE\r
144 *SpaRange;\r
145 VOID *Nfit;\r
146 UINT32 NfitLen;\r
147 UINTN MemoryMapSize;\r
148 UINTN MapKey;\r
149 UINTN DescriptorSize;\r
150 UINT32 DescriptorVersion;\r
151 UINT64 CurrentData;\r
152 UINT8 Checksum;\r
153 BOOLEAN MemoryFound;\r
154\r
155 //\r
156 // Get the EFI memory map.\r
157 //\r
158 MemoryMapSize = 0;\r
159 MemoryMap = NULL;\r
160 MemoryFound = FALSE;\r
161\r
162 Status = gBS->GetMemoryMap (\r
163 &MemoryMapSize,\r
164 MemoryMap,\r
165 &MapKey,\r
166 &DescriptorSize,\r
167 &DescriptorVersion\r
168 );\r
169 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
170 do {\r
171 MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);\r
172 ASSERT (MemoryMap != NULL);\r
173 Status = gBS->GetMemoryMap (\r
174 &MemoryMapSize,\r
175 MemoryMap,\r
176 &MapKey,\r
177 &DescriptorSize,\r
178 &DescriptorVersion\r
179 );\r
180 if (EFI_ERROR (Status)) {\r
181 FreePool (MemoryMap);\r
182 }\r
183 } while (Status == EFI_BUFFER_TOO_SMALL);\r
184 ASSERT_EFI_ERROR (Status);\r
185\r
186 MemoryMapEntry = MemoryMap;\r
187 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
188 while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {\r
189 if ((MemoryMapEntry->Type == EfiReservedMemoryType) &&\r
190 (MemoryMapEntry->PhysicalStart <= PrivateData->StartingAddr) &&\r
191 (MemoryMapEntry->PhysicalStart +\r
192 MultU64x32 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SIZE)\r
193 >= PrivateData->StartingAddr + PrivateData->Size)) {\r
194 MemoryFound = TRUE;\r
195 DEBUG ((\r
196 EFI_D_INFO,\r
197 "RamDiskPublishNfit: RAM disk with reserved meomry type, will publish to NFIT.\n"\r
198 ));\r
199 break;\r
200 }\r
201 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
202 }\r
203 FreePool (MemoryMap);\r
204\r
205 if (!MemoryFound) {\r
206 return EFI_NOT_FOUND;\r
207 }\r
208\r
209 //\r
210 // Determine whether there is a NFIT already in the ACPI table.\r
211 //\r
3ab7066e
HW
212 Status = EFI_SUCCESS;\r
213 TableIndex = 0;\r
214 TableKey = 0;\r
215 TableHeader = NULL;\r
07a3fecd
HW
216\r
217 while (!EFI_ERROR (Status)) {\r
218 Status = mAcpiSdtProtocol->GetAcpiTable (\r
219 TableIndex,\r
220 (EFI_ACPI_SDT_HEADER **)&TableHeader,\r
221 &TableVersion,\r
222 &TableKey\r
223 );\r
224 if (!EFI_ERROR (Status)) {\r
225 TableIndex++;\r
226\r
227 if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==\r
228 EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {\r
229 break;\r
230 }\r
231 }\r
232 }\r
233\r
234 if (!EFI_ERROR (Status)) {\r
235 //\r
236 // A NFIT is already in the ACPI table.\r
237 //\r
238 DEBUG ((\r
239 EFI_D_INFO,\r
240 "RamDiskPublishNfit: A NFIT is already exist in the ACPI Table.\n"\r
241 ));\r
242\r
243 NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)TableHeader;\r
244 NfitLen = NfitHeader->Length + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);\r
245 Nfit = AllocateZeroPool (NfitLen);\r
246 if (Nfit == NULL) {\r
247 return EFI_OUT_OF_RESOURCES;\r
248 }\r
249 CopyMem (Nfit, TableHeader, NfitHeader->Length);\r
250\r
251 //\r
252 // Update the NFIT head pointer.\r
253 //\r
254 NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;\r
255\r
256 //\r
257 // Uninstall the origin NFIT from the ACPI table.\r
258 //\r
259 Status = mAcpiTableProtocol->UninstallAcpiTable (\r
260 mAcpiTableProtocol,\r
261 TableKey\r
262 );\r
263 ASSERT_EFI_ERROR (Status);\r
264\r
265 if (EFI_ERROR (Status)) {\r
266 FreePool (Nfit);\r
267 return Status;\r
268 }\r
269\r
270 //\r
271 // Append the System Physical Address (SPA) Range Structure at the end\r
272 // of the origin NFIT.\r
273 //\r
274 SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)\r
275 ((UINT8 *)Nfit + NfitHeader->Length);\r
276\r
277 //\r
278 // Update the length field of the NFIT\r
279 //\r
280 NfitHeader->Length = NfitLen;\r
281\r
282 //\r
283 // The checksum will be updated after the new contents are appended.\r
284 //\r
285 NfitHeader->Checksum = 0;\r
286 } else {\r
287 //\r
288 // Assumption is made that if no NFIT is in the ACPI table, there is no\r
289 // NVDIMM root device in the \SB scope.\r
290 // Therefore, a NVDIMM root device will be reported via Secondary System\r
291 // Description Table (SSDT).\r
292 //\r
293 Status = RamDiskPublishSsdt ();\r
294 if (EFI_ERROR (Status)) {\r
295 return Status;\r
296 }\r
297\r
298 //\r
299 // No NFIT is in the ACPI table, we will create one here.\r
300 //\r
301 DEBUG ((\r
302 EFI_D_INFO,\r
303 "RamDiskPublishNfit: No NFIT is in the ACPI Table, will create one.\n"\r
304 ));\r
305\r
306 NfitLen = sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE) +\r
307 sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);\r
308 Nfit = AllocateZeroPool (NfitLen);\r
309 if (Nfit == NULL) {\r
310 return EFI_OUT_OF_RESOURCES;\r
311 }\r
312\r
313 SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)\r
314 ((UINT8 *)Nfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));\r
315\r
316 NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;\r
317 NfitHeader->Signature = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE;\r
318 NfitHeader->Length = NfitLen;\r
319 NfitHeader->Revision = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION;\r
320 NfitHeader->Checksum = 0;\r
321 NfitHeader->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
322 NfitHeader->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
323 NfitHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
324 CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);\r
325 CopyMem (NfitHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NfitHeader->OemId));\r
326 CopyMem (&NfitHeader->OemTableId, &CurrentData, sizeof (UINT64));\r
327 }\r
328\r
329 //\r
330 // Fill in the content of the SPA Range Structure.\r
331 //\r
332 SpaRange->Type = EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE;\r
333 SpaRange->Length = sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);\r
334 SpaRange->SystemPhysicalAddressRangeBase = PrivateData->StartingAddr;\r
335 SpaRange->SystemPhysicalAddressRangeLength = PrivateData->Size;\r
336 CopyGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid);\r
337\r
338 Checksum = CalculateCheckSum8((UINT8 *)Nfit, NfitHeader->Length);\r
339 NfitHeader->Checksum = Checksum;\r
340\r
341 //\r
342 // Publish the NFIT to the ACPI table.\r
343 // Note, since the NFIT might be modified by other driver, therefore, we\r
344 // do not track the returning TableKey from the InstallAcpiTable().\r
345 //\r
346 Status = mAcpiTableProtocol->InstallAcpiTable (\r
347 mAcpiTableProtocol,\r
348 Nfit,\r
349 NfitHeader->Length,\r
350 &TableKey\r
351 );\r
352 ASSERT_EFI_ERROR (Status);\r
353\r
354 FreePool (Nfit);\r
355\r
356 if (EFI_ERROR (Status)) {\r
357 return Status;\r
358 }\r
359\r
360 PrivateData->InNfit = TRUE;\r
361\r
362 return EFI_SUCCESS;\r
363}\r
364\r
365\r
366/**\r
367 Unpublish the RAM disk NVDIMM Firmware Interface Table (NFIT) from the\r
368 ACPI table.\r
369\r
370 @param[in] PrivateData Points to RAM disk private data.\r
371\r
372 @retval EFI_SUCCESS The RAM disk NFIT has been unpublished.\r
373 @retval others The RAM disk NFIT has not been unpublished.\r
374\r
375**/\r
376EFI_STATUS\r
377RamDiskUnpublishNfit (\r
378 IN RAM_DISK_PRIVATE_DATA *PrivateData\r
379 )\r
380{\r
381 EFI_STATUS Status;\r
382 UINTN TableIndex;\r
383 VOID *TableHeader;\r
384 EFI_ACPI_TABLE_VERSION TableVersion;\r
385 UINTN TableKey;\r
386 EFI_ACPI_DESCRIPTION_HEADER *NewNfitHeader;\r
387 EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE\r
388 *SpaRange;\r
389 VOID *NewNfit;\r
390 VOID *NewNfitPtr;\r
391 EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *NfitStructHeader;\r
392 UINT32 NewNfitLen;\r
393 UINT32 RemainLen;\r
394 UINT8 Checksum;\r
395\r
396 //\r
397 // Find the NFIT in the ACPI table.\r
398 //\r
3ab7066e
HW
399 Status = EFI_SUCCESS;\r
400 TableIndex = 0;\r
401 TableKey = 0;\r
402 TableHeader = NULL;\r
07a3fecd
HW
403\r
404 while (!EFI_ERROR (Status)) {\r
405 Status = mAcpiSdtProtocol->GetAcpiTable (\r
406 TableIndex,\r
407 (EFI_ACPI_SDT_HEADER **)&TableHeader,\r
408 &TableVersion,\r
409 &TableKey\r
410 );\r
411 if (!EFI_ERROR (Status)) {\r
412 TableIndex++;\r
413\r
414 if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==\r
415 EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {\r
416 break;\r
417 }\r
418 }\r
419 }\r
420\r
421 if (EFI_ERROR (Status)) {\r
422 //\r
423 // No NFIT is found in the ACPI table.\r
424 //\r
425 return EFI_NOT_FOUND;\r
426 }\r
427\r
428 NewNfitLen = ((EFI_ACPI_DESCRIPTION_HEADER *)TableHeader)->Length -\r
429 sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);\r
430\r
431 //\r
432 // After removing this RAM disk from the NFIT, if no other structure is in\r
433 // the NFIT, we just remove the NFIT and the SSDT which is used to report\r
434 // the NVDIMM root device.\r
435 //\r
436 if (NewNfitLen == sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)) {\r
437 //\r
438 // Remove the NFIT.\r
439 //\r
440 Status = mAcpiTableProtocol->UninstallAcpiTable (\r
441 mAcpiTableProtocol,\r
442 TableKey\r
443 );\r
444 ASSERT_EFI_ERROR (Status);\r
445 if (EFI_ERROR (Status)) {\r
446 return Status;\r
447 }\r
448\r
449 //\r
450 // Remove the SSDT which is used by RamDiskDxe driver to report the NVDIMM\r
451 // root device.\r
452 // We do not care the return status since this SSDT might already be\r
453 // uninstalled by other drivers to update the information of the NVDIMM\r
454 // root device.\r
455 //\r
456 if (mRamDiskSsdtTableKeyValid) {\r
457 mRamDiskSsdtTableKeyValid = FALSE;\r
458\r
459 mAcpiTableProtocol->UninstallAcpiTable (\r
460 mAcpiTableProtocol,\r
461 mRamDiskSsdtTableKey\r
462 );\r
463 }\r
464\r
465 return EFI_SUCCESS;\r
466 }\r
467\r
468 NewNfit = AllocateZeroPool (NewNfitLen);\r
469 if (NewNfit == NULL) {\r
470 return EFI_OUT_OF_RESOURCES;\r
471 }\r
472\r
473 //\r
474 // Get a copy of the old NFIT header content.\r
475 //\r
476 CopyMem (NewNfit, TableHeader, sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));\r
477 NewNfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)NewNfit;\r
478 NewNfitHeader->Length = NewNfitLen;\r
479 NewNfitHeader->Checksum = 0;\r
480\r
481 //\r
482 // Copy the content of required NFIT structures.\r
483 //\r
484 NewNfitPtr = (UINT8 *)NewNfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);\r
485 RemainLen = NewNfitLen - sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);\r
486 NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)\r
487 ((UINT8 *)TableHeader + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));\r
488 while (RemainLen > 0) {\r
489 if ((NfitStructHeader->Type == EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE) &&\r
490 (NfitStructHeader->Length == sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE))) {\r
491 SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)NfitStructHeader;\r
492\r
493 if ((SpaRange->SystemPhysicalAddressRangeBase == PrivateData->StartingAddr) &&\r
494 (SpaRange->SystemPhysicalAddressRangeLength == PrivateData->Size) &&\r
495 (CompareGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid))) {\r
496 //\r
497 // Skip the SPA Range Structure for the RAM disk to be unpublished\r
498 // from NFIT.\r
499 //\r
500 NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)\r
501 ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);\r
502 continue;\r
503 }\r
504 }\r
505\r
506 //\r
507 // Copy the content of origin NFIT.\r
508 //\r
509 CopyMem (NewNfitPtr, NfitStructHeader, NfitStructHeader->Length);\r
510 NewNfitPtr = (UINT8 *)NewNfitPtr + NfitStructHeader->Length;\r
511\r
512 //\r
513 // Move to the header of next NFIT structure.\r
514 //\r
515 RemainLen -= NfitStructHeader->Length;\r
516 NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)\r
517 ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);\r
518 }\r
519\r
520 Checksum = CalculateCheckSum8((UINT8 *)NewNfit, NewNfitHeader->Length);\r
521 NewNfitHeader->Checksum = Checksum;\r
522\r
523 Status = mAcpiTableProtocol->UninstallAcpiTable (\r
524 mAcpiTableProtocol,\r
525 TableKey\r
526 );\r
527 ASSERT_EFI_ERROR (Status);\r
528\r
529 if (EFI_ERROR (Status)) {\r
530 FreePool (NewNfit);\r
531 return Status;\r
532 }\r
533\r
534 //\r
535 // Publish the NFIT to the ACPI table.\r
536 // Note, since the NFIT might be modified by other driver, therefore, we\r
537 // do not track the returning TableKey from the InstallAcpiTable().\r
538 //\r
539 Status = mAcpiTableProtocol->InstallAcpiTable (\r
540 mAcpiTableProtocol,\r
541 NewNfit,\r
542 NewNfitLen,\r
543 &TableKey\r
544 );\r
545 ASSERT_EFI_ERROR (Status);\r
546\r
547 FreePool (NewNfit);\r
548 if (EFI_ERROR (Status)) {\r
549 return Status;\r
550 }\r
551\r
552 return EFI_SUCCESS;\r
553}\r
554\r
555\r
20752cb8
HW
556/**\r
557 Register a RAM disk with specified address, size and type.\r
558\r
559 @param[in] RamDiskBase The base address of registered RAM disk.\r
560 @param[in] RamDiskSize The size of registered RAM disk.\r
561 @param[in] RamDiskType The type of registered RAM disk. The GUID can be\r
562 any of the values defined in section 9.3.6.9, or a\r
563 vendor defined GUID.\r
564 @param[in] ParentDevicePath\r
565 Pointer to the parent device path. If there is no\r
566 parent device path then ParentDevicePath is NULL.\r
567 @param[out] DevicePath On return, points to a pointer to the device path\r
568 of the RAM disk device.\r
569 If ParentDevicePath is not NULL, the returned\r
570 DevicePath is created by appending a RAM disk node\r
571 to the parent device path. If ParentDevicePath is\r
572 NULL, the returned DevicePath is a RAM disk device\r
573 path without appending. This function is\r
574 responsible for allocating the buffer DevicePath\r
575 with the boot service AllocatePool().\r
576\r
577 @retval EFI_SUCCESS The RAM disk is registered successfully.\r
578 @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.\r
579 RamDiskSize is 0.\r
580 @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created\r
581 is already present in the handle database.\r
582 @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to\r
583 resource limitation.\r
584\r
585**/\r
586EFI_STATUS\r
587EFIAPI\r
588RamDiskRegister (\r
589 IN UINT64 RamDiskBase,\r
590 IN UINT64 RamDiskSize,\r
591 IN EFI_GUID *RamDiskType,\r
592 IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,\r
593 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
594 )\r
595{\r
596 EFI_STATUS Status;\r
597 RAM_DISK_PRIVATE_DATA *PrivateData;\r
598 RAM_DISK_PRIVATE_DATA *RegisteredPrivateData;\r
599 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;\r
600 UINTN DevicePathSize;\r
601 LIST_ENTRY *Entry;\r
20752cb8
HW
602\r
603 if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) {\r
604 return EFI_INVALID_PARAMETER;\r
605 }\r
606\r
607 //\r
608 // Add check to prevent data read across the memory boundary\r
609 //\r
38c9fbdc
HW
610 if ((RamDiskSize > MAX_UINTN) ||\r
611 (RamDiskBase > MAX_UINTN - RamDiskSize + 1)) {\r
20752cb8
HW
612 return EFI_INVALID_PARAMETER;\r
613 }\r
614\r
615 RamDiskDevNode = NULL;\r
616\r
617 //\r
618 // Create a new RAM disk instance and initialize its private data\r
619 //\r
620 PrivateData = AllocateCopyPool (\r
621 sizeof (RAM_DISK_PRIVATE_DATA),\r
622 &mRamDiskPrivateDataTemplate\r
623 );\r
624 if (NULL == PrivateData) {\r
625 return EFI_OUT_OF_RESOURCES;\r
626 }\r
627\r
628 PrivateData->StartingAddr = RamDiskBase;\r
629 PrivateData->Size = RamDiskSize;\r
630 CopyGuid (&PrivateData->TypeGuid, RamDiskType);\r
631 InitializeListHead (&PrivateData->ThisInstance);\r
632\r
633 //\r
634 // Generate device path information for the registered RAM disk\r
635 //\r
636 RamDiskDevNode = AllocateCopyPool (\r
637 sizeof (MEDIA_RAM_DISK_DEVICE_PATH),\r
638 &mRamDiskDeviceNodeTemplate\r
639 );\r
640 if (NULL == RamDiskDevNode) {\r
641 Status = EFI_OUT_OF_RESOURCES;\r
642 goto ErrorExit;\r
643 }\r
644\r
645 RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);\r
646\r
647 *DevicePath = AppendDevicePathNode (\r
648 ParentDevicePath,\r
649 (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode\r
650 );\r
651 if (NULL == *DevicePath) {\r
652 Status = EFI_OUT_OF_RESOURCES;\r
653 goto ErrorExit;\r
654 }\r
655\r
656 PrivateData->DevicePath = *DevicePath;\r
657\r
658 //\r
659 // Check whether the created device path is already present in the handle\r
660 // database\r
661 //\r
20752cb8
HW
662 if (!IsListEmpty(&RegisteredRamDisks)) {\r
663 DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);\r
664\r
665 EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {\r
666 RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);\r
667 if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {\r
668 //\r
669 // Compare device path\r
670 //\r
671 if ((CompareMem (\r
672 PrivateData->DevicePath,\r
673 RegisteredPrivateData->DevicePath,\r
674 DevicePathSize)) == 0) {\r
675 *DevicePath = NULL;\r
676 Status = EFI_ALREADY_STARTED;\r
677 goto ErrorExit;\r
678 }\r
679 }\r
680 }\r
681 }\r
20752cb8
HW
682\r
683 //\r
684 // Fill Block IO protocol informations for the RAM disk\r
685 //\r
686 RamDiskInitBlockIo (PrivateData);\r
687\r
688 //\r
216fefa3 689 // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new\r
20752cb8
HW
690 // handle\r
691 //\r
692 Status = gBS->InstallMultipleProtocolInterfaces (\r
693 &PrivateData->Handle,\r
694 &gEfiBlockIoProtocolGuid,\r
695 &PrivateData->BlockIo,\r
216fefa3
HW
696 &gEfiBlockIo2ProtocolGuid,\r
697 &PrivateData->BlockIo2,\r
20752cb8
HW
698 &gEfiDevicePathProtocolGuid,\r
699 PrivateData->DevicePath,\r
700 NULL\r
701 );\r
702 if (EFI_ERROR (Status)) {\r
703 goto ErrorExit;\r
704 }\r
705\r
706 //\r
707 // Insert the newly created one to the registered RAM disk list\r
708 //\r
20752cb8 709 InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);\r
20752cb8
HW
710\r
711 gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);\r
712\r
713 FreePool (RamDiskDevNode);\r
714\r
07a3fecd
HW
715 if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {\r
716 RamDiskPublishNfit (PrivateData);\r
717 }\r
718\r
20752cb8
HW
719 return EFI_SUCCESS;\r
720\r
721ErrorExit:\r
722 if (RamDiskDevNode != NULL) {\r
723 FreePool (RamDiskDevNode);\r
724 }\r
725\r
726 if (PrivateData != NULL) {\r
727 if (PrivateData->DevicePath) {\r
728 FreePool (PrivateData->DevicePath);\r
729 }\r
730\r
731 FreePool (PrivateData);\r
732 }\r
733\r
734 return Status;\r
735}\r
736\r
737\r
738/**\r
739 Unregister a RAM disk specified by DevicePath.\r
740\r
741 @param[in] DevicePath A pointer to the device path that describes a RAM\r
742 Disk device.\r
743\r
744 @retval EFI_SUCCESS The RAM disk is unregistered successfully.\r
745 @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
746 @retval EFI_UNSUPPORTED The device specified by DevicePath is not a\r
747 valid ramdisk device path and not supported\r
748 by the driver.\r
749 @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't\r
750 exist.\r
751\r
752**/\r
753EFI_STATUS\r
754EFIAPI\r
755RamDiskUnregister (\r
756 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
757 )\r
758{\r
759 LIST_ENTRY *Entry;\r
760 LIST_ENTRY *NextEntry;\r
761 BOOLEAN Found;\r
762 UINT64 StartingAddr;\r
763 UINT64 EndingAddr;\r
764 EFI_DEVICE_PATH_PROTOCOL *Header;\r
765 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;\r
766 RAM_DISK_PRIVATE_DATA *PrivateData;\r
20752cb8
HW
767\r
768 if (NULL == DevicePath) {\r
769 return EFI_INVALID_PARAMETER;\r
770 }\r
771\r
772 //\r
773 // Locate the RAM disk device node.\r
774 //\r
775 RamDiskDevNode = NULL;\r
776 Header = DevicePath;\r
777 do {\r
778 //\r
779 // Test if the current device node is a RAM disk.\r
780 //\r
781 if ((MEDIA_DEVICE_PATH == Header->Type) &&\r
782 (MEDIA_RAM_DISK_DP == Header->SubType)) {\r
783 RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;\r
784\r
785 break;\r
786 }\r
787\r
788 Header = NextDevicePathNode (Header);\r
789 } while ((Header->Type != END_DEVICE_PATH_TYPE));\r
790\r
791 if (NULL == RamDiskDevNode) {\r
792 return EFI_UNSUPPORTED;\r
793 }\r
794\r
795 Found = FALSE;\r
796 StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));\r
797 EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));\r
798\r
20752cb8
HW
799 if (!IsListEmpty(&RegisteredRamDisks)) {\r
800 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {\r
801 PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);\r
802\r
803 //\r
804 // Unregister the RAM disk given by its starting address, ending address\r
805 // and type guid.\r
806 //\r
807 if ((StartingAddr == PrivateData->StartingAddr) &&\r
5eae4ff0 808 (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&\r
20752cb8 809 (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {\r
07a3fecd
HW
810 //\r
811 // Remove the content for this RAM disk in NFIT.\r
812 //\r
813 if (PrivateData->InNfit) {\r
814 RamDiskUnpublishNfit (PrivateData);\r
815 }\r
816\r
20752cb8 817 //\r
216fefa3 818 // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL\r
20752cb8
HW
819 //\r
820 gBS->UninstallMultipleProtocolInterfaces (\r
821 PrivateData->Handle,\r
822 &gEfiBlockIoProtocolGuid,\r
823 &PrivateData->BlockIo,\r
216fefa3
HW
824 &gEfiBlockIo2ProtocolGuid,\r
825 &PrivateData->BlockIo2,\r
20752cb8 826 &gEfiDevicePathProtocolGuid,\r
28620e60 827 (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,\r
20752cb8
HW
828 NULL\r
829 );\r
830\r
831 RemoveEntryList (&PrivateData->ThisInstance);\r
832\r
833 if (RamDiskCreateHii == PrivateData->CreateMethod) {\r
834 //\r
835 // If a RAM disk is created within HII, then the RamDiskDxe driver\r
836 // driver is responsible for freeing the allocated memory for the\r
837 // RAM disk.\r
838 //\r
839 FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);\r
840 }\r
841\r
20752cb8
HW
842 FreePool (PrivateData->DevicePath);\r
843 FreePool (PrivateData);\r
20752cb8
HW
844 Found = TRUE;\r
845\r
846 break;\r
847 }\r
848 }\r
849 }\r
20752cb8
HW
850\r
851 if (TRUE == Found) {\r
852 return EFI_SUCCESS;\r
853 } else {\r
854 return EFI_NOT_FOUND;\r
855 }\r
856}\r