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