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