Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: SPITIS_TPM20.cpp
- Revision:
- 1:fd0a59e55a85
- Parent:
- 0:b11c8971edd9
- Child:
- 2:526bf792254d
diff -r b11c8971edd9 -r fd0a59e55a85 SPITIS_TPM20.cpp --- a/SPITIS_TPM20.cpp Mon Mar 23 19:03:50 2015 +0000 +++ b/SPITIS_TPM20.cpp Tue Apr 07 15:57:47 2015 +0000 @@ -1,4 +1,4 @@ -/* mbed TCG TIS 1.3 SPI TPM 2.0 Library, +/* mbed TCG SPI TPM 2.0 TIS 1.3 driver, * Copyright (c) 2015, Microsoft Coprporation Inc. * by Stefan Thom (LordOfDorks) StefanTh@Microsoft.com, Stefan@ThomsR.Us * @@ -19,161 +19,412 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. + * */ - - #include "SPITIS_TPM20.h" - -TISTPM20::TISTPM20( - PinName mosi, - PinName miso, - PinName clk, - PinName cs - ) + +#include "SPITIS_TPM20.h" +#include "TPM20Tables.h" + +TIS_TPM20::TIS_RESULT +TIS_TPM20::InitializeTis() { + TIS_RESULT result = TIS_SESSION_RESULT_COMPLETE; + uint8_t dataRegister[sizeof(m_intfCabability)] = {0}; + + if(RequestLocality(TIS_LOCALITY_0) == false) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } + + // Read the TIS capabilities + if(ReadRegister(TIS_INTF_CAPABILITY_REGISTER, dataRegister, sizeof(dataRegister)) == false) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } + m_intfCabability = LE_BYTEARRAY_TO_UINT32(dataRegister, 0); + #ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Init: "); + printf("TIS.InitializeTis.IntfCapability = 0x%08x\n\r", m_intfCabability); #endif - m_SPITpmDev = new SPI(mosi, miso, clk); - m_SPITpmDev->format(8, 0); - m_SPITpmDev->frequency(4000000); - m_SPICSTpmDev = new DigitalOut(cs); - *m_SPICSTpmDev = 1; - m_ExclusiveAccess = false; + + // If the TIS interface has a fixed burst count use that number instead of asking the TPM over and over and save cycles + if(m_intfCabability & TIS_INTF_CAPPABILITY_BURST_COUNT_STATIC) + { + if((m_intfCabability & TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_MASK) == TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_8B) + { + m_fixedBurstCount = 8; + } + else if((m_intfCabability & TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_MASK) == TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_32B) + { + m_fixedBurstCount = 32; + } + else if ((m_intfCabability & TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_MASK) == TIS_INTF_CAPPABILITY_DATA_TRANSFER_SIZE_SUPPORT_64B) + { + m_fixedBurstCount = 64; + } #ifdef TPM_TIS_DEBUG_OUTPUT - printf("OK.\n\r"); + printf("TIS.InitializeTis.FixedBurstCount = %d\n\r", m_fixedBurstCount); #endif + } + + result = TIS_SESSION_RESULT_COMPLETE; + +Cleanup: + ReleaseLocality(); + return result; } -// Release all held resources -TISTPM20::~TISTPM20() +#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) { -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Destroy: "); -#endif - if(m_SPITpmDev != NULL) + 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++) { - delete m_SPITpmDev; - m_SPITpmDev = NULL; + 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; + } + } } - if(m_SPICSTpmDev != NULL) + + 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_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) { - delete m_SPICSTpmDev; - m_SPICSTpmDev = NULL; +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.Schedule: TIS busy at locality %d\n\r", m_locality); +#endif + // Can we preemt? + if(m_locality < locality) + { + result = TIS_SESSION_RESULT_OCCUPIED; + goto Cleanup; + } + else + { + result = TIS_SESSION_RESULT_PREEMPTED; + goto Cleanup; + } + } + +#ifndef TPM_TIS_NO_COMMAND_FILTERING + // Apply command filtering + if(ApplyFilter(locality, pbCmd, cbCmd) == TIS_SESSION_RESULT_FILTERED) + { +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.Schedule: Command filtered\n\r"); +#endif + result = TIS_SESSION_RESULT_FILTERED; + goto Cleanup; + } +#endif + +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.Command: "); + for(uint32_t n = 0; n < cbCmd; n++) printf("%02x ", pbCmd[n]); + printf("\n\r"); +#endif + + // Assert the locality + + if(!RequestLocality(locality)) + { + 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()) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } } #ifdef TPM_TIS_DEBUG_OUTPUT - printf("OK.\n\r"); + printf("TIS.ReadyForCommand\n\r"); +#endif + + // Submit Command + do + { + uint16_t iteration = 0; + + if((burstCount = GetBurstCount()) == 0) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } + + // Assemble the buffer for transmission + iteration = min((cbCmd - 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, &pbCmd[index], iteration)) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } + + // Update the index + index += iteration; + } while((cbCmd - index) > 0); + + // Command complete? + if((!ReadRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) || + (!(tisStatus & TIS_STS_VALID) || (tisStatus & TIS_STS_DATA_EXPECT))) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.CommandComplete\n\r"); +#endif + + // Arm the Interrupt + if(!TpmInteruptOn(TIS_INT_ENABLE_DATA_AVAILABLE_INT_ENABLE)) + { + goto Cleanup; + } + + // Kick the command off + tisStatus = TIS_STS_GO; + if(!WriteRegister(TIS_STS_REGISTER, &tisStatus, sizeof(tisStatus))) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } + +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.Go."); +#endif + + result = TIS_SESSION_RESULT_COMPLETE; + +Cleanup: + if(result != TIS_SESSION_RESULT_COMPLETE) + { + AbortCommand(); + } + return result; } -uint32_t -TISTPM20::Execute( - uint8_t locality, - uint8_t* pbCmd, - uint32_t cbCmd, +TIS_TPM20::TIS_RESULT +TIS_TPM20::RetrieveResponse( uint8_t* pbRsp, uint32_t cbRsp, - uint32_t timeout + uint32_t* pcbRsp ) { - uint32_t result = 0; - Timeout watchdog; + TIS_RESULT result = TIS_SESSION_RESULT_COMPLETE; + uint8_t tisStatus = 0; + uint16_t burstCount = 0; + uint32_t index = 0; + uint32_t rspSize = 0; -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.ExecuteWaitForAccess."); -#endif - - // Only one caller should be talking to the TPM at any given time - while(m_ExclusiveAccess) + if(m_interrupt != 0) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("."); #endif - wait_us(500); + result = TIS_SESSION_RESULT_PENDING; + return result; } - m_ExclusiveAccess = true; #ifdef TPM_TIS_DEBUG_OUTPUT - printf("OK\n\r"); -#endif - - // Set the requested locality for the call - m_Locality = locality; -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Locality = %d\n\r", m_Locality); + printf("IRQ!\r\n"); #endif -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.SetupTimeout\n\r"); -#endif - // Setup TPM timeout - m_TimeoutTriggered = false; - watchdog.attach(this, &TISTPM20::TimeoutTrigger, 0.0001 * timeout); - -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Execute: "); - for(uint32_t n = 0; n < cbCmd; n++) printf("%02x ", pbCmd[n]); - printf("\n\r"); -#endif - - // Execute command on the TPM - if((result = ExecuteTIS(pbCmd, cbCmd, pbRsp, cbRsp)) == 0) + // Disarm the Interrupt + if(!TpmInteruptOn(0)) { -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Failed\n\r"); -#endif 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))) || + (!ReadRegister(TIS_DATA_FIFO, &pbRsp[index], (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t))))) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } + index += (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t)); + rspSize = BE_BYTEARRAY_TO_UINT32(pbRsp, sizeof(uint16_t)); +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("Tis.ResponseSize = %d\r\n", rspSize); +#endif + + if(min(rspSize, cbRsp) > index) + { + 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)) + { + result = TIS_SESSION_RESULT_FAILED; + goto Cleanup; + } + iteration = min((rspSize - index), min((cbRsp - index), min(burstCount, TIS_MAX_HW_FRAME_SIZE))); +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.ReceivingBurst = %d\r\n", iteration); +#endif + + // Read the data for this iteration + if(!ReadRegister(TIS_DATA_FIFO, &pbRsp[index], iteration)) + { + goto Cleanup; + } + index += iteration; + } + while(index < min(rspSize, cbRsp)); + } + + *pcbRsp = index; + #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Response: "); - for(uint32_t n = 0; n < result; n++) printf("%02x ", pbRsp[n]); + for(uint32_t n = 0; n < *pcbRsp; n++) printf("%02x ", pbRsp[n]); printf("\n\r"); #endif -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.CancelTimeout\n\r"); -#endif + result = TIS_SESSION_RESULT_COMPLETE; Cleanup: - watchdog.detach(); - m_ExclusiveAccess = false; + if((result != TIS_SESSION_RESULT_COMPLETE) && (result != TIS_SESSION_RESULT_PENDING)) + { + AbortCommand(); + } + // Release the locality again +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.ReleaseLocality\r\n"); +#endif + ReleaseLocality(); return result; } uint32_t -TISTPM20::ParseResponseHeader( - uint8_t* pbRsp, - uint32_t rspLen, - uint16_t* rspTag, - uint32_t* rspSize, - uint32_t* cursor - ) +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(rspLen < (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t))) + if(cbRsp < (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t))) { #ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.ResponseHdr.rspLen = 0x%08x\n\r", rspLen); + printf("TIS.ResponseHdr: Too short = 0x%08x\n\r", cbRsp); #endif rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } - + // Read the header components - *rspTag = BYTEARRAY_TO_UINT16(pbRsp, *cursor); - *cursor += sizeof(uint16_t); - *rspSize = BYTEARRAY_TO_UINT32(pbRsp, *cursor); - *cursor += sizeof(uint32_t); - rspResponseCode = BYTEARRAY_TO_UINT32(pbRsp, *cursor); - *cursor += sizeof(uint32_t); + *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 != rspLen)) + (*rspSize != cbRsp)) { #ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.ResponseHdr.rspTag = 0x%04x.rspLen=0x%08x\n\r", *rspTag, rspLen); + printf("TIS.ResponseHdr: Tag=0x%04x, Len=0x%08x, RC=0x%08x\n\r", *rspTag, *rspSize, rspResponseCode); #endif rspResponseCode = TPM_RC_FAILURE; goto Cleanup; @@ -183,482 +434,10 @@ return rspResponseCode; } -uint32_t -TISTPM20::TPM2_Startup( - uint8_t locality, - uint16_t startupType - ) -{ - uint32_t rspLen = 0; - uint16_t rspTag = 0; - uint32_t rspSize = 0; - uint32_t rspResponseCode = 0; - uint32_t cursor = 0; - uint8_t tpmCmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; -#ifndef TPM_TIS_DEBUG_OUTPUT - uint32_t timeout = 2000; -#else - uint32_t timeout = 20000; -#endif - UINT16_TO_BYTEARRAY(startupType, tpmCmd, sizeof(tpmCmd) - 2); - -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_Startup(0x%04x)\n\r", startupType); -#endif - - if((rspLen = Execute(locality, tpmCmd, sizeof(tpmCmd), tpmCmd, sizeof(tpmCmd), timeout)) == 0) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) - { - goto Cleanup; - } - - if(rspSize != 0x0000000a) - { - rspResponseCode = TPM_RC_FAILURE; - } - -Cleanup: -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_Startup.ResponseCode = 0x%08x\n\r", rspResponseCode); -#endif - return rspResponseCode; -} - -uint32_t -TISTPM20::TPM2_Shutdown( - uint8_t locality, - uint16_t shutdownType - ) -{ - uint32_t rspLen = 0; - uint16_t rspTag = 0; - uint32_t rspSize = 0; - uint32_t rspResponseCode = 0; - uint32_t cursor = 0; - uint8_t tpmCmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x45, 0x00, 0x00}; -#ifndef TPM_TIS_DEBUG_OUTPUT - uint32_t timeout = 2000; -#else - uint32_t timeout = 20000; -#endif - UINT16_TO_BYTEARRAY(shutdownType, tpmCmd, sizeof(tpmCmd) - 2); - -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_Shutdown(0x%04x)\n\r", shutdownType); -#endif - - if((rspLen = Execute(locality, tpmCmd, sizeof(tpmCmd), tpmCmd, sizeof(tpmCmd), timeout)) == 0) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) - { - goto Cleanup; - } - - if(rspSize != 0x0000000a) - { - rspResponseCode = TPM_RC_FAILURE; - } - -Cleanup: -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_Shutdown.ResponseCode = 0x%08x\n\r", rspResponseCode); -#endif - return rspResponseCode; -} - -uint32_t -TISTPM20::TPM2_SelfTest( - uint8_t locality, - uint8_t fullTest - ) -{ - uint32_t rspLen = 0; - uint16_t rspTag = 0; - uint32_t rspSize = 0; - uint32_t rspResponseCode = 0; - uint32_t cursor = 0; - uint8_t tpmCmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x43, 0x00}; -#ifndef TPM_TIS_DEBUG_OUTPUT - uint32_t timeout = 2000; -#else - uint32_t timeout = 20000; -#endif - tpmCmd[sizeof(tpmCmd) - 1] = fullTest; - -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_SelfTest(0x%02x)\n\r", fullTest); -#endif - - if((rspLen = Execute(locality, tpmCmd, sizeof(tpmCmd), tpmCmd, sizeof(tpmCmd), timeout)) == 0) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) - { - goto Cleanup; - } - - if(rspSize != 0x0000000a) - { - rspResponseCode = TPM_RC_FAILURE; - } - -Cleanup: -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_SelfTest.ResponseCode = 0x%08x\n\r", rspResponseCode); -#endif - return rspResponseCode; -} - -uint32_t -TISTPM20::TPM2_GetRandom( - uint8_t locality, - uint16_t bytesRequested, - uint8_t* randomBytes - ) -{ - uint32_t cursor = 0; - uint32_t rspLen = 0; - uint16_t rspTag = 0; - uint32_t rspSize = 0; - uint32_t rspResponseCode = 0; - uint32_t tpmMax = sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + bytesRequested; - uint8_t* tpmCmd = new uint8_t[tpmMax]; - uint16_t bytesReturned = 0; -#ifndef TPM_TIS_DEBUG_OUTPUT - uint32_t timeout = 2000; -#else - uint32_t timeout = 20000; -#endif - - if(tpmCmd == NULL) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - - // Build command - UINT16_TO_BYTEARRAY(TPM_ST_NO_SESSIONS, tpmCmd, cursor); - cursor += sizeof(uint16_t) + sizeof(cursor); - UINT32_TO_BYTEARRAY(TPM_CC_GetRandom, tpmCmd, cursor); - cursor += sizeof(TPM_CC_GetRandom); - UINT16_TO_BYTEARRAY(bytesRequested, tpmCmd, cursor); - cursor += sizeof(bytesRequested); - UINT32_TO_BYTEARRAY(cursor, tpmCmd, sizeof(uint16_t)); - -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_GetRandom(%d)\n\r", bytesRequested); -#endif - - if((rspLen = Execute(locality, tpmCmd, cursor, tpmCmd, tpmMax, timeout)) == 0) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - cursor = 0; - if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) - { - goto Cleanup; - } - - if(rspSize != tpmMax) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - - // Copy the random bytes out - bytesReturned = BYTEARRAY_TO_UINT16(tpmCmd, cursor); - cursor += sizeof(uint16_t); - memcpy(randomBytes, &tpmCmd[cursor], (size_t)min(bytesReturned, bytesRequested)); - - Cleanup: -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_GetRandom.ResponseCode = 0x%08x\n\r", rspResponseCode); -#endif - if(tpmCmd != NULL) - { - delete[] tpmCmd; - tpmCmd = NULL; - } - return rspResponseCode; -} - -uint32_t -TISTPM20::TPM2_StirRandom( - uint8_t locality, - uint16_t inDataLen, - uint8_t* inData - ) -{ - uint32_t cursor = 0; - uint32_t rspLen = 0; - uint16_t rspTag = 0; - uint32_t rspSize = 0; - uint32_t rspResponseCode = 0; - uint32_t tpmMax = sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + inDataLen; - uint8_t* tpmCmd = new uint8_t[tpmMax]; - #ifndef TPM_TIS_DEBUG_OUTPUT - uint32_t timeout = 2000; -#else - uint32_t timeout = 20000; -#endif - - if(tpmCmd == NULL) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - - // Build command - UINT16_TO_BYTEARRAY(TPM_ST_NO_SESSIONS, tpmCmd, cursor); - cursor += sizeof(uint16_t) + sizeof(cursor); - UINT32_TO_BYTEARRAY(TPM_CC_StirRandom, tpmCmd, cursor); - cursor += sizeof(TPM_CC_GetRandom); - UINT16_TO_BYTEARRAY(inDataLen, tpmCmd, cursor); - cursor += sizeof(inDataLen); - memcpy(&tpmCmd[cursor], inData, inDataLen); - cursor += inDataLen; - UINT32_TO_BYTEARRAY(cursor, tpmCmd, sizeof(uint16_t)); - -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_StirRandom(%d)\n\r", inDataLen); -#endif - - if((rspLen = Execute(locality, tpmCmd, cursor, tpmCmd, tpmMax, timeout)) == 0) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - cursor = 0; - if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) - { - goto Cleanup; - } - - if(rspSize != 0x0000000a) - { - rspResponseCode = TPM_RC_FAILURE; - goto Cleanup; - } - - Cleanup: -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.TPM2_StirRandom.ResponseCode = 0x%08x\n\r", rspResponseCode); -#endif - if(tpmCmd != NULL) - { - delete[] tpmCmd; - tpmCmd = NULL; - } - return rspResponseCode; -} - -void -TISTPM20::TimeoutTrigger( - void - ) -{ - m_TimeoutTriggered = true; -} - -uint32_t -TISTPM20::ExecuteTIS( - uint8_t* pbCmd, - uint32_t cbCmd, - uint8_t* pbRsp, - uint32_t cbRsp - ) -{ - uint32_t result = 0; - uint8_t tisStatus = 0xFF; - uint32_t index = 0; - uint32_t rspSize = 0; - uint16_t tisBurstCount = 0; - - // Lock the requested locality -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.RequestLocality\r\n"); -#endif - if(!RequestLocality()) - { - goto Cleanup; - } - - // Check the status before writing the command - if(!GetStatus(&tisStatus)) - { - goto Cleanup; - } - // Abort anything that may still be stuck in the TPM - if((tisStatus & TIS_STS_COMMAND_READY) == 0) - { -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.GetReady\r\n"); -#endif - uint8_t mask = TIS_STS_COMMAND_READY; - if(!Abort() || !WaitForStatus(mask)) - { - goto Cleanup; - } - } -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.ReadyForCommand\r\n"); -#endif - - // Send the command to the TPM - do - { - uint16_t cbIteration = 0; - - // Get the maximum bytes we can send for this iteration - if((!GetBurstCount(&tisBurstCount)) || (tisBurstCount == 0)) - { - goto Cleanup; - } -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.GetBurstCount = %d\r\n", tisBurstCount); -#endif - - // Assemble the buffer for transmission - cbIteration = min((cbCmd - index), min(tisBurstCount, TIS_MAX_HW_FRAME_SIZE)); -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.SendingBurst = %d\r\n", cbIteration); -#endif - if(!SPIFullDuplex(false, TIS_DATA_FIFO, &pbCmd[index], cbIteration)) - { - goto Cleanup; - } - - // Update the counts - index += cbIteration; -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Remaining = %d\r\n", (cbCmd - index)); -#endif - } while((cbCmd - index) > 0); - - // Wait for the TPM to get ready and kick the command off -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.StatusValid\r\n"); -#endif - if(!WaitForStatus(TIS_STS_VALID) || !Go()) - { - goto Cleanup; - } - -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Go\r\n"); -#endif - - // Wait for the TPM to finish the command execution - do - { - wait_us(1000); - tisStatus = 0xFF; - if(!GetStatus(&tisStatus) || ((tisStatus & TIS_STS_VALID) == 0)) - { - goto Cleanup; - } - } - while(((tisStatus & TIS_STS_DATA_AVAIL) == 0) && (!m_TimeoutTriggered)); - - if(m_TimeoutTriggered) - { - goto Cleanup; - } - - // Get the response header from the TPM - index = 0; -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("Tis.ReadResponseHeader\r\n"); -#endif - if(!GetBurstCount(&tisBurstCount) || - (tisBurstCount < (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t))) || - !SPIFullDuplex(true, TIS_DATA_FIFO, &pbRsp[index], (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t)))) - { - goto Cleanup; - } - index += (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t)); - - rspSize = BYTEARRAY_TO_UINT32(pbRsp, sizeof(uint16_t)); -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("Tis.ResponseSize = %d\r\n", rspSize); -#endif - - if(rspSize > index) - { -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("Tis.ReadResponse\r\n"); -#endif - do - { - uint16_t cbIteration = 0; - - // Check to make sure the TPM has still data for us - if(!GetStatus(&tisStatus) || ((tisStatus & TIS_STS_DATA_AVAIL) == 0)) - { - goto Cleanup; - } - - // Get the number of available bytes for reading in this iteration - if(!GetBurstCount(&tisBurstCount)) - { - goto Cleanup; - } -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.GetBurstCount = %d\r\n", tisBurstCount); -#endif - - cbIteration = min((rspSize - index), min((cbRsp - index), min(tisBurstCount, TIS_MAX_HW_FRAME_SIZE))); -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.ReceivingBurst = %d\r\n", cbIteration); -#endif - - // Read the data for this iteration - if(!SPIFullDuplex(true, TIS_DATA_FIFO, &pbRsp[index], cbIteration)) - { - goto Cleanup; - } - index += cbIteration; -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Remaining = %d\r\n", (min(rspSize, cbRsp) - index)); -#endif - } - while(index < min(rspSize, cbRsp)); - } - - result = index; - -Cleanup: - // Always leave the TPM in a clean state if somethign fishy happened - if(result == 0) - { -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.Abort\r\n"); -#endif - Abort(); - } - - // Release the locality again -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS.ReleaseLocality\r\n"); -#endif - ReleaseLocality(); - return result; -} - bool -TISTPM20::SPIFullDuplex( +TIS_TPM20::FullDuplex( bool readCycle, - uint8_t tisRegister, + uint16_t reg, uint8_t* pbBuffer, uint16_t cbBuffer ) @@ -668,207 +447,215 @@ uint8_t dataByteOut; // Lock the bus for this operation - *m_SPICSTpmDev = 0; + m_chipSelect = 0; // Send the TIS header - uint32_t tisHdr = TIS_HEADER(m_Locality, readCycle, tisRegister, cbBuffer); -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("TIS(LC:%d,RG:%02x,SZ:%02x,%s):", m_Locality, tisRegister, cbBuffer, (readCycle) ? "RD" : "WR"); + uint32_t tisHdr = TIS_HEADER(m_locality, readCycle, reg, cbBuffer); +#ifdef TPM_TIS_INTERFACE_DEBUG_OUTPUT + printf("TIS(LC:%d,RG:%02x,SZ:%02x,%s):", m_locality, reg, cbBuffer, (readCycle) ? "RD" : "WR"); #endif for(uint8_t n = 0; n < sizeof(tisHdr); n++) { - dataByteOut = tisHdr >> (8 * (3 - n)); - dataByteIn = m_SPITpmDev->write(dataByteOut); + dataByteOut = tisHdr >> (8 * (3 - n)); + dataByteIn = m_spi.write(dataByteOut); +//#ifdef TPM_TIS_INTERFACE_DEBUG_OUTPUT +// if(n < (sizeof(tisHdr) - 1)) printf("%02x ", dataByteOut); +// else printf("%02x", dataByteOut); +//#endif } - - // The last read bit is the wait state indicator - if((dataByteIn & 0x01) == 0) - { - do - { -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("."); -#endif - // Do we still have to wait? - if((dataByteIn = m_SPITpmDev->write(0xFF)) != 0x01) - { - wait_us(10); - } - } - while((dataByteIn != 0x01) && (!m_TimeoutTriggered)); - - // Check if we timed out - if((dataByteIn != 0x01) && (m_TimeoutTriggered)) - { - goto Cleanup; - } - } - - // Do the remaining bytes now - for(uint8_t n = 0; n < cbBuffer; n++) + + // The last bit we read full duplex is the first wait state indicator + int16_t waitCycleRetry = 100; + while(!(dataByteIn & 0x01)) { - dataByteOut = (readCycle) ? 0xFF : pbBuffer[n]; - dataByteIn = m_SPITpmDev->write(dataByteOut); - if(readCycle) pbBuffer[n] = dataByteIn; -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("0x%02x ", (readCycle) ? dataByteIn : dataByteOut); -#endif - } - result = true; -#ifdef TPM_TIS_DEBUG_OUTPUT - printf("\r\n"); +#ifdef TPM_TIS_INTERFACE_DEBUG_OUTPUT + printf("."); #endif - -Cleanup: - // Make sure to release the bus before we leave - *m_SPICSTpmDev = 1; - return result; -} - -bool -TISTPM20::RequestLocality() -{ - do - { - // Do we have access already? - uint8_t dataByte = 0xFF; - if(!SPIFullDuplex(true, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) - { - return false; - } - if((dataByte & TIS_ACCESS_ACTIVE_LOCALITY) && - (dataByte & TIS_ACCESS_VALID)) + // Read the next byte to see is we still have to wait + if((dataByteIn = m_spi.write(0x00)) == 0x01) { break; } - // Request access - dataByte = TIS_ACCESS_REQUEST_USE; - if(!SPIFullDuplex(false, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) - { - return false; - } - if(m_TimeoutTriggered) + // Check the timeout + if(waitCycleRetry-- <= 0) { - // We give up eventually - return false; + result = false; + goto Cleanup; } - wait_us(10); } - while(1); - return true; + + // Full duplex the payload + for(uint8_t n = 0; n < cbBuffer; n++) + { + dataByteOut = (readCycle) ? 0x00 : pbBuffer[n]; + dataByteIn = m_spi.write(dataByteOut); + if(readCycle) pbBuffer[n] = dataByteIn; +#ifdef TPM_TIS_INTERFACE_DEBUG_OUTPUT + printf("%02x ", (readCycle) ? dataByteIn : dataByteOut); +#endif + } + result = true; + +Cleanup: +#ifdef TPM_TIS_INTERFACE_DEBUG_OUTPUT + printf("\r\n"); +#endif + // Make sure to release the bus before we leave + m_chipSelect = 1; + return result; } -bool TISTPM20::ReleaseLocality() +uint16_t +TIS_TPM20::GetBurstCount() { - do + if(m_fixedBurstCount != 0) { - // Do we even have access? - uint8_t dataByte = 0xFF; - if(!SPIFullDuplex(true, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) + return m_fixedBurstCount; + } + else + { + uint8_t dataBytes[sizeof(uint16_t)] = {0}; + if(!ReadRegister(TIS_STS_BURSTCOUNT_REGISTER, dataBytes, sizeof(dataBytes))) { - return false; - } - if(!(dataByte & TIS_ACCESS_ACTIVE_LOCALITY) && - (dataByte & TIS_ACCESS_VALID)) - { - break; + return 0; } - - // Release access - dataByte = TIS_ACCESS_ACTIVE_LOCALITY; - if(!SPIFullDuplex(false, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) - { - return false; - } - if(m_TimeoutTriggered) - { - // We give up eventually - return false; - } - wait_us(10); +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.BurstCount = %d\r\n", LE_BYTEARRAY_TO_UINT16(dataBytes , 0)); +#endif + return LE_BYTEARRAY_TO_UINT16(dataBytes , 0); } - while(1); - return true; } bool -TISTPM20::GetBurstCount( - uint16_t* pBurstCount - ) +TIS_TPM20::RequestLocality(TIS_TPM20::TIS_LOCALITY locality) { - uint8_t dataBytes[sizeof(*pBurstCount)] = {0}; - do + m_locality = locality; + + for(uint8_t n = 0; n < 100; n++) { - if(!SPIFullDuplex(true, TIS_BURSTCOUNT_REGISTER, dataBytes, sizeof(dataBytes))) + uint8_t dataByte = 0; + // Read a valid access register. Turns out, it may take a couple of times if the TPM was sleeping + do { - return false; - } - *pBurstCount = (uint16_t)dataBytes[0] | (uint16_t)(dataBytes[1] << 8); - - // Burst count can be 0 if we are too fast - if(*pBurstCount != 0) - { - break; + dataByte = 0; + if(!ReadRegister(TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) + { + goto Cleanup; + } + + // First time we hit that, the TPM has to wake up give it some time + if(!(dataByte & TIS_ACCESS_VALID)) + { + wait_us(5000); + } } - if(m_TimeoutTriggered) + while(!(dataByte & TIS_ACCESS_VALID)); + + // If we have the locality we are done + if(dataByte & TIS_ACCESS_ACTIVE_LOCALITY) { - // We give up eventually - return false; +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.LocalityAquired\n\r"); +#endif + return true; } - wait_us(10); - } - while(1); - return true; -} -bool -TISTPM20::GetStatus( - uint8_t* pStatus - ) -{ - bool result = SPIFullDuplex(true, TIS_STATUS_REGISTER, pStatus, sizeof(*pStatus)); - return result; + // Request the locality + dataByte = TIS_ACCESS_REQUEST_USE; + if(!WriteRegister(TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) + { + goto Cleanup; + } + } + + m_locality = TIS_NOT_IN_USE; +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.LocalityRequest = FAILED\n\r"); +#endif +Cleanup: + return false; } bool -TISTPM20::WaitForStatus( - uint8_t statusMask - ) +TIS_TPM20::ReleaseLocality() { - bool result = false; - uint8_t tisStatus = 0xFF; + for(uint8_t n = 0; n < 100; n++) + { + uint8_t dataByte = 0; + // Read a valid access register. Turns out, it may take a couple of times if the TPM was sleeping + do + { + if(!ReadRegister(TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) + { + break; + } + + // First time we hit that, the TPM has to wake up give it some time + if(!(dataByte & TIS_ACCESS_VALID)) + { + wait_us(5000); + } + } + while(!(dataByte & TIS_ACCESS_VALID)); - do - { - if(!GetStatus(&tisStatus)) + // If we don't have the locality we are done + if(!(dataByte & TIS_ACCESS_ACTIVE_LOCALITY)) { - goto Cleanup; +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.LocalityReleased\n\r"); +#endif + m_locality = TIS_NOT_IN_USE; + return true; } - if((tisStatus & statusMask) == statusMask) + + // Drop the locality + dataByte = TIS_ACCESS_ACTIVE_LOCALITY; + if(!WriteRegister(TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) { - result = true; break; } - wait_us(10); } - while(!m_TimeoutTriggered); +#ifdef TPM_TIS_DEBUG_OUTPUT + printf("TIS.LocalityReleased = FAILED\n\r"); +#endif -Cleanup: - return result; + return false; } bool -TISTPM20::Abort() +TIS_TPM20::TpmInteruptOn(uint32_t intEnable) { - uint8_t dataByte = TIS_STS_COMMAND_READY; - return SPIFullDuplex(false, TIS_STATUS_REGISTER, &dataByte, sizeof(dataByte)); + uint32_t int_enable = TIS_INT_ENABLE_TYPE_POLARITY_LOW; + uint8_t dataRegister[sizeof(uint32_t)] = {0}; + uint8_t dataByte = 0; + + if(intEnable != 0) + { + int_enable |= (uint32_t)TIS_INT_ENABLE_GLOBAL_INT_ENABLE | intEnable; + } + + // Read the Interrupt state + ReadRegister(TIS_INT_STATUS_REGISTER, &dataByte, sizeof(dataByte)); + + 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); +#endif + return ((WriteRegister(TIS_INT_STATUS_REGISTER, &dataByte, sizeof(dataByte))) && + (WriteRegister(TIS_INT_ENABLE_REGISTER, dataRegister, sizeof(dataRegister)))); } bool -TISTPM20::Go() +TIS_TPM20::AbortCommand() { - uint8_t dataByte = TIS_STS_GO; - return SPIFullDuplex(false, TIS_STATUS_REGISTER, &dataByte, sizeof(dataByte)); -} \ No newline at end of file + 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)); +}