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