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 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 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 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 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 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 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 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 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 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 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 290 _plat__ClearNvAvail( 291 void 292 ) 293 { 294 s_NvIsAvailable = FALSE; 295 return; 296 } 297