mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
f4ab2beaa8
Commit 891eb3b0 was fixing an issue with PS and EPC1 not being preserved after the window spill procedure. It did so by saving PS in a2 and EPC1 in a4. However the a4 register may be a live register of another window in the call stack, and if it is overwritten and then spilled to the stack, then the corresponding register value will end up being corrupted. In practice the problem would show up as an IllegalInstruction exception, when trying to return from a function when a0 value was 0x40020. Fix by using a0 register instead of a4 as scratch. Also fix a comment about xthal_save_extra_nw, as this function in fact doesn't clobber a4 or a5 because XCHAL_NCP_NUM_ATMPS is defined as 1. Closes https://github.com/espressif/esp-idf/issues/5758
44 lines
1.3 KiB
C
44 lines
1.3 KiB
C
#include "unity.h"
|
|
#include "esp_intr_alloc.h"
|
|
|
|
#if defined(__XTENSA__)
|
|
#include "xtensa/config/core-isa.h"
|
|
#include "xtensa/hal.h"
|
|
#if defined(XCHAL_HAVE_WINDOWED)
|
|
/* Regression test for a0 register being corrupted in _xt_context_save.
|
|
*
|
|
* The idea in this test is to have a function which recursively calls itself
|
|
* with call4, eventually filling up all the register windows. At that point,
|
|
* it does some lengthy operation. If an interrupt occurs at that point, and
|
|
* corrupts a0 register of one of the windows, this will cause an exception
|
|
* when the recursive function returns.
|
|
*/
|
|
|
|
|
|
/* See test_context_save_clober_func.S */
|
|
extern void test_context_save_clober_func(void);
|
|
|
|
static void int_timer_handler(void *arg)
|
|
{
|
|
xthal_set_ccompare(1, xthal_get_ccount() + 10000);
|
|
(*(int*) arg)++;
|
|
}
|
|
|
|
TEST_CASE("context save doesn't corrupt return address register", "[freertos]")
|
|
{
|
|
/* set up an interrupt */
|
|
intr_handle_t ih;
|
|
int int_triggered = 0;
|
|
TEST_ESP_OK(esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, 0, int_timer_handler, &int_triggered, &ih));
|
|
xthal_set_ccompare(1, xthal_get_ccount() + 10000);
|
|
|
|
/* fill all the windows and delay a bit, waiting for an interrupt to happen */
|
|
test_context_save_clober_func();
|
|
|
|
esp_intr_free(ih);
|
|
TEST_ASSERT_GREATER_THAN(0, int_triggered);
|
|
}
|
|
|
|
#endif // XCHAL_HAVE_WINDOWED
|
|
#endif // __XTENSA__
|