// 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 "InternalRoutines.h"
#include "PP_fp.h"

//
//
//             Functions
//
//             PhysicalPresencePreInstall_Init()
//
//       This function is used to initialize the array of commands that require confirmation with physical presence.
//       The array is an array of bits that has a correspondence with the command code.
//       This command should only ever be executable in a manufacturing setting or in a simulation.
//
void
PhysicalPresencePreInstall_Init(
     void
     )
{
     // Clear all the PP commands
     MemorySet(&gp.ppList, 0,
//
                ((TPM_CC_PP_LAST - TPM_CC_PP_FIRST + 1) + 7) / 8);
   // TPM_CC_PP_Commands always requires PP
   if(CommandIsImplemented(TPM_CC_PP_Commands))
       PhysicalPresenceCommandSet(TPM_CC_PP_Commands);
   // Write PP list to NV
   NvWriteReserved(NV_PP_LIST, &gp.ppList);
   return;
}
//
//
//          PhysicalPresenceCommandSet()
//
//     This function is used to indicate a command that requires PP confirmation.
//
void
PhysicalPresenceCommandSet(
   TPM_CC               commandCode       // IN: command code
   )
{
   UINT32         bitPos;
   // Assume command is implemented. It should be checked before this
   // function is called
   pAssert(CommandIsImplemented(commandCode));
   // If the command is not a PP command, ignore it
   if(commandCode < TPM_CC_PP_FIRST || commandCode > TPM_CC_PP_LAST)
       return;
   bitPos = commandCode - TPM_CC_PP_FIRST;
   // Set bit
   gp.ppList[bitPos/8] |= 1 << (bitPos % 8);
   return;
}
//
//
//          PhysicalPresenceCommandClear()
//
//     This function is used to indicate a command that no longer requires PP confirmation.
//
void
PhysicalPresenceCommandClear(
   TPM_CC               commandCode       // IN: command code
   )
{
   UINT32         bitPos;
   // Assume command is implemented. It should be checked before this
   // function is called
   pAssert(CommandIsImplemented(commandCode));
   // If the command is not a PP command, ignore it
   if(commandCode < TPM_CC_PP_FIRST || commandCode > TPM_CC_PP_LAST)
       return;
   // if the input code is TPM_CC_PP_Commands, it can not be cleared
   if(commandCode == TPM_CC_PP_Commands)
       return;
   bitPos = commandCode - TPM_CC_PP_FIRST;
     // Set bit
     gp.ppList[bitPos/8] |= (1 << (bitPos % 8));
     // Flip it to off
     gp.ppList[bitPos/8] ^= (1 << (bitPos % 8));
     return;
}
//
//
//           PhysicalPresenceIsRequired()
//
//      This function indicates if PP confirmation is required for a command.
//
//      Return Value                      Meaning
//
//      TRUE                              if physical presence is required
//      FALSE                             if physical presence is not required
//
BOOL
PhysicalPresenceIsRequired(
     TPM_CC             commandCode           // IN: command code
     )
{
     UINT32        bitPos;
     // if the input commandCode is not a PP command, return FALSE
     if(commandCode < TPM_CC_PP_FIRST || commandCode > TPM_CC_PP_LAST)
         return FALSE;
     bitPos = commandCode - TPM_CC_PP_FIRST;
     // Check the bit map. If the bit is SET, PP authorization is required
     return ((gp.ppList[bitPos/8] & (1 << (bitPos % 8))) != 0);
}
//
//
//           PhysicalPresenceCapGetCCList()
//
//      This function returns a list of commands that require PP confirmation. The list starts from the first
//      implemented command that has a command code that the same or greater than commandCode.
//
//      Return Value                      Meaning
//
//      YES                               if there are more command codes available
//      NO                                all the available command codes have been returned
//
TPMI_YES_NO
PhysicalPresenceCapGetCCList(
     TPM_CC             commandCode,          // IN: start command code
     UINT32             count,                // IN: count of returned TPM_CC
     TPML_CC           *commandList           // OUT: list of TPM_CC
     )
{
     TPMI_YES_NO       more = NO;
     UINT32            i;
     // Initialize output handle list
     commandList->count = 0;
     // The maximum count of command we may return is MAX_CAP_CC
     if(count > MAX_CAP_CC) count = MAX_CAP_CC;
     // Collect PP commands
     for(i = commandCode; i <= TPM_CC_PP_LAST; i++)
     {
         if(PhysicalPresenceIsRequired(i))
         {
             if(commandList->count < count)
             {
                 // If we have not filled up the return list, add this command
                 // code to it
                 commandList->commandCodes[commandList->count] = i;
                 commandList->count++;
             }
             else
             {
                 // If the return list is full but we still have PP command
                 // available, report this and stop iterating
                 more = YES;
                 break;
             }
         }
     }
     return more;
}