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
RamDiskInitDeviceNode(IN RAM_DISK_PRIVATE_DATA * PrivateData,IN OUT MEDIA_RAM_DISK_DEVICE_PATH * RamDiskDevNode)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
RamDiskPublishSsdt(VOID)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
RamDiskPublishNfit(IN RAM_DISK_PRIVATE_DATA * PrivateData)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
RamDiskUnpublishNfit(IN RAM_DISK_PRIVATE_DATA * PrivateData)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
RamDiskRegister(IN UINT64 RamDiskBase,IN UINT64 RamDiskSize,IN EFI_GUID * RamDiskType,IN EFI_DEVICE_PATH * ParentDevicePath OPTIONAL,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)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 (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 1) {
617 return EFI_INVALID_PARAMETER;
618 }
619
620 RamDiskDevNode = NULL;
621
622 //
623 // Create a new RAM disk instance and initialize its private data
624 //
625 PrivateData = AllocateCopyPool (
626 sizeof (RAM_DISK_PRIVATE_DATA),
627 &mRamDiskPrivateDataTemplate
628 );
629 if (NULL == PrivateData) {
630 return EFI_OUT_OF_RESOURCES;
631 }
632
633 PrivateData->StartingAddr = RamDiskBase;
634 PrivateData->Size = RamDiskSize;
635 CopyGuid (&PrivateData->TypeGuid, RamDiskType);
636 InitializeListHead (&PrivateData->ThisInstance);
637
638 //
639 // Generate device path information for the registered RAM disk
640 //
641 RamDiskDevNode = AllocateCopyPool (
642 sizeof (MEDIA_RAM_DISK_DEVICE_PATH),
643 &mRamDiskDeviceNodeTemplate
644 );
645 if (NULL == RamDiskDevNode) {
646 Status = EFI_OUT_OF_RESOURCES;
647 goto ErrorExit;
648 }
649
650 RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);
651
652 *DevicePath = AppendDevicePathNode (
653 ParentDevicePath,
654 (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode
655 );
656 if (NULL == *DevicePath) {
657 Status = EFI_OUT_OF_RESOURCES;
658 goto ErrorExit;
659 }
660
661 PrivateData->DevicePath = *DevicePath;
662
663 //
664 // Check whether the created device path is already present in the handle
665 // database
666 //
667 if (!IsListEmpty(&RegisteredRamDisks)) {
668 DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);
669
670 EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
671 RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
672 if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {
673 //
674 // Compare device path
675 //
676 if ((CompareMem (
677 PrivateData->DevicePath,
678 RegisteredPrivateData->DevicePath,
679 DevicePathSize)) == 0) {
680 *DevicePath = NULL;
681 Status = EFI_ALREADY_STARTED;
682 goto ErrorExit;
683 }
684 }
685 }
686 }
687
688 //
689 // Fill Block IO protocol informations for the RAM disk
690 //
691 RamDiskInitBlockIo (PrivateData);
692
693 //
694 // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new
695 // handle
696 //
697 Status = gBS->InstallMultipleProtocolInterfaces (
698 &PrivateData->Handle,
699 &gEfiBlockIoProtocolGuid,
700 &PrivateData->BlockIo,
701 &gEfiBlockIo2ProtocolGuid,
702 &PrivateData->BlockIo2,
703 &gEfiDevicePathProtocolGuid,
704 PrivateData->DevicePath,
705 NULL
706 );
707 if (EFI_ERROR (Status)) {
708 goto ErrorExit;
709 }
710
711 //
712 // Insert the newly created one to the registered RAM disk list
713 //
714 InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);
715
716 gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);
717
718 FreePool (RamDiskDevNode);
719
720 if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {
721 RamDiskPublishNfit (PrivateData);
722 }
723
724 return EFI_SUCCESS;
725
726 ErrorExit:
727 if (RamDiskDevNode != NULL) {
728 FreePool (RamDiskDevNode);
729 }
730
731 if (PrivateData != NULL) {
732 if (PrivateData->DevicePath) {
733 FreePool (PrivateData->DevicePath);
734 }
735
736 FreePool (PrivateData);
737 }
738
739 return Status;
740 }
741
742
743 /**
744 Unregister a RAM disk specified by DevicePath.
745
746 @param[in] DevicePath A pointer to the device path that describes a RAM
747 Disk device.
748
749 @retval EFI_SUCCESS The RAM disk is unregistered successfully.
750 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
751 @retval EFI_UNSUPPORTED The device specified by DevicePath is not a
752 valid ramdisk device path and not supported
753 by the driver.
754 @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
755 exist.
756
757 **/
758 EFI_STATUS
759 EFIAPI
RamDiskUnregister(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)760 RamDiskUnregister (
761 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
762 )
763 {
764 LIST_ENTRY *Entry;
765 LIST_ENTRY *NextEntry;
766 BOOLEAN Found;
767 UINT64 StartingAddr;
768 UINT64 EndingAddr;
769 EFI_DEVICE_PATH_PROTOCOL *Header;
770 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
771 RAM_DISK_PRIVATE_DATA *PrivateData;
772
773 if (NULL == DevicePath) {
774 return EFI_INVALID_PARAMETER;
775 }
776
777 //
778 // Locate the RAM disk device node.
779 //
780 RamDiskDevNode = NULL;
781 Header = DevicePath;
782 do {
783 //
784 // Test if the current device node is a RAM disk.
785 //
786 if ((MEDIA_DEVICE_PATH == Header->Type) &&
787 (MEDIA_RAM_DISK_DP == Header->SubType)) {
788 RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;
789
790 break;
791 }
792
793 Header = NextDevicePathNode (Header);
794 } while ((Header->Type != END_DEVICE_PATH_TYPE));
795
796 if (NULL == RamDiskDevNode) {
797 return EFI_UNSUPPORTED;
798 }
799
800 Found = FALSE;
801 StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));
802 EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));
803
804 if (!IsListEmpty(&RegisteredRamDisks)) {
805 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
806 PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
807
808 //
809 // Unregister the RAM disk given by its starting address, ending address
810 // and type guid.
811 //
812 if ((StartingAddr == PrivateData->StartingAddr) &&
813 (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&
814 (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {
815 //
816 // Remove the content for this RAM disk in NFIT.
817 //
818 if (PrivateData->InNfit) {
819 RamDiskUnpublishNfit (PrivateData);
820 }
821
822 //
823 // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL
824 //
825 gBS->UninstallMultipleProtocolInterfaces (
826 PrivateData->Handle,
827 &gEfiBlockIoProtocolGuid,
828 &PrivateData->BlockIo,
829 &gEfiBlockIo2ProtocolGuid,
830 &PrivateData->BlockIo2,
831 &gEfiDevicePathProtocolGuid,
832 (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,
833 NULL
834 );
835
836 RemoveEntryList (&PrivateData->ThisInstance);
837
838 if (RamDiskCreateHii == PrivateData->CreateMethod) {
839 //
840 // If a RAM disk is created within HII, then the RamDiskDxe driver
841 // driver is responsible for freeing the allocated memory for the
842 // RAM disk.
843 //
844 FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);
845 }
846
847 FreePool (PrivateData->DevicePath);
848 FreePool (PrivateData);
849 Found = TRUE;
850
851 break;
852 }
853 }
854 }
855
856 if (TRUE == Found) {
857 return EFI_SUCCESS;
858 } else {
859 return EFI_NOT_FOUND;
860 }
861 }
862