UINT16 Checksum;\r
UINT16 Identifier;\r
UINT16 SequenceNum;\r
- UINT64 TimeStamp;\r
+ UINT32 TimeStamp;\r
UINT8 Data[1];\r
} ICMPX_ECHO_REQUEST_REPLY;\r
#pragma pack()\r
typedef struct _PING_ICMP_TX_INFO {\r
LIST_ENTRY Link;\r
UINT16 SequenceNum;\r
- UINT64 TimeStamp;\r
+ UINT32 TimeStamp;\r
PING_IPX_COMPLETION_TOKEN *Token;\r
} PING_ICMPX_TX_INFO;\r
\r
#define DEFAULT_BUFFER_SIZE 16\r
#define ICMP_V4_ECHO_REQUEST 0x8\r
#define ICMP_V4_ECHO_REPLY 0x0\r
+#define STALL_1_MILLI_SECOND 1000\r
\r
#define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')\r
typedef struct _PING_PRIVATE_DATA {\r
EFI_HANDLE IpChildHandle;\r
EFI_EVENT Timer;\r
\r
+ UINT32 TimerPeriod;\r
+ UINT32 RttTimerTick; \r
+ EFI_EVENT RttTimer;\r
+\r
EFI_STATUS Status;\r
LIST_ENTRY TxList;\r
UINT16 RxCount;\r
//\r
STATIC CONST CHAR16 *mDstString;\r
STATIC CONST CHAR16 *mSrcString;\r
-STATIC UINT64 mFrequency = 0;\r
-EFI_CPU_ARCH_PROTOCOL *gCpu = NULL;\r
\r
/**\r
- Read the current time.\r
+ RTT timer tick routine.\r
+\r
+ @param[in] Event A EFI_EVENT type event.\r
+ @param[in] Context The pointer to Context.\r
\r
- @retval the current tick value.\r
**/\r
-UINT64\r
-ReadTime (\r
+VOID\r
+EFIAPI\r
+RttTimerTickRoutine (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UINT32 *RttTimerTick;\r
+\r
+ RttTimerTick = (UINT32*) Context;\r
+ (*RttTimerTick)++;\r
+}\r
+\r
+/**\r
+ Get the timer period of the system.\r
+\r
+ This function tries to get the system timer period by creating\r
+ an 1ms period timer.\r
+\r
+ @return System timer period in MS, or 0 if operation failed.\r
+\r
+**/\r
+UINT32\r
+GetTimerPeriod(\r
VOID\r
)\r
{\r
- UINT64 TimerPeriod;\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
+ UINT32 RttTimerTick;\r
+ EFI_EVENT TimerEvent;\r
+ UINT32 StallCounter;\r
+ EFI_TPL OldTpl;\r
\r
- ASSERT (gCpu != NULL);\r
+ RttTimerTick = 0;\r
+ StallCounter = 0;\r
\r
- Status = gCpu->GetTimerValue (gCpu, 0, &mCurrentTick, &TimerPeriod);\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ RttTimerTickRoutine,\r
+ &RttTimerTick,\r
+ &TimerEvent\r
+ );\r
if (EFI_ERROR (Status)) {\r
- //\r
- // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the\r
- // TimerPeriod by ourselves.\r
- //\r
- mCurrentTick += 1000000;\r
+ return 0;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ Status = gBS->SetTimer (\r
+ TimerEvent,\r
+ TimerPeriodic,\r
+ TICKS_PER_MS\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (TimerEvent);\r
+ return 0;\r
+ }\r
+\r
+ while (RttTimerTick < 10) {\r
+ gBS->Stall (STALL_1_MILLI_SECOND);\r
+ ++StallCounter;\r
}\r
- \r
- return mCurrentTick;\r
-}\r
\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ gBS->SetTimer (TimerEvent, TimerCancel, 0);\r
+ gBS->CloseEvent (TimerEvent);\r
+\r
+ return StallCounter / RttTimerTick;\r
+}\r
\r
/**\r
- Get and calculate the frequency in ticks/ms.\r
- The result is saved in the global variable mFrequency\r
+ Initialize the timer event for RTT (round trip time).\r
\r
- @retval EFI_SUCCESS Calculated the frequency successfully.\r
- @retval Others Failed to calculate the frequency.\r
+ @param[in] Private The pointer to PING_PRIVATE_DATA.\r
+\r
+ @retval EFI_SUCCESS RTT timer is started.\r
+ @retval Others Failed to start the RTT timer.\r
\r
**/\r
EFI_STATUS\r
-GetFrequency (\r
- VOID\r
+PingInitRttTimer (\r
+ PING_PRIVATE_DATA *Private\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT64 CurrentTick;\r
- UINT64 TimerPeriod;\r
+ EFI_STATUS Status;\r
+\r
+ Private->TimerPeriod = GetTimerPeriod ();\r
+ if (Private->TimerPeriod == 0) {\r
+ return EFI_ABORTED;\r
+ }\r
+ \r
+ Private->RttTimerTick = 0;\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ RttTimerTickRoutine,\r
+ &Private->RttTimerTick,\r
+ &Private->RttTimer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
- Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &gCpu);\r
+ Status = gBS->SetTimer (\r
+ Private->RttTimer,\r
+ TimerPeriodic,\r
+ TICKS_PER_MS\r
+ );\r
if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (Private->RttTimer);\r
return Status;\r
}\r
\r
- Status = gCpu->GetTimerValue (gCpu, 0, &CurrentTick, &TimerPeriod);\r
+ return EFI_SUCCESS;\r
+}\r
\r
- if (EFI_ERROR (Status)) {\r
- TimerPeriod = DEFAULT_TIMER_PERIOD;\r
+/**\r
+ Free RTT timer event resource.\r
+\r
+ @param[in] Private The pointer to PING_PRIVATE_DATA.\r
+\r
+**/\r
+VOID\r
+PingFreeRttTimer (\r
+ PING_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ if (Private->RttTimer != NULL) {\r
+ gBS->SetTimer (Private->RttTimer, TimerCancel, 0);\r
+ gBS->CloseEvent (Private->RttTimer);\r
}\r
+}\r
\r
- //\r
- // The timer period is in femtosecond (1 femtosecond is 1e-15 second).\r
- // So 1e+12 is divided by timer period to produce the freq in ticks/ms.\r
- //\r
- mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
+/**\r
+ Read the current time.\r
+ \r
+ @param[in] Private The pointer to PING_PRIVATE_DATA.\r
\r
- return EFI_SUCCESS;\r
+ @retval the current tick value.\r
+**/\r
+UINT32\r
+ReadTime (\r
+ PING_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ return Private->RttTimerTick;\r
}\r
\r
/**\r
Calculate a duration in ms.\r
\r
- @param[in] Begin The start point of time.\r
- @param[in] End The end point of time.\r
+ @param[in] Private The pointer to PING_PRIVATE_DATA.\r
+ @param[in] Begin The start point of time.\r
+ @param[in] End The end point of time.\r
\r
@return The duration in ms.\r
@retval 0 The parameters were not valid.\r
**/\r
-UINT64\r
+UINT32\r
CalculateTick (\r
- IN UINT64 Begin,\r
- IN UINT64 End\r
+ PING_PRIVATE_DATA *Private,\r
+ IN UINT32 Begin,\r
+ IN UINT32 End\r
)\r
{\r
- if (End <= Begin) {\r
+ if (End < Begin) {\r
return (0);\r
}\r
- return DivU64x64Remainder (End - Begin, mFrequency, NULL);\r
+\r
+ return (End - Begin) * Private->TimerPeriod;\r
}\r
\r
/**\r
PING_PRIVATE_DATA *Private;\r
ICMPX_ECHO_REQUEST_REPLY *Reply;\r
UINT32 PayLoad;\r
- UINT64 Rtt;\r
- CHAR8 Near;\r
+ UINT32 Rtt;\r
\r
Private = (PING_PRIVATE_DATA *) Context;\r
\r
//\r
// Display statistics on this icmp6 echo reply packet.\r
//\r
- Rtt = CalculateTick (Reply->TimeStamp, ReadTime ());\r
- if (Rtt != 0) {\r
- Near = (CHAR8) '=';\r
- } else {\r
- Near = (CHAR8) '<';\r
- }\r
+ Rtt = CalculateTick (Private, Reply->TimeStamp, ReadTime (Private));\r
\r
Private->RttSum += Rtt;\r
Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
mDstString,\r
Reply->SequenceNum,\r
Private->IpChoice == PING_IP_CHOICE_IP6?((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->HopLimit:0,\r
- Near,\r
- Rtt\r
+ Rtt,\r
+ Rtt + Private->TimerPeriod\r
);\r
\r
ON_EXIT:\r
PING_IPX_COMPLETION_TOKEN *\r
PingGenerateToken (\r
IN PING_PRIVATE_DATA *Private,\r
- IN UINT64 TimeStamp,\r
+ IN UINT32 TimeStamp,\r
IN UINT16 SequenceNum\r
)\r
{\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- TxInfo->TimeStamp = ReadTime ();\r
+ TxInfo->TimeStamp = ReadTime (Private);\r
TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
TxInfo->Token = PingGenerateToken (\r
Private,\r
//\r
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
- Time = CalculateTick (TxInfo->TimeStamp, ReadTime ());\r
+ Time = CalculateTick (Private, TxInfo->TimeStamp, ReadTime (Private));\r
\r
//\r
// Remove the timeout echo request from txlist.\r
}\r
}\r
\r
+\r
/**\r
The Ping Process.\r
\r
ShellStatus = SHELL_ACCESS_DENIED;\r
goto ON_EXIT;\r
}\r
+\r
+ //\r
+ // Start a timer to calculate the RTT.\r
+ //\r
+ Status = PingInitRttTimer (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+ \r
//\r
// Create a ipv6 token to send the first icmp6 echo request packet.\r
//\r
STRING_TOKEN (STR_PING_RTT),\r
gShellNetwork1HiiHandle,\r
Private->RttMin,\r
+ Private->RttMin + Private->TimerPeriod,\r
Private->RttMax,\r
- DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL)\r
+ Private->RttMax + Private->TimerPeriod,\r
+ DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL),\r
+ DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod\r
);\r
}\r
\r
PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
}\r
\r
+ PingFreeRttTimer (Private);\r
+\r
if (Private->Timer != NULL) {\r
gBS->CloseEvent (Private->Timer);\r
}\r
goto ON_EXIT;\r
}\r
}\r
- //\r
- // Get frequency to calculate the time from ticks.\r
- //\r
- Status = GetFrequency ();\r
\r
- if (EFI_ERROR(Status)) {\r
- goto ON_EXIT;\r
- }\r
//\r
// Enter into ping process.\r
//\r