878ddf1f |
1 | /*++\r |
2 | \r |
3 | Copyright (c) 2006, Intel Corporation \r |
4 | All rights reserved. This program and the accompanying materials \r |
5 | are licensed and made available under the terms and conditions of the BSD License \r |
6 | which accompanies this distribution. The full text of the license may be found at \r |
7 | http://opensource.org/licenses/bsd-license.php \r |
8 | \r |
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r |
11 | \r |
12 | Module Name:\r |
13 | \r |
14 | MonotonicCounter.c\r |
15 | \r |
16 | Abstract:\r |
17 | \r |
18 | Produced the Monotonic Counter Services as defined in the DXE CIS\r |
19 | \r |
20 | Revision History:\r |
21 | \r |
22 | --*/\r |
23 | \r |
24 | #include "MonotonicCounter.h"\r |
25 | \r |
26 | //\r |
27 | // The Monotonic Counter Handle\r |
28 | //\r |
29 | EFI_HANDLE mMonotonicCounterHandle = NULL;\r |
30 | \r |
31 | //\r |
32 | // The current Monotonic count value\r |
33 | //\r |
34 | UINT64 mEfiMtc;\r |
35 | \r |
878ddf1f |
36 | //\r |
37 | // Event to use to update the Mtc's high part when wrapping\r |
38 | //\r |
39 | EFI_EVENT mEfiMtcEvent;\r |
40 | \r |
41 | //\r |
42 | // EfiMtcName - Variable name of the MTC value\r |
43 | //\r |
44 | CHAR16 *mEfiMtcName = (CHAR16 *) L"MTC";\r |
45 | \r |
46 | //\r |
47 | // EfiMtcGuid - Guid of the MTC value\r |
48 | //\r |
49 | EFI_GUID mEfiMtcGuid = { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } };\r |
50 | \r |
51 | //\r |
52 | // Worker functions\r |
53 | //\r |
1cc8ee78 |
54 | STATIC\r |
878ddf1f |
55 | EFI_STATUS\r |
56 | EFIAPI\r |
57 | MonotonicCounterDriverGetNextMonotonicCount (\r |
58 | OUT UINT64 *Count\r |
59 | )\r |
60 | /*++\r |
61 | \r |
62 | Routine Description:\r |
63 | \r |
64 | Arguments:\r |
65 | \r |
66 | Returns:\r |
67 | \r |
68 | --*/\r |
69 | {\r |
70 | EFI_TPL OldTpl;\r |
71 | \r |
72 | //\r |
73 | // Can not be called after ExitBootServices()\r |
74 | //\r |
75 | if (EfiAtRuntime ()) {\r |
76 | return EFI_UNSUPPORTED;\r |
77 | }\r |
78 | //\r |
79 | // Check input parameters\r |
80 | //\r |
81 | if (Count == NULL) {\r |
82 | return EFI_INVALID_PARAMETER;\r |
83 | }\r |
84 | //\r |
85 | // Update the monotonic counter with a lock\r |
86 | //\r |
87 | OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r |
88 | *Count = mEfiMtc;\r |
89 | mEfiMtc++;\r |
90 | gBS->RestoreTPL (OldTpl);\r |
91 | \r |
92 | //\r |
93 | // If the MSB bit of the low part toggled, then signal that the high\r |
94 | // part needs updated now\r |
95 | //\r |
96 | if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) {\r |
97 | gBS->SignalEvent (mEfiMtcEvent);\r |
98 | }\r |
99 | \r |
100 | return EFI_SUCCESS;\r |
101 | }\r |
102 | \r |
2f23473f |
103 | \r |
2f23473f |
104 | /**\r |
88c8537c |
105 | Returns the next high 32 bits of the platform's monotonic counter.\r |
106 | \r |
107 | The GetNextHighMonotonicCount() function returns the next high 32 bits \r |
108 | of the platform's monotonic counter. The platform's monotonic counter is \r |
109 | comprised of two 32 bit quantities: the high 32 bits and the low 32 bits. \r |
110 | During boot service time the low 32 bit value is volatile: it is reset to \r |
111 | zero on every system reset and is increased by 1 on every call to GetNextMonotonicCount().\r |
112 | The high 32 bit value is non-volatile and is increased by 1 whenever the system resets \r |
113 | or whenever the low 32 bit count [returned by GetNextMonoticCount()] overflows.\r |
114 | The GetNextMonotonicCount() function is only available at boot services time. \r |
115 | If the operating system wishes to extend the platform monotonic counter to runtime, \r |
116 | it may do so by utilizing GetNextHighMonotonicCount(). To do this, before calling \r |
117 | ExitBootServices() the operating system would call GetNextMonotonicCount() to obtain \r |
118 | the current platform monotonic count. The operating system would then provide an \r |
119 | interface that returns the next count by: \r |
120 | Adding 1 to the last count.\r |
121 | Before the lower 32 bits of the count overflows, call GetNextHighMonotonicCount(). \r |
122 | This will increase the high 32 bits of the platform's non-volatile portion of the monotonic \r |
123 | count by 1.\r |
124 | \r |
125 | This function may only be called at Runtime.\r |
126 | \r |
127 | @param[out] HighCount Pointer to returned value.\r |
128 | \r |
129 | @retval EFI_INVALID_PARAMETER If HighCount is NULL.\r |
130 | @retval EFI_SUCCESS Operation is successful.\r |
131 | @retval EFI_OUT_OF_RESOURCES If variable service reports that not enough storage \r |
132 | is available to hold the variable and its data.\r |
133 | @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.\r |
2f23473f |
134 | \r |
135 | **/\r |
1cc8ee78 |
136 | STATIC\r |
878ddf1f |
137 | EFI_STATUS\r |
138 | EFIAPI\r |
139 | MonotonicCounterDriverGetNextHighMonotonicCount (\r |
140 | OUT UINT32 *HighCount\r |
141 | )\r |
142 | /*++\r |
143 | \r |
144 | Routine Description:\r |
145 | \r |
146 | Arguments:\r |
147 | \r |
148 | Returns:\r |
149 | \r |
150 | --*/\r |
151 | {\r |
878ddf1f |
152 | EFI_TPL OldTpl;\r |
153 | \r |
154 | //\r |
155 | // Check input parameters\r |
156 | //\r |
157 | if (HighCount == NULL) {\r |
158 | return EFI_INVALID_PARAMETER;\r |
159 | }\r |
160 | \r |
161 | if (!EfiAtRuntime ()) {\r |
162 | //\r |
163 | // Use a lock if called before ExitBootServices()\r |
164 | //\r |
165 | OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r |
166 | *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1;\r |
167 | mEfiMtc = LShiftU64 (*HighCount, 32);\r |
168 | gBS->RestoreTPL (OldTpl);\r |
169 | } else {\r |
170 | *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1;\r |
171 | mEfiMtc = LShiftU64 (*HighCount, 32);\r |
172 | }\r |
173 | //\r |
174 | // Update the NvRam store to match the new high part\r |
175 | //\r |
88c8537c |
176 | return EfiSetVariable (\r |
177 | mEfiMtcName,\r |
178 | &mEfiMtcGuid,\r |
179 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r |
180 | sizeof (UINT32),\r |
181 | HighCount\r |
182 | );\r |
183 | \r |
878ddf1f |
184 | }\r |
185 | \r |
1cc8ee78 |
186 | STATIC\r |
878ddf1f |
187 | VOID\r |
188 | EFIAPI\r |
189 | EfiMtcEventHandler (\r |
190 | IN EFI_EVENT Event,\r |
191 | IN VOID *Context\r |
192 | )\r |
193 | /*++\r |
194 | \r |
195 | Routine Description:\r |
196 | \r |
197 | Monotonic count event handler. This handler updates the high monotonic count.\r |
198 | \r |
199 | Arguments:\r |
200 | \r |
201 | Event The event to handle\r |
202 | Context The event context\r |
203 | \r |
204 | Returns:\r |
205 | \r |
206 | EFI_SUCCESS The event has been handled properly \r |
207 | EFI_NOT_FOUND An error occurred updating the variable.\r |
208 | \r |
209 | --*/\r |
210 | {\r |
211 | UINT32 HighCount;\r |
212 | \r |
213 | MonotonicCounterDriverGetNextHighMonotonicCount (&HighCount);\r |
214 | }\r |
215 | \r |
216 | EFI_STATUS\r |
217 | EFIAPI\r |
218 | MonotonicCounterDriverInitialize (\r |
219 | IN EFI_HANDLE ImageHandle,\r |
220 | IN EFI_SYSTEM_TABLE *SystemTable\r |
221 | )\r |
222 | /*++\r |
223 | \r |
224 | Routine Description:\r |
225 | \r |
226 | Arguments:\r |
227 | (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r |
228 | \r |
229 | Returns:\r |
230 | \r |
231 | --*/\r |
232 | {\r |
233 | EFI_STATUS Status;\r |
234 | UINT32 HighCount;\r |
235 | UINTN BufferSize;\r |
236 | \r |
237 | //\r |
238 | // Make sure the Monotonic Counter Architectural Protocol is not already installed in the system\r |
239 | //\r |
240 | ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiMonotonicCounterArchProtocolGuid);\r |
241 | \r |
242 | //\r |
243 | // Initialize event to handle overflows\r |
244 | //\r |
245 | Status = gBS->CreateEvent (\r |
246 | EFI_EVENT_NOTIFY_SIGNAL,\r |
247 | EFI_TPL_CALLBACK,\r |
248 | EfiMtcEventHandler,\r |
249 | NULL,\r |
250 | &mEfiMtcEvent\r |
251 | );\r |
252 | \r |
253 | ASSERT_EFI_ERROR (Status);\r |
254 | \r |
255 | //\r |
256 | // Read the last high part\r |
257 | //\r |
258 | BufferSize = sizeof (UINT32);\r |
259 | Status = gRT->GetVariable (\r |
260 | mEfiMtcName,\r |
261 | &mEfiMtcGuid,\r |
262 | NULL,\r |
263 | &BufferSize,\r |
264 | &HighCount\r |
265 | );\r |
266 | if (EFI_ERROR (Status)) {\r |
267 | HighCount = 0;\r |
268 | }\r |
269 | //\r |
270 | // Set the current value\r |
271 | //\r |
272 | mEfiMtc = LShiftU64 (HighCount, 32);\r |
273 | \r |
274 | //\r |
275 | // Increment the upper 32 bits for this boot\r |
276 | // Continue even if it fails. It will only fail if the variable services are\r |
277 | // not functional.\r |
278 | //\r |
279 | Status = MonotonicCounterDriverGetNextHighMonotonicCount (&HighCount);\r |
280 | \r |
281 | //\r |
282 | // Fill in the EFI Boot Services and EFI Runtime Services Monotonic Counter Fields\r |
283 | //\r |
284 | gBS->GetNextMonotonicCount = MonotonicCounterDriverGetNextMonotonicCount;\r |
285 | gRT->GetNextHighMonotonicCount = MonotonicCounterDriverGetNextHighMonotonicCount;\r |
286 | \r |
287 | //\r |
288 | // Install the Monotonic Counter Architctural Protocol onto a new handle\r |
289 | //\r |
290 | Status = gBS->InstallMultipleProtocolInterfaces (\r |
291 | &mMonotonicCounterHandle,\r |
292 | &gEfiMonotonicCounterArchProtocolGuid,\r |
293 | NULL,\r |
294 | NULL\r |
295 | );\r |
296 | ASSERT_EFI_ERROR (Status);\r |
297 | \r |
298 | return EFI_SUCCESS;\r |
299 | }\r |