// 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 "Shutdown_fp.h"
//
//
//     Error Returns                   Meaning
//
//     TPM_RC_TYPE                     if PCR bank has been re-configured, a CLEAR StateSave() is
//                                     required
//
TPM_RC
TPM2_Shutdown(
   Shutdown_In       *in               // IN: input parameter list
   )
{
   TPM_RC            result;

   // 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

   // If PCR bank has been reconfigured, a CLEAR state save is required
   if(g_pcrReConfig && in->shutdownType == TPM_SU_STATE)
       return TPM_RC_TYPE + RC_Shutdown_shutdownType;

// Internal Data Update

   // PCR private date state save
   PCRStateSave(in->shutdownType);

   // Get DRBG state
   CryptDrbgGetPutState(GET_STATE);

   // Save all orderly data
   NvWriteReserved(NV_ORDERLY_DATA, &go);

   // Save RAM backed NV index data
   NvStateSave();

   if(in->shutdownType == TPM_SU_STATE)
   {
       // Save STATE_RESET and STATE_CLEAR data
       NvWriteReserved(NV_STATE_CLEAR, &gc);
       NvWriteReserved(NV_STATE_RESET, &gr);
   }
   else if(in->shutdownType == TPM_SU_CLEAR)
   {
       // Save STATE_RESET data
       NvWriteReserved(NV_STATE_RESET, &gr);
   }

   // Write orderly shut down state
   if(in->shutdownType == TPM_SU_CLEAR)
       gp.orderlyState = TPM_SU_CLEAR;
   else if(in->shutdownType == TPM_SU_STATE)
   {
       gp.orderlyState = TPM_SU_STATE;
       // Hack for the H-CRTM and Startup locality settings
         if(g_DrtmPreStartup)
             gp.orderlyState |= PRE_STARTUP_FLAG;
         else if(g_StartupLocality3)
             gp.orderlyState |= STARTUP_LOCALITY_3;
   }
   else
       pAssert(FALSE);

   NvWriteReserved(NV_ORDERLY, &gp.orderlyState);

   //   If PRE_STARTUP_FLAG was SET, then it will stay set in gp.orderlyState even
   //   if the TPM isn't actually shut down. This is OK because all other checks
   //   of gp.orderlyState are to see if it is SHUTDOWN_NONE. So, having
   //   gp.orderlyState set to another value that is also not SHUTDOWN_NONE, is not
   //   an issue. This must be the case, otherwise, it would be impossible to add
   //   an additional shutdown type without major changes to the code.

   return TPM_RC_SUCCESS;
}