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 | //
|
---|
72 | // Check input parameters
|
---|
73 | //
|
---|
74 | if (Count == NULL) {
|
---|
75 | return EFI_INVALID_PARAMETER;
|
---|
76 | }
|
---|
77 |
|
---|
78 | //
|
---|
79 | // Update the monotonic counter with a lock
|
---|
80 | //
|
---|
81 | OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
---|
82 | *Count = mEfiMtc;
|
---|
83 | mEfiMtc++;
|
---|
84 | gBS->RestoreTPL (OldTpl);
|
---|
85 |
|
---|
86 | //
|
---|
87 | // If the low 32-bit counter overflows (MSB bit toggled),
|
---|
88 | // then signal that the high part needs update now.
|
---|
89 | //
|
---|
90 | if ((((UINT32)mEfiMtc) ^ ((UINT32)*Count)) & BIT31) {
|
---|
91 | gBS->SignalEvent (mEfiMtcEvent);
|
---|
92 | }
|
---|
93 |
|
---|
94 | return EFI_SUCCESS;
|
---|
95 | }
|
---|
96 |
|
---|
97 | /**
|
---|
98 | Returns the next high 32 bits of the platform's monotonic counter.
|
---|
99 |
|
---|
100 | The GetNextHighMonotonicCount() function returns the next high 32 bits
|
---|
101 | of the platform's monotonic counter. The platform's monotonic counter is
|
---|
102 | comprised of two 32 bit quantities: the high 32 bits and the low 32 bits.
|
---|
103 | During boot service time the low 32 bit value is volatile: it is reset to
|
---|
104 | zero on every system reset and is increased by 1 on every call to GetNextMonotonicCount().
|
---|
105 | The high 32 bit value is non-volatile and is increased by 1 whenever the system resets,
|
---|
106 | whenever GetNextHighMonotonicCount() is called, or whenever the low 32 bit count
|
---|
107 | (returned by GetNextMonoticCount()) overflows.
|
---|
108 | The GetNextMonotonicCount() function is only available at boot services time.
|
---|
109 | If the operating system wishes to extend the platform monotonic counter to runtime,
|
---|
110 | it may do so by utilizing GetNextHighMonotonicCount(). To do this, before calling
|
---|
111 | ExitBootServices() the operating system would call GetNextMonotonicCount() to obtain
|
---|
112 | the current platform monotonic count. The operating system would then provide an
|
---|
113 | interface that returns the next count by:
|
---|
114 | Adding 1 to the last count.
|
---|
115 | Before the lower 32 bits of the count overflows, call GetNextHighMonotonicCount().
|
---|
116 | This will increase the high 32 bits of the platform's non-volatile portion of the monotonic
|
---|
117 | count by 1.
|
---|
118 |
|
---|
119 | This function may only be called at Runtime.
|
---|
120 |
|
---|
121 | @param HighCount Pointer to returned value.
|
---|
122 |
|
---|
123 | @retval EFI_SUCCESS The next high monotonic count was returned.
|
---|
124 | @retval EFI_INVALID_PARAMETER HighCount is NULL.
|
---|
125 | @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
|
---|
126 | @retval EFI_OUT_OF_RESOURCES If variable service reports that not enough storage
|
---|
127 | is available to hold the variable and its data.
|
---|
128 | @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made.
|
---|
129 | The platform should describe this runtime service as unsupported at runtime
|
---|
130 | via an EFI_RT_PROPERTIES_TABLE configuration table.
|
---|
131 |
|
---|
132 | **/
|
---|
133 | EFI_STATUS
|
---|
134 | EFIAPI
|
---|
135 | MonotonicCounterDriverGetNextHighMonotonicCount (
|
---|
136 | OUT UINT32 *HighCount
|
---|
137 | )
|
---|
138 | {
|
---|
139 | EFI_TPL OldTpl;
|
---|
140 |
|
---|
141 | //
|
---|
142 | // Check input parameters
|
---|
143 | //
|
---|
144 | if (HighCount == NULL) {
|
---|
145 | return EFI_INVALID_PARAMETER;
|
---|
146 | }
|
---|
147 |
|
---|
148 | if (!EfiAtRuntime ()) {
|
---|
149 | //
|
---|
150 | // Use a lock if called before ExitBootServices()
|
---|
151 | //
|
---|
152 | OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
---|
153 | *HighCount = (UINT32)RShiftU64 (mEfiMtc, 32) + 1;
|
---|
154 | mEfiMtc = LShiftU64 (*HighCount, 32);
|
---|
155 | gBS->RestoreTPL (OldTpl);
|
---|
156 | } else {
|
---|
157 | *HighCount = (UINT32)RShiftU64 (mEfiMtc, 32) + 1;
|
---|
158 | mEfiMtc = LShiftU64 (*HighCount, 32);
|
---|
159 | }
|
---|
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 | Monotonic counter event handler. This handler updates the high part of monotonic counter.
|
---|
175 |
|
---|
176 | @param Event The event to handle.
|
---|
177 | @param Context The event context.
|
---|
178 |
|
---|
179 | **/
|
---|
180 | VOID
|
---|
181 | EFIAPI
|
---|
182 | EfiMtcEventHandler (
|
---|
183 | IN EFI_EVENT Event,
|
---|
184 | IN VOID *Context
|
---|
185 | )
|
---|
186 | {
|
---|
187 | UINT32 HighCount;
|
---|
188 |
|
---|
189 | MonotonicCounterDriverGetNextHighMonotonicCount (&HighCount);
|
---|
190 | }
|
---|
191 |
|
---|
192 | /**
|
---|
193 | Entry point of monotonic counter driver.
|
---|
194 |
|
---|
195 | @param ImageHandle The image handle of this driver.
|
---|
196 | @param SystemTable The pointer of EFI_SYSTEM_TABLE.
|
---|
197 |
|
---|
198 | @retval EFI_SUCCESS The initialization is successful.
|
---|
199 |
|
---|
200 | **/
|
---|
201 | EFI_STATUS
|
---|
202 | EFIAPI
|
---|
203 | MonotonicCounterDriverInitialize (
|
---|
204 | IN EFI_HANDLE ImageHandle,
|
---|
205 | IN EFI_SYSTEM_TABLE *SystemTable
|
---|
206 | )
|
---|
207 | {
|
---|
208 | EFI_STATUS Status;
|
---|
209 | UINT32 HighCount;
|
---|
210 | UINTN BufferSize;
|
---|
211 |
|
---|
212 | //
|
---|
213 | // Make sure the Monotonic Counter Architectural Protocol has not been installed in the system yet.
|
---|
214 | //
|
---|
215 | ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiMonotonicCounterArchProtocolGuid);
|
---|
216 |
|
---|
217 | //
|
---|
218 | // Initialize event to handle low-part overflow
|
---|
219 | //
|
---|
220 | Status = gBS->CreateEvent (
|
---|
221 | EVT_NOTIFY_SIGNAL,
|
---|
222 | TPL_CALLBACK,
|
---|
223 | EfiMtcEventHandler,
|
---|
224 | NULL,
|
---|
225 | &mEfiMtcEvent
|
---|
226 | );
|
---|
227 | ASSERT_EFI_ERROR (Status);
|
---|
228 |
|
---|
229 | //
|
---|
230 | // Read the last high part
|
---|
231 | //
|
---|
232 | BufferSize = sizeof (UINT32);
|
---|
233 | Status = EfiGetVariable (
|
---|
234 | MTC_VARIABLE_NAME,
|
---|
235 | &gMtcVendorGuid,
|
---|
236 | NULL,
|
---|
237 | &BufferSize,
|
---|
238 | &HighCount
|
---|
239 | );
|
---|
240 | if (EFI_ERROR (Status)) {
|
---|
241 | HighCount = 0;
|
---|
242 | }
|
---|
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 | }
|
---|