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