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