Stefan Thom / SPITIS_TPM20
Revision:
3:4b9ad18eae02
Parent:
2:526bf792254d
diff -r 526bf792254d -r 4b9ad18eae02 SPITIS_TPM20.cpp
--- a/SPITIS_TPM20.cpp	Tue Apr 07 19:13:09 2015 +0000
+++ b/SPITIS_TPM20.cpp	Sat Apr 11 04:01:54 2015 +0000
@@ -23,7 +23,6 @@
  */
 
 #include "SPITIS_TPM20.h"
-#include "TPM20Tables.h"
 
 TIS_TPM20::TIS_RESULT
 TIS_TPM20::InitializeTis()
@@ -43,7 +42,7 @@
         result = TIS_SESSION_RESULT_FAILED;
         goto Cleanup;
     }
-    m_intfCabability = LE_BYTEARRAY_TO_UINT32(dataRegister, 0);
+    m_intfCabability = BYTE_ARRAY_TO_LEUINT32(dataRegister);
 
 #ifdef TPM_TIS_DEBUG_OUTPUT
     printf("TIS.InitializeTis.IntfCapability = 0x%08x\n\r", m_intfCabability);
@@ -85,87 +84,12 @@
     return result;
 }
 
-#ifndef TPM_TPM_TIS_NO_COMMAND_FILTERING
 TIS_TPM20::TIS_RESULT
-TIS_TPM20::ApplyFilter(TIS_TPM20::TIS_LOCALITY locality, uint8_t* pbCmd, uint32_t cbCmd)
-{
-    uint32_t cursor = sizeof(uint16_t) + sizeof(uint32_t);
-    uint32_t ordinal = BE_BYTEARRAY_TO_UINT32(pbCmd, cursor);
-    int32_t handleCount = -1;
-
-    // First filter ordinals based on locality
-    if(locality == TIS_LOCALITY_0)
-    {
-        switch(ordinal)
-        {
-            // We will not allow certain from locality 0 - aka the external TPM channel
-            case TPM_CC_ChangeEPS:
-            case TPM_CC_ChangePPS:
-            case TPM_CC_Clear:
-            case TPM_CC_ClearControl:
-            case TPM_CC_ClockSet:
-            case TPM_CC_PCR_Allocate:
-            case TPM_CC_PCR_SetAuthPolicy:
-            case TPM_CC_Shutdown:
-                return TIS_SESSION_RESULT_FILTERED;
-            default:
-                break;
-        }
-    }
-    
-    // Move on the and lets look at the handle filter
-    cursor += sizeof(ordinal);
-    
-    // Lookup the number of handles in the command
-    for(uint32_t n = 0; s_ccAttr[n].commandIndex != 0x0000 ;n++)
-    {
-        if(s_ccAttr[n].commandIndex == ordinal)
-        {
-            handleCount = s_ccAttr[n].cHandles;
-            break;
-        }
-    }
-    
-    // Easy elimination of invalid cases
-    if((handleCount < 0) || (handleCount > 3) ||
-       (cbCmd < (cursor + (sizeof(uint32_t) * handleCount))))
-    {
-        return TIS_SESSION_RESULT_FILTERED;
-    }
-    
-    // Read the handles from the command and see if they are allowed
-    for(uint32_t n = 0 ;n < handleCount; n++)
-    {
-        uint32_t objectHandle = BE_BYTEARRAY_TO_UINT32(pbCmd, cursor);
-        cursor += sizeof(objectHandle);
-        
-        if(locality == TIS_LOCALITY_0)
-        {
-            switch(objectHandle)
-            {
-                // We will not allow the platform entity to be used from locality 0
-                case TPM_RH_PLATFORM:
-                    return TIS_SESSION_RESULT_FILTERED;
-                default:
-                    break;
-            }
-        }
-    }
-    
-    return TIS_SESSION_RESULT_COMPLETE;
-}
-#endif
-
-TIS_TPM20::TIS_RESULT
-TIS_TPM20::SendCommand(
-    uint8_t* pbCmd,
-    uint32_t cbCmd,
-    TIS_TPM20::TIS_LOCALITY locality)
+TIS_TPM20::StartSession(
+    TIS_TPM20::TIS_LOCALITY locality
+    )
 {
     TIS_RESULT result = TIS_SESSION_RESULT_COMPLETE;
-    uint8_t tisStatus = 0;
-    uint16_t burstCount = 0;
-    uint32_t index = 0;
 
     // Is the driver busy?
     if(m_locality != TIS_NOT_IN_USE)
@@ -186,9 +110,73 @@
         }
     }
 
+    // Request the locality
+    if(!RequestLocality(locality))
+    {
+        result = TIS_SESSION_RESULT_FAILED;
+        goto Cleanup;
+    }
+
+Cleanup:
+    return result;
+}
+
+TIS_TPM20::TIS_RESULT
+TIS_TPM20::EndSession()
+{
+    if(m_locality != TIS_NOT_IN_USE)
+    {
+        // Release the locality again
+#ifdef TPM_TIS_DEBUG_OUTPUT
+        printf("TIS.ReleaseLocality\r\n");
+#endif
+        if(!ReleaseLocality())
+        {
+            return TIS_SESSION_RESULT_FAILED;
+        }
+    }
+    return TIS_SESSION_RESULT_COMPLETE;
+}
+
+TIS_TPM20::TIS_RESULT
+TIS_TPM20::AbortCommand()
+{
+    TIS_RESULT result = TIS_SESSION_RESULT_COMPLETE;
+    uint8_t tisStatus = TIS_STS_COMMAND_READY;
+#ifdef TPM_TIS_DEBUG_OUTPUT
+    printf("TIS.AbortCommand\n\r");
+#endif
+    if((!WriteRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) ||
+       (!ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) ||
+       ((tisStatus & TIS_STS_COMMAND_READY) == 0))
+    {
+        result = TIS_SESSION_RESULT_FAILED;
+    }
+    return result;
+}
+
+TIS_TPM20::TIS_RESULT
+TIS_TPM20::SendCommand(
+    uint8_t* pbCmd,
+    uint32_t cbCmd,
+    uint8_t* pbTrailingData, 
+    uint32_t cbTrailingData)
+{
+    TIS_RESULT result = TIS_SESSION_RESULT_COMPLETE;
+    uint8_t tisStatus = 0;
+    uint16_t burstCount = 0;
+    uint32_t index = 0;
+    
+    // In all TPM, a buffer size of 1,024 octets is allowed.
+    if(cbTrailingData > 1024)
+    {
+        result = TIS_SESSION_RESULT_FAILED;
+        goto Cleanup;        
+    }
+
 #ifndef TPM_TIS_NO_COMMAND_FILTERING
     // Apply command filtering
-    if(ApplyFilter(locality, pbCmd, cbCmd) == TIS_SESSION_RESULT_FILTERED)
+    if(ApplyFilter(m_locality, pbCmd, cbCmd) == TIS_SESSION_RESULT_FILTERED)
     {
 #ifdef TPM_TIS_DEBUG_OUTPUT
         printf("TIS.Schedule: Command filtered\n\r");
@@ -204,30 +192,23 @@
     printf("\n\r");
 #endif
 
-    // Assert the locality
-
-    if(!RequestLocality(locality))
+    // Make sure the TPM is ready for a command
+    do
     {
-        result = TIS_SESSION_RESULT_FAILED;
-        goto Cleanup;
-    }
-
-    // Make sure the TPM is ready for a command
-    if(!ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus)))
-    {
-        result = TIS_SESSION_RESULT_FAILED;
-        goto Cleanup;
-    }
-
-    // Get TPM ready
-    if((tisStatus & TIS_STS_COMMAND_READY) == 0)
-    {
-        if(!AbortCommand())
+        tisStatus = TIS_STS_COMMAND_READY;
+        if(!WriteRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus)))
+        {
+            result = TIS_SESSION_RESULT_FAILED;
+            goto Cleanup;
+        }
+        if(!ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus)))
         {
             result = TIS_SESSION_RESULT_FAILED;
             goto Cleanup;
         }
     }
+    while((tisStatus & TIS_STS_COMMAND_READY) == 0);
+
 #ifdef TPM_TIS_DEBUG_OUTPUT
         printf("TIS.ReadyForCommand\n\r");
 #endif
@@ -258,6 +239,36 @@
         index += iteration;
     } while((cbCmd - index) > 0);
 
+    // Submit trailing data if there is any
+    if((pbTrailingData != NULL) && (cbTrailingData != 0))
+    {
+        index = 0;
+        do
+        {
+            uint16_t iteration = 0;
+    
+            if((burstCount = GetBurstCount()) == 0)
+            {
+                result = TIS_SESSION_RESULT_FAILED;
+                goto Cleanup;
+            }
+    
+            // Assemble the buffer for transmission
+            iteration = min((cbTrailingData - index), min(burstCount, TIS_MAX_HW_FRAME_SIZE));
+#ifdef TPM_TIS_DEBUG_OUTPUT
+            printf("TIS.SendingBurst = %d\r\n", iteration);
+#endif
+            if(!WriteRegister(TIS_DATA_FIFO, &pbTrailingData[index], iteration))
+            {
+                result = TIS_SESSION_RESULT_FAILED;
+                goto Cleanup;
+            }
+    
+            // Update the index
+            index += iteration;
+        } while((cbTrailingData - index) > 0);
+    }
+
     // Command complete?
     if((!ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) ||
        (!(tisStatus & TIS_STS_VALID) || (tisStatus & TIS_STS_DATA_EXPECT)))
@@ -305,7 +316,6 @@
     )
 {
     TIS_RESULT result = TIS_SESSION_RESULT_COMPLETE;
-    uint8_t tisStatus = 0;
     uint16_t burstCount = 0;
     uint32_t index = 0;
     uint32_t rspSize = 0;
@@ -328,16 +338,6 @@
         goto Cleanup;
     }
 
-    if((!ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) ||
-       (!(tisStatus & TIS_STS_VALID) || !(tisStatus & TIS_STS_DATA_AVAIL)))
-    {
-        result = TIS_SESSION_RESULT_FAILED;
-        goto Cleanup;
-    }
-#ifdef TPM_TIS_DEBUG_OUTPUT
-    printf("TIS.DataAvailable\r\n");
-#endif
-
     // Get the response header from the TPM
     if(((burstCount = GetBurstCount()) == 0) ||
        (burstCount < (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t))) ||
@@ -347,7 +347,8 @@
         goto Cleanup;
     }
     index += (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t));
-    rspSize = BE_BYTEARRAY_TO_UINT32(pbRsp, sizeof(uint16_t));
+    rspSize = BYTE_ARRAY_TO_UINT32(&pbRsp[sizeof(uint16_t)]);
+    
 #ifdef TPM_TIS_DEBUG_OUTPUT
     printf("Tis.ResponseSize = %d\r\n", rspSize);
 #endif
@@ -356,17 +357,14 @@
     {
         do
         {
-            uint16_t iteration = 0;
-
-            // Check to make sure the TPM has still data for us
-            if((!ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) ||
-               (!(tisStatus & TIS_STS_VALID) || !(tisStatus & TIS_STS_DATA_AVAIL))  ||
-               ((burstCount = GetBurstCount()) == 0))
+            // Calculate the response iteration size
+            uint16_t iteration = min((rspSize - index), (cbRsp - index));
+            if((burstCount = GetBurstCount()) == 0)
             {
                 result = TIS_SESSION_RESULT_FAILED;
-                goto Cleanup;
+                goto Cleanup;               
             }
-            iteration = min((rspSize - index), min((cbRsp - index), min(burstCount, TIS_MAX_HW_FRAME_SIZE)));
+            iteration = min(iteration, burstCount);
 #ifdef TPM_TIS_DEBUG_OUTPUT
             printf("TIS.ReceivingBurst = %d\r\n", iteration);
 #endif
@@ -374,6 +372,7 @@
             // Read the data for this iteration
             if(!ReadRegister(TIS_DATA_FIFO, &pbRsp[index], iteration))
             {
+                result = TIS_SESSION_RESULT_FAILED;
                 goto Cleanup;
             }
             index += iteration;
@@ -396,53 +395,9 @@
     {
         AbortCommand();
     }
-    // Release the locality again
-#ifdef TPM_TIS_DEBUG_OUTPUT
-    printf("TIS.ReleaseLocality\r\n");
-#endif
-    ReleaseLocality();
     return result;
 }
 
-uint32_t
-TIS_TPM20::ParseResponseHeader(uint8_t* pbRsp, uint32_t cbRsp, uint16_t* rspTag, uint32_t* rspSize)
-{
-    uint32_t rspResponseCode = 0;
-    uint32_t cursor = 0;
-
-    // Check that the response header is well formatted
-    if(cbRsp < (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t)))
-    {
-#ifdef TPM_TIS_DEBUG_OUTPUT
-        printf("TIS.ResponseHdr: Too short = 0x%08x\n\r", cbRsp);
-#endif
-        rspResponseCode = TPM_RC_FAILURE;
-        goto Cleanup;
-    }
-
-    // Read the header components
-    *rspTag = BE_BYTEARRAY_TO_UINT16(pbRsp, cursor);
-    cursor += sizeof(*rspTag);
-    *rspSize = BE_BYTEARRAY_TO_UINT32(pbRsp, cursor);
-    cursor += sizeof(*rspSize);
-    rspResponseCode = BE_BYTEARRAY_TO_UINT32(pbRsp, cursor);
-    cursor += sizeof(rspResponseCode);
-
-    // Check the components
-    if(((*rspTag != TPM_ST_NO_SESSIONS) && (*rspTag != TPM_ST_SESSIONS)) ||
-       (*rspSize != cbRsp))
-    {
-#ifdef TPM_TIS_DEBUG_OUTPUT
-        printf("TIS.ResponseHdr: Tag=0x%04x, Len=0x%08x, RC=0x%08x\n\r", *rspTag, *rspSize, rspResponseCode);
-#endif
-        rspResponseCode = TPM_RC_FAILURE;
-        goto Cleanup;
-    }
-
-Cleanup:    
-    return rspResponseCode;
-}
-
 bool
 TIS_TPM20::FullDuplex(
     bool readCycle,
@@ -531,7 +486,7 @@
         {
             return 0;
         }
-        burstCount = min(LE_BYTEARRAY_TO_UINT16(dataBytes , 0), m_maxBurstCount);
+        burstCount = min(BYTE_ARRAY_TO_LEUINT16(dataBytes), m_maxBurstCount);
 #ifdef TPM_TIS_DEBUG_OUTPUT
         printf("TIS.BurstCount = %d\r\n", burstCount);
 #endif
@@ -642,31 +597,44 @@
     uint8_t dataRegister[sizeof(uint32_t)] = {0};
     uint8_t dataByte = 0;
 
-    if(intEnable != 0)
+    if(intEnable == 0)
     {
+        // Reset the interrupt. Turns out the TPM needs some time to actually do this let me tell you:
+        // That was a very interesting bug hunt! What we end up with here is the following - We reset
+        // the interrupts now and don't look at them. While the TPM actually resets the line, we use
+        // that time to send the next command but before interrupts are turned on for the next command
+        // execution we have to wait until the line is back up again (see below).
+        dataByte = TIS_INT_STATUS_RESET_ALL;
+        if(!WriteRegister(TIS_INT_STATUS_REGISTER, &dataByte, sizeof(dataByte)))
+        {
+            return false;
+        }
+    }
+    else
+    {
+        // Make sure the interrupt is really, really clear before we turn it back on. The TPM takes
+        // around 5-10ms to transition the line back high.
+#ifdef TPM_TIS_DEBUG_OUTPUT
+        if(intEnable == 0) printf("TIS.InteruptStillActive\n\r");
+#endif
+        while(m_interrupt == 0)
+        {
+            wait_us(1000);
+        }
+
         int_enable |= (uint32_t)TIS_INT_ENABLE_GLOBAL_INT_ENABLE | intEnable;
     }
 
-    // Read the Interrupt state
-    ReadRegister(TIS_INT_STATUS_REGISTER, &dataByte, sizeof(dataByte));
+    LEUINT32_TO_BYTE_ARRAY(int_enable, dataRegister);
 
-    dataByte = TIS_INT_STATUS_RESET_ALL;
-    LE_UINT32_TO_BYTEARRAY(int_enable, dataRegister, 0);
 #ifdef TPM_TIS_DEBUG_OUTPUT
-    printf("TIS.ArmTpmInterupt = 0x%08x\n\r", intEnable);
+    if(intEnable)
+        printf("TIS.TpmInterupt = 0x%08x\n\r", intEnable);
+    else
+        printf("TIS.TpmInterupt = OFF\n\r");
 #endif
-    return ((WriteRegister(TIS_INT_STATUS_REGISTER, &dataByte, sizeof(dataByte))) &&
-            (WriteRegister(TIS_INT_ENABLE_REGISTER, dataRegister, sizeof(dataRegister))));
+    return(WriteRegister(TIS_INT_ENABLE_REGISTER, dataRegister, sizeof(dataRegister)));
 }
 
-bool
-TIS_TPM20::AbortCommand()
-{
-    uint8_t tisStatus = TIS_STS_COMMAND_READY;
-#ifdef TPM_TIS_DEBUG_OUTPUT
-    printf("TIS.AbortCommand\n\r");
-#endif
-    return((WriteRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) &&
-           (ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) &&
-           ((tisStatus & TIS_STS_COMMAND_READY) != 0));
-}
+
+