// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 3: Commands
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014
#include "InternalRoutines.h"
#include "Startup_fp.h"
#include "Unique_fp.h"
//
//
// Error Returns Meaning
//
// TPM_RC_LOCALITY a Startup(STATE) does not have the same H-CRTM state as the
// previous Startup() or the locality of the startup is not 0 pr 3
// TPM_RC_NV_UNINITIALIZED the saved state cannot be recovered and a Startup(CLEAR) is
// requried.
// TPM_RC_VALUE start up type is not compatible with previous shutdown sequence
//
TPM_RC
TPM2_Startup(
Startup_In *in // IN: input parameter list
)
{
STARTUP_TYPE startup;
TPM_RC result;
BOOL prevDrtmPreStartup;
BOOL prevStartupLoc3;
BYTE locality = _plat__LocalityGet();
// In the PC Client specification, only locality 0 and 3 are allowed
if(locality != 0 && locality != 3)
return TPM_RC_LOCALITY;
// Indicate that the locality was 3 unless there was an H-CRTM
if(g_DrtmPreStartup)
locality = 0;
g_StartupLocality3 = (locality == 3);
// The command needs NV update. Check if NV is available.
// A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
// this point
result = NvIsAvailable();
if(result != TPM_RC_SUCCESS)
return result;
// Input Validation
// Read orderly shutdown states from previous power cycle
NvReadReserved(NV_ORDERLY, &g_prevOrderlyState);
// See if the orderly state indicates that state was saved
if( (g_prevOrderlyState & ~(PRE_STARTUP_FLAG | STARTUP_LOCALITY_3))
== TPM_SU_STATE)
{
// If so, extrat the saved flags (HACK)
prevDrtmPreStartup = (g_prevOrderlyState & PRE_STARTUP_FLAG) != 0;
prevStartupLoc3 = (g_prevOrderlyState & STARTUP_LOCALITY_3) != 0;
g_prevOrderlyState = TPM_SU_STATE;
}
else
{
prevDrtmPreStartup = 0;
prevStartupLoc3 = 0;
}
// if this startup is a TPM Resume, then the H-CRTM states have to match.
if(in->startupType == TPM_SU_STATE)
{
if(g_DrtmPreStartup != prevDrtmPreStartup)
return TPM_RC_VALUE + RC_Startup_startupType;
if(g_StartupLocality3 != prevStartupLoc3)
return TPM_RC_LOCALITY;
}
// if the previous power cycle was shut down with no StateSave command, or
// with StateSave command for CLEAR, or the part of NV used for TPM_SU_STATE
// cannot be recovered, then this cycle can not startup up with STATE
if(in->startupType == TPM_SU_STATE)
{
if( g_prevOrderlyState == SHUTDOWN_NONE
|| g_prevOrderlyState == TPM_SU_CLEAR)
return TPM_RC_VALUE + RC_Startup_startupType;
if(g_nvOk == FALSE)
return TPM_RC_NV_UNINITIALIZED;
}
// Internal Date Update
// Translate the TPM2_ShutDown and TPM2_Startup sequence into the startup
// types. Will only be a SU_RESTART if the NV is OK
if( in->startupType == TPM_SU_CLEAR
&& g_prevOrderlyState == TPM_SU_STATE
&& g_nvOk == TRUE)
{
startup = SU_RESTART;
// Read state reset data
NvReadReserved(NV_STATE_RESET, &gr);
}
// In this check, we don't need to look at g_nvOk because that was checked
// above
else if(in->startupType == TPM_SU_STATE && g_prevOrderlyState == TPM_SU_STATE)
{
// Read state clear and state reset data
NvReadReserved(NV_STATE_CLEAR, &gc);
NvReadReserved(NV_STATE_RESET, &gr);
startup = SU_RESUME;
}
else
{
startup = SU_RESET;
}
// Read persistent data from NV
NvReadPersistent();
// Crypto Startup
CryptUtilStartup(startup);
// Read the platform unique value that is used as VENDOR_PERMANENT auth value
g_platformUniqueDetails.t.size = (UINT16)_plat__GetUnique(1,
sizeof(g_platformUniqueDetails.t.buffer),
g_platformUniqueDetails.t.buffer);
// Start up subsystems
// Start counters and timers
TimeStartup(startup);
// Start dictionary attack subsystem
DAStartup(startup);
// Enable hierarchies
HierarchyStartup(startup);
// Restore/Initialize PCR
PCRStartup(startup, locality);
// Restore/Initialize command audit information
CommandAuditStartup(startup);
// Object context variables
if(startup == SU_RESET)
{
// Reset object context ID to 0
gr.objectContextID = 0;
// Reset clearCount to 0
gr.clearCount= 0;
}
// Initialize session table
SessionStartup(startup);
// Initialize index/evict data. This function clear read/write locks
// in NV index
NvEntityStartup(startup);
// Initialize the orderly shut down flag for this cycle to SHUTDOWN_NONE.
gp.orderlyState = SHUTDOWN_NONE;
NvWriteReserved(NV_ORDERLY, &gp.orderlyState);
// Update TPM internal states if command succeeded.
// Record a TPM2_Startup command has been received.
TPMRegisterStartup();
// The H-CRTM state no longer matters
g_DrtmPreStartup = FALSE;
#ifdef EMBEDDED_MODE
if (startup == SU_RESET)
_plat__ResetCallback();
#endif
return TPM_RC_SUCCESS;
}