/** @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/Cpu.h>

EFI_GUID gEfiCpuArchProtocolGuid = 
                { 0x26BACCB1, 0x6F42, 0x11D4, 
                        { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};
                        
extern EFI_BOOT_SERVICES         *gBS;

/***
  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_CPU_ARCH_PROTOCOL  *Cpu;
  UINT64                 TimerValue;
  UINT64                 StartTimerValue;  
  UINT64                 EndTimerValue;  
  UINT64                 TimerPerioid;
  EFI_STATUS             Status;
  UINT64                 tmp;
  
  //
  // Locate the Cpu Arch Protocol.
  //
  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, &Cpu);
  if (EFI_ERROR (Status)) {
    Print(L"Can't find EFI_CPU_ARCH_PROTOCOL\n");
    return Status;
  }

  //Get some base information
  Cpu->GetTimerValue(
        Cpu,
        0, //There is only one timer in system
        &TimerValue,
        &TimerPerioid
  );
  
  //Usually there is only one timer in this protocol
  Print(L"NumberOfTimers: %d\n",Cpu->NumberOfTimers);  
  //The unite of one timer ,femtoseconds 10^(-15)s
  Print(L"Timer period  : %ld\n",TimerPerioid);
  
  //Make a simple test here, delay 1 second
  //And check how long it is in the timer
  Print(L"Timer Test Start delay 1s\n");
  Cpu->GetTimerValue(
                Cpu,
                0, //There is only one timer in system
                &StartTimerValue,
                &TimerPerioid
        );  
  Print(L"   Start at: %ld\n",StartTimerValue);
  gBS->Stall(1000000UL);
  Cpu->GetTimerValue(
                Cpu,
                0, //There is only one timer in system
                &EndTimerValue,
                &TimerPerioid
        );  
  Print(L"     End at: %ld\n",EndTimerValue);
  tmp = MultU64x64(EndTimerValue-StartTimerValue,TimerPerioid);
  tmp = DivU64x32 (tmp,1000000000UL);
  Print(L"    Elapsed: %ld us\n",tmp);
  
  return 0;
}
