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