1 /** @file
2   Generic Monotonic Counter services
3 
4   Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
5   Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
6 
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 
16 **/
17 
18 
19 //
20 // The current Monotonic count value
21 //
22 UINT64      mEfiMtc = 0;
23 
24 
25 //
26 // Event to use to update the Mtc's high part when wrapping
27 //
28 EFI_EVENT   mEfiMtcEvent;
29 
30 //
31 // EfiMtcName - Variable name of the MTC value
32 //
33 CHAR16      *mEfiMtcName = L"MTC";
34 
35 //
36 // EfiMtcGuid - Guid of the MTC value
37 //
38 EFI_GUID    mEfiMtcGuid = { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } };
39 
40 
41 
42 //
43 // Worker functions
44 //
45 
46 
47 VOID
48 EFIAPI
EfiMtcEventHandler(IN EFI_EVENT Event,IN VOID * Context)49 EfiMtcEventHandler (
50   IN EFI_EVENT                Event,
51   IN VOID                     *Context
52   )
53 /*++
54 
55 Routine Description:
56 
57   Monotonic count event handler.  This handler updates the high monotonic count.
58 
59 Arguments:
60 
61   Event         The event to handle
62   Context       The event context
63 
64 Returns:
65 
66   EFI_SUCCESS       The event has been handled properly
67   EFI_NOT_FOUND     An error occurred updating the variable.
68 
69 --*/
70 {
71   UINT32  HighCount;
72 
73   EfiGetNextHighMonotonicCount (&HighCount);
74   return;
75 }
76 
77 
78 
79 VOID
LibMtcVirtualAddressChangeEvent(VOID)80 LibMtcVirtualAddressChangeEvent (VOID)
81 {
82 }
83 
84 
85 EFI_STATUS
86 EFIAPI
LibMtcGetNextHighMonotonicCount(OUT UINT32 * HighCount)87 LibMtcGetNextHighMonotonicCount (
88   OUT UINT32  *HighCount
89   )
90 {
91   EFI_STATUS  Status;
92   EFI_TPL     OldTpl;
93 
94   //
95   // Check input parameters
96   //
97   if (HighCount == NULL) {
98     return EFI_INVALID_PARAMETER;
99   }
100 
101 
102   if (!EfiAtRuntime ()) {
103     // Use a lock if called before ExitBootServices()
104     OldTpl      = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
105   }
106 
107   *HighCount  = (UINT32) RShiftU64 (mEfiMtc, 32) + 1;
108   mEfiMtc     = LShiftU64 (*HighCount, 32);
109 
110   if (!EfiAtRuntime ()) {
111     gBS->RestoreTPL (OldTpl);
112   }
113 
114   //
115   // Update the NvRam store to match the new high part
116   //
117   Status = EfiSetVariable (
118               mEfiMtcName,
119               &mEfiMtcGuid,
120               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
121               sizeof (UINT32),
122               HighCount
123               );
124 
125   return Status;
126 }
127 
128 
129 EFI_STATUS
LibMtcGetNextMonotonicCount(OUT UINT64 * Count)130 LibMtcGetNextMonotonicCount (
131   OUT UINT64  *Count
132   )
133 {
134   EFI_STATUS    Status;
135   EFI_TPL       OldTpl;
136   UINT32        HighCount;
137   UINTN         BufferSize;
138 
139   //
140   // Can not be called after ExitBootServices()
141   //
142   if (EfiAtRuntime ()) {
143     return EFI_UNSUPPORTED;
144   }
145 
146   //
147   // Check input parameters
148   //
149   if (Count == NULL) {
150     return EFI_INVALID_PARAMETER;
151   }
152 
153   if (mEfiMtc == 0) {
154     //
155     // If the MTC has not been initialized read the variable
156     //
157 
158     //
159     // Read the last high part
160     //
161     BufferSize = sizeof (UINT32);
162     Status = EfiGetVariable (
163                 mEfiMtcName,
164                 &mEfiMtcGuid,
165                 NULL,
166                 &BufferSize,
167                 &HighCount
168                 );
169     if (EFI_ERROR (Status)) {
170       HighCount = 0;
171     }
172 
173     //
174     // Set the current value
175     //
176     mEfiMtc = LShiftU64 (HighCount, 32);
177     //
178     // Increment the upper 32 bits for this boot
179     // Continue even if it fails.  It will only fail if the variable services are
180     // not functional.
181     //
182     Status = EfiGetNextHighMonotonicCount (&HighCount);
183   }
184 
185 
186   //
187   // Update the monotonic counter with a lock
188   //
189   OldTpl  = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
190   *Count  = mEfiMtc;
191   mEfiMtc++;
192   gBS->RestoreTPL (OldTpl);
193 
194   //
195   // If the MSB bit of the low part toggled, then signal that the high
196   // part needs updated now
197   //
198   if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) {
199     gBS->SignalEvent (mEfiMtcEvent);
200   }
201 
202   return EFI_SUCCESS;
203 }
204 
205 
206 
207 VOID
LibMtcInitialize(VOID)208 LibMtcInitialize (
209   VOID
210   )
211 {
212   EFI_STATUS  Status;
213 
214   //
215   // Initialize event to handle overflows
216   //
217   Status = gBS->CreateEvent (
218                   EVT_NOTIFY_SIGNAL,
219                   EFI_TPL_CALLBACK,
220                   EfiMtcEventHandler,
221                   NULL,
222                   &mEfiMtcEvent
223                   );
224   ASSERT_EFI_ERROR (Status);
225 }
226 
227