1 // This file was extracted from the TCG Published
2 // Trusted Platform Module Library
3 // Part 4: Supporting Routines
4 // Family "2.0"
5 // Level 00 Revision 01.16
6 // October 30, 2014
7 
8 #include     <memory.h>
9 #include     <stdio.h>
10 #include     <string.h>
11 
12 #include     "PlatformData.h"
13 #include     "TpmError.h"
14 #include     "assert.h"
15 
16 #ifndef EMBEDDED_MODE
17 #define FILE_BACKED_NV
18 #endif
19 
20 #if defined FILE_BACKED_NV
21 static   FILE*                  s_NVFile;
22 #endif
23 static   unsigned char          s_NV[NV_MEMORY_SIZE];
24 static   BOOL                   s_NvIsAvailable;
25 static   BOOL                   s_NV_unrecoverable;
26 static   BOOL                   s_NV_recoverable;
27 //
28 //
29 //          Functions
30 //
31 //          _plat__NvErrors()
32 //
33 //     This function is used by the simulator to set the error flags in the NV subsystem to simulate an error in the
34 //     NV loading process
35 //
36 LIB_EXPORT void
_plat__NvErrors(BOOL recoverable,BOOL unrecoverable)37 _plat__NvErrors(
38      BOOL                 recoverable,
39      BOOL                 unrecoverable
40      )
41 {
42      s_NV_unrecoverable = unrecoverable;
43      s_NV_recoverable = recoverable;
44 }
45 //
46 //
47 //          _plat__NVEnable()
48 //
49 //     Enable NV memory.
50 //     This version just pulls in data from a file. In a real TPM, with NV on chip, this function would verify the
51 //     integrity of the saved context. If the NV memory was not on chip but was in something like RPMB, the NV
52 //     state would be read in, decrypted and integrity checked.
53 //     The recovery from an integrity failure depends on where the error occurred. It it was in the state that is
54 //     discarded by TPM Reset, then the error is recoverable if the TPM is reset. Otherwise, the TPM must go
55 //     into failure mode.
56 //
57 //     Return Value                      Meaning
58 //
59 //     0                                 if success
60 //     >0                                if receive recoverable error
61 //     <0                                if unrecoverable error
62 //
63 LIB_EXPORT int
_plat__NVEnable(void * platParameter)64 _plat__NVEnable(
65      void                *platParameter       // IN: platform specific parameter
66      )
67 {
68      // Start assuming everything is OK
69    s_NV_unrecoverable = FALSE;
70    s_NV_recoverable = FALSE;
71 #ifdef FILE_BACKED_NV
72    if(s_NVFile != NULL) return 0;
73    // Try to open an exist NVChip file for read/write
74    s_NVFile = fopen("NVChip", "r+b");
75    if(NULL != s_NVFile)
76    {
77        // See if the NVChip file is empty
78        fseek(s_NVFile, 0, SEEK_END);
79        if(0 == ftell(s_NVFile))
80            s_NVFile = NULL;
81    }
82    if(s_NVFile == NULL)
83    {
84        // Initialize all the byte in the new file to 0
85        memset(s_NV, 0, NV_MEMORY_SIZE);
86           // If NVChip file does not exist, try to create it for read/write
87           s_NVFile = fopen("NVChip", "w+b");
88           // Start initialize at the end of new file
89           fseek(s_NVFile, 0, SEEK_END);
90           // Write 0s to NVChip file
91           fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile);
92    }
93    else
94    {
95        // If NVChip file exist, assume the size is correct
96        fseek(s_NVFile, 0, SEEK_END);
97        assert(ftell(s_NVFile) == NV_MEMORY_SIZE);
98        // read NV file data to memory
99        fseek(s_NVFile, 0, SEEK_SET);
100        assert(1 == fread(s_NV, NV_MEMORY_SIZE, 1, s_NVFile));
101    }
102 #endif
103    // NV contents have been read and the error checks have been performed. For
104    // simulation purposes, use the signaling interface to indicate if an error is
105    // to be simulated and the type of the error.
106    if(s_NV_unrecoverable)
107        return -1;
108    return s_NV_recoverable;
109 }
110 //
111 //
112 //         _plat__NVDisable()
113 //
114 //     Disable NV memory
115 //
116 LIB_EXPORT void
_plat__NVDisable(void)117 _plat__NVDisable(
118    void
119    )
120 {
121 #ifdef     FILE_BACKED_NV
122    assert(s_NVFile != NULL);
123    // Close NV file
124    fclose(s_NVFile);
125    // Set file handle to NULL
126 //
127     s_NVFile = NULL;
128 #endif
129     return;
130 }
131 //
132 //
133 //          _plat__IsNvAvailable()
134 //
135 //      Check if NV is available
136 //
137 //      Return Value                      Meaning
138 //
139 //      0                                 NV is available
140 //      1                                 NV is not available due to write failure
141 //      2                                 NV is not available due to rate limit
142 //
143 LIB_EXPORT int
_plat__IsNvAvailable(void)144 _plat__IsNvAvailable(
145     void
146     )
147 {
148     // NV is not available if the TPM is in failure mode
149     if(!s_NvIsAvailable)
150         return 1;
151 #ifdef FILE_BACKED_NV
152    if(s_NVFile == NULL)
153        return 1;
154 #endif
155     return 0;
156 }
157 //
158 //
159 //          _plat__NvMemoryRead()
160 //
161 //      Function: Read a chunk of NV memory
162 //
163 LIB_EXPORT void
_plat__NvMemoryRead(unsigned int startOffset,unsigned int size,void * data)164 _plat__NvMemoryRead(
165     unsigned int           startOffset,       // IN: read start
166     unsigned int           size,              // IN: size of bytes to read
167     void                  *data               // OUT: data buffer
168     )
169 {
170     assert(startOffset + size <= NV_MEMORY_SIZE);
171     // Copy data from RAM
172     memcpy(data, &s_NV[startOffset], size);
173     return;
174 }
175 //
176 //
177 //          _plat__NvIsDifferent()
178 //
179 //      This function checks to see if the NV is different from the test value. This is so that NV will not be written if
180 //      it has not changed.
181 //
182 //
183 //
184 //
185 //      Return Value                  Meaning
186 //
187 //      TRUE                          the NV location is different from the test value
188 //      FALSE                         the NV location is the same as the test value
189 //
190 LIB_EXPORT BOOL
_plat__NvIsDifferent(unsigned int startOffset,unsigned int size,void * data)191 _plat__NvIsDifferent(
192    unsigned int        startOffset,       // IN: read start
193    unsigned int        size,              // IN: size of bytes to read
194    void               *data               // IN: data buffer
195    )
196 {
197    return (memcmp(&s_NV[startOffset], data, size) != 0);
198 }
199 //
200 //
201 //         _plat__NvMemoryWrite()
202 //
203 //      This function is used to update NV memory. The write is to a memory copy of NV. At the end of the
204 //      current command, any changes are written to the actual NV memory.
205 //
206 LIB_EXPORT void
_plat__NvMemoryWrite(unsigned int startOffset,unsigned int size,void * data)207 _plat__NvMemoryWrite(
208    unsigned int        startOffset,       // IN: write start
209    unsigned int        size,              // IN: size of bytes to write
210    void               *data               // OUT: data buffer
211    )
212 {
213    assert(startOffset + size <= NV_MEMORY_SIZE);
214    // Copy the data to the NV image
215    memcpy(&s_NV[startOffset], data, size);
216 }
217 //
218 //
219 //         _plat__NvMemoryMove()
220 //
221 //      Function: Move a chunk of NV memory from source to destination This function should ensure that if
222 //      there overlap, the original data is copied before it is written
223 //
224 LIB_EXPORT void
_plat__NvMemoryMove(unsigned int sourceOffset,unsigned int destOffset,unsigned int size)225 _plat__NvMemoryMove(
226    unsigned int        sourceOffset,      // IN: source offset
227    unsigned int        destOffset,        // IN: destination offset
228    unsigned int        size               // IN: size of data being moved
229    )
230 {
231    assert(sourceOffset + size <= NV_MEMORY_SIZE);
232    assert(destOffset + size <= NV_MEMORY_SIZE);
233    // Move data in RAM
234    memmove(&s_NV[destOffset], &s_NV[sourceOffset], size);
235    return;
236 }
237 //
238 //
239 //         _plat__NvCommit()
240 //
241 //      Update NV chip
242 //
243 //
244 //
245 //      Return Value                      Meaning
246 //
247 //      0                                 NV write success
248 //      non-0                             NV write fail
249 //
250 LIB_EXPORT int
_plat__NvCommit(void)251 _plat__NvCommit(
252    void
253    )
254 {
255 #ifdef FILE_BACKED_NV
256    // If NV file is not available, return failure
257    if(s_NVFile == NULL)
258        return 1;
259    // Write RAM data to NV
260    fseek(s_NVFile, 0, SEEK_SET);
261    fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile);
262    return 0;
263 #else
264    return 0;
265 #endif
266 }
267 //
268 //
269 //       _plat__SetNvAvail()
270 //
271 //      Set the current NV state to available. This function is for testing purpose only. It is not part of the
272 //      platform NV logic
273 //
274 LIB_EXPORT void
_plat__SetNvAvail(void)275 _plat__SetNvAvail(
276    void
277    )
278 {
279    s_NvIsAvailable = TRUE;
280    return;
281 }
282 //
283 //
284 //       _plat__ClearNvAvail()
285 //
286 //      Set the current NV state to unavailable. This function is for testing purpose only. It is not part of the
287 //      platform NV logic
288 //
289 LIB_EXPORT void
_plat__ClearNvAvail(void)290 _plat__ClearNvAvail(
291    void
292    )
293 {
294    s_NvIsAvailable = FALSE;
295    return;
296 }
297