/* Microsoft Reference Implementation for TPM 2.0 | |
* | |
* The copyright in this software is being made available under the BSD License, | |
* included below. This software may be subject to other third party and | |
* contributor rights, including patent rights, and no such rights are granted | |
* under this license. | |
* | |
* Copyright (c) Microsoft Corporation | |
* | |
* All rights reserved. | |
* | |
* BSD License | |
* | |
* Redistribution and use in source and binary forms, with or without modification, | |
* are permitted provided that the following conditions are met: | |
* | |
* Redistributions of source code must retain the above copyright notice, this list | |
* of conditions and the following disclaimer. | |
* | |
* Redistributions in binary form must reproduce the above copyright notice, this | |
* list of conditions and the following disclaimer in the documentation and/or | |
* other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
//** Introduction | |
// The NV memory is divided into two areas: dynamic space for user defined NV | |
// Indices and evict objects, and reserved space for TPM persistent and state save | |
// data. | |
// | |
// The entries in dynamic space are a linked list of entries. Each entry has, as its | |
// first field, a size. If the size field is zero, it marks the end of the | |
// list. | |
// | |
// An allocation of an Index or evict object may use almost all of the remaining | |
// NV space such that the size field will not fit. The functions that search the | |
// list are aware of this and will terminate the search if they either find a zero | |
// size or recognize that there is insufficient space for the size field. | |
// | |
// An Index allocation will contain an NV_INDEX structure. If the Index does not | |
// have the orderly attribute, the NV_INDEX is followed immediately by the NV data. | |
// | |
// An evict object entry contains a handle followed by an OBJECT structure. This | |
// results in both the Index and Evict Object having an identifying handle as the | |
// first field following the size field. | |
// | |
// When an Index has the orderly attribute, the data is kept in RAM. This RAM is | |
// saved to backing store in NV memory on any orderly shutdown. The entries in | |
// orderly memory are also a linked list using a size field as the first entry. As | |
// with the NV memory, the list is terminated by a zero size field or when the last | |
// entry leaves insufficient space for the terminating size field. | |
// | |
// The attributes of an orderly index are maintained in RAM memory in order to | |
// reduce the number of NV writes needed for orderly data. When an orderly index | |
// is created, an entry is made in the dynamic NV memory space that holds the Index | |
// authorizations (authPolicy and authValue) and the size of the data. This entry is | |
// only modified if the authValue of the index is changed. The more volatile data | |
// of the index is kept in RAM. When an orderly Index is created or deleted, the | |
// RAM data is copied to NV backing store so that the image in the backing store | |
// matches the layout of RAM. In normal operation. The RAM data is also copied on | |
// any orderly shutdown. In normal operation, the only other reason for writing | |
// to the backing store for RAM is when a counter is first written (TPMA_NV_WRITTEN | |
// changes from CLEAR to SET) or when a counter "rolls over." | |
// | |
// Static space contains items that are individually modifiable. The values are in | |
// the 'gp' PERSISTENT_DATA structure in RAM and mapped to locations in NV. | |
// | |
//** Includes, Defines | |
#define NV_C | |
#include "Tpm.h" | |
//************************************************ | |
//** Functions | |
//************************************************ | |
//*** NvInitStatic() | |
// This function initializes the static variables used in the NV subsystem. | |
static void | |
NvInitStatic( | |
void | |
) | |
{ | |
// In some implementations, the end of NV is variable and is set at boot time. | |
// This value will be the same for each boot, but is not necessarily known | |
// at compile time. | |
s_evictNvEnd = (NV_REF)NV_MEMORY_SIZE; | |
return; | |
} | |
//*** NvCheckState() | |
// Function to check the NV state by accessing the platform-specific function | |
// to get the NV state. The result state is registered in s_NvIsAvailable | |
// that will be reported by NvIsAvailable. | |
// | |
// This function is called at the beginning of ExecuteCommand before any potential | |
// check of g_NvStatus. | |
void | |
NvCheckState( | |
void | |
) | |
{ | |
int func_return; | |
// | |
func_return = _plat__IsNvAvailable(); | |
if(func_return == 0) | |
g_NvStatus = TPM_RC_SUCCESS; | |
else if(func_return == 1) | |
g_NvStatus = TPM_RC_NV_UNAVAILABLE; | |
else | |
g_NvStatus = TPM_RC_NV_RATE; | |
return; | |
} | |
//*** NvCommit | |
// This is a wrapper for the platform function to commit pending NV writes. | |
BOOL | |
NvCommit( | |
void | |
) | |
{ | |
return (_plat__NvCommit() == 0); | |
} | |
//*** NvPowerOn() | |
// This function is called at _TPM_Init to initialize the NV environment. | |
// Return Type: BOOL | |
// TRUE(1) all NV was initialized | |
// FALSE(0) the NV containing saved state had an error and | |
// TPM2_Startup(CLEAR) is required | |
BOOL | |
NvPowerOn( | |
void | |
) | |
{ | |
int nvError = 0; | |
// If power was lost, need to re-establish the RAM data that is loaded from | |
// NV and initialize the static variables | |
if(g_powerWasLost) | |
{ | |
if((nvError = _plat__NVEnable(0)) < 0) | |
FAIL(FATAL_ERROR_NV_UNRECOVERABLE); | |
NvInitStatic(); | |
} | |
return nvError == 0; | |
} | |
//*** NvManufacture() | |
// This function initializes the NV system at pre-install time. | |
// | |
// This function should only be called in a manufacturing environment or in a | |
// simulation. | |
// | |
// The layout of NV memory space is an implementation choice. | |
void | |
NvManufacture( | |
void | |
) | |
{ | |
#if SIMULATION | |
// Simulate the NV memory being in the erased state. | |
_plat__NvMemoryClear(0, NV_MEMORY_SIZE); | |
#endif | |
// Initialize static variables | |
NvInitStatic(); | |
// Clear the RAM used for Orderly Index data | |
MemorySet(s_indexOrderlyRam, 0, RAM_INDEX_SPACE); | |
// Write that Orderly Index data to NV | |
NvUpdateIndexOrderlyData(); | |
// Initialize the next offset of the first entry in evict/index list to 0 (the | |
// end of list marker) and the initial s_maxCounterValue; | |
NvSetMaxCount(0); | |
// Put the end of list marker at the end of memory. This contains the MaxCount | |
// value as well as the end marker. | |
NvWriteNvListEnd(NV_USER_DYNAMIC); | |
return; | |
} | |
//*** NvRead() | |
// This function is used to move reserved data from NV memory to RAM. | |
void | |
NvRead( | |
void *outBuffer, // OUT: buffer to receive data | |
UINT32 nvOffset, // IN: offset in NV of value | |
UINT32 size // IN: size of the value to read | |
) | |
{ | |
// Input type should be valid | |
pAssert(nvOffset + size < NV_MEMORY_SIZE); | |
_plat__NvMemoryRead(nvOffset, size, outBuffer); | |
return; | |
} | |
//*** NvWrite() | |
// This function is used to post reserved data for writing to NV memory. Before | |
// the TPM completes the operation, the value will be written. | |
BOOL | |
NvWrite( | |
UINT32 nvOffset, // IN: location in NV to receive data | |
UINT32 size, // IN: size of the data to move | |
void *inBuffer // IN: location containing data to write | |
) | |
{ | |
// Input type should be valid | |
if(nvOffset + size <= NV_MEMORY_SIZE) | |
{ | |
// Set the flag that a NV write happened | |
SET_NV_UPDATE(UT_NV); | |
return _plat__NvMemoryWrite(nvOffset, size, inBuffer); | |
} | |
return FALSE; | |
} | |
//*** NvUpdatePersistent() | |
// This function is used to update a value in the PERSISTENT_DATA structure and | |
// commits the value to NV. | |
void | |
NvUpdatePersistent( | |
UINT32 offset, // IN: location in PERMANENT_DATA to be updated | |
UINT32 size, // IN: size of the value | |
void *buffer // IN: the new data | |
) | |
{ | |
pAssert(offset + size <= sizeof(gp)); | |
MemoryCopy(&gp + offset, buffer, size); | |
NvWrite(offset, size, buffer); | |
} | |
//*** NvClearPersistent() | |
// This function is used to clear a persistent data entry and commit it to NV | |
void | |
NvClearPersistent( | |
UINT32 offset, // IN: the offset in the PERMANENT_DATA | |
// structure to be cleared (zeroed) | |
UINT32 size // IN: number of bytes to clear | |
) | |
{ | |
pAssert(offset + size <= sizeof(gp)); | |
MemorySet((&gp) + offset, 0, size); | |
NvWrite(offset, size, (&gp) + offset); | |
} | |
//*** NvReadPersistent() | |
// This function reads persistent data to the RAM copy of the 'gp' structure. | |
void | |
NvReadPersistent( | |
void | |
) | |
{ | |
NvRead(&gp, NV_PERSISTENT_DATA, sizeof(gp)); | |
return; | |
} |