BaseMemoryLib: Add missing ASSERT()s for some interfaces.
[people/mcb30/edk2.git] / edk2 / MdePkg / Library / BaseTimerLibLocalApic / x86TimerLib.c
1 /** @file\r
2   Timer Library functions built upon local APIC on IA32/x64.\r
3 \r
4   @bug Should use PCD to retrieve all the constants including index of\r
5   the IA32_APIC_BASE MSR, the offsets of InitialCount, CorrentCount\r
6   and DivideConfiguration.\r
7 \r
8   Copyright (c) 2006, Intel Corporation<BR>\r
9   All rights reserved. This program and the accompanying materials\r
10   are licensed and made available under the terms and conditions of the BSD License\r
11   which accompanies this distribution.  The full text of the license may be found at\r
12   http://opensource.org/licenses/bsd-license.php\r
13 \r
14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16 \r
17   Module Name:  x86TimerLib.c\r
18 \r
19 **/\r
20 \r
21 static\r
22 UINTN\r
23 EFIAPI\r
24 DelayWorker (\r
25   IN      UINT64                    NDelay\r
26   )\r
27 {\r
28   UINT64                            Ticks;\r
29 \r
30   Ticks = GetPerformanceCounter ();\r
31   Ticks -= DivU64x32 (\r
32              MultU64x64 (\r
33                GetPerformanceCounterProperties (NULL, NULL),\r
34                NDelay\r
35                ),\r
36              1000000000u\r
37              );\r
38   while (Ticks <= GetPerformanceCounter ());\r
39   return (UINTN)Ticks;\r
40 }\r
41 \r
42 /**\r
43   Stalls the CPU for at least the given number of microseconds.\r
44 \r
45   Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
46 \r
47   @param  MicroSeconds  The minimum number of microseconds to delay.\r
48 \r
49   @return Return value depends on implementation.\r
50 \r
51 **/\r
52 UINTN\r
53 EFIAPI\r
54 MicroSecondDelay (\r
55   IN      UINTN                     MicroSeconds\r
56   )\r
57 {\r
58   return DelayWorker (MicroSeconds * 1000ull);\r
59 }\r
60 \r
61 /**\r
62   Stalls the CPU for at least the given number of nanoseconds.\r
63 \r
64   Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
65 \r
66   @param  NanoSeconds The minimum number of nanoseconds to delay.\r
67 \r
68   @return Return value depends on implementation.\r
69 \r
70 **/\r
71 UINTN\r
72 EFIAPI\r
73 NanoSecondDelay (\r
74   IN      UINTN                     NanoSeconds\r
75   )\r
76 {\r
77   return DelayWorker (NanoSeconds);\r
78 }\r
79 \r
80 static\r
81 UINTN\r
82 EFIAPI\r
83 GetApicBase (\r
84   VOID\r
85   )\r
86 {\r
87   return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;\r
88 }\r
89 \r
90 /**\r
91   Retrieves the current value of a 64-bit free running performance counter.\r
92 \r
93   Retrieves the current value of a 64-bit free running performance counter. The\r
94   counter can either count up by 1 or count down by 1. If the physical\r
95   performance counter counts by a larger increment, then the counter values\r
96   must be translated. The properties of the counter can be retrieved from\r
97   GetPerformanceCounterProperties().\r
98 \r
99   @return The current value of the free running performance counter.\r
100 \r
101 **/\r
102 UINT64\r
103 EFIAPI\r
104 GetPerformanceCounter (\r
105   VOID\r
106   )\r
107 {\r
108   return MmioRead32 (GetApicBase () + 0x390);\r
109 }\r
110 \r
111 /**\r
112   Retrieves the 64-bit frequency in Hz and the range of performance counter\r
113   values.\r
114 \r
115   If StartValue is not NULL, then the value that the performance counter starts\r
116   with immediately after is it rolls over is returned in StartValue. If\r
117   EndValue is not NULL, then the value that the performance counter end with\r
118   immediately before it rolls over is returned in EndValue. The 64-bit\r
119   frequency of the performance counter in Hz is always returned. If StartValue\r
120   is less than EndValue, then the performance counter counts up. If StartValue\r
121   is greater than EndValue, then the performance counter counts down. For\r
122   example, a 64-bit free running counter that counts up would have a StartValue\r
123   of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter\r
124   that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.\r
125 \r
126   @param  StartValue  The value the performance counter starts with when it\r
127                       rolls over.\r
128   @param  EndValue    The value that the performance counter ends with before\r
129                       it rolls over.\r
130 \r
131   @return The frequency in Hz.\r
132 \r
133 **/\r
134 UINT64\r
135 EFIAPI\r
136 GetPerformanceCounterProperties (\r
137   IN      UINT64                    *StartValue,\r
138   IN      UINT64                    *EndValue\r
139   )\r
140 {\r
141   static const UINT32               mFrequencies[] = {\r
142     100000000,\r
143     133000000,\r
144     200000000,\r
145     166000000\r
146   };\r
147   static const UINT8                mDivisor[] = {\r
148     0x02, 0x04, 0x08, 0x10,\r
149     0x02, 0x04, 0x08, 0x10,\r
150     0x20, 0x40, 0x80, 0x01,\r
151     0x20, 0x40, 0x80, 0x01\r
152   };\r
153 \r
154   UINTN                             ApicBase;\r
155 \r
156   ApicBase = GetApicBase ();\r
157 \r
158   if (StartValue != NULL) {\r
159     *StartValue = MmioRead32 (ApicBase + 0x380);\r
160   }\r
161 \r
162   if (EndValue != NULL) {\r
163     *EndValue = 0;\r
164   }\r
165 \r
166   return mFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] /\r
167          mDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];\r
168 }\r