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