833 lines
24 KiB
C
833 lines
24 KiB
C
/** @file
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2015 - 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.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
/*
|
|
* Copyright (c) 1999, 2000
|
|
* Intel Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. All advertising materials mentioning features or use of this software must
|
|
* display the following acknowledgement:
|
|
*
|
|
* This product includes software developed by Intel Corporation and its
|
|
* contributors.
|
|
*
|
|
* 4. Neither the name of Intel Corporation or its contributors may be used to
|
|
* endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#include "RamDisk.h"
|
|
#include "FileExplorer.h"
|
|
#include "RamDiskImpl.h"
|
|
#include <Library/PcdLib.h>
|
|
|
|
extern STRING_DEPOSITORY *mRamDiskFileOptionStrDepository;
|
|
extern ENROLL_MENU_OPTION mRamDiskFsOptionMenu;
|
|
extern ENROLL_MENU_OPTION mRamDiskDirectoryMenu;
|
|
|
|
|
|
EFI_RAM_DISK_PROTOCOL *mRamDiskProtocol;
|
|
EFI_RAM_DISK_REGISTER_RAMDISK mRegisterRamDisk;
|
|
EFI_RAM_DISK_UNREGISTER_RAMDISK mUnregisterRamDisk;
|
|
|
|
//
|
|
// RamDiskDxe driver maintains a list of registered RAM disks.
|
|
//
|
|
LIST_ENTRY mRegisteredRamDisks;
|
|
|
|
LIST_ENTRY mRamDiskDeviceList;
|
|
UINT32 mRamDiskDeviceLNum;
|
|
H2O_DIALOG_PROTOCOL *mH2ODialog;
|
|
|
|
//
|
|
// EFI device path definition
|
|
//
|
|
H2O_RAM_DISK_DEVICE_PATH mH2ORamDiskDevicePath =
|
|
{
|
|
MESSAGING_DEVICE_PATH,
|
|
MSG_VENDOR_DP,
|
|
sizeof (H2O_RAM_DISK_DEVICE_PATH) - END_DEVICE_PATH_LENGTH,
|
|
0,
|
|
H2O_RAM_DISK_GUID,
|
|
0,0,0,0,0,0,0,0, // ID assigned below
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
END_DEVICE_PATH_LENGTH
|
|
};
|
|
|
|
|
|
/**
|
|
Lookup table of total sectors vs. cluster size.
|
|
RAM Disk sizes between 0x20D0 (4.1MB) and 0x100000 (512MB) sectors are valid FAT16 drive sizes.
|
|
**/
|
|
STATIC
|
|
FAT16TABLE fat16tbl[] =
|
|
{
|
|
{0x00000800, 1}, // 800 sectors * 1 sec/cluster * 512 bytes = 1 M
|
|
{0x00001000, 1}, // 1000 sectors * 1 sec/cluster * 512 bytes = 2 M
|
|
{0x00001800, 1}, // 1800 sectors * 1 sec/cluster * 512 bytes = 3 M
|
|
{0x00007FA8, 2},
|
|
{0x00040000, 4},
|
|
{0x00080000, 8},
|
|
{0x00100000,16},
|
|
{0xFFFFFFFF, 0}
|
|
};
|
|
|
|
/**
|
|
RAM pseudo-boot sector. No code.
|
|
Needs BS_Sig, BPB_SecPerClus, BPB_TotSec32, g_bs.BPB_TotSec16,
|
|
and BPB_FATSz16 filled out properly by FormatRamdisk().
|
|
**/
|
|
STATIC
|
|
BOOTSEC g_bs =
|
|
{
|
|
{0xeb,0x0,0x90}, // BS_jmpBoot
|
|
{'E','F','I','R','D','I','S','K'}, // BS_OEMName
|
|
512, // BPB_BytsPerSec
|
|
0, // BPB_SecPerClus
|
|
1, // BPB_RsvdSecCnt
|
|
2, // BPB_NumFATs
|
|
512, // BPB_RootEntCnt
|
|
0, // BPB_TotSec16
|
|
0xF8, // BPB_Media
|
|
0, // BPB_FATSz16
|
|
0, // BPB_SecPerTrk
|
|
0, // BPB_NumHeads
|
|
0, // BPB_HiddSec
|
|
0, // BPB_TotSec32
|
|
0, // BS_DrvNum
|
|
0, // BS_Reserved1
|
|
0x29, // BS_BootSig
|
|
0, // BS_VolID
|
|
{'N','O',' ','N','A','M','E',' ',' ',' '}, // BS_VolLab
|
|
{'F','A','T','1','6',' ',' ',' '} // BS_FilSysType
|
|
};
|
|
|
|
H2O_RAM_DISK_SERVICES_PROTOCOL *mH2ORamDiskServicesProtocol;
|
|
|
|
/**
|
|
Helper function to compute cluster size vs. total sectors on drive.
|
|
|
|
@param[in] ts total sectors.
|
|
|
|
@retval value The number of sectors per cluster.
|
|
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
size2spc (
|
|
IN UINT32 ts
|
|
)
|
|
{
|
|
int i = 0;
|
|
|
|
while (fat16tbl[i].size != 0xFFFFFFFF)
|
|
{
|
|
if(ts <= fat16tbl[i].size) {
|
|
return fat16tbl[i].spc;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
Check required RAM Disk size, if size equal ZERO, will use default size.
|
|
If required RAM Disk size less then minimal support size, or large then maxmal
|
|
support size, return the minmal/maxmal size.
|
|
|
|
@param[in] RamdiskSize Required RAM Disk size.
|
|
|
|
@retval value The created RAM Disk size (MB).
|
|
|
|
**/
|
|
UINT32
|
|
GetDiskSize (
|
|
IN UINT32 RamDiskSize
|
|
)
|
|
{
|
|
if (RamDiskSize == 0) {
|
|
RamDiskSize = PcdGet32(PcdH2ORamDiskSize);
|
|
}
|
|
|
|
RamDiskSize = MAX(RamDiskSize, MIN_DISK_SIZE);
|
|
RamDiskSize = MIN(RamDiskSize, MAX_DISK_SIZE);
|
|
|
|
return (RamDiskSize * 1024 * 1024);
|
|
}
|
|
|
|
/**
|
|
Given a block of memory representing a RAM Disk, build a pseudo-boot sector
|
|
and initialize the drive.
|
|
|
|
Assumes the global boot sector structure g_bs has been filled out with the
|
|
static information the boot sector requires. Also assumes the RAM Disk size
|
|
is between 4.1MB and 512MB as appropriate for FAT16 file system.
|
|
|
|
@param[in] pStart Physical start address.
|
|
@param[in] Size RAM Disk size.
|
|
|
|
@retval EFI_SUCCESS Format RAM Disk success.
|
|
@retval EFI_BAD_BUFFER_SIZE Required RAM Disk size not support.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
FormatRamDisk (
|
|
IN VOID* pStart,
|
|
IN UINT32 Size
|
|
)
|
|
{
|
|
UINT32 TotalSectors,RootDirSectors,FatSz,tmp1,tmp2;
|
|
UINT8 *Fat1,*Fat2;
|
|
|
|
// The boot signature needs to be filled out
|
|
g_bs.BS_Sig = 0xAA55;
|
|
|
|
// Compute the total sectors and appropriate cluster size
|
|
TotalSectors = Size / g_bs.BPB_BytsPerSec;
|
|
g_bs.BPB_SecPerClus = size2spc (TotalSectors);
|
|
if (g_bs.BPB_SecPerClus == 0) {
|
|
DEBUG((EFI_D_ERROR, "RamDiskDxe: Sector per cluster not support\n"));
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
// Compute how many root directory sectors are needed
|
|
RootDirSectors = (g_bs.BPB_RootEntCnt * 32 + g_bs.BPB_BytsPerSec - 1) / g_bs.BPB_BytsPerSec;
|
|
|
|
// Compute how many sectors are required per FAT
|
|
tmp1 = TotalSectors - (g_bs.BPB_RsvdSecCnt + RootDirSectors);
|
|
tmp2 = 256 * g_bs.BPB_SecPerClus + g_bs.BPB_NumFATs;
|
|
FatSz = (tmp1 + tmp2 - 1) / tmp2;
|
|
if (FatSz > 0xFFFF) {
|
|
DEBUG ((EFI_D_ERROR, "RamDiskDxe: Sectors required per FAT not support\n"));
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
// Store the total sectors and fat size values
|
|
if (TotalSectors > 0xFFFF) {
|
|
g_bs.BPB_TotSec32 = TotalSectors;
|
|
} else {
|
|
g_bs.BPB_TotSec16 = (UINT16)TotalSectors;
|
|
}
|
|
|
|
g_bs.BPB_FATSz16 = (UINT16)FatSz;
|
|
|
|
//
|
|
//The FAT table and root directory need to be all zeroes.
|
|
//We'll zero the whole drive.
|
|
//
|
|
ZeroMem (pStart,Size);
|
|
|
|
// Write the completed boot sector to the RAM Disk
|
|
CopyMem (pStart,&g_bs,512);
|
|
|
|
// Compute the starting offsets of the two FATs
|
|
Fat1 = (UINT8*)pStart + g_bs.BPB_RsvdSecCnt * 512;
|
|
Fat2 = (UINT8*)pStart + (g_bs.BPB_RsvdSecCnt + FatSz) * 512;
|
|
|
|
// Initialize FAT1
|
|
Fat1[0] = g_bs.BPB_Media;
|
|
Fat1[1] = 0xFF;
|
|
Fat1[2] = 0xFF;
|
|
Fat1[3] = 0xFF;
|
|
|
|
// Initialize FAT2
|
|
Fat2[0] = g_bs.BPB_Media;
|
|
Fat2[1] = 0xFF;
|
|
Fat2[2] = 0xFF;
|
|
Fat2[3] = 0xFF;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Implementation of block I/O read.
|
|
|
|
@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
|
|
RamDiskReadBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA LBA,
|
|
IN UINTN BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
|
RAM_DISK_DEV *RamDiskDev;
|
|
EFI_PHYSICAL_ADDRESS RamDiskLBA;
|
|
|
|
Media = This->Media;
|
|
|
|
if (BufferSize % Media->BlockSize != 0) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
if (LBA > Media->LastBlock) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
RamDiskDev = RAM_DISK_FROM_THIS(This);
|
|
RamDiskLBA = RamDiskDev->Start + MultU64x32 (LBA, Media->BlockSize);
|
|
CopyMem (Buffer, (VOID*)RamDiskLBA, BufferSize);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Implementation of block I/O write
|
|
|
|
@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
|
|
RamDiskWriteBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA LBA,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
|
RAM_DISK_DEV *RamDiskDev;
|
|
EFI_PHYSICAL_ADDRESS RamDiskLBA;
|
|
|
|
Media = This->Media;
|
|
if (Media->ReadOnly) {
|
|
return EFI_WRITE_PROTECTED;
|
|
}
|
|
|
|
if (BufferSize % Media->BlockSize != 0) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
if (LBA > Media->LastBlock) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
RamDiskDev = RAM_DISK_FROM_THIS(This);
|
|
RamDiskLBA = RamDiskDev->Start + MultU64x32 (LBA, Media->BlockSize);
|
|
CopyMem ((VOID*)RamDiskLBA, Buffer, BufferSize);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Implementation of block I/O flush
|
|
|
|
@param[in] This Indicates the EFI_BLOCK_IO instance.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RamDiskFlushBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
)
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
To create a new RAM Disk.
|
|
|
|
@param[in] Size The size for new RAM Disk.
|
|
@param[in] Removable If TRUE, then new created RAM Disk could be remove.
|
|
@param[out] RamDiskId The DiskId for new RAM Disk.
|
|
|
|
@retval EFI_SUCCESS Create new RAM Disk successfully.
|
|
@retval other Some error occurred when executing function.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateRamDisk (
|
|
IN UINT32 Size,
|
|
IN BOOLEAN Removable,
|
|
OUT UINT64 *RamDiskId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 DiskId;
|
|
UINT32 NumPages;
|
|
UINT32 BlockSize;
|
|
UINT32 RamDiskSize;
|
|
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;
|
|
}
|
|
|
|
RamDiskSize = GetDiskSize (Size);
|
|
|
|
BlockSize = 512;
|
|
|
|
//
|
|
// Compute the number of 4KB pages needed by the RAM Disk and allocate the memory.
|
|
//
|
|
NumPages = RamDiskSize / EFI_PAGE_SIZE;
|
|
if (NumPages % RamDiskSize) {
|
|
NumPages++;
|
|
}
|
|
|
|
Status = gBS->AllocatePages (
|
|
AllocateAnyPages,
|
|
EfiBootServicesData,
|
|
NumPages,
|
|
&RamDiskDev->Start
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
FreePool (RamDiskDev);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Initialize the RAM Disk's device info.
|
|
//
|
|
Status = gBS->GetNextMonotonicCount (&DiskId);
|
|
CopyMem (&mH2ORamDiskDevicePath.DiskId, &DiskId, sizeof(DiskId));
|
|
CopyMem (RamDiskId, &DiskId, sizeof(DiskId));
|
|
|
|
RamDiskDev->Signature = PBLOCK_DEVICE_SIGNATURE;
|
|
RamDiskDev->BlkIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION;
|
|
RamDiskDev->BlkIo.Media = &RamDiskDev->Media;
|
|
RamDiskDev->Media.RemovableMedia = (Removable ? TRUE : FALSE);
|
|
RamDiskDev->Media.MediaPresent = TRUE;
|
|
|
|
RamDiskDev->Media.LastBlock = RamDiskSize / 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);
|
|
|
|
//
|
|
// Build a FAT16 file system on the RAM Disk.
|
|
//
|
|
Status = FormatRamDisk ((VOID*)RamDiskDev->Start,RamDiskSize);
|
|
if (EFI_ERROR(Status)) {
|
|
if (&RamDiskDev->Start != NULL) {
|
|
FreePool (&RamDiskDev->Start);
|
|
}
|
|
if (RamDiskDev->DevicePath != NULL) {
|
|
FreePool (RamDiskDev->DevicePath);
|
|
}
|
|
FreePool (RamDiskDev);
|
|
return Status;
|
|
}
|
|
|
|
Status = mRamDiskProtocol->Register(
|
|
(UINT64)RamDiskDev->Start,
|
|
RamDiskSize,
|
|
&gEfiVirtualDiskGuid,
|
|
RamDiskDev->DevicePath,
|
|
&RamDiskDev->DevicePath
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
if (&RamDiskDev->Start != NULL) {
|
|
FreePool (&RamDiskDev->Start);
|
|
}
|
|
if (RamDiskDev->DevicePath != NULL) {
|
|
FreePool (RamDiskDev->DevicePath);
|
|
}
|
|
FreePool (RamDiskDev);
|
|
return Status;
|
|
}
|
|
|
|
InsertTailList (&mRamDiskDeviceList, &RamDiskDev->Link);
|
|
mRamDiskDeviceLNum += 1;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
To remove a specified RAM Disk selected by DiskId.
|
|
|
|
@param[in] RamDiskId The RAM Disk with the same DiskId will be removed.
|
|
|
|
@retval EFI_SUCCESS Remove successfully.
|
|
@retval other Some error occurred when executing function.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RemoveRamDisk (
|
|
IN UINT64 RamDiskId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *Link;
|
|
RAM_DISK_DEV *RamDiskDev = NULL;
|
|
BOOLEAN RamDiskFound;
|
|
|
|
RamDiskFound = FALSE;
|
|
Status = EFI_SUCCESS;
|
|
|
|
if (mRamDiskDeviceLNum == 0) {
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
for (Link = mRamDiskDeviceList.ForwardLink; Link != &mRamDiskDeviceList; Link = Link->ForwardLink) {
|
|
RamDiskDev = RAM_DISK_FROM_LINK (Link);
|
|
if (RamDiskDev != NULL) {
|
|
if (CompareMem (&(((H2O_RAM_DISK_DEVICE_PATH*) RamDiskDev->DevicePath)->DiskId), &RamDiskId, sizeof(UINT64)) == 0) {
|
|
RamDiskFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RamDiskFound) {
|
|
if (RamDiskDev->Media.RemovableMedia){
|
|
RemoveEntryList (&RamDiskDev->Link);
|
|
mRamDiskDeviceLNum -= 1;
|
|
Status = mRamDiskProtocol->Unregister((VOID *)RamDiskDev->DevicePath);
|
|
if (&RamDiskDev->Start != NULL) {
|
|
FreePages(
|
|
(VOID *)RamDiskDev->Start,
|
|
EFI_SIZE_TO_PAGES((RamDiskDev->Media.LastBlock + 1) * RamDiskDev->Media.BlockSize)
|
|
);
|
|
}
|
|
if (RamDiskDev != NULL) {
|
|
FreePool (RamDiskDev);
|
|
}
|
|
} else {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
} else {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Return current RAM Disk devices counts.
|
|
|
|
@retval value Number of RAM Disk devices.
|
|
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
GetRamDiskCount (
|
|
VOID
|
|
)
|
|
{
|
|
return mRamDiskDeviceLNum;
|
|
}
|
|
|
|
/**
|
|
Return current RAM Disk device information.
|
|
|
|
@param[in] DeviceNum Number of RAM Disk device.
|
|
@param[out] DiskSize Size of the RAM Disk.
|
|
@param[out] DiskId DiskId of the RAM Disk.
|
|
@param[out] Removable If TRUE, it is a removable RAM Disk.
|
|
|
|
@retval EFI_SUCCESS Get RAM Disk information success.
|
|
@retval other Cannot find specific RAM Disk.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetRamDiskInfo (
|
|
IN UINT32 DeviceNum,
|
|
OUT UINT64 *DiskSize,
|
|
OUT UINT64 *DiskId,
|
|
OUT BOOLEAN *Removable
|
|
)
|
|
{
|
|
UINTN Index;
|
|
LIST_ENTRY *Link;
|
|
RAM_DISK_DEV *RamDiskDev = NULL;
|
|
BOOLEAN RamDiskFound;
|
|
|
|
if (DeviceNum >= mRamDiskDeviceLNum) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Index = 0;
|
|
RamDiskFound = FALSE;
|
|
for (Link = mRamDiskDeviceList.ForwardLink; Link != &mRamDiskDeviceList; Link = Link->ForwardLink) {
|
|
RamDiskDev = RAM_DISK_FROM_LINK (Link);
|
|
if (RamDiskDev != NULL) {
|
|
if (Index == DeviceNum) {
|
|
RamDiskFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
Index++;
|
|
}
|
|
|
|
if (RamDiskFound) {
|
|
*DiskSize = RamDiskDev->Media.BlockSize * (RamDiskDev->Media.LastBlock + 1);
|
|
CopyMem (DiskId, &(((H2O_RAM_DISK_DEVICE_PATH*) RamDiskDev->DevicePath)->DiskId), sizeof(UINT64));
|
|
*Removable = RamDiskDev->Media.RemovableMedia;
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
Hook RAM Disk Protocol.
|
|
|
|
@retval EFI_NOT_READY gEfiRamDiskProtocolGuid is not installed.
|
|
@retval EFI_OUT_OF_RESOURCES lack of resources.
|
|
@retval EFI_SUCCES hook successly.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HookRamDiskProtocol (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
|
|
EFI_HII_HANDLE *HiiHandles;
|
|
UINT8 Index;
|
|
|
|
//
|
|
// If already started, return.
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiRamDiskProtocolGuid,
|
|
NULL,
|
|
(VOID**)&mRamDiskProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO, "gEfiRamDiskProtocolGuid not installed!\n"));
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
//
|
|
// Create a private data structure.
|
|
//
|
|
ConfigPrivate = AllocateCopyPool (sizeof (RAM_DISK_CONFIG_PRIVATE_DATA), &mRamDiskConfigPrivateDataTemplate);
|
|
if (ConfigPrivate == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Remove existing RAM Disk HiiHandles
|
|
//
|
|
HiiHandles = HiiGetHiiHandles (&gRamDiskFormSetGuid);
|
|
if (HiiHandles != NULL){
|
|
for (Index = 0; HiiHandles[Index] != NULL; Index++) {
|
|
HiiRemovePackages (HiiHandles[Index]);
|
|
}
|
|
FreePool (HiiHandles);
|
|
}
|
|
|
|
//
|
|
// Install RAM disk configuration form
|
|
//
|
|
Status = InstallRamDiskConfigForm (ConfigPrivate);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Initialize the list of registered RAM disks maintained by the driver
|
|
//
|
|
InitializeListHead (&mRegisteredRamDisks);
|
|
|
|
//
|
|
// Hook
|
|
//
|
|
mRegisterRamDisk = mRamDiskProtocol->Register;
|
|
mUnregisterRamDisk = mRamDiskProtocol->Unregister;
|
|
|
|
mRamDiskProtocol->Register = RamDiskRegiterHook;
|
|
mRamDiskProtocol->Unregister = RamDiskUnregiterHook;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (ConfigPrivate != NULL) {
|
|
UninstallRamDiskConfigForm (ConfigPrivate);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
The Driver Entry Point.
|
|
|
|
The function is the driver Entry point which will produce H2ORamDiskServicesProtocol.
|
|
|
|
@param[in] ImageHandle A handle for the image that is initializing this driver
|
|
@param[in] SystemTable A pointer to the EFI system table
|
|
|
|
@retval EFI_SUCCESS: Driver initialized successfully
|
|
@retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded
|
|
@retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitializeRamDiskDriver(
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 *AutoCreateRamDiskList = NULL;
|
|
UINT64 DiskId = 0;
|
|
UINTN Index = 0;
|
|
|
|
mRamDiskDeviceLNum = 0;
|
|
InitializeListHead (&mRamDiskDeviceList);
|
|
|
|
Status = HookRamDiskProtocol();
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
AutoCreateRamDiskList = (UINT32*)PcdGetPtr (PcdH2ORamDiskAutoCreatedList);
|
|
if (AutoCreateRamDiskList != NULL) {
|
|
for (Index = 0; AutoCreateRamDiskList[Index] != 0; Index++) {
|
|
Status = CreateRamDisk (
|
|
AutoCreateRamDiskList[Index],
|
|
FALSE,
|
|
&DiskId
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If PcdH2ORamDiskApiSupported set to FALSE, skip producing H2O_RAM_DISK_SERVICES_PROTOCOL interface
|
|
//
|
|
if (PcdGetBool (PcdH2ORamDiskApiSupported) == FALSE){
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
mRamDiskFileOptionStrDepository = AllocateZeroPool (sizeof (STRING_DEPOSITORY));
|
|
|
|
if (mRamDiskFileOptionStrDepository == NULL){
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
InitializeListHead (&mRamDiskDirectoryMenu.Head);
|
|
InitializeListHead (&mRamDiskFsOptionMenu.Head);
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gH2ODialogProtocolGuid,
|
|
NULL,
|
|
(VOID **) &mH2ODialog
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Allocate memory for RAM Disk protocol on the heap.
|
|
//
|
|
mH2ORamDiskServicesProtocol = AllocateZeroPool (sizeof(H2O_RAM_DISK_SERVICES_PROTOCOL));
|
|
if(mH2ORamDiskServicesProtocol == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
mH2ORamDiskServicesProtocol->Create = CreateRamDisk;
|
|
mH2ORamDiskServicesProtocol->Remove = RemoveRamDisk;
|
|
mH2ORamDiskServicesProtocol->GetRamDiskCount = GetRamDiskCount;
|
|
mH2ORamDiskServicesProtocol->GetRamDiskInfo = GetRamDiskInfo;
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&ImageHandle,
|
|
&gH2ORamDiskServicesProtocolGuid,
|
|
mH2ORamDiskServicesProtocol,
|
|
NULL
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
|