/** @file
The realization of EFI_RAM_DISK_PROTOCOL.
Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
(C) Copyright 2016 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "RamDiskImpl.h"
RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = {
RAM_DISK_PRIVATE_DATA_SIGNATURE,
NULL
};
MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = {
{
MEDIA_DEVICE_PATH,
MEDIA_RAM_DISK_DP,
{
(UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)),
(UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8)
}
}
};
extern EFI_RAM_DISK_REGISTER_RAMDISK mRegisterRamDisk;
extern EFI_RAM_DISK_UNREGISTER_RAMDISK mUnregisterRamDisk;
extern LIST_ENTRY mRegisteredRamDisks;
BOOLEAN mRamDiskSsdtTableKeyValid = FALSE;
UINTN mRamDiskSsdtTableKey;
/**
Initialize the RAM disk device node.
@param[in] PrivateData Points to RAM disk private data.
@param[in, out] RamDiskDevNode Points to the RAM disk device node.
**/
VOID
RamDiskInitDeviceNode (
IN RAM_DISK_PRIVATE_DATA *PrivateData,
IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode
)
{
WriteUnaligned64 (
(UINT64 *) &(RamDiskDevNode->StartingAddr[0]),
(UINT64) PrivateData->StartingAddr
);
WriteUnaligned64 (
(UINT64 *) &(RamDiskDevNode->EndingAddr[0]),
(UINT64) PrivateData->StartingAddr + PrivateData->Size - 1
);
CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid);
RamDiskDevNode->Instance = PrivateData->InstanceNumber;
}
/**
Register a RAM disk with specified address, size and type.
@param[in] RamDiskBase The base address of registered RAM disk.
@param[in] RamDiskSize The size of registered RAM disk.
@param[in] RamDiskType The type of registered RAM disk. The GUID can be
any of the values defined in section 9.3.6.9, or a
vendor defined GUID.
@param[in] ParentDevicePath
Pointer to the parent device path. If there is no
parent device path then ParentDevicePath is NULL.
@param[out] DevicePath On return, points to a pointer to the device path
of the RAM disk device.
If ParentDevicePath is not NULL, the returned
DevicePath is created by appending a RAM disk node
to the parent device path. If ParentDevicePath is
NULL, the returned DevicePath is a RAM disk device
path without appending. This function is
responsible for allocating the buffer DevicePath
with the boot service AllocatePool().
@retval EFI_SUCCESS The RAM disk is registered successfully.
@retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.
RamDiskSize is 0.
@retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created
is already present in the handle database.
@retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to
resource limitation.
**/
EFI_STATUS
RamDiskRegiterHook (
IN UINT64 RamDiskBase,
IN UINT64 RamDiskSize,
IN EFI_GUID *RamDiskType,
IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
)
{
EFI_STATUS Status;
RAM_DISK_PRIVATE_DATA *PrivateData;
MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
Status = mRegisterRamDisk(
RamDiskBase,
RamDiskSize,
RamDiskType,
ParentDevicePath,
DevicePath
);
if (EFI_ERROR(Status)){
return Status;
}
//
// Create a new RAM disk instance and initialize its private data
//
PrivateData = AllocateCopyPool (
sizeof (RAM_DISK_PRIVATE_DATA),
&mRamDiskPrivateDataTemplate
);
if (NULL == PrivateData) {
return EFI_OUT_OF_RESOURCES;
}
PrivateData->StartingAddr = RamDiskBase;
PrivateData->Size = RamDiskSize;
CopyGuid (&PrivateData->TypeGuid, RamDiskType);
InitializeListHead (&PrivateData->ThisInstance);
//
// Generate device path information for the registered RAM disk
//
RamDiskDevNode = AllocateCopyPool (
sizeof (MEDIA_RAM_DISK_DEVICE_PATH),
&mRamDiskDeviceNodeTemplate
);
if (NULL == RamDiskDevNode) {
Status = EFI_OUT_OF_RESOURCES;
goto ErrorExit;
}
RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);
*DevicePath = AppendDevicePathNode (
ParentDevicePath,
(EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode
);
if (NULL == *DevicePath) {
Status = EFI_OUT_OF_RESOURCES;
goto ErrorExit;
}
PrivateData->DevicePath = *DevicePath;
//
// Insert the newly created one to the registered RAM disk list
//
InsertTailList (&mRegisteredRamDisks, &PrivateData->ThisInstance);
FreePool (RamDiskDevNode);
return Status;
ErrorExit:
if (RamDiskDevNode != NULL) {
FreePool (RamDiskDevNode);
}
if (PrivateData != NULL) {
if (PrivateData->DevicePath) {
FreePool (PrivateData->DevicePath);
}
FreePool (PrivateData);
}
return Status;
}
/**
Unregister a RAM disk specified by DevicePath.
@param[in] DevicePath A pointer to the device path that describes a RAM
Disk device.
@retval EFI_SUCCESS The RAM disk is unregistered successfully.
@retval EFI_INVALID_PARAMETER DevicePath is NULL.
@retval EFI_UNSUPPORTED The device specified by DevicePath is not a
valid ramdisk device path and not supported
by the driver.
@retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
exist.
**/
EFI_STATUS
RamDiskUnregiterHook (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *NextEntry;
UINT64 StartingAddr;
UINT64 EndingAddr;
EFI_DEVICE_PATH_PROTOCOL *Header;
MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
RAM_DISK_PRIVATE_DATA *PrivateData;
EFI_STATUS Status;
Status = mUnregisterRamDisk(DevicePath);
if (EFI_ERROR(Status)){
return Status;
}
if (NULL == DevicePath) {
return EFI_INVALID_PARAMETER;
}
//
// Locate the RAM disk device node.
//
RamDiskDevNode = NULL;
Header = DevicePath;
do {
//
// Test if the current device node is a RAM disk.
//
if ((MEDIA_DEVICE_PATH == Header->Type) &&
(MEDIA_RAM_DISK_DP == Header->SubType)) {
RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;
break;
}
Header = NextDevicePathNode (Header);
} while ((Header->Type != END_DEVICE_PATH_TYPE));
if (NULL == RamDiskDevNode) {
return EFI_UNSUPPORTED;
}
StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));
EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));
if (!IsListEmpty(&mRegisteredRamDisks)) {
EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mRegisteredRamDisks) {
PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
//
// Unregister the RAM disk given by its starting address, ending address
// and type guid.
//
if ((StartingAddr == PrivateData->StartingAddr) &&
(EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&
(CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {
RemoveEntryList (&PrivateData->ThisInstance);
break;
}
}
}
return Status;
}