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