/** @file
    A simple, basic, application showing how the Hello application could be
    built using the "Standard C Libraries" from StdLib.

    Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
    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.

    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 <Library/BaseLib.h>
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/ShellCEntryLib.h>

#include <Protocol/RamDisk.h>

#include <Protocol/DevicePathToText.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

extern EFI_BOOT_SERVICES         *gBS;

/*
EFI_GUID gEfiVirtualDiskGuid = 
           { 0x77AB535A, 0x45FC, 0x624B, 
                {0x55, 0x60, 0xF7, 0xB2, 0x81, 0xD1, 0xF9, 0x6E }};
   */             
/***
  Demonstrates basic workings of the main() function by displaying a
  welcoming message.

  Note that the UEFI command line is composed of 16-bit UCS2 wide characters.
  The easiest way to access the command line parameters is to cast Argv as:
      wchar_t **wArgv = (wchar_t **)Argv;

  @param[in]  Argc    Number of argument tokens pointed to by Argv.
  @param[in]  Argv    Array of Argc pointers to command line tokens.

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
int
main (
  IN int Argc,
  IN char **Argv
  )
{
        EFI_STATUS               Status;
        EFI_RAM_DISK_PROTOCOL    *MyRamDisk;
        UINT64                   *StartingAddr;
        EFI_DEVICE_PATH_PROTOCOL *DevicePath;
        EFI_FILE_HANDLE          FileHandle;
        EFI_FILE_INFO            *FileInfo;  
        UINTN                    ReadSize; 
  
  // Look for Ram Disk Protocol
        Status = gBS->LocateProtocol (
                        &gEfiRamDiskProtocolGuid,
                        NULL,
                        &MyRamDisk
                 );
        if (EFI_ERROR (Status)) {
            Print(L"Couldn't find RamDiskProtocol\n");
            return EFI_ALREADY_STARTED;
        }

  //Open one Image and load it to the memory
        //Open the file given by the parameter
        Status = ShellOpenFileByName(
                        L"MemTest.IMG", 
                        (SHELL_FILE_HANDLE *)&FileHandle,
                        EFI_FILE_MODE_READ, 
                        0);
        if(EFI_ERROR (Status)) {
                Print(L"OpenFile failed! Error=[%r]\n",Status);
                return EFI_SUCCESS;
        }                                                        
  
        //Get file size
        FileInfo = ShellGetFileInfo((SHELL_FILE_HANDLE)FileHandle);    
        
        //Allocate a memory for Image
        Status = gBS->AllocatePool (
                    EfiReservedMemoryType,
                    (UINTN)FileInfo-> FileSize,
                    (VOID**)&StartingAddr
                    ); 
        if(EFI_ERROR (Status)) {
                Print(L"Allocate Memory failed!\n");
                return EFI_SUCCESS;
        } 
        
        //Load the whole file to the buffer
        Status = ShellReadFile(FileHandle,&ReadSize,StartingAddr);
        if(EFI_ERROR (Status)) {
                Print(L"Read file failed!\n");
                return EFI_SUCCESS;
        } 
        
        //
        // Register the newly created RAM disk.
        //
        Status = MyRamDisk->Register (
             ((UINT64)(UINTN) StartingAddr),
             FileInfo-> FileSize,
             &gEfiVirtualDiskGuid,
             NULL,
             &DevicePath
             );
        if (EFI_ERROR (Status)) {
                Print(L"Can't create RAM Disk!\n");
                return EFI_SUCCESS;
        }

        //Show RamDisk DevicePath
        {
                EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* Device2TextProtocol;
                CHAR16*                           TextDevicePath = 0;
                Status = gBS->LocateProtocol(
                             &gEfiDevicePathToTextProtocolGuid,
                             NULL,
                             (VOID**)&Device2TextProtocol
                        );  
                TextDevicePath = 
                        Device2TextProtocol->ConvertDevicePathToText(DevicePath, FALSE, TRUE); 
                Print(L"DevicePath=%s\n", TextDevicePath);
                Print(L"Disk Size =%d Bytes\n", FileInfo-> FileSize);
                if(TextDevicePath)gBS->FreePool(TextDevicePath);
        }      
  
  Print(L"Creat Ram Disk success!\n");
  return 0;
}
