| // This file was extracted from the TCG Published |
| // Trusted Platform Module Library |
| // Part 4: Supporting Routines |
| // Family "2.0" |
| // Level 00 Revision 01.16 |
| // October 30, 2014 |
| |
| #include <memory.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "PlatformData.h" |
| #include "TpmError.h" |
| #include "assert.h" |
| |
| #ifndef EMBEDDED_MODE |
| #define FILE_BACKED_NV |
| #endif |
| |
| #if defined FILE_BACKED_NV |
| static FILE* s_NVFile; |
| #endif |
| static unsigned char s_NV[NV_MEMORY_SIZE]; |
| static BOOL s_NvIsAvailable; |
| static BOOL s_NV_unrecoverable; |
| static BOOL s_NV_recoverable; |
| // |
| // |
| // Functions |
| // |
| // _plat__NvErrors() |
| // |
| // This function is used by the simulator to set the error flags in the NV subsystem to simulate an error in the |
| // NV loading process |
| // |
| LIB_EXPORT void |
| _plat__NvErrors( |
| BOOL recoverable, |
| BOOL unrecoverable |
| ) |
| { |
| s_NV_unrecoverable = unrecoverable; |
| s_NV_recoverable = recoverable; |
| } |
| // |
| // |
| // _plat__NVEnable() |
| // |
| // Enable NV memory. |
| // This version just pulls in data from a file. In a real TPM, with NV on chip, this function would verify the |
| // integrity of the saved context. If the NV memory was not on chip but was in something like RPMB, the NV |
| // state would be read in, decrypted and integrity checked. |
| // The recovery from an integrity failure depends on where the error occurred. It it was in the state that is |
| // discarded by TPM Reset, then the error is recoverable if the TPM is reset. Otherwise, the TPM must go |
| // into failure mode. |
| // |
| // Return Value Meaning |
| // |
| // 0 if success |
| // >0 if receive recoverable error |
| // <0 if unrecoverable error |
| // |
| LIB_EXPORT int |
| _plat__NVEnable( |
| void *platParameter // IN: platform specific parameter |
| ) |
| { |
| // Start assuming everything is OK |
| s_NV_unrecoverable = FALSE; |
| s_NV_recoverable = FALSE; |
| #ifdef FILE_BACKED_NV |
| if(s_NVFile != NULL) return 0; |
| // Try to open an exist NVChip file for read/write |
| s_NVFile = fopen("NVChip", "r+b"); |
| if(NULL != s_NVFile) |
| { |
| // See if the NVChip file is empty |
| fseek(s_NVFile, 0, SEEK_END); |
| if(0 == ftell(s_NVFile)) |
| s_NVFile = NULL; |
| } |
| if(s_NVFile == NULL) |
| { |
| // Initialize all the byte in the new file to 0 |
| memset(s_NV, 0, NV_MEMORY_SIZE); |
| // If NVChip file does not exist, try to create it for read/write |
| s_NVFile = fopen("NVChip", "w+b"); |
| // Start initialize at the end of new file |
| fseek(s_NVFile, 0, SEEK_END); |
| // Write 0s to NVChip file |
| fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile); |
| } |
| else |
| { |
| // If NVChip file exist, assume the size is correct |
| fseek(s_NVFile, 0, SEEK_END); |
| assert(ftell(s_NVFile) == NV_MEMORY_SIZE); |
| // read NV file data to memory |
| fseek(s_NVFile, 0, SEEK_SET); |
| assert(1 == fread(s_NV, NV_MEMORY_SIZE, 1, s_NVFile)); |
| } |
| #endif |
| // NV contents have been read and the error checks have been performed. For |
| // simulation purposes, use the signaling interface to indicate if an error is |
| // to be simulated and the type of the error. |
| if(s_NV_unrecoverable) |
| return -1; |
| return s_NV_recoverable; |
| } |
| // |
| // |
| // _plat__NVDisable() |
| // |
| // Disable NV memory |
| // |
| LIB_EXPORT void |
| _plat__NVDisable( |
| void |
| ) |
| { |
| #ifdef FILE_BACKED_NV |
| assert(s_NVFile != NULL); |
| // Close NV file |
| fclose(s_NVFile); |
| // Set file handle to NULL |
| // |
| s_NVFile = NULL; |
| #endif |
| return; |
| } |
| // |
| // |
| // _plat__IsNvAvailable() |
| // |
| // Check if NV is available |
| // |
| // Return Value Meaning |
| // |
| // 0 NV is available |
| // 1 NV is not available due to write failure |
| // 2 NV is not available due to rate limit |
| // |
| LIB_EXPORT int |
| _plat__IsNvAvailable( |
| void |
| ) |
| { |
| // NV is not available if the TPM is in failure mode |
| if(!s_NvIsAvailable) |
| return 1; |
| #ifdef FILE_BACKED_NV |
| if(s_NVFile == NULL) |
| return 1; |
| #endif |
| return 0; |
| } |
| // |
| // |
| // _plat__NvMemoryRead() |
| // |
| // Function: Read a chunk of NV memory |
| // |
| LIB_EXPORT void |
| _plat__NvMemoryRead( |
| unsigned int startOffset, // IN: read start |
| unsigned int size, // IN: size of bytes to read |
| void *data // OUT: data buffer |
| ) |
| { |
| assert(startOffset + size <= NV_MEMORY_SIZE); |
| // Copy data from RAM |
| memcpy(data, &s_NV[startOffset], size); |
| return; |
| } |
| // |
| // |
| // _plat__NvIsDifferent() |
| // |
| // This function checks to see if the NV is different from the test value. This is so that NV will not be written if |
| // it has not changed. |
| // |
| // |
| // |
| // |
| // Return Value Meaning |
| // |
| // TRUE the NV location is different from the test value |
| // FALSE the NV location is the same as the test value |
| // |
| LIB_EXPORT BOOL |
| _plat__NvIsDifferent( |
| unsigned int startOffset, // IN: read start |
| unsigned int size, // IN: size of bytes to read |
| void *data // IN: data buffer |
| ) |
| { |
| return (memcmp(&s_NV[startOffset], data, size) != 0); |
| } |
| // |
| // |
| // _plat__NvMemoryWrite() |
| // |
| // This function is used to update NV memory. The write is to a memory copy of NV. At the end of the |
| // current command, any changes are written to the actual NV memory. |
| // |
| LIB_EXPORT void |
| _plat__NvMemoryWrite( |
| unsigned int startOffset, // IN: write start |
| unsigned int size, // IN: size of bytes to write |
| void *data // OUT: data buffer |
| ) |
| { |
| assert(startOffset + size <= NV_MEMORY_SIZE); |
| // Copy the data to the NV image |
| memcpy(&s_NV[startOffset], data, size); |
| } |
| // |
| // |
| // _plat__NvMemoryMove() |
| // |
| // Function: Move a chunk of NV memory from source to destination This function should ensure that if |
| // there overlap, the original data is copied before it is written |
| // |
| LIB_EXPORT void |
| _plat__NvMemoryMove( |
| unsigned int sourceOffset, // IN: source offset |
| unsigned int destOffset, // IN: destination offset |
| unsigned int size // IN: size of data being moved |
| ) |
| { |
| assert(sourceOffset + size <= NV_MEMORY_SIZE); |
| assert(destOffset + size <= NV_MEMORY_SIZE); |
| // Move data in RAM |
| memmove(&s_NV[destOffset], &s_NV[sourceOffset], size); |
| return; |
| } |
| // |
| // |
| // _plat__NvCommit() |
| // |
| // Update NV chip |
| // |
| // |
| // |
| // Return Value Meaning |
| // |
| // 0 NV write success |
| // non-0 NV write fail |
| // |
| LIB_EXPORT int |
| _plat__NvCommit( |
| void |
| ) |
| { |
| #ifdef FILE_BACKED_NV |
| // If NV file is not available, return failure |
| if(s_NVFile == NULL) |
| return 1; |
| // Write RAM data to NV |
| fseek(s_NVFile, 0, SEEK_SET); |
| fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile); |
| return 0; |
| #else |
| return 0; |
| #endif |
| } |
| // |
| // |
| // _plat__SetNvAvail() |
| // |
| // Set the current NV state to available. This function is for testing purpose only. It is not part of the |
| // platform NV logic |
| // |
| LIB_EXPORT void |
| _plat__SetNvAvail( |
| void |
| ) |
| { |
| s_NvIsAvailable = TRUE; |
| return; |
| } |
| // |
| // |
| // _plat__ClearNvAvail() |
| // |
| // Set the current NV state to unavailable. This function is for testing purpose only. It is not part of the |
| // platform NV logic |
| // |
| LIB_EXPORT void |
| _plat__ClearNvAvail( |
| void |
| ) |
| { |
| s_NvIsAvailable = FALSE; |
| return; |
| } |