ZHCZ038A October 2017 – June 2025 MSP432E401Y , MSP432E411Y
要解决错误 HIB#16 在清除期间,应用代码可能丢失新的篡改事件 ,必须将 HibernateTamperEventsClear() API 替换为以下 API:
HibernateTamperEventsClearNoLock();
HibernateTamperUnLock();
HibernateTamperLock();
API 定义如下:
//*****************************************************************************
//
//! Clears the tamper feature events without Unlock and Lock.
//!
//! This function is used to clear all tamper events without unlock/locking
//! the tamper control registers, so API HibernateTamperUnLock() should be
//! called before this function, and API HibernateTamperLock() should be
//! called after to ensure that tamper control registers are locked.
//!
//! This function doesn't block until the write is complete.
//! Therefore, care must be taken to ensure the next immediate write will
//! occure only after the write complete bit is set.
//!
//! This function is used to implement a software workaround in NMI interrupt
//! handler to fix an issue when a new tamper event could be missed during
//! the clear of current tamper event.
//!
//! \note The hibernate tamper feature is not available on all
//! devices. Please consult the data sheet for the device that you
//! are using to determine if this feature is available.
//!
//! \return None.
//
//*****************************************************************************
void
HibernateTamperEventsClearNoLock(void)
{
//
// Wait for write completion.
//
_HibernateWriteComplete();
//
//
// Set the tamper event clear bit.
//
HWREG(HIB_TPCTL) |= HIB_TPCTL_TPCLR;
}
//*****************************************************************************
//
//! Unlock temper registers.
//!
//! This function is used to unlock the temper control registers. This
//! function should be only used before calling API
//! HibernateTamperEventsClearNoLock().
//!
//! \note The hibernate tamper feature is not available on all
//! devices. Please consult the data sheet for the device that you
//! are using to determine if this feature is available.
//!
//! \return None.
//
//*****************************************************************************
void
HibernateTamperUnLock(void)
{
//
// Unlock the tamper registers.
//
HWREG(HIB_LOCK) = HIB_LOCK_HIBLOCK_KEY;
_HibernateWriteComplete();
}
//*****************************************************************************
//
//! Lock temper registers.
//!
//! This function is used to lock the temper control registers. This
//! function should be used after calling API
//! HibernateTamperEventsClearNoLock().
//!
//! \note The hibernate tamper feature is not available on all
//! devices. Please consult the data sheet for the device that you
//! are using to determine if this feature is available.
//!
//! \return None.
//
//*****************************************************************************
void
HibernateTamperLock(void)
{
//
// Wait for write completion.
//
_HibernateWriteComplete();
//
// Lock the tamper registers.
//
HWREG(HIB_LOCK) = 0;
_HibernateWriteComplete();
}
必须将软件权变措施添加到 NMI 处理程序中。代码主要在篡改清除同步期间轮询篡改日志条目。
具有此权变措施的 NMI 处理程序示例如下所示。
static uint32_t g_ui32RTCLog[4];
static uint32_t g_ui32EventLog[4];
//*****************************************************************************
//
// Handles an NMI interrupt generated by a Tamper event.
//
//*****************************************************************************
void
NMITamperEventHandler(void)
{
uint32_t ui32NMIStatus, ui32TamperStatus;
uint32_t pui32Buf[3];
uint8_t ui8Idx, ui8StartIdx;
bool bDetectedEventsDuringClear;
//
// Get the cause of the NMI event.
//
ui32NMIStatus = SysCtlNMIStatus();
//
// We should have got the cause of the NMI event from the above function.
// But in Snowflake RA0 the NMIC register is not set correctly when an
// event occurs. So as a work around check if the NMI event is caused by a
// tamper event and append this to the return value from SysCtlNMIStatus().
// This way only this section can be removed once the bug is fixed in next
// silicon rev.
//
ui32TamperStatus = HibernateTamperStatusGet();
if(ui32TamperStatus & (HIBERNATE_TAMPER_STATUS_EVENT |
HIBERNATE_TAMPER_STATUS_EXT_OSC_FAILED))
{
ui32NMIStatus |= SYSCTL_NMI_TAMPER;
}
//
// Check if SysCtlNMIStatus() returned a valid value.
//
if(ui32NMIStatus)
{
//
// Check if the NMI Interrupt is due to a Tamper event.
//
if(ui32NMIStatus & SYSCTL_NMI_TAMPER)
{
//
// If the previous NMI event has not been processed by main
// thread, we need to OR the new event along with the old ones.
//
if(g_ui32NMIEvent == 0)
{
//
// Reset variables that used for tamper event.
//
g_ui32TamperEventFlag = 0;
g_ui32TamperRTCLog = 0;
//
// Clean the log data for debugging purpose.
//
memset(g_ui32RTCLog, 0, (sizeof(g_ui32RTCLog))<<2);
memset(g_ui32EventLog, 0, (sizeof(g_ui32EventLog))<<2);
}
//
// Log the tamper event data before clearing tamper events.
//
for(ui8Idx = 0; ui8Idx< 4; ui8Idx++)
{
if(HibernateTamperEventsGet(ui8Idx,
&g_ui32RTCLog[ui8Idx],
&g_ui32EventLog[ui8Idx]))
{
//
// Event in this log entry, store it.
//
g_ui32TamperEventFlag |= g_ui32EventLog[ui8Idx];
g_ui32TamperRTCLog = g_ui32RTCLog[ui8Idx];
}
else
{
//
// No event in this log entry. Done checking the logs.
//
break;
}
}
//
// Process external oscillator failed event.
//
if(ui32TamperStatus & HIBERNATE_TAMPER_STATUS_EXT_OSC_FAILED)
{
g_ui32TamperXOSCFailEvent++;
g_ui32TamperEventFlag |= HIBERNATE_TAMPER_EVENT_EXT_OSC;
g_ui32TamperRTCLog = HWREG(HIB_TPLOG0);
}
权变措施代码块由此开始。
// The following block of code is to workaround hardware defect
// which results in missing new tamper events during tamper clear
// synchronization.
//
// There is a window after the application code writes the tamper
// clear where a new tamper event can be missed if the application
// requires more than one tamper event pins detection.
//
// The tamper Clear is synchronized to the hibernate 32kHz clock
// domain. The clear takes 3 rising edges of the 32KHz clock.
// During this window, new tamper events could be missed.
// A software workaround is to poll the tamper log during the
// tamper event clear synchronization.
//
//
// Clear the flag for the case there are events triggered
// during clear execution.
//
bDetectedEventsDuringClear = false;
//
// Unlock the Tamper Control register. This is required before
// calling HibernateTamperEventsClearNoLock().
//
HibernateTamperUnLock();
do
{
//
// We will start to poll the log registers at index 1 for
// any new events.
//
ui8StartIdx = 1;
//
// Clear the Tamper event.
// Note this API doesn't wait for synchronization, which
// allows us to check the tamper log during
// synchronization.
//
HibernateTamperEventsClearNoLock();
//
// Check new tamper event during tamper event clear
// synchronization.
// This will take about 92us(three clock cycles) at most.
//
while(HibernateTamperStatusGet() & HIBERNATE_TAMPER_STATUS_EVENT)
{
//
// Clear execution isn't done yet , poll for new events.
// If there were any new event, it will be logged in log 1
// registers and so on.
//
for(ui8Idx = ui8StartIdx; ui8Idx< 4; ui8Idx++)
{
if(HibernateTamperEventsGet(ui8Idx,
&g_ui32RTCLog[ui8Idx],
&g_ui32EventLog[ui8Idx]))
{
//
// detected new event, store it.
//
g_ui32TamperEventFlag |= g_ui32EventLog[ui8Idx];
//
// check for more event.
//
continue;
}
else
{
//
// no new event in this log, update the log index
// to be checked next, and break out of loop.
//
ui8StartIdx = ui8Idx;
break;
}
}
//
// all last three logs have info. Check if all 4 logs
// have the same info. This is to detect the case that
// events happen during clear execution.
//
if(ui8Idx == 4)
{
//
// If events happens during clear
// execution, all four log registers will be
// logged with the same event, to detect this
// condition, we will compare with all four log data.
//
if(HibernateTamperEventsGet(0, &g_ui32RTCLog[0], &g_ui32EventLog[0]))
{
if((g_ui32RTCLog[0] == g_ui32RTCLog[1]) &&
(g_ui32EventLog[0] == g_ui32EventLog[1]) &&
(g_ui32RTCLog[0] == g_ui32RTCLog[2]) &&
(g_ui32EventLog[0] == g_ui32EventLog[2]) &&
(g_ui32RTCLog[0] == g_ui32RTCLog[3]) &&
(g_ui32EventLog[0] == g_ui32EventLog[3]))
{
//
// Detected events during clear execution.
// Event logging takes priority, the clear
// will not be done in this case. We will need
// to go back to the beginning of the loop and
// clear the events.
//
if(bDetectedEventsDuringClear)
{
//
// This condition has already detected,
// we have cleared the event,
// clear the flag.
//
bDetectedEventsDuringClear = false;
}
else
{
// This is the first time it has been
// detected, set the flag.
//
bDetectedEventsDuringClear = true;
}
//
// Break out of while loop so that we can
// clear the events, and start the
// workaround all over again.
//
break;
}
}
else
{
//
// Log 0 didn't detect any events. So this is not
// the case of missing events during clear
// execution.
// Update the log index at which we will poll next.
// It should be the last log entry that OR all the
// new events.
//
ui8StartIdx = 3;
}
}
}
}
while(bDetectedEventsDuringClear);
//
// Lock the Tamper Control register.
//
HibernateTamperLock();
权变措施代码块由此结束。
//
// Save the tamper event and RTC log info in the Hibernate Memory
//
HibernateDataGet(pui32Buf, 3);
pui32Buf[1] = g_ui32TamperEventFlag;
pui32Buf[2] = g_ui32TamperRTCLog;
HibernateDataSet(pui32Buf, 3);
//
// Signal the main loop that an NMI event occurred.
//
g_ui32NMIEvent++;
}
//
// Clear NMI events
//
SysCtlNMIClear(ui32NMIStatus);
}
}