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