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