VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounter.c

Last change on this file was 105670, checked in by vboxsync, 6 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 7.9 KB
Line 
1/** @file
2 Produce the UEFI boot service GetNextMonotonicCount() and runtime service
3 GetNextHighMonotonicCount().
4
5Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6SPDX-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//
25EFI_HANDLE mMonotonicCounterHandle = NULL;
26
27//
28// The current monotonic counter value
29//
30UINT64 mEfiMtc;
31
32//
33// Event to update the monotonic Counter's high part when low part overflows.
34//
35EFI_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**/
56EFI_STATUS
57EFIAPI
58MonotonicCounterDriverGetNextMonotonicCount (
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**/
133EFI_STATUS
134EFIAPI
135MonotonicCounterDriverGetNextHighMonotonicCount (
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**/
180VOID
181EFIAPI
182EfiMtcEventHandler (
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**/
201EFI_STATUS
202EFIAPI
203MonotonicCounterDriverInitialize (
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}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette