From 20752cb8e79b3effedd9a8d34f228f9d37f9eeff Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Wed, 3 Feb 2016 14:14:47 +0800 Subject: [PATCH] MdeModulePkg: Add RamDiskDxe driver implementation The RamDiskDxe driver will: 1. Produce the EFI RAM Disk Protocol 2. Install RAM disk device path and block I/O related protocols on the RAM disk device handle. 3. Install RAM disk configuration form to HII database Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Samer El-Haj-Mahmoud Reviewed-by: Feng Tian --- MdeModulePkg/Include/Guid/RamDiskHii.h | 25 + MdeModulePkg/MdeModulePkg.dec | 3 + MdeModulePkg/MdeModulePkg.dsc | 1 + .../Disk/RamDiskDxe/RamDiskBlockIo.c | 258 ++++++ .../Universal/Disk/RamDiskDxe/RamDiskDriver.c | 170 ++++ .../Universal/Disk/RamDiskDxe/RamDiskDxe.inf | 78 ++ .../Universal/Disk/RamDiskDxe/RamDiskDxe.uni | 20 + .../Disk/RamDiskDxe/RamDiskFileExplorer.c | 253 ++++++ .../Universal/Disk/RamDiskDxe/RamDiskHii.vfr | 93 ++ .../Disk/RamDiskDxe/RamDiskHiiStrings.uni | 42 + .../Universal/Disk/RamDiskDxe/RamDiskImpl.c | 807 ++++++++++++++++++ .../Universal/Disk/RamDiskDxe/RamDiskImpl.h | 499 +++++++++++ .../Universal/Disk/RamDiskDxe/RamDiskNVData.h | 43 + .../Disk/RamDiskDxe/RamDiskProtocol.c | 356 ++++++++ 14 files changed, 2648 insertions(+) create mode 100644 MdeModulePkg/Include/Guid/RamDiskHii.h create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h create mode 100644 MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c diff --git a/MdeModulePkg/Include/Guid/RamDiskHii.h b/MdeModulePkg/Include/Guid/RamDiskHii.h new file mode 100644 index 0000000000..0457ee223d --- /dev/null +++ b/MdeModulePkg/Include/Guid/RamDiskHii.h @@ -0,0 +1,25 @@ +/** @file + GUIDs used as HII FormSet and HII Package list GUID in RamDiskDxe driver. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __RAM_DISK_HII_GUID_H__ +#define __RAM_DISK_HII_GUID_H__ + +#define RAM_DISK_FORM_SET_GUID \ + { \ + 0x2a46715f, 0x3581, 0x4a55, {0x8e, 0x73, 0x2b, 0x76, 0x9a, 0xaa, 0x30, 0xc5} \ + } + +extern EFI_GUID gRamDiskFormSetGuid; + +#endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index af7bcab3ba..b685132e5d 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -343,6 +343,9 @@ gEfiIfrFrontPageGuid = { 0xe58809f8, 0xfbc1, 0x48e2, { 0x88, 0x3a, 0xa3, 0x0f, 0xdc, 0x4b, 0x44, 0x1e } } + ## Include/Guid/RamDiskHii.h + gRamDiskFormSetGuid = { 0x2a46715f, 0x3581, 0x4a55, { 0x8e, 0x73, 0x2b, 0x76, 0x9a, 0xaa, 0x30, 0xc5 }} + [Ppis] ## Include/Ppi/AtaController.h diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index ad2b913197..0b54030f5b 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -322,6 +322,7 @@ MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf + MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c new file mode 100644 index 0000000000..1687da3690 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c @@ -0,0 +1,258 @@ +/** @file + Produce EFI_BLOCK_IO_PROTOCOL on a RAM disk device. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "RamDiskImpl.h" + +// +// The EFI_BLOCK_IO_PROTOCOL instances that is installed onto the handle +// for newly registered RAM disks +// +EFI_BLOCK_IO_PROTOCOL mRamDiskBlockIoTemplate = { + EFI_BLOCK_IO_PROTOCOL_REVISION, + (EFI_BLOCK_IO_MEDIA *) 0, + RamDiskBlkIoReset, + RamDiskBlkIoReadBlocks, + RamDiskBlkIoWriteBlocks, + RamDiskBlkIoFlushBlocks +}; + + +/** + Initialize the BlockIO protocol of a RAM disk device. + + @param[in] PrivateData Points to RAM disk private data. + +**/ +VOID +RamDiskInitBlockIo ( + IN RAM_DISK_PRIVATE_DATA *PrivateData + ) +{ + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO_MEDIA *Media; + + BlockIo = &PrivateData->BlockIo; + Media = &PrivateData->Media; + + CopyMem (BlockIo, &mRamDiskBlockIoTemplate, sizeof (EFI_BLOCK_IO_PROTOCOL)); + + BlockIo->Media = Media; + Media->RemovableMedia = FALSE; + Media->MediaPresent = TRUE; + Media->LogicalPartition = FALSE; + Media->ReadOnly = FALSE; + Media->WriteCaching = FALSE; + Media->BlockSize = RAM_DISK_BLOCK_SIZE; + Media->LastBlock = DivU64x32 ( + PrivateData->Size + RAM_DISK_BLOCK_SIZE - 1, + RAM_DISK_BLOCK_SIZE + ) - 1; +} + + +/** + Reset the Block Device. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return EFI_SUCCESS; +} + + +/** + Read BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId Id of the media, changes every time the media is + replaced. + @param[in] Lba The starting Logical Block Address to read from. + @param[in] BufferSize Size of Buffer, must be a multiple of device block + size. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for either having + implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while performing + the read. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId does not matched the current + device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block + size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + RAM_DISK_PRIVATE_DATA *PrivateData; + UINTN NumberOfBlocks; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This); + + if (MediaId != PrivateData->Media.MediaId) { + return EFI_MEDIA_CHANGED; + } + + if ((BufferSize % PrivateData->Media.BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (Lba > PrivateData->Media.LastBlock) { + return EFI_INVALID_PARAMETER; + } + + NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize; + if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) { + return EFI_INVALID_PARAMETER; + } + + CopyMem ( + Buffer, + (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)), + BufferSize + ); + + return EFI_SUCCESS; +} + + +/** + Write BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId The media ID that the write request is for. + @param[in] Lba The starting logical block address to be written. + The caller is responsible for writing to only + legitimate locations. + @param[in] BufferSize Size of Buffer, must be a multiple of device block + size. + @param[in] Buffer A pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data was written correctly to the device. + @retval EFI_WRITE_PROTECTED The device can not be written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing + the write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current + device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block + size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not + valid, or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + RAM_DISK_PRIVATE_DATA *PrivateData; + UINTN NumberOfBlocks; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This); + + if (MediaId != PrivateData->Media.MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (TRUE == PrivateData->Media.ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + if ((BufferSize % PrivateData->Media.BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (Lba > PrivateData->Media.LastBlock) { + return EFI_INVALID_PARAMETER; + } + + NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize; + if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) { + return EFI_INVALID_PARAMETER; + } + + CopyMem ( + (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)), + Buffer, + BufferSize + ); + + return EFI_SUCCESS; +} + + +/** + Flush the Block Device. + + @param[in] This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data was written to the device. + @retval EFI_DEVICE_ERROR The device reported an error while writting + back the data + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c new file mode 100644 index 0000000000..7d068b25c9 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c @@ -0,0 +1,170 @@ +/** @file + The driver entry point for RamDiskDxe driver. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "RamDiskImpl.h" + +// +// Handle for the EFI_RAM_DISK_PROTOCOL instance +// +EFI_HANDLE mRamDiskHandle = NULL; + +// +// The EFI_RAM_DISK_PROTOCOL instances that is installed onto the driver +// handle +// +EFI_RAM_DISK_PROTOCOL mRamDiskProtocol = { + RamDiskRegister, + RamDiskUnregister +}; + +// +// RamDiskDxe driver maintains a list of registered RAM disks. +// +LIST_ENTRY RegisteredRamDisks; +UINTN ListEntryNum; + + +/** + The entry point for RamDiskDxe driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of + resources. + @retval EFI_SUCCES All the related protocols are installed on + the driver. + +**/ +EFI_STATUS +EFIAPI +RamDiskDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; + VOID *DummyInterface; + + // + // If already started, return. + // + Status = gBS->LocateProtocol ( + &gEfiRamDiskProtocolGuid, + NULL, + &DummyInterface + ); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Driver already started!\n")); + return EFI_ALREADY_STARTED; + } + + // + // Create a private data structure. + // + ConfigPrivate = AllocateCopyPool (sizeof (RAM_DISK_CONFIG_PRIVATE_DATA), &mRamDiskConfigPrivateDataTemplate); + if (ConfigPrivate == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Install RAM disk configuration form + // + Status = InstallRamDiskConfigForm (ConfigPrivate); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Install the EFI_RAM_DISK_PROTOCOL and RAM disk private data onto a + // new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mRamDiskHandle, + &gEfiRamDiskProtocolGuid, + &mRamDiskProtocol, + &gEfiCallerIdGuid, + ConfigPrivate, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Initialize the list of registered RAM disks maintained by the driver + // + InitializeListHead (&RegisteredRamDisks); + + return EFI_SUCCESS; + +ErrorExit: + if (ConfigPrivate != NULL) { + UninstallRamDiskConfigForm (ConfigPrivate); + } + + return Status; +} + + +/** + Unload the RamDiskDxe driver and its configuration form. + + @param[in] ImageHandle The driver's image handle. + + @retval EFI_SUCCESS The RamDiskDxe driver and its configuration + form is unloaded. + @retval Others Failed to unload the form. + +**/ +EFI_STATUS +EFIAPI +RamDiskDxeUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; + + Status = gBS->HandleProtocol ( + mRamDiskHandle, + &gEfiCallerIdGuid, + (VOID **) &ConfigPrivate + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (ConfigPrivate->Signature == RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE); + + // + // Unregister all registered RAM disks + // + UnregisterAllRamDisks (); + + gBS->UninstallMultipleProtocolInterfaces ( + mRamDiskHandle, + &gEfiRamDiskProtocolGuid, + &mRamDiskProtocol, + &gEfiCallerIdGuid, + ConfigPrivate, + NULL + ); + + UninstallRamDiskConfigForm (ConfigPrivate); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf new file mode 100644 index 0000000000..85913c55cb --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf @@ -0,0 +1,78 @@ +## @file +# Produces EFI_RAM_DISK_PROTOCOL and provides the capability to +# create/remove RAM disks in a setup browser. +# +# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RamDiskDxe + MODULE_UNI_FILE = RamDiskDxe.uni + FILE_GUID = 28A03FF4-12B3-4305-A417-BB1A4F94081E + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RamDiskDxeEntryPoint + UNLOAD_IMAGE = RamDiskDxeUnload + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + RamDiskDriver.c + RamDiskImpl.c + RamDiskBlockIo.c + RamDiskProtocol.c + RamDiskFileExplorer.c + RamDiskImpl.h + RamDiskHii.vfr + RamDiskHiiStrings.uni + RamDiskNVData.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + UefiLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiHiiServicesLib + MemoryAllocationLib + HiiLib + FileExplorerLib + DevicePathLib + PrintLib + +[Guids] + gEfiIfrTianoGuid ## PRODUCES ## GUID # HII opcode + ## PRODUCES ## HII + ## CONSUMES ## HII + gRamDiskFormSetGuid + gEfiVirtualDiskGuid ## SOMETIMES_CONSUMES ## GUID + gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID # Indicate the information type + +[Protocols] + gEfiRamDiskProtocolGuid ## PRODUCES + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## PRODUCES + gEfiBlockIoProtocolGuid ## PRODUCES + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + +[Depex] + gEfiHiiConfigRoutingProtocolGuid AND + gEfiHiiDatabaseProtocolGuid diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni new file mode 100644 index 0000000000..19ffdbdd8e --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni @@ -0,0 +1,20 @@ +// /** @file +// Produces EFI_RAM_DISK_PROTOCOL and provides the capability to +// create/remove RAM disks in a setup browser. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser." + +#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser." + diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c new file mode 100644 index 0000000000..2cfd4bbf6c --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c @@ -0,0 +1,253 @@ +/** @file + Internal file explorer helper functions for RamDiskDxe driver. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "RamDiskImpl.h" + + +/** + Helper function called as part of the code needed to allocate the proper + sized buffer for various EFI interfaces. + + @param[in, out] Status Current status. + @param[in, out] Buffer Current allocated buffer, or NULL. + @param[in] BufferSize Current buffer size needed. + + @retval TRUE If the buffer was reallocated and the caller should + try the API again. + @retval FALSE The caller should not call this function again. + +**/ +BOOLEAN +GrowBuffer ( + IN OUT EFI_STATUS *Status, + IN OUT VOID **Buffer, + IN UINTN BufferSize + ) +{ + BOOLEAN TryAgain; + + // + // If this is an initial request, buffer will be null with a new buffer size + // + if ((*Buffer == NULL) && (BufferSize != 0)) { + *Status = EFI_BUFFER_TOO_SMALL; + } + // + // If the status code is "buffer too small", resize the buffer + // + TryAgain = FALSE; + if (*Status == EFI_BUFFER_TOO_SMALL) { + + if (*Buffer != NULL) { + FreePool (*Buffer); + } + + *Buffer = AllocateZeroPool (BufferSize); + + if (*Buffer != NULL) { + TryAgain = TRUE; + } else { + *Status = EFI_OUT_OF_RESOURCES; + } + } + // + // If there's an error, free the buffer + // + if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) { + FreePool (*Buffer); + *Buffer = NULL; + } + + return TryAgain; +} + + +/** + This function gets the file information from an open file descriptor, + and stores it in a buffer allocated from pool. + + @param[in] FHand File Handle. + + @return A pointer to a buffer with file information or NULL is returned. + +**/ +EFI_FILE_INFO * +FileInfo ( + IN EFI_FILE_HANDLE FHand + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *Buffer; + UINTN BufferSize; + + // + // Initialize for GrowBuffer loop + // + Buffer = NULL; + BufferSize = SIZE_OF_EFI_FILE_INFO + 200; + + // + // Call the real function + // + while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) { + Status = FHand->GetInfo ( + FHand, + &gEfiFileInfoGuid, + &BufferSize, + Buffer + ); + } + + return Buffer; +} + + +/** + This function will open a file or directory referenced by DevicePath. + + This function opens a file with the open mode according to the file path. The + Attributes is valid only for EFI_FILE_MODE_CREATE. + + @param[in, out] FilePath On input, the device path to the file. + On output, the remaining device path. + @param[out] FileHandle Pointer to the file handle. + @param[in] OpenMode The mode to open the file with. + @param[in] Attributes The file's file attributes. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or + the medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open + the file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +OpenFileByDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; + EFI_FILE_PROTOCOL *Handle1; + EFI_FILE_PROTOCOL *Handle2; + EFI_HANDLE DeviceHandle; + + if ((FilePath == NULL || FileHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + FilePath, + &DeviceHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol( + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID**)&EfiSimpleFileSystemProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1); + if (EFI_ERROR (Status)) { + FileHandle = NULL; + return Status; + } + + // + // go down directories one node at a time. + // + while (!IsDevicePathEnd (*FilePath)) { + // + // For file system access each node should be a file path component + // + if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || + DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP + ) { + FileHandle = NULL; + return (EFI_INVALID_PARAMETER); + } + // + // Open this file path node + // + Handle2 = Handle1; + Handle1 = NULL; + + // + // Try to test opening an existing file + // + Status = Handle2->Open ( + Handle2, + &Handle1, + ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, + OpenMode &~EFI_FILE_MODE_CREATE, + 0 + ); + + // + // see if the error was that it needs to be created + // + if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { + Status = Handle2->Open ( + Handle2, + &Handle1, + ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, + OpenMode, + Attributes + ); + } + // + // Close the last node + // + Handle2->Close (Handle2); + + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // Get the next node + // + *FilePath = NextDevicePathNode (*FilePath); + } + + // + // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! + // + *FileHandle = (VOID*)Handle1; + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr new file mode 100644 index 0000000000..9c3e3e44d2 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr @@ -0,0 +1,93 @@ +///** @file +// VFR file used by the RamDiskDxe driver. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +//**/ + +#include "RamDiskNVData.h" + +formset + guid = RAM_DISK_FORM_SET_GUID, + title = STRING_TOKEN(STR_FORM_SET_TITLE), + help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + varstore RAM_DISK_CONFIGURATION, + varid = RAM_DISK_CONFIGURATION_VARSTORE_ID, + name = RAM_DISK_CONFIGURATION, + guid = RAM_DISK_FORM_SET_GUID; + + // + // Form #1 "Main Form - Add/Remove/Show RAM Disks" + // + form formid = MAIN_FORM_ID, + title = STRING_TOKEN(STR_MAIN_FORM_TITLE); + + goto CREATE_RAW_RAM_DISK_FORM_ID, + prompt = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM), + help = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM_HELP); + + goto MAIN_FORM_ID, + prompt = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM), + help = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM_HELP), + flags = INTERACTIVE, + key = MAIN_GOTO_FILE_EXPLORER_ID; + + subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); + subtitle text = STRING_TOKEN(STR_RAM_DISK_LIST_TEXT); + + label MAIN_LABEL_LIST_START; + label MAIN_LABEL_LIST_END; + + subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); + + text + help = STRING_TOKEN(STR_REMOVE_SEL_HELP), + text = STRING_TOKEN(STR_REMOVE_SEL_TEXT), + flags = INTERACTIVE, + key = MAIN_REMOVE_RD_QUESTION_ID; + + endform; + + // + // Form #2 "Add New Raw RAM Disk" + // + form formid = CREATE_RAW_RAM_DISK_FORM_ID, + title = STRING_TOKEN(STR_ADD_RAW_FORM_TITLE); + + subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); + + numeric varid = RAM_DISK_CONFIGURATION.Size, + questionid = CREATE_RAW_SIZE_QUESTION_ID, + prompt = STRING_TOKEN(STR_SIZE_PROMPT), + help = STRING_TOKEN(STR_SIZE_HELP), + flags = DISPLAY_UINT_HEX | INTERACTIVE, + minimum = 1, + maximum = 0xFFFFFFFFFFFFFFFF, + endnumeric; + + subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING); + + text + help = STRING_TOKEN(STR_CREATE_AND_EXIT_HELP), + text = STRING_TOKEN(STR_CREATE_AND_EXIT_PROMPT), + flags = INTERACTIVE, + key = CREATE_RAW_SUBMIT_QUESTION_ID; + + text + help = STRING_TOKEN(STR_DISCARD_AND_EXIT_HELP), + text = STRING_TOKEN(STR_DISCARD_AND_EXIT_PROMPT), + flags = INTERACTIVE, + key = CREATE_RAW_DISCARD_QUESTION_ID; + + endform; + +endformset; diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni new file mode 100644 index 0000000000..3329f902e5 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni @@ -0,0 +1,42 @@ +// /** @file +// String definitions for RamDiskDxe driver form. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#langdef en-US "English" + +#string STR_FORM_SET_TITLE #language en-US "RAM Disk Configutation" +#string STR_FORM_SET_TITLE_HELP #language en-US "Press to add/remove RAM disks." + +#string STR_MAIN_FORM_TITLE #language en-US "RAM Disk HII Main Screen" +#string STR_RAM_DISK_NULL_STRING #language en-US "" + +#string STR_RAM_DISK_LIST_TEXT #language en-US "Created RAM disk list:" +#string STR_RAM_DISK_LIST_HELP #language en-US "Select for remove" +#string STR_GOTO_ADD_RAW_FORM #language en-US "Create raw" +#string STR_GOTO_ADD_RAW_FORM_HELP #language en-US "Create a raw RAM disk." +#string STR_GOTO_ADD_FROM_FILE_FORM #language en-US "Create from file" +#string STR_GOTO_ADD_FROM_FILE_FORM_HELP #language en-US "Create a RAM disk from a given file." +#string STR_REMOVE_SEL_HELP #language en-US "Remove selected RAM disk(s)" +#string STR_REMOVE_SEL_TEXT #language en-US "Remove selected RAM disk(s)." + +#string STR_ADD_RAW_FORM_TITLE #language en-US "Add A Raw RAM Disk" +#string STR_ADD_RAW_FORM_SUBTITLE_TEXT #language en-US " " + +#string STR_SIZE_PROMPT #language en-US "Size (Hex):" +#string STR_SIZE_HELP #language en-US "The valid RAM disk size should be multiples of the RAM disk block size." + +#string STR_CREATE_AND_EXIT_HELP #language en-US "Create a new RAM disk with the given starting and ending address." +#string STR_CREATE_AND_EXIT_PROMPT #language en-US "Create & Exit" +#string STR_DISCARD_AND_EXIT_HELP #language en-US "Discard and exit." +#string STR_DISCARD_AND_EXIT_PROMPT #language en-US "Discard & Exit" diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c new file mode 100644 index 0000000000..a2c48b23e3 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c @@ -0,0 +1,807 @@ +/** @file + HII Config Access protocol implementation of RamDiskDxe driver. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "RamDiskImpl.h" + +CHAR16 mRamDiskStorageName[] = L"RAM_DISK_CONFIGURATION"; + +RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate = { + RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE, + { + RamDiskExtractConfig, + RamDiskRouteConfig, + RamDiskCallback + } +}; + +HII_VENDOR_DEVICE_PATH mRamDiskHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + RAM_DISK_FORM_SET_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + + +/** + This function publish the RAM disk configuration Form. + + @param[in, out] ConfigPrivateData + Points to RAM disk configuration private data. + + @retval EFI_SUCCESS HII Form is installed successfully. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallRamDiskConfigForm ( + IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + DriverHandle = NULL; + ConfigAccess = &ConfigPrivateData->ConfigAccess; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DriverHandle, + &gEfiDevicePathProtocolGuid, + &mRamDiskHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ConfigPrivateData->DriverHandle = DriverHandle; + + // + // Publish the HII package list + // + HiiHandle = HiiAddPackages ( + &gRamDiskFormSetGuid, + DriverHandle, + RamDiskDxeStrings, + RamDiskHiiBin, + NULL + ); + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + DriverHandle, + &gEfiDevicePathProtocolGuid, + &mRamDiskHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + return EFI_OUT_OF_RESOURCES; + } + + ConfigPrivateData->HiiHandle = HiiHandle; + + return EFI_SUCCESS; +} + + +/** + This function removes RAM disk configuration Form. + + @param[in, out] ConfigPrivateData + Points to RAM disk configuration private data. + +**/ +VOID +UninstallRamDiskConfigForm ( + IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData + ) +{ + // + // Uninstall HII package list + // + if (ConfigPrivateData->HiiHandle != NULL) { + HiiRemovePackages (ConfigPrivateData->HiiHandle); + ConfigPrivateData->HiiHandle = NULL; + } + + // + // Uninstall HII Config Access Protocol + // + if (ConfigPrivateData->DriverHandle != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + ConfigPrivateData->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mRamDiskHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &ConfigPrivateData->ConfigAccess, + NULL + ); + ConfigPrivateData->DriverHandle = NULL; + } + + FreePool (ConfigPrivateData); +} + + +/** + Unregister all registered RAM disks. + +**/ +VOID +UnregisterAllRamDisks ( + VOID + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + RAM_DISK_PRIVATE_DATA *PrivateData; + + if (!IsListEmpty(&RegisteredRamDisks)) { + EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) { + PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); + + gBS->UninstallMultipleProtocolInterfaces ( + PrivateData->Handle, + &gEfiBlockIoProtocolGuid, + &PrivateData->BlockIo, + &gEfiDevicePathProtocolGuid, + (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath, + NULL + ); + + RemoveEntryList (&PrivateData->ThisInstance); + + if (RamDiskCreateHii == PrivateData->CreateMethod) { + // + // If a RAM disk is created within HII, then the RamDiskDxe driver + // driver is responsible for freeing the allocated memory for the + // RAM disk. + // + FreePool ((VOID *)(UINTN) PrivateData->StartingAddr); + } + + + gBS->DisconnectController (PrivateData->Handle, NULL, NULL); + + FreePool (PrivateData->DevicePath); + FreePool (PrivateData); + ListEntryNum--; + } + } +} + + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested + values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in + this driver. + +**/ +EFI_STATUS +EFIAPI +RamDiskExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + RAM_DISK_CONFIGURATION *Configuration; + EFI_STRING ConfigRequest; + EFI_STRING ConfigRequestHdr; + RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; + UINTN Size; + BOOLEAN AllocatedRequest; + + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Request; + if ((Request != NULL) && + !HiiIsConfigHdrMatch (Request, &gRamDiskFormSetGuid, mRamDiskStorageName)) { + return EFI_NOT_FOUND; + } + + ConfigRequestHdr = NULL; + ConfigRequest = NULL; + AllocatedRequest = FALSE; + Size = 0; + + // + // Convert buffer data to by helper function BlockToConfig() + // + ConfigPrivate = RAM_DISK_CONFIG_PRIVATE_FROM_THIS (This); + BufferSize = sizeof (RAM_DISK_CONFIGURATION) + ListEntryNum; + Configuration = AllocateZeroPool (BufferSize); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ConfigRequest = Request; + if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { + // + // Request has no request element, construct full request string. + // Allocate and fill a buffer large enough to hold the template + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator + // + ConfigRequestHdr = HiiConstructConfigHdr ( + &gRamDiskFormSetGuid, + mRamDiskStorageName, + ConfigPrivate->DriverHandle + ); + Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + ASSERT (ConfigRequest != NULL); + AllocatedRequest = TRUE; + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); + FreePool (ConfigRequestHdr); + } + + Status = gHiiConfigRouting->BlockToConfig ( + gHiiConfigRouting, + ConfigRequest, + (UINT8 *) &Configuration, + BufferSize, + Results, + Progress + ); + // + // Free the allocated config request string and RAM disk configuration data. + // + if (AllocatedRequest) { + FreePool (ConfigRequest); + ConfigRequest = NULL; + } + FreePool (Configuration); + + // + // Set Progress string to the original request string. + // + if (Request == NULL) { + *Progress = NULL; + } else if (StrStr (Request, L"OFFSET") == NULL) { + *Progress = Request + StrLen (Request); + } + + return Status; +} + + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in + this driver. + +**/ +EFI_STATUS +EFIAPI +RamDiskRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + if (!HiiIsConfigHdrMatch (Configuration, &gRamDiskFormSetGuid, mRamDiskStorageName)) { + return EFI_NOT_FOUND; + } + + *Progress = Configuration + StrLen (Configuration); + + return EFI_SUCCESS; +} + + +/** + Allocate memory and register the RAM disk created within RamDiskDxe + driver HII. + + @param[in] Size If creating raw, size of the RAM disk to create. + If creating from file, zero. + @param[in] FileHandle If creating raw, NULL. If creating from file, the + file handle. + + @retval EFI_SUCCESS RAM disk is created and registered. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to match the + size required. + +**/ +EFI_STATUS +HiiCreateRamDisk ( + IN UINT64 Size, + IN EFI_FILE_HANDLE FileHandle + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + UINT64 StartingAddr; + EFI_INPUT_KEY Key; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + RAM_DISK_PRIVATE_DATA *PrivateData; + EFI_FILE_INFO *FileInformation; + + FileInformation = NULL; + + if (FileHandle != NULL) { + // + // Create from file. + // + FileInformation = FileInfo (FileHandle); + if (NULL == FileInformation) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"", + L"Not enough memory to get the file information!", + L"Press ENTER to continue ...", + L"", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + return EFI_OUT_OF_RESOURCES; + } + + // + // Update the size of RAM disk according to the file size. + // + Size = FileInformation->FileSize; + } + + StartingAddr = (UINTN) AllocatePool ((UINTN) Size); + if (0 == StartingAddr) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"", + L"Not enough memory to create the RAM disk!", + L"Press ENTER to continue ...", + L"", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + return EFI_OUT_OF_RESOURCES; + } + + if (FileHandle != NULL) { + // + // Copy the file content to the RAM disk. + // + BufferSize = (UINTN) Size; + FileHandle->Read ( + FileHandle, + &BufferSize, + (VOID *)(UINTN) StartingAddr + ); + if (BufferSize != FileInformation->FileSize) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"", + L"File content read error!", + L"Press ENTER to continue ...", + L"", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + return EFI_DEVICE_ERROR; + } + } + + // + // Register the newly created RAM disk. + // + Status = RamDiskRegister ( + StartingAddr, + Size, + &gEfiVirtualDiskGuid, + NULL, + &DevicePath + ); + if (EFI_ERROR (Status)) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"", + L"Fail to register the newly created RAM disk!", + L"Press ENTER to continue ...", + L"", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + return Status; + } + + // + // If RAM disk is created within HII, memory should be freed when the + // RAM disk is unregisterd. + // + PrivateData = RAM_DISK_PRIVATE_FROM_THIS (RegisteredRamDisks.BackLink); + PrivateData->CreateMethod = RamDiskCreateHii; + + return EFI_SUCCESS; +} + + +/** + This function updates the registered RAM disks list on the main form. + + @param[in, out] ConfigPrivate + Private data for configurating hii data for RAM + disks. + +**/ +VOID +UpdateMainForm ( + IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate + ) +{ + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + LIST_ENTRY *Entry; + UINTN Index; + RAM_DISK_PRIVATE_DATA *PrivateData; + CHAR16 *String; + CHAR16 RamDiskStr[128]; + EFI_STRING_ID StringId; + EFI_TPL OldTpl; + + // + // Init OpCode Handle + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode as the start opcode + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = MAIN_LABEL_LIST_START; + + // + // Create Hii Extend Label OpCode as the end opcode + // + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = MAIN_LABEL_LIST_END; + + Index = 0; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) { + PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); + String = RamDiskStr; + + UnicodeSPrint ( + String, + sizeof (RamDiskStr), + L" RAM Disk %d: [0x%lx, 0x%lx]\n", + Index, + PrivateData->StartingAddr, + PrivateData->StartingAddr + PrivateData->Size + ); + + StringId = HiiSetString (ConfigPrivate->HiiHandle, 0, RamDiskStr, NULL); + ASSERT (StringId != 0); + + HiiCreateCheckBoxOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (MAIN_CHECKBOX_QUESTION_ID_START + Index), + RAM_DISK_CONFIGURATION_VARSTORE_ID, + (UINT16) (RAM_DISK_LIST_VAR_OFFSET + Index), + StringId, + STRING_TOKEN (STR_RAM_DISK_LIST_HELP), + 0, + 0, + NULL + ); + + Index++; + } + gBS->RestoreTPL (OldTpl); + + HiiUpdateForm ( + ConfigPrivate->HiiHandle, + &gRamDiskFormSetGuid, + MAIN_FORM_ID, + StartOpCodeHandle, + EndOpCodeHandle + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +RamDiskCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_STATUS Status; + UINTN Index; + RAM_DISK_PRIVATE_DATA *PrivateData; + RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; + RAM_DISK_CONFIGURATION *Configuration; + EFI_DEVICE_PATH_PROTOCOL *FileDevPath; + EFI_FILE_HANDLE FileHandle; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + EFI_TPL OldTpl; + + if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Action == EFI_BROWSER_ACTION_RETRIEVE) { + Status = EFI_UNSUPPORTED; + if (QuestionId == CREATE_RAW_SIZE_QUESTION_ID) { + Value->u64 = EFI_PAGE_SIZE; + Status = EFI_SUCCESS; + } + return Status; + } + + if ((Action != EFI_BROWSER_ACTION_CHANGED) && + (Action != EFI_BROWSER_ACTION_CHANGING) && + (Action != EFI_BROWSER_ACTION_FORM_OPEN)) { + return EFI_UNSUPPORTED; + } + + ConfigPrivate = RAM_DISK_CONFIG_PRIVATE_FROM_THIS (This); + + // + // Update the RAM disk list show at the main form first. + // + if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { + Status = EFI_UNSUPPORTED; + if (QuestionId == MAIN_GOTO_FILE_EXPLORER_ID) { + UpdateMainForm (ConfigPrivate); + Status = EFI_SUCCESS; + } + return Status; + } + + // + // Get Browser data + // + Configuration = AllocateZeroPool (sizeof (RAM_DISK_CONFIGURATION) + ListEntryNum); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = EFI_SUCCESS; + + HiiGetBrowserData ( + &gRamDiskFormSetGuid, + mRamDiskStorageName, + sizeof (RAM_DISK_CONFIGURATION) + ListEntryNum, + (UINT8 *) Configuration + ); + + if (Action == EFI_BROWSER_ACTION_CHANGING) { + switch (QuestionId) { + case MAIN_GOTO_FILE_EXPLORER_ID: + Status = ChooseFile (NULL, NULL, NULL, &FileDevPath); + if (EFI_ERROR (Status)) { + break; + } + + if (FileDevPath != NULL) { + // + // Open the file. + // + Status = OpenFileByDevicePath ( + &FileDevPath, + &FileHandle, + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + break; + } + + // + // Create from file, RAM disk size is zero. It will be updated + // according to the file size. + // + Status = HiiCreateRamDisk (0, FileHandle); + if (EFI_ERROR (Status)) { + break; + } + + // + // Refresh the registered RAM disks list. + // + UpdateMainForm (ConfigPrivate); + } + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; + break; + + default: + break; + } + } else if (Action == EFI_BROWSER_ACTION_CHANGED) { + switch (QuestionId) { + case MAIN_REMOVE_RD_QUESTION_ID: + // + // Remove the selected RAM disks + // + Index = 0; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) { + if (Configuration->RamDiskList[Index++] != 0) { + PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); + + RamDiskUnregister ( + (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath + ); + } + } + gBS->RestoreTPL (OldTpl); + + UpdateMainForm (ConfigPrivate); + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + ZeroMem (Configuration->RamDiskList, ListEntryNum); + break; + + case CREATE_RAW_SUBMIT_QUESTION_ID: + // + // Create raw, FileHandle is NULL. + // + Status = HiiCreateRamDisk (Configuration->Size, NULL); + if (EFI_ERROR (Status)) { + break; + } + + // + // Refresh the registered RAM disks list. + // + UpdateMainForm (ConfigPrivate); + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; + break; + + case CREATE_RAW_DISCARD_QUESTION_ID: + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; + break; + + default: + break; + } + } + + if (!EFI_ERROR (Status)) { + HiiSetBrowserData ( + &gRamDiskFormSetGuid, + mRamDiskStorageName, + sizeof (RAM_DISK_CONFIGURATION) + ListEntryNum, + (UINT8 *) Configuration, + NULL + ); + } + FreePool (Configuration); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h new file mode 100644 index 0000000000..47250068d7 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h @@ -0,0 +1,499 @@ +/** @file + The header file of RamDiskDxe driver. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _RAM_DISK_IMPL_H_ +#define _RAM_DISK_IMPL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RamDiskNVData.h" + +/// +/// RAM disk general definitions and declarations +/// + +// +// Block size for RAM disk +// +#define RAM_DISK_BLOCK_SIZE 512 + +// +// Iterate through the doule linked list. NOT delete safe +// +#define EFI_LIST_FOR_EACH(Entry, ListHead) \ + for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink) + +// +// Iterate through the doule linked list. This is delete-safe. +// Do not touch NextEntry +// +#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \ + for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\ + Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink) + +// +// RamDiskDxe driver maintains a list of registered RAM disks. +// +extern LIST_ENTRY RegisteredRamDisks; +extern UINTN ListEntryNum; + +// +// RAM Disk create method. +// +typedef enum _RAM_DISK_CREATE_METHOD { + RamDiskCreateOthers = 0, + RamDiskCreateHii +} RAM_DISK_CREATE_METHOD; + +// +// RamDiskDxe driver maintains a list of registered RAM disks. +// The struct contains the list entry and the information of each RAM +// disk +// +typedef struct { + UINTN Signature; + + EFI_HANDLE Handle; + + EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_BLOCK_IO_MEDIA Media; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + UINT64 StartingAddr; + UINT64 Size; + EFI_GUID TypeGuid; + UINT16 InstanceNumber; + RAM_DISK_CREATE_METHOD CreateMethod; + + LIST_ENTRY ThisInstance; +} RAM_DISK_PRIVATE_DATA; + +#define RAM_DISK_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'D', 'S', 'K') +#define RAM_DISK_PRIVATE_FROM_BLKIO(a) CR (a, RAM_DISK_PRIVATE_DATA, BlockIo, RAM_DISK_PRIVATE_DATA_SIGNATURE) +#define RAM_DISK_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_PRIVATE_DATA, ThisInstance, RAM_DISK_PRIVATE_DATA_SIGNATURE) + +/// +/// RAM disk HII-related definitions and declarations +/// + +// +// Tool generated IFR binary data and String package data +// +extern UINT8 RamDiskHiiBin[]; +extern UINT8 RamDiskDxeStrings[]; + +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +typedef struct { + UINTN Signature; + + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE HiiHandle; +} RAM_DISK_CONFIG_PRIVATE_DATA; + +extern RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate; + +#define RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'C', 'F', 'G') +#define RAM_DISK_CONFIG_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_CONFIG_PRIVATE_DATA, ConfigAccess, RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE) + +#define RAM_DISK_LIST_VAR_OFFSET ((UINT16) OFFSET_OF (RAM_DISK_CONFIGURATION, RamDiskList)) + +/** + 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 +EFIAPI +RamDiskRegister ( + IN UINT64 RamDiskBase, + IN UINT64 RamDiskSize, + IN EFI_GUID *RamDiskType, + IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL, + OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +/** + 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 +EFIAPI +RamDiskUnregister ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Initialize the BlockIO protocol of a RAM disk device. + + @param[in] PrivateData Points to RAM disk private data. + +**/ +VOID +RamDiskInitBlockIo ( + IN RAM_DISK_PRIVATE_DATA *PrivateData + ); + +/** + Reset the Block Device. + + @param[in] This Indicates a pointer to the calling context. + @param[in] ExtendedVerification + Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and + could not be reset. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Read BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId Id of the media, changes every time the media is + replaced. + @param[in] Lba The starting Logical Block Address to read from. + @param[in] BufferSize Size of Buffer, must be a multiple of device block + size. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for either having + implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while performing + the read. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId does not matched the current + device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block + size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Write BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId The media ID that the write request is for. + @param[in] Lba The starting logical block address to be written. + The caller is responsible for writing to only + legitimate locations. + @param[in] BufferSize Size of Buffer, must be a multiple of device block + size. + @param[in] Buffer A pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data was written correctly to the device. + @retval EFI_WRITE_PROTECTED The device can not be written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing + the write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current + device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block + size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not + valid, or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flush the Block Device. + + @param[in] This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data was written to the device. + @retval EFI_DEVICE_ERROR The device reported an error while writting + back the data + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +RamDiskBlkIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + +/** + This function publish the RAM disk configuration Form. + + @param[in, out] ConfigPrivateData + Points to RAM disk configuration private data. + + @retval EFI_SUCCESS HII Form is installed successfully. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallRamDiskConfigForm ( + IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData + ); + +/** + This function removes RAM disk configuration Form. + + @param[in, out] ConfigPrivateData + Points to RAM disk configuration private data. + +**/ +VOID +UninstallRamDiskConfigForm ( + IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData + ); + +/** + Unregister all registered RAM disks. + +**/ +VOID +UnregisterAllRamDisks ( + VOID + ); + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested + values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in + this driver. + +**/ +EFI_STATUS +EFIAPI +RamDiskExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ); + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in + this driver. + +**/ +EFI_STATUS +EFIAPI +RamDiskRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +RamDiskCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ); + + +/** + This function gets the file information from an open file descriptor, + and stores it in a buffer allocated from pool. + + @param[in] FHand File Handle. + + @return A pointer to a buffer with file information or NULL is returned. + +**/ +EFI_FILE_INFO * +FileInfo ( + IN EFI_FILE_HANDLE FHand + ); + + +/** + This function will open a file or directory referenced by DevicePath. + + This function opens a file with the open mode according to the file path. The + Attributes is valid only for EFI_FILE_MODE_CREATE. + + @param[in, out] FilePath On input, the device path to the file. + On output, the remaining device path. + @param[out] FileHandle Pointer to the file handle. + @param[in] OpenMode The mode to open the file with. + @param[in] Attributes The file's file attributes. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or + the medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open + the file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +OpenFileByDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +#endif diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h new file mode 100644 index 0000000000..2b5d045198 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h @@ -0,0 +1,43 @@ +/** @file + Header file for NV data structure definition. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _RAM_DISK_NVDATA_H_ +#define _RAM_DISK_NVDATA_H_ + +#include +#include + +#define RAM_DISK_CONFIGURATION_VARSTORE_ID 0x0001 + +#define MAIN_FORM_ID 0x1000 +#define MAIN_GOTO_FILE_EXPLORER_ID 0x1001 +#define MAIN_REMOVE_RD_QUESTION_ID 0x1002 +#define MAIN_CHECKBOX_QUESTION_ID_START 0x1003 +#define MAIN_LABEL_LIST_START 0x1004 +#define MAIN_LABEL_LIST_END 0x1005 + +#define CREATE_RAW_RAM_DISK_FORM_ID 0x2000 +#define CREATE_RAW_SIZE_QUESTION_ID 0x2001 +#define CREATE_RAW_SUBMIT_QUESTION_ID 0x2002 +#define CREATE_RAW_DISCARD_QUESTION_ID 0x2003 + +typedef struct { + UINT64 Size; + // + // CheckBox status for created RAM disks + // + UINT8 RamDiskList[0]; +} RAM_DISK_CONFIGURATION; + +#endif diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c new file mode 100644 index 0000000000..9fe888eb9b --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c @@ -0,0 +1,356 @@ +/** @file + The realization of EFI_RAM_DISK_PROTOCOL. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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) + } + } +}; + + +/** + 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 + ); + 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 +EFIAPI +RamDiskRegister ( + 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; + RAM_DISK_PRIVATE_DATA *RegisteredPrivateData; + MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode; + UINTN DevicePathSize; + LIST_ENTRY *Entry; + EFI_TPL OldTpl; + + if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) { + return EFI_INVALID_PARAMETER; + } + + // + // Add check to prevent data read across the memory boundary + // + if (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 1) { + return EFI_INVALID_PARAMETER; + } + + RamDiskDevNode = NULL; + + // + // 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; + + // + // Check whether the created device path is already present in the handle + // database + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (!IsListEmpty(&RegisteredRamDisks)) { + DevicePathSize = GetDevicePathSize (PrivateData->DevicePath); + + EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) { + RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); + if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) { + // + // Compare device path + // + if ((CompareMem ( + PrivateData->DevicePath, + RegisteredPrivateData->DevicePath, + DevicePathSize)) == 0) { + *DevicePath = NULL; + Status = EFI_ALREADY_STARTED; + goto ErrorExit; + } + } + } + } + gBS->RestoreTPL (OldTpl); + + // + // Fill Block IO protocol informations for the RAM disk + // + RamDiskInitBlockIo (PrivateData); + + // + // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO_PROTOCOL on a new + // handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &PrivateData->Handle, + &gEfiBlockIoProtocolGuid, + &PrivateData->BlockIo, + &gEfiDevicePathProtocolGuid, + PrivateData->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Insert the newly created one to the registered RAM disk list + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance); + ListEntryNum++; + gBS->RestoreTPL (OldTpl); + + gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE); + + FreePool (RamDiskDevNode); + + return EFI_SUCCESS; + +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 +EFIAPI +RamDiskUnregister ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + BOOLEAN Found; + UINT64 StartingAddr; + UINT64 EndingAddr; + EFI_DEVICE_PATH_PROTOCOL *Header; + MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode; + RAM_DISK_PRIVATE_DATA *PrivateData; + EFI_TPL OldTpl; + + 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; + } + + Found = FALSE; + StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0])); + EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0])); + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (!IsListEmpty(&RegisteredRamDisks)) { + EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) { + 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) && + (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) { + // + // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO_PROTOCOL + // + gBS->UninstallMultipleProtocolInterfaces ( + PrivateData->Handle, + &gEfiBlockIoProtocolGuid, + &PrivateData->BlockIo, + &gEfiDevicePathProtocolGuid, + DevicePath, + NULL + ); + + RemoveEntryList (&PrivateData->ThisInstance); + + if (RamDiskCreateHii == PrivateData->CreateMethod) { + // + // If a RAM disk is created within HII, then the RamDiskDxe driver + // driver is responsible for freeing the allocated memory for the + // RAM disk. + // + FreePool ((VOID *)(UINTN) PrivateData->StartingAddr); + } + + gBS->DisconnectController (PrivateData->Handle, NULL, NULL); + + FreePool (PrivateData->DevicePath); + FreePool (PrivateData); + ListEntryNum--; + Found = TRUE; + + break; + } + } + } + gBS->RestoreTPL (OldTpl); + + if (TRUE == Found) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} -- 2.39.2