blob: cb64907f8fd309ca9983e7efe4e4c1b9ffdf6bba [file] [log] [blame]
/*
* Copyright (c) 1999, 2000
* Intel Corporation.
* All rights reserved.
* Copyright (c) Huawei Technologies Co., Ltd. 2013. 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 <Uefi.h>
#include <Protocol/BlockIo.h>
#include <Protocol/LoadedImage.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DevicePathLib.h>
#include "./ramdisk.h"
#define DEFAULT_DISK_SIZE 30 /* in MBs */
UINT32 GetDiskSize( EFI_HANDLE ImageHandle );
/* Embedded version string for VERS utility */
//static char v[] = "version_number=1.00 ";
/* EFI device path definition */
static RAM_DISK_DEVICE_PATH RamDiskDevicePath =
{
{
MESSAGING_DEVICE_PATH,
MSG_VENDOR_DP,
{
sizeof(RAM_DISK_DEVICE_PATH) - END_DEVICE_PATH_LENGTH,
0
},
},
// {06ED4DD0-FF78-11d3-BDC4-00A0C94053D1}
{
0x6ed4dd0, 0xff78, 0x11d3,
{0xbd, 0xc4, 0x0, 0xa0, 0xc9, 0x40, 0x53, 0xd1},
},
{0,0,0,0,0,0,0,0}, // ID assigned below
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
END_DEVICE_PATH_LENGTH,
0
},
},
};
/* Lookup table of total sectors vs. cluster size.
* Ramdisk sizes between 0x20D0 (4.1MB) and 0x100000 (512MB) sectors are valid FAT16 drive sizes.
*/
/* #define MIN_DISK_SIZE 5 */
#define MIN_DISK_SIZE 1
#define MAX_DISK_SIZE 512
static FAT16TABLE fat16tbl[] =
{
/* {0x000020D0, 0}, */
{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}
};
VOID CopyBOOTSEC(VOID* Start,BOOTSEC* bsc)
{
UINT32 index=0;
UINT8* pStart=(UINT8*)Start;
CopyMem(&(pStart[index]), &(bsc->BS_jmpBoot[0]), sizeof(bsc->BS_jmpBoot));
index+=sizeof(bsc->BS_jmpBoot);
CopyMem(&(pStart[index]), &(bsc->BS_OEMName[0]), sizeof(bsc->BS_OEMName));
index+=sizeof(bsc->BS_OEMName);
CopyMem(&(pStart[index]), &(bsc->BPB_BytsPerSec), sizeof(bsc->BPB_BytsPerSec));
index+=sizeof(bsc->BPB_BytsPerSec);
CopyMem(&(pStart[index]), &(bsc->BPB_SecPerClus), sizeof(bsc->BPB_SecPerClus));
index+=sizeof(bsc->BPB_SecPerClus);
CopyMem(&(pStart[index]), &(bsc->BPB_RsvdSecCnt), sizeof(bsc->BPB_RsvdSecCnt));
index+=sizeof(bsc->BPB_RsvdSecCnt);
CopyMem(&(pStart[index]), &(bsc->BPB_NumFATs), sizeof(bsc->BPB_NumFATs));
index+=sizeof(bsc->BPB_NumFATs);
CopyMem(&(pStart[index]), &(bsc->BPB_NumFATs), sizeof(bsc->BPB_NumFATs));
index+=sizeof(bsc->BPB_NumFATs);
CopyMem(&(pStart[index]), &(bsc->BPB_RootEntCnt), sizeof(bsc->BPB_RootEntCnt));
index+=sizeof(bsc->BPB_RootEntCnt);
CopyMem(&(pStart[index]), &(bsc->BPB_TotSec16), sizeof(bsc->BPB_TotSec16));
index+=sizeof(bsc->BPB_TotSec16);
CopyMem(&(pStart[index]), &(bsc->BPB_Media), sizeof(bsc->BPB_Media));
index+=sizeof(bsc->BPB_Media);
CopyMem(&(pStart[index]), &(bsc->BPB_FATSz16), sizeof(bsc->BPB_FATSz16));
index+=sizeof(bsc->BPB_FATSz16);
CopyMem(&(pStart[index]), &(bsc->BPB_SecPerTrk), sizeof(bsc->BPB_SecPerTrk));
index+=sizeof(bsc->BPB_SecPerTrk);
CopyMem(&(pStart[index]), &(bsc->BPB_NumHeads), sizeof(bsc->BPB_NumHeads));
index+=sizeof(bsc->BPB_NumHeads);
CopyMem(&(pStart[index]), &(bsc->BPB_HiddSec), sizeof(bsc->BPB_HiddSec));
index+=sizeof(bsc->BPB_HiddSec);
CopyMem(&(pStart[index]), &(bsc->BPB_TotSec32), sizeof(bsc->BPB_TotSec32));
index+=sizeof(bsc->BPB_TotSec32);
CopyMem(&(pStart[index]), &(bsc->BS_DrvNum), sizeof(bsc->BS_DrvNum));
index+=sizeof(bsc->BS_DrvNum);
CopyMem(&(pStart[index]), &(bsc->BS_Reserved1), sizeof(bsc->BS_Reserved1));
index+=sizeof(bsc->BS_Reserved1);
CopyMem(&(pStart[index]), &(bsc->BS_BootSig), sizeof(bsc->BS_BootSig));
index+=sizeof(bsc->BS_BootSig);
CopyMem(&(pStart[index]), &(bsc->BS_VolID), sizeof(bsc->BS_VolID));
index+=sizeof(bsc->BS_VolID);
CopyMem(&(pStart[index]), &(bsc->BS_VolLab[0]), sizeof(bsc->BS_VolLab));
index+=sizeof(bsc->BS_VolLab);
CopyMem(&(pStart[index]), &(bsc->BS_FilSysType[0]), sizeof(bsc->BS_FilSysType));
index+=sizeof(bsc->BS_FilSysType);
CopyMem(&(pStart[index]), &(bsc->BS_Code[0]), sizeof(bsc->BS_Code));
index+=sizeof(bsc->BS_Code);
CopyMem(&(pStart[index]), &(bsc->BS_Sig), sizeof(bsc->BS_Sig));
}
/*++
Routine Description:
Convert hex string to uint
Arguments:
Str - The string
Returns:
--*/
STATIC UINTN Atoi ( CHAR16 *str)
{
UINTN u;
CHAR16 c;
UINTN m;
UINTN n;
ASSERT (str != NULL);
m = (UINTN) -1 / 10;
n = (UINTN) -1 % 10;
//
// skip preceeding white space
//
while (*str && (*str == ' '))
{
str += 1;
}
//
// convert digits
//
u = 0;
c = *(str++);
while (c)
{
if ((c >= '0') && (c <= '9'))
{
if ((u >= m) && ((c - '0') > (INTN) n))
{
return (UINTN) -1;
}
u = (u * 10) + c - '0';
}
else
{
break;
}
c = *(str++);
}
return u;
}
/* Helper function to compute cluster size
* vs. total sectors on drive.
*/
STATIC UINT8 size2spc(UINT32 ts)
{
int i = 0;
while(fat16tbl[i].size != 0xFFFFFFFF)
{
if(ts <= fat16tbl[i].size)
return fat16tbl[i].spc;
++i;
}
return 0;
}
UINT8 TestSize(UINT32 ts)
{
int i = 0;
while(fat16tbl[i].size != 0xFFFFFFFF)
{
if(ts <= fat16tbl[i].size)
return fat16tbl[i].spc;
++i;
}
return 0;
}
EFI_SYSTEM_TABLE BackupSystemTable;
/*
* Entry point for RamDisk driver.
*/
EFI_STATUS InitializeRamDiskDriver(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS Status;
RAM_DISK_DEV *RamDiskDev;
UINT32 RamDiskSize;
UINT32 NumPages;
UINT32 BlockSize;
UINT64 DiskId;
/*
* Make a copy of the system table to workaround load command bug
*/
CopyMem(&BackupSystemTable,SystemTable,sizeof(BackupSystemTable));
/*
* Initialize EFI library
*/
//InitializeLib(ImageHandle,&BackupSystemTable);
/* IA64 compiler is removing version string (unused?) so I use it */
//v[0] = 'v';
/*
* Set the disk size
*/
RamDiskSize = GetDiskSize(ImageHandle);
BlockSize = 512;
/* Allocate storage for ramdisk device info on the heap.
*/
RamDiskDev = AllocateZeroPool(sizeof(RAM_DISK_DEV));
if(RamDiskDev == NULL)
return EFI_OUT_OF_RESOURCES;
/*
* Compute the number of 4KB pages needed by the ramdisk 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 ramdisk's device info.
*/
(void)gBS->GetNextMonotonicCount(&DiskId);
CopyMem(&RamDiskDevicePath.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 = 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*)&RamDiskDevicePath);
/*
* Build a FAT16 file system on the ramdisk.
*/
FormatRamdisk((VOID*)(UINTN)RamDiskDev->Start,RamDiskSize);
/*
* Install the device.
*/
Status = gBS->InstallMultipleProtocolInterfaces(
&ImageHandle,
&gEfiBlockIoProtocolGuid,
&RamDiskDev->BlkIo,
&gEfiDevicePathProtocolGuid,
RamDiskDev->DevicePath,
NULL);
DEBUG((EFI_D_ERROR,"ramdisk:blckio install. Status=%r\n",Status));
return Status;
}
UINT32
GetDiskSize( EFI_HANDLE ImageHandle )
{
EFI_STATUS Status;
EFI_LOADED_IMAGE *Image;
UINT32 DiskSize = DEFAULT_DISK_SIZE;
/*
* Check load options to see if they want to specify disk size in MBs
*/
Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&Image);
if (!EFI_ERROR(Status)) {
if (Image->LoadOptions && Image->LoadOptionsSize) {
#define MAX_ARG_SIZE 32
CHAR16 Size[ MAX_ARG_SIZE ];
CHAR16 *CmdLine = Image->LoadOptions;
INT32 CmdLen = (INT32)Image->LoadOptionsSize;
/*
* Get past program name
*/
while( CmdLen > 0 && *CmdLine != L' ' ) {
CmdLen -= sizeof(CHAR16);
CmdLine++;
}
if ( CmdLen > 0 ) {
/*
* Make sure we're null terminated
*/
CopyMem( Size, CmdLine, MIN(CmdLen, sizeof(Size)));
Size[MAX_ARG_SIZE - 1] = 0;
/*
* Atoi() will skip any leading white space
*/
DiskSize = (UINT32)Atoi(Size);
if (DiskSize == 0)
DiskSize = DEFAULT_DISK_SIZE;
DiskSize = MAX(DiskSize, MIN_DISK_SIZE);
DiskSize = MIN(DiskSize, MAX_DISK_SIZE);
}
}
}
return (DiskSize * 1024 * 1024);
}
/* Given a block of memory representing a ramdisk, 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 ramdisk size
* is between 4.1MB and 512MB as appropriate for FAT16 file system.
*/
STATIC VOID FormatRamdisk(
IN VOID* pStart,
IN UINT32 Size)
{
UINT32 TotalSectors,RootDirSectors,FatSz,tmp1,tmp2;
UINT8 *Fat1,*Fat2;
BOOTSEC g_bs={
/* BS_jmpBoot */ {0xeb,0x0,0x90},
/* BS_OEMName */ {'E','F','I','R','D','I','S','K'},
/* BPB_BytsPerSec */ 512,
/* BPB_SecPerClus */ 0,
/* BPB_RsvdSecCnt */ 1,
/* BPB_NumFATs */ 2,
/* BPB_RootEntCnt */ 512,
/* BPB_TotSec16 */ 0,
/* BPB_Media */ 0xF8,
/* BPB_FATSz16 */ 0,
/* BPB_SecPerTrk */ 0,
/* BPB_NumHeads */ 0,
/* BPB_HiddSec */ 0,
/* BPB_TotSec32 */ 0,
/* BS_DrvNum */ 0,
/* BS_Reserved1 */ 0,
/* BS_BootSig */ 0x29,
/* BS_VolID */ 0,
/* BS_VolLab */ {'N','O',' ','N','A','M','E',' ',' ',' '},
/* BS_FilSysType */ {'F','A','T','1','6',' ',' ',' '}
};
/* 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);
ASSERT(g_bs.BPB_SecPerClus != 0);
/* 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;
ASSERT(FatSz <= 0xFFFF);
/* 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 ramdisk */
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;
}
/* Implementation of block I/O read */
STATIC EFI_STATUS RamDiskReadBlocks(
IN EFI_BLOCK_IO *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*)(UINTN)RamDiskLBA,BufferSize);
return EFI_SUCCESS;
}
/* Implementation of block I/O write */
STATIC EFI_STATUS RamDiskWriteBlocks(
IN EFI_BLOCK_IO *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*)(UINTN)RamDiskLBA,Buffer,BufferSize);
return EFI_SUCCESS;
}
/* Implementation of block I/O flush */
STATIC EFI_STATUS RamDiskFlushBlocks(
IN EFI_BLOCK_IO *This)
{
return EFI_SUCCESS;
}