]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
MdeModulePkg/PartitionDxe: Ensure blocksize holds MBR (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
4 Copyright (c) 2016, 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
616 if (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 1) {\r
617 return EFI_INVALID_PARAMETER;\r
618 }\r
619\r
620 RamDiskDevNode = NULL;\r
621\r
622 //\r
623 // Create a new RAM disk instance and initialize its private data\r
624 //\r
625 PrivateData = AllocateCopyPool (\r
626 sizeof (RAM_DISK_PRIVATE_DATA),\r
627 &mRamDiskPrivateDataTemplate\r
628 );\r
629 if (NULL == PrivateData) {\r
630 return EFI_OUT_OF_RESOURCES;\r
631 }\r
632\r
633 PrivateData->StartingAddr = RamDiskBase;\r
634 PrivateData->Size = RamDiskSize;\r
635 CopyGuid (&PrivateData->TypeGuid, RamDiskType);\r
636 InitializeListHead (&PrivateData->ThisInstance);\r
637\r
638 //\r
639 // Generate device path information for the registered RAM disk\r
640 //\r
641 RamDiskDevNode = AllocateCopyPool (\r
642 sizeof (MEDIA_RAM_DISK_DEVICE_PATH),\r
643 &mRamDiskDeviceNodeTemplate\r
644 );\r
645 if (NULL == RamDiskDevNode) {\r
646 Status = EFI_OUT_OF_RESOURCES;\r
647 goto ErrorExit;\r
648 }\r
649\r
650 RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);\r
651\r
652 *DevicePath = AppendDevicePathNode (\r
653 ParentDevicePath,\r
654 (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode\r
655 );\r
656 if (NULL == *DevicePath) {\r
657 Status = EFI_OUT_OF_RESOURCES;\r
658 goto ErrorExit;\r
659 }\r
660\r
661 PrivateData->DevicePath = *DevicePath;\r
662\r
663 //\r
664 // Check whether the created device path is already present in the handle\r
665 // database\r
666 //\r
20752cb8
HW
667 if (!IsListEmpty(&RegisteredRamDisks)) {\r
668 DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);\r
669\r
670 EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {\r
671 RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);\r
672 if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {\r
673 //\r
674 // Compare device path\r
675 //\r
676 if ((CompareMem (\r
677 PrivateData->DevicePath,\r
678 RegisteredPrivateData->DevicePath,\r
679 DevicePathSize)) == 0) {\r
680 *DevicePath = NULL;\r
681 Status = EFI_ALREADY_STARTED;\r
682 goto ErrorExit;\r
683 }\r
684 }\r
685 }\r
686 }\r
20752cb8
HW
687\r
688 //\r
689 // Fill Block IO protocol informations for the RAM disk\r
690 //\r
691 RamDiskInitBlockIo (PrivateData);\r
692\r
693 //\r
216fefa3 694 // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new\r
20752cb8
HW
695 // handle\r
696 //\r
697 Status = gBS->InstallMultipleProtocolInterfaces (\r
698 &PrivateData->Handle,\r
699 &gEfiBlockIoProtocolGuid,\r
700 &PrivateData->BlockIo,\r
216fefa3
HW
701 &gEfiBlockIo2ProtocolGuid,\r
702 &PrivateData->BlockIo2,\r
20752cb8
HW
703 &gEfiDevicePathProtocolGuid,\r
704 PrivateData->DevicePath,\r
705 NULL\r
706 );\r
707 if (EFI_ERROR (Status)) {\r
708 goto ErrorExit;\r
709 }\r
710\r
711 //\r
712 // Insert the newly created one to the registered RAM disk list\r
713 //\r
20752cb8 714 InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);\r
20752cb8
HW
715\r
716 gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);\r
717\r
718 FreePool (RamDiskDevNode);\r
719\r
07a3fecd
HW
720 if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {\r
721 RamDiskPublishNfit (PrivateData);\r
722 }\r
723\r
20752cb8
HW
724 return EFI_SUCCESS;\r
725\r
726ErrorExit:\r
727 if (RamDiskDevNode != NULL) {\r
728 FreePool (RamDiskDevNode);\r
729 }\r
730\r
731 if (PrivateData != NULL) {\r
732 if (PrivateData->DevicePath) {\r
733 FreePool (PrivateData->DevicePath);\r
734 }\r
735\r
736 FreePool (PrivateData);\r
737 }\r
738\r
739 return Status;\r
740}\r
741\r
742\r
743/**\r
744 Unregister a RAM disk specified by DevicePath.\r
745\r
746 @param[in] DevicePath A pointer to the device path that describes a RAM\r
747 Disk device.\r
748\r
749 @retval EFI_SUCCESS The RAM disk is unregistered successfully.\r
750 @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
751 @retval EFI_UNSUPPORTED The device specified by DevicePath is not a\r
752 valid ramdisk device path and not supported\r
753 by the driver.\r
754 @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't\r
755 exist.\r
756\r
757**/\r
758EFI_STATUS\r
759EFIAPI\r
760RamDiskUnregister (\r
761 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
762 )\r
763{\r
764 LIST_ENTRY *Entry;\r
765 LIST_ENTRY *NextEntry;\r
766 BOOLEAN Found;\r
767 UINT64 StartingAddr;\r
768 UINT64 EndingAddr;\r
769 EFI_DEVICE_PATH_PROTOCOL *Header;\r
770 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;\r
771 RAM_DISK_PRIVATE_DATA *PrivateData;\r
20752cb8
HW
772\r
773 if (NULL == DevicePath) {\r
774 return EFI_INVALID_PARAMETER;\r
775 }\r
776\r
777 //\r
778 // Locate the RAM disk device node.\r
779 //\r
780 RamDiskDevNode = NULL;\r
781 Header = DevicePath;\r
782 do {\r
783 //\r
784 // Test if the current device node is a RAM disk.\r
785 //\r
786 if ((MEDIA_DEVICE_PATH == Header->Type) &&\r
787 (MEDIA_RAM_DISK_DP == Header->SubType)) {\r
788 RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;\r
789\r
790 break;\r
791 }\r
792\r
793 Header = NextDevicePathNode (Header);\r
794 } while ((Header->Type != END_DEVICE_PATH_TYPE));\r
795\r
796 if (NULL == RamDiskDevNode) {\r
797 return EFI_UNSUPPORTED;\r
798 }\r
799\r
800 Found = FALSE;\r
801 StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));\r
802 EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));\r
803\r
20752cb8
HW
804 if (!IsListEmpty(&RegisteredRamDisks)) {\r
805 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {\r
806 PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);\r
807\r
808 //\r
809 // Unregister the RAM disk given by its starting address, ending address\r
810 // and type guid.\r
811 //\r
812 if ((StartingAddr == PrivateData->StartingAddr) &&\r
5eae4ff0 813 (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&\r
20752cb8 814 (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {\r
07a3fecd
HW
815 //\r
816 // Remove the content for this RAM disk in NFIT.\r
817 //\r
818 if (PrivateData->InNfit) {\r
819 RamDiskUnpublishNfit (PrivateData);\r
820 }\r
821\r
20752cb8 822 //\r
216fefa3 823 // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL\r
20752cb8
HW
824 //\r
825 gBS->UninstallMultipleProtocolInterfaces (\r
826 PrivateData->Handle,\r
827 &gEfiBlockIoProtocolGuid,\r
828 &PrivateData->BlockIo,\r
216fefa3
HW
829 &gEfiBlockIo2ProtocolGuid,\r
830 &PrivateData->BlockIo2,\r
20752cb8 831 &gEfiDevicePathProtocolGuid,\r
28620e60 832 (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,\r
20752cb8
HW
833 NULL\r
834 );\r
835\r
836 RemoveEntryList (&PrivateData->ThisInstance);\r
837\r
838 if (RamDiskCreateHii == PrivateData->CreateMethod) {\r
839 //\r
840 // If a RAM disk is created within HII, then the RamDiskDxe driver\r
841 // driver is responsible for freeing the allocated memory for the\r
842 // RAM disk.\r
843 //\r
844 FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);\r
845 }\r
846\r
20752cb8
HW
847 FreePool (PrivateData->DevicePath);\r
848 FreePool (PrivateData);\r
20752cb8
HW
849 Found = TRUE;\r
850\r
851 break;\r
852 }\r
853 }\r
854 }\r
20752cb8
HW
855\r
856 if (TRUE == Found) {\r
857 return EFI_SUCCESS;\r
858 } else {\r
859 return EFI_NOT_FOUND;\r
860 }\r
861}\r