The _plat__NVEnable() function documents its return codes as:
// 0 if success
// > 0 if receive recoverable error
// <0 if unrecoverable error
But the success path (when s_NVInitialized is already TRUE after successful _plat__NvInitFromStorage()) returns _plat__NvEnable_RC_SUCCESS (0). Meanwhile, the caller in fTPM.c (TA_CreateEntryPoint) checks:
if (_plat__NVEnable(NULL)) {
TEE_Panic(TEE_ERROR_BAD_STATE);
}
This means the caller panics when _plat__NVEnable returns non-zero (error), which is correct per the documented semantics. However, the _plat__NVEnable success-with-existing-state path returns _plat__NvEnable_RC_SUCCESS (0), while the success-after-first-init path returns retVal which can be _plat__NvEnable_RC_FAIL_RECOVERABLE (1) when storage was inaccessible but manufacture is needed. The caller treats 1 as an error and panics, even though the platform layer considers this a recoverable state.
This makes the fTPM TA crash (TEE_Panic) on first boot when no prior NV state exists, because _plat__NVEnable returns 1 (needs manufacture), and the caller interprets 1 as failure.
The _plat__NVEnable() function documents its return codes as:
// 0 if success
// > 0 if receive recoverable error
// <0 if unrecoverable error
But the success path (when s_NVInitialized is already TRUE after successful _plat__NvInitFromStorage()) returns _plat__NvEnable_RC_SUCCESS (0). Meanwhile, the caller in fTPM.c (TA_CreateEntryPoint) checks:
if (_plat__NVEnable(NULL)) {
TEE_Panic(TEE_ERROR_BAD_STATE);
}
This means the caller panics when _plat__NVEnable returns non-zero (error), which is correct per the documented semantics. However, the _plat__NVEnable success-with-existing-state path returns _plat__NvEnable_RC_SUCCESS (0), while the success-after-first-init path returns retVal which can be _plat__NvEnable_RC_FAIL_RECOVERABLE (1) when storage was inaccessible but manufacture is needed. The caller treats 1 as an error and panics, even though the platform layer considers this a recoverable state.
This makes the fTPM TA crash (TEE_Panic) on first boot when no prior NV state exists, because _plat__NVEnable returns 1 (needs manufacture), and the caller interprets 1 as failure.