blob: 7df79b4dc512bd35f85b7bdcfa3342b0387babb1 [file] [log] [blame]
/* 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.
*/
#include "Tpm.h"
#include "Startup_fp.h"
#ifdef TPM_CC_Startup // Conditional expansion of this file
/*(See part 3 specification)
// Initialize TPM because a system-wide reset
*/
// return type: TPM_RC
// 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 required.
// 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;
BYTE locality = _plat__LocalityGet();
// The command needs NV update.
RETURN_IF_NV_IS_NOT_AVAILABLE;
// Get the flags for the current startup locality and the H-CRTM.
// Rather than generalizing the locality setting, this code takes advantage
// of the fact that the PC Client specification only allows Startup()
// from locality 0 and 3. To generalize this probably would require a
// redo of the NV space and since this is a feature that is hardly ever used
// outside of the PC Client, this code just support the PC Client needs.
// Input Validation
// Check that the locality is a supported value
if(locality != 0 && locality != 3)
return TPM_RC_LOCALITY;
// If there was a H-CRTM, then treat the locality as being 3
// regardless of what the Startup() was. This is done to preserve the
// H-CRTM PCR so that they don't get overwritten with the normal
// PCR startup initialization. This basically means that g_StartupLocality3
// and g_DrtmPreStartup can't both be SET at the same time.
if(g_DrtmPreStartup)
locality = 0;
g_StartupLocality3 = (locality == 3);
#ifdef USE_DA_USED
// If there was no orderly shutdown, then their might have been a write to
// failedTries that didn't get recorded but only if g_daUsed was SET in the
// shutdown state
g_daUsed = (gp.orderlyState == SU_DA_USED_VALUE);
if(g_daUsed)
gp.orderlyState = SU_NONE_VALUE;
#endif
g_prevOrderlyState = gp.orderlyState;
// If this is a Resume,
if(in->startupType == TPM_SU_STATE)
{
// Turn of the startup modifiers in the recovered state. This will modify
// the SU_NONE_VALUE but not make it anything that would be recognized as
// a valid shutdown
g_prevOrderlyState &= ~(PRE_STARTUP_FLAG | STARTUP_LOCALITY_3);
// then there must have been a prior TPM2_ShutdownState(STATE)
if(g_prevOrderlyState != TPM_SU_STATE)
return TPM_RCS_VALUE + RC_Startup_startupType;
// and the part of NV used for state save must have been recovered
// correctly.
// NOTE: if this fails, then the caller will need to do Startup(CLEAR). The
// code for Startup(Clear) cannot fail if the NV can't be read correctly
// because that would prevent the TPM from ever getting unstuck.
if(g_nvOk == FALSE)
return TPM_RC_NV_UNINITIALIZED;
// For Resume, the H-CRTM has to be the same as the previous boot
if(g_DrtmPreStartup != ((gp.orderlyState & PRE_STARTUP_FLAG) != 0))
return TPM_RCS_VALUE + RC_Startup_startupType;
if(g_StartupLocality3 != ((gp.orderlyState & STARTUP_LOCALITY_3) != 0))
return TPM_RC_LOCALITY;
gp.orderlyState = g_prevOrderlyState;
}
// Internal Date Update
if((gp.orderlyState == TPM_SU_STATE) && (g_nvOk == TRUE))
{
// Always read the data that is only cleared on a Reset because this is not
// a reset
NvRead(&gr, NV_STATE_RESET_DATA, sizeof(gr));
if(in->startupType == TPM_SU_STATE)
{
// If this is a startup STATE (a Resume) need to read the data
// that is cleared on a startup CLEAR because this is not a Reset
// or Restart.
NvRead(&gc, NV_STATE_CLEAR_DATA, sizeof(gc));
startup = SU_RESUME;
}
else
startup = SU_RESTART;
}
else
// Will do a TPM reset if Shutdown(CLEAR) and Startup(CLEAR) or no shutdown
// or there was a failure reading the NV data.
startup = SU_RESET;
// Startup for cryptographic library. Don't do this until after the orderly
// state has been read in from NV.
CryptStartup(startup);
// When the cryptographic library has been started, indicate that a TPM2_Startup
// command has been received.
TPMRegisterStartup();
// Read the platform unique value that is used as VENDOR_PERMANENT
// authorization value
g_platformUniqueDetails.t.size
= (UINT16)_plat__GetUnique(1, sizeof(g_platformUniqueDetails.t.buffer),
g_platformUniqueDetails.t.buffer);
// Start up subsystems
// Start set the safe flag
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);
//// The following code was moved from Time.c where it made no sense
switch (startup)
{
case SU_RESUME:
// Resume sequence
gr.restartCount++;
break;
case SU_RESTART:
// Hibernate sequence
gr.clearCount++;
gr.restartCount++;
break;
default:
// Reset object context ID to 0
gr.objectContextID = 0;
// Reset clearCount to 0
gr.clearCount = 0;
// Reset sequence
// Increase resetCount
gp.resetCount++;
// Write resetCount to NV
NV_SYNC_PERSISTENT(resetCount);
gp.totalResetCount++;
// We do not expect the total reset counter overflow during the life
// time of TPM. if it ever happens, TPM will be put to failure mode
// and there is no way to recover it.
// The reason that there is no recovery is that we don't increment
// the NV totalResetCount when incrementing would make it 0. When the
// TPM starts up again, the old value of totalResetCount will be read
// and we will get right back to here with the increment failing.
if(gp.totalResetCount == 0)
FAIL(FATAL_ERROR_INTERNAL);
// Write total reset counter to NV
NV_SYNC_PERSISTENT(totalResetCount);
// Reset restartCount
gr.restartCount = 0;
break;
}
////
// Initialize session table
SessionStartup(startup);
// Initialize object table
ObjectStartup();
// Initialize index/evict data. This function clears read/write locks
// in NV index
NvEntityStartup(startup);
// Initialize the orderly shut down flag for this cycle to SU_NONE_VALUE.
gp.orderlyState = SU_NONE_VALUE;
NV_SYNC_PERSISTENT(orderlyState);
// This can be reset after the first completion of a TPM2_Startup() after
// a power loss. It can probably be reset earlier but this is an OK place.
g_powerWasLost = FALSE;
return TPM_RC_SUCCESS;
}
#endif // CC_Startup