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