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