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