Coverage Report

Created: 2026-07-25 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ibmswtpm2/src/NVMem.c
Line
Count
Source
1
/********************************************************************************/
2
/*                    */
3
/*       NV read and write access methods     */
4
/*           Written by Ken Goldman       */
5
/*           IBM Thomas J. Watson Research Center     */
6
/*            $Id: NVMem.c 1313 2018-08-27 16:43:31Z kgoldman $     */
7
/*                    */
8
/*  Licenses and Notices              */
9
/*                    */
10
/*  1. Copyright Licenses:              */
11
/*                    */
12
/*  - Trusted Computing Group (TCG) grants to the user of the source code in  */
13
/*    this specification (the "Source Code") a worldwide, irrevocable,    */
14
/*    nonexclusive, royalty free, copyright license to reproduce, create  */
15
/*    derivative works, distribute, display and perform the Source Code and */
16
/*    derivative works thereof, and to grant others the rights granted herein.  */
17
/*                    */
18
/*  - The TCG grants to the user of the other parts of the specification  */
19
/*    (other than the Source Code) the rights to reproduce, distribute,   */
20
/*    display, and perform the specification solely for the purpose of    */
21
/*    developing products based on such documents.        */
22
/*                    */
23
/*  2. Source Code Distribution Conditions:         */
24
/*                    */
25
/*  - Redistributions of Source Code must retain the above copyright licenses,  */
26
/*    this list of conditions and the following disclaimers.      */
27
/*                    */
28
/*  - Redistributions in binary form must reproduce the above copyright   */
29
/*    licenses, this list of conditions and the following disclaimers in the  */
30
/*    documentation and/or other materials provided with the distribution.  */
31
/*                    */
32
/*  3. Disclaimers:               */
33
/*                    */
34
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
35
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
36
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
37
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.   */
38
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for    */
39
/*  information on specification licensing rights available through TCG   */
40
/*  membership agreements.              */
41
/*                    */
42
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED   */
43
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR   */
44
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR    */
45
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY    */
46
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.   */
47
/*                    */
48
/*  - Without limitation, TCG and its members and licensors disclaim all  */
49
/*    liability, including liability for infringement of any proprietary  */
50
/*    rights, relating to use of information in this specification and to the */
51
/*    implementation of this specification, and TCG disclaims all liability for */
52
/*    cost of procurement of substitute goods or services, lost profits, loss   */
53
/*    of use, loss of data or any incidental, consequential, direct, indirect,  */
54
/*    or special damages, whether under contract, tort, warranty or otherwise,  */
55
/*    arising in any way out of use or reliance upon this specification or any  */
56
/*    information herein.             */
57
/*                    */
58
/*  (c) Copyright IBM Corp. and others, 2016 - 2018       */
59
/*                    */
60
/********************************************************************************/
61
62
/* C.6 NVMem.c */
63
/* C.6.1. Description */
64
/* This file contains the NV read and write access methods.  This implementation uses RAM/file and
65
   does not manage the RAM/file as NV blocks. The implementation may become more sophisticated over
66
   time. */
67
/* C.6.2. Includes and Local */
68
#include <memory.h>
69
#include <string.h>
70
#include <assert.h>
71
#include "PlatformData.h"
72
#include "Platform_fp.h"
73
#if FILE_BACKED_NV
74
#   include         <stdio.h>
75
FILE                *s_NvFile = NULL;
76
#endif
77
78
/* C.6.3. Functions */
79
/* C.6.3.1. NvFileOpen() */
80
/* Function to open the NV file */
81
#if FILE_BACKED_NV
82
/* Return Value Meaning */
83
/* 0  success */
84
/* -1 error */
85
static int
86
NvFileOpen(
87
     const char      *mode
88
     )
89
970
{
90
    // Try to open an exist NVChip file for read/write
91
#   if defined _MSC_VER && 1
92
    if(0 != fopen_s(&s_NvFile, "NVChip", mode))
93
  s_NvFile = NULL;
94
#   else
95
970
    s_NvFile = fopen("NVChip", mode);
96
970
#   endif
97
970
    return (s_NvFile == NULL) ? -1 : 0;
98
970
}
99
/* C.6.3.2. NvFileCommit() */
100
/* Write all of the contents of the NV image to a file. */
101
/* Return Value Meaning */
102
/* 0  failure */
103
/* 1  success */
104
static int
105
NvFileCommit(
106
        )
107
1.94k
{
108
1.94k
    int         OK;
109
    // If NV file is not available, return failure
110
1.94k
    if(s_NvFile == NULL)
111
0
  return 1;
112
    // Write RAM data to NV
113
1.94k
    fseek(s_NvFile, 0, SEEK_SET);
114
1.94k
    OK = (NV_MEMORY_SIZE == fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NvFile));
115
1.94k
    OK = OK && (0 == fflush(s_NvFile));
116
1.94k
    assert(OK);
117
1.94k
    return OK;
118
1.94k
}
119
/* C.6.3.3. NvFileSize() */
120
/* This function gets the size of the NV file and puts the file pointer were desired using the seek
121
   method values. SEEK_SET => beginning; SEEK_CUR => current position and SEEK_END => to the end of
122
   the file. */
123
static long
124
NvFileSize(
125
     int         leaveAt
126
     )
127
970
{
128
970
    long    fileSize;
129
970
    long    filePos = ftell(s_NvFile);
130
    //
131
970
    assert(NULL != s_NvFile);
132
    
133
970
    fseek(s_NvFile, 0, SEEK_END);
134
970
    fileSize = ftell(s_NvFile);
135
970
    switch(leaveAt)
136
970
  {
137
970
    case SEEK_SET:
138
970
      filePos = 0;
139
970
    case SEEK_CUR:
140
970
      fseek(s_NvFile, filePos, SEEK_SET);
141
970
      break;
142
0
    case SEEK_END:
143
0
      break;
144
0
    default:
145
0
      assert(FALSE);
146
0
      break;
147
970
  }
148
970
    return fileSize;
149
970
}
150
#endif
151
152
/* C.6.3.4. _plat__NvErrors() */
153
/* This function is used by the simulator to set the error flags in the NV subsystem to simulate an
154
   error in the NV loading process */
155
LIB_EXPORT void
156
_plat__NvErrors(
157
    int              recoverable,
158
    int            unrecoverable
159
    )
160
0
{
161
0
    s_NV_unrecoverable = unrecoverable;
162
0
    s_NV_recoverable = recoverable;
163
0
}
164
/* C.6.3.5. _plat__NVEnable() */
165
/* Enable NV memory. */
166
/* This version just pulls in data from a file. In a real TPM, with NV on chip, this function would
167
   verify the integrity of the saved context. If the NV memory was not on chip but was in something
168
   like RPMB, the NV state would be read in, decrypted and integrity checked. */
169
/* The recovery from an integrity failure depends on where the error occurred. It it was in the
170
   state that is discarded by TPM Reset, then the error is recoverable if the TPM is
171
   reset. Otherwise, the TPM must go into failure mode. */
172
/* Return Values Meaning */
173
/* 0 if success */
174
/* > 0 if receive recoverable error */
175
/* <0 if unrecoverable error */
176
LIB_EXPORT int
177
_plat__NVEnable(
178
    void            *platParameter  // IN: platform specific parameters
179
    )
180
971
{
181
971
    NOT_REFERENCED(platParameter);          // to keep compiler quiet
182
    //
183
    // Start assuming everything is OK
184
971
    s_NV_unrecoverable = FALSE;
185
971
    s_NV_recoverable = FALSE;
186
971
#if FILE_BACKED_NV
187
971
    if(s_NvFile != NULL)
188
1
  return 0;
189
    // Initialize all the bytes in the ram copy of the NV
190
970
    _plat__NvMemoryClear(0, NV_MEMORY_SIZE);
191
    
192
    // If the file exists
193
970
    if(0 == NvFileOpen("r+b"))
194
970
  {
195
970
      long    fileSize = NvFileSize(SEEK_SET);    // get the file size and leave the
196
      // file pointer at the start
197
      //
198
      // If the size is right, read the data
199
970
      if(NV_MEMORY_SIZE == fileSize)
200
970
    fread(s_NV, 1, NV_MEMORY_SIZE, s_NvFile);
201
0
      else
202
0
    NvFileCommit();     // for any other size, initialize it
203
970
  }
204
    // If NVChip file does not exist, try to create it for read/write.
205
0
    else if(0 == NvFileOpen("w+b"))
206
0
  NvFileCommit();             // Initialize the file
207
970
    assert(NULL != s_NvFile);       // Just in case we are broken for some reason.
208
970
#endif
209
    // NV contents have been initialized and the error checks have been performed. For
210
    // simulation purposes, use the signaling interface to indicate if an error is
211
    // to be simulated and the type of the error.
212
970
    if(s_NV_unrecoverable)
213
0
  return -1;
214
970
    return s_NV_recoverable;
215
970
}
216
217
/* C.6.3.6. _plat__NVDisable() */
218
/* Disable NV memory */
219
LIB_EXPORT void
220
_plat__NVDisable(
221
     void
222
     )
223
970
{
224
970
#if FILE_BACKED_NV
225
970
    if(NULL != s_NvFile);
226
970
    fclose(s_NvFile);    // Close NV file
227
970
    s_NvFile = NULL;        // Set file handle to NULL
228
970
#endif
229
970
    return;
230
970
}
231
232
/* C.6.3.7. _plat__IsNvAvailable() */
233
/* Check if NV is available */
234
/* Return Values Meaning */
235
/* 0 NV is available */
236
/* 1 NV is not available due to write failure */
237
/* 2 NV is not available due to rate limit */
238
LIB_EXPORT int
239
_plat__IsNvAvailable(
240
         void
241
         )
242
9.88k
{
243
9.88k
    int         retVal = 0;
244
    // NV is not available if the TPM is in failure mode
245
9.88k
    if(!s_NvIsAvailable)
246
0
  retVal = 1;
247
9.88k
#if FILE_BACKED_NV
248
9.88k
    else
249
9.88k
  retVal = (s_NvFile == NULL);
250
9.88k
#endif
251
9.88k
    return retVal;
252
9.88k
}
253
254
/* C.6.3.8. _plat__NvMemoryRead() */
255
/* Function: Read a chunk of NV memory */
256
LIB_EXPORT void
257
_plat__NvMemoryRead(
258
        unsigned int     startOffset,   // IN: read start
259
        unsigned int     size,          // IN: size of bytes to read
260
        void            *data           // OUT: data buffer
261
        )
262
2
{
263
2
    assert(startOffset + size <= NV_MEMORY_SIZE);
264
2
    memcpy(data, &s_NV[startOffset], size); // Copy data from RAM
265
2
    return;
266
2
}
267
/* C.6.3.9. _plat__NvIsDifferent() */
268
/* This function checks to see if the NV is different from the test value. This is so that NV will
269
   not be written if it has not changed. */
270
/* Return Values Meaning */
271
/* TRUE(1) the NV location is different from the test value */
272
/* FALSE(0) the NV location is the same as the test value */
273
LIB_EXPORT int
274
_plat__NvIsDifferent(
275
         unsigned int     startOffset,   // IN: read start
276
         unsigned int     size,          // IN: size of bytes to read
277
         void            *data           // IN: data buffer
278
         )
279
0
{
280
0
    return (memcmp(&s_NV[startOffset], data, size) != 0);
281
0
}
282
/* C.6.3.10. _plat__NvMemoryWrite() */
283
/* This function is used to update NV memory. The write is to a memory copy of NV. At the end of the
284
   current command, any changes are written to the actual NV memory. */
285
/* NOTE: A useful optimization would be for this code to compare the current contents of NV with the
286
   local copy and note the blocks that have changed. Then only write those blocks when
287
   _plat__NvCommit() is called. */
288
LIB_EXPORT void
289
_plat__NvMemoryWrite(
290
         unsigned int     startOffset,   // IN: write start
291
         unsigned int     size,          // IN: size of bytes to write
292
         void            *data           // OUT: data buffer
293
         )
294
65.9k
{
295
65.9k
    assert(startOffset + size <= NV_MEMORY_SIZE);
296
65.9k
    memcpy(&s_NV[startOffset], data, size);    // Copy the data to the NV image
297
65.9k
}
298
/* C.6.3.11. _plat__NvMemoryClear() */
299
/* Function is used to set a range of NV memory bytes to an implementation-dependent value. The
300
   value represents the erase state of the memory. */
301
LIB_EXPORT void
302
_plat__NvMemoryClear(
303
         unsigned int     start,         // IN: clear start
304
         unsigned int     size           // IN: number of bytes to clear
305
         )
306
970
{
307
970
    assert(start + size <= NV_MEMORY_SIZE);
308
    // In this implementation, assume that the erase value for NV is all 1s
309
970
    memset(&s_NV[start], 0xff, size);
310
970
}
311
/* C.6.3.12. _plat__NvMemoryMove() */
312
/* Function: Move a chunk of NV memory from source to destination This function should ensure that
313
   if there overlap, the original data is copied before it is written */
314
LIB_EXPORT void
315
_plat__NvMemoryMove(
316
        unsigned int     sourceOffset,  // IN: source offset
317
        unsigned int     destOffset,    // IN: destination offset
318
        unsigned int     size           // IN: size of data being moved
319
        )
320
0
{
321
0
    assert(sourceOffset + size <= NV_MEMORY_SIZE);
322
0
    assert(destOffset + size <= NV_MEMORY_SIZE);
323
0
    memmove(&s_NV[destOffset], &s_NV[sourceOffset], size);  // Move data in RAM
324
0
    return;
325
0
}
326
/* C.6.3.13. _plat__NvCommit() */
327
/* This function writes the local copy of NV to NV for permanent store. It will write NV_MEMORY_SIZE
328
   bytes to NV. If a file is use, the entire file is written. */
329
/* Return Values Meaning */
330
/* 0 NV write success */
331
/* non-0 NV write fail */
332
LIB_EXPORT int
333
_plat__NvCommit(
334
    void
335
    )
336
1.94k
{
337
1.94k
#if FILE_BACKED_NV
338
1.94k
    return (NvFileCommit() ? 0 : 1);
339
#else
340
    return 0;
341
#endif
342
1.94k
}
343
344
/* C.6.3.14. _plat__SetNvAvail() */
345
/* Set the current NV state to available.  This function is for testing purpose only.  It is not
346
   part of the platform NV logic */
347
LIB_EXPORT void
348
_plat__SetNvAvail(
349
      void
350
      )
351
1.94k
{
352
1.94k
    s_NvIsAvailable = TRUE;
353
1.94k
    return;
354
1.94k
}
355
/* C.6.3.15. _plat__ClearNvAvail() */
356
/* Set the current NV state to unavailable.  This function is for testing purpose only.  It is not
357
   part of the platform NV logic */
358
LIB_EXPORT void
359
_plat__ClearNvAvail(
360
        void
361
        )
362
0
{
363
0
    s_NvIsAvailable = FALSE;
364
0
    return;
365
0
}