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