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