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