1 /** @file
2 Generic Monotonic Counter services
3
4 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15
16 **/
17
18
19 //
20 // The current Monotonic count value
21 //
22 UINT64 mEfiMtc = 0;
23
24
25 //
26 // Event to use to update the Mtc's high part when wrapping
27 //
28 EFI_EVENT mEfiMtcEvent;
29
30 //
31 // EfiMtcName - Variable name of the MTC value
32 //
33 CHAR16 *mEfiMtcName = L"MTC";
34
35 //
36 // EfiMtcGuid - Guid of the MTC value
37 //
38 EFI_GUID mEfiMtcGuid = { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } };
39
40
41
42 //
43 // Worker functions
44 //
45
46
47 VOID
48 EFIAPI
EfiMtcEventHandler(IN EFI_EVENT Event,IN VOID * Context)49 EfiMtcEventHandler (
50 IN EFI_EVENT Event,
51 IN VOID *Context
52 )
53 /*++
54
55 Routine Description:
56
57 Monotonic count event handler. This handler updates the high monotonic count.
58
59 Arguments:
60
61 Event The event to handle
62 Context The event context
63
64 Returns:
65
66 EFI_SUCCESS The event has been handled properly
67 EFI_NOT_FOUND An error occurred updating the variable.
68
69 --*/
70 {
71 UINT32 HighCount;
72
73 EfiGetNextHighMonotonicCount (&HighCount);
74 return;
75 }
76
77
78
79 VOID
LibMtcVirtualAddressChangeEvent(VOID)80 LibMtcVirtualAddressChangeEvent (VOID)
81 {
82 }
83
84
85 EFI_STATUS
86 EFIAPI
LibMtcGetNextHighMonotonicCount(OUT UINT32 * HighCount)87 LibMtcGetNextHighMonotonicCount (
88 OUT UINT32 *HighCount
89 )
90 {
91 EFI_STATUS Status;
92 EFI_TPL OldTpl;
93
94 //
95 // Check input parameters
96 //
97 if (HighCount == NULL) {
98 return EFI_INVALID_PARAMETER;
99 }
100
101
102 if (!EfiAtRuntime ()) {
103 // Use a lock if called before ExitBootServices()
104 OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
105 }
106
107 *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1;
108 mEfiMtc = LShiftU64 (*HighCount, 32);
109
110 if (!EfiAtRuntime ()) {
111 gBS->RestoreTPL (OldTpl);
112 }
113
114 //
115 // Update the NvRam store to match the new high part
116 //
117 Status = EfiSetVariable (
118 mEfiMtcName,
119 &mEfiMtcGuid,
120 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
121 sizeof (UINT32),
122 HighCount
123 );
124
125 return Status;
126 }
127
128
129 EFI_STATUS
LibMtcGetNextMonotonicCount(OUT UINT64 * Count)130 LibMtcGetNextMonotonicCount (
131 OUT UINT64 *Count
132 )
133 {
134 EFI_STATUS Status;
135 EFI_TPL OldTpl;
136 UINT32 HighCount;
137 UINTN BufferSize;
138
139 //
140 // Can not be called after ExitBootServices()
141 //
142 if (EfiAtRuntime ()) {
143 return EFI_UNSUPPORTED;
144 }
145
146 //
147 // Check input parameters
148 //
149 if (Count == NULL) {
150 return EFI_INVALID_PARAMETER;
151 }
152
153 if (mEfiMtc == 0) {
154 //
155 // If the MTC has not been initialized read the variable
156 //
157
158 //
159 // Read the last high part
160 //
161 BufferSize = sizeof (UINT32);
162 Status = EfiGetVariable (
163 mEfiMtcName,
164 &mEfiMtcGuid,
165 NULL,
166 &BufferSize,
167 &HighCount
168 );
169 if (EFI_ERROR (Status)) {
170 HighCount = 0;
171 }
172
173 //
174 // Set the current value
175 //
176 mEfiMtc = LShiftU64 (HighCount, 32);
177 //
178 // Increment the upper 32 bits for this boot
179 // Continue even if it fails. It will only fail if the variable services are
180 // not functional.
181 //
182 Status = EfiGetNextHighMonotonicCount (&HighCount);
183 }
184
185
186 //
187 // Update the monotonic counter with a lock
188 //
189 OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
190 *Count = mEfiMtc;
191 mEfiMtc++;
192 gBS->RestoreTPL (OldTpl);
193
194 //
195 // If the MSB bit of the low part toggled, then signal that the high
196 // part needs updated now
197 //
198 if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) {
199 gBS->SignalEvent (mEfiMtcEvent);
200 }
201
202 return EFI_SUCCESS;
203 }
204
205
206
207 VOID
LibMtcInitialize(VOID)208 LibMtcInitialize (
209 VOID
210 )
211 {
212 EFI_STATUS Status;
213
214 //
215 // Initialize event to handle overflows
216 //
217 Status = gBS->CreateEvent (
218 EVT_NOTIFY_SIGNAL,
219 EFI_TPL_CALLBACK,
220 EfiMtcEventHandler,
221 NULL,
222 &mEfiMtcEvent
223 );
224 ASSERT_EFI_ERROR (Status);
225 }
226
227