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