/** @file ;****************************************************************************** ;* Copyright (c) 2020, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ /** @file HII Config Access protocol implementation of RamDiskDxe driver. Copyright (c) 2016, Intel Corporation. All rights reserved.
(C) Copyright 2016-2018 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "RamDiskImpl.h" #include "RamDisk.h" #include "FileExplorer.h" extern LIST_ENTRY mRegisteredRamDisks; extern LIST_ENTRY mRamDiskDeviceList; extern H2O_RAM_DISK_DEVICE_PATH mH2ORamDiskDevicePath; extern UINT32 mRamDiskDeviceLNum; extern EFI_RAM_DISK_PROTOCOL *mRamDiskProtocol; RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate = { RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE, { EFI_PAGE_SIZE, RAM_DISK_BOOT_SERVICE_DATA_MEMORY }, { 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) } }, H2O_RAM_DISK_FORMSET_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8) (END_DEVICE_PATH_LENGTH), (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) } } }; /** Insert a RAM Disk into link list of H2O RAM Disk Protocol. @param[in] StartingAddress Base Address of the RAM Disk @param[in] Size Size of the RAM Disk @retval EFI_SUCCESS HII Form is installed successfully. @retval EFI_OUT_OF_RESOURCES Not enough resource for updating link list of RAM Disk of H2O RAM Disk Protocol. **/ EFI_STATUS UpdateRamDiskDeviceList( IN UINT64 StartingAddress, IN UINT64 Size ) { EFI_STATUS Status; UINT64 DiskId; UINT32 BlockSize; RAM_DISK_DEV *RamDiskDev = NULL; // // Allocate storage for RAM Disk device info on the heap. // RamDiskDev = AllocateZeroPool (sizeof(RAM_DISK_DEV)); if (RamDiskDev == NULL) { return EFI_OUT_OF_RESOURCES; } BlockSize = 512; RamDiskDev->Start = StartingAddress; // // Initialize the RAM Disk's device info. // Status = gBS->GetNextMonotonicCount (&DiskId); CopyMem (&mH2ORamDiskDevicePath.DiskId, &DiskId, sizeof(DiskId)); RamDiskDev->Signature = PBLOCK_DEVICE_SIGNATURE; RamDiskDev->BlkIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION; RamDiskDev->BlkIo.Media = &RamDiskDev->Media; RamDiskDev->Media.RemovableMedia = FALSE; RamDiskDev->Media.MediaPresent = TRUE; RamDiskDev->Media.LastBlock = Size / BlockSize - 1; RamDiskDev->Media.BlockSize = BlockSize; RamDiskDev->Media.LogicalPartition = TRUE; RamDiskDev->Media.ReadOnly = FALSE; RamDiskDev->Media.WriteCaching = TRUE; RamDiskDev->BlkIo.ReadBlocks = RamDiskReadBlocks; RamDiskDev->BlkIo.WriteBlocks = RamDiskWriteBlocks; RamDiskDev->BlkIo.FlushBlocks = RamDiskFlushBlocks; RamDiskDev->DevicePath = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&mH2ORamDiskDevicePath); InsertTailList (&mRamDiskDeviceList, &RamDiskDev->Link); mRamDiskDeviceLNum += 1; return EFI_SUCCESS; } /** 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 ( &gH2ORamDiskFormSetGuid, DriverHandle, RamDiskDxeDriverStrings, 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); } /** 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 ) { if (Progress == NULL || Results == NULL) { return EFI_INVALID_PARAMETER; } *Progress = Request; return EFI_NOT_FOUND; } /** 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; return EFI_NOT_FOUND; } /** 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. @param[in] MemoryType Type of memory to be used to create RAM Disk. @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, IN UINT8 MemoryType ) { 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; StartingAddr = 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; } if (Size > (UINTN) -1) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"", L"The given RAM disk size is too large!", L"Press ENTER to continue ...", L"", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); return EFI_OUT_OF_RESOURCES; } StartingAddr = NULL; if (MemoryType == RAM_DISK_BOOT_SERVICE_DATA_MEMORY) { StartingAddr = AllocatePool((UINTN)Size); } else if (MemoryType == RAM_DISK_RESERVED_MEMORY) { StartingAddr = AllocateReservedPool((UINTN)Size); } if (StartingAddr == NULL) { 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 = mRamDiskProtocol->Register( ((UINT64)(UINTN) 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; } // // Update link list of RAM Disk of H2O RAM Disk protocol for RamDiskApp // Status = UpdateRamDiskDeviceList((UINT64)(UINTN)StartingAddr, Size); // // If RAM disk is created within HII, memory should be freed when the // RAM disk is unregisterd. // PrivateData = RAM_DISK_PRIVATE_FROM_THIS (mRegisteredRamDisks.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; // // 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; EFI_LIST_FOR_EACH (Entry, &mRegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); PrivateData->CheckBoxId = (EFI_QUESTION_ID) (MAIN_CHECKBOX_QUESTION_ID_START + Index); // // CheckBox is unchecked by default. // PrivateData->CheckBoxChecked = FALSE; String = RamDiskStr; UnicodeSPrint ( String, sizeof (RamDiskStr), L" RAM Disk %d Size: 0x%lx\n", Index, PrivateData->Size ); StringId = HiiSetString (ConfigPrivate->HiiHandle, 0, RamDiskStr, NULL); ASSERT (StringId != 0); HiiCreateCheckBoxOpCode ( StartOpCodeHandle, PrivateData->CheckBoxId, 0, 0, StringId, STRING_TOKEN (STR_RAM_DISK_LIST_HELP), EFI_IFR_FLAG_CALLBACK, 0, NULL ); Index++; } HiiUpdateForm ( ConfigPrivate->HiiHandle, &gH2ORamDiskFormSetGuid, 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; RAM_DISK_PRIVATE_DATA *PrivateData; RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate; LIST_ENTRY *Entry; LIST_ENTRY *NextEntry; if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; } ConfigPrivate = RAM_DISK_CONFIG_PRIVATE_FROM_THIS (This); if (Action == EFI_BROWSER_ACTION_RETRIEVE) { Status = EFI_UNSUPPORTED; if (QuestionId == CREATE_RAW_SIZE_QUESTION_ID) { Value->u64 = EFI_PAGE_SIZE; ConfigPrivate->ConfigStore.Size = EFI_PAGE_SIZE; Status = EFI_SUCCESS; } else if (QuestionId == CREATE_RAW_MEMORY_TYPE_QUESTION_ID) { Value->u8 = RAM_DISK_BOOT_SERVICE_DATA_MEMORY; ConfigPrivate->ConfigStore.MemType = RAM_DISK_BOOT_SERVICE_DATA_MEMORY; 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; } // // Update the RAM disk list show at the main form first. // if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { Status = EFI_UNSUPPORTED; if (QuestionId == KEY_FILE_EXPLORER) { UpdateMainForm (ConfigPrivate); Status = EFI_SUCCESS; } return Status; } Status = EFI_SUCCESS; if (Action == EFI_BROWSER_ACTION_CHANGING) { switch (QuestionId) { case KEY_FILE_EXPLORER: Status = InitializeCreateFromFileMenu (ConfigPrivate); if (EFI_ERROR (Status)) { break; } break; default: if (QuestionId >= FILE_EXPLORER_RETRIEVE_ID) { if (UpdateRdFileExplorer (ConfigPrivate, QuestionId)) { ConfigPrivate->DisplayContext = EM_UNKNOWN_CONTEXT; UpdateRdFileExplorer (ConfigPrivate, 0); } } break; } } else if (Action == EFI_BROWSER_ACTION_CHANGED) { switch (QuestionId) { case MAIN_REMOVE_RD_QUESTION_ID: // // Remove the selected RAM disks // EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mRegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); if (PrivateData->CheckBoxChecked) { mRamDiskProtocol->Unregister( (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath ); } } UpdateMainForm (ConfigPrivate); *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; break; case CREATE_RAW_SIZE_QUESTION_ID: ConfigPrivate->ConfigStore.Size = Value->u64; break; case CREATE_RAW_MEMORY_TYPE_QUESTION_ID: ConfigPrivate->ConfigStore.MemType = Value->u8; break; case CREATE_RAW_SUBMIT_QUESTION_ID: // // Create raw, FileHandle is NULL. // Status = HiiCreateRamDisk ( ConfigPrivate->ConfigStore.Size, NULL, ConfigPrivate->ConfigStore.MemType ); 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: // // QuestionIds for checkboxes // if ((QuestionId >= MAIN_CHECKBOX_QUESTION_ID_START) && (QuestionId < CREATE_RAW_RAM_DISK_FORM_ID)) { EFI_LIST_FOR_EACH (Entry, &mRegisteredRamDisks) { PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); if (PrivateData->CheckBoxId == QuestionId) { PrivateData->CheckBoxChecked = (BOOLEAN) (Value->u8 != 0); } } } break; } } return EFI_SUCCESS; }