esp32/esp32s2 set_stack是如何实现的?

vsf_simon
Posts: 20
Joined: Mon Nov 02, 2020 7:30 pm

esp32/esp32s2 set_stack是如何实现的?

Postby vsf_simon » Tue Nov 03, 2020 4:40 am

刚刚开始玩esp32,在移植自己的系统,需要实现一个set_stack设置堆栈的接口。

Code: Select all

static ALWAYS_INLINE void vsf_arch_set_stack(uint32_t stack)
{
//    VSF_ARCH_ASSERT(false);
    // TODO: remove after tested
#if     defined(__CPU_X86__)
    __asm__("movl %0, %%esp" : : "r"(stack));
#elif   defined(__CPU_X64__)
    __asm__("movq %0, %%rsp" : : "r"(stack));
#endif
}
由于使用setjmp库实现的任务切换,所以只需要能够设置堆栈就可以了。
请问这个在esp32/esp32s2上是怎么实现的?

ESP_morris
Posts: 290
Joined: Wed Sep 05, 2018 6:23 am

Re: esp32/esp32s2 set_stack是如何实现的?

Postby ESP_morris » Tue Nov 03, 2020 9:56 am

这个是IDF中查询sp地址的代码

Code: Select all

static inline void* cpu_ll_get_sp(void)
{
    void *sp;
    asm volatile ("mov %0, sp;" : "=r" (sp));
    return sp;
}
对应的设置sp的代码应该也是类似吧,你可以试一下

vsf_simon
Posts: 20
Joined: Mon Nov 02, 2020 7:30 pm

Re: esp32/esp32s2 set_stack是如何实现的?

Postby vsf_simon » Tue Nov 03, 2020 6:37 pm

多谢,测试OK

之前被xt_instr_macros.h里的SET_STACK宏误导

vsf_simon
Posts: 20
Joined: Mon Nov 02, 2020 7:30 pm

Re: esp32/esp32s2 set_stack是如何实现的?

Postby vsf_simon » Wed Nov 04, 2020 6:22 pm

测试还是有问题,移植的是一个基于setjmp实现的协程(arm/x86等都可以使用,只需要实现set_stack),和set_stack相关的部分代码如下:

Code: Select all

static void __vsf_thread_evthandler(uintptr_t local, vsf_evt_t evt)
{
    jmp_buf ret;

    VSF_KERNEL_ASSERT(local != (uintptr_t)NULL);
    class_internal( *(void **)((uintptr_t)local - sizeof(uintptr_t)),
                    this_ptr, vsf_thread_cb_t);
    this_ptr->ret = &ret;
    if (!setjmp(ret)) {
        if (VSF_EVT_INIT == evt) {
            uintptr_t stack = (uintptr_t)(&this_ptr->stack[(this_ptr->stack_size>>3)]);
            printf("set_stack to 0x%08X %d \r\n", stack, this_ptr->stack_size);
            __asm__("mov sp, %0;" : : "r"(stack));
            printf("run on new stack\r\n");
            __vsf_thread_entry();

        } else {
            longjmp(*(this_ptr->pos), evt);
        }
    }
}
这里需要通过set_stack设置新任务的堆栈,原来的堆栈,在之前的setjmp里被记录下来了,新任务返回后,会longjmp到原来的堆栈。

运行结果如下:
I (6018) heap_init: Initializing. RAM available for dynamic allocation:
I (6052) heap_init: At 3FF80000 len 00002000 (8 KiB): RTCRAM
I (6067) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (6083) heap_init: At 3FFB4A10 len 0002B5F0 (173 KiB): DRAM
I (6094) heap_init: At 3FFE0440 len 0001FBC0 (126 KiB): D/IRAM
I (6109) heap_init: At 40078000 len 00008000 (32 KiB): IRAM
I (6116) heap_init: At 4008A844 len 000157BC (85 KiB): IRAM
I (6307) spi_flash: detected chip: gd
I (6371) spi_flash: flash io: dio
W (6386) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (6436) cpu_start: Starting scheduler on PRO CPU.
set_stack to 0x3FFB4160 4096
Guru Meditation Error: Core 0 panic'ed (Double exception).

Core 0 register dump:
PC : 0x400849c3 PS : 0x00040136 A0 : 0x00000000 A1 : 0x3ffb4110
A2 : 0x3f400c9c A3 : 0x3ffafe24 A4 : 0x00001000 A5 : 0x3ffb8540
A6 : 0x3ffb84f0 A7 : 0x3ffb8540 A8 : 0x800d7960 A9 : 0x3ffb3e00
A10 : 0x00002889 A11 : 0x3ffb3e10 A12 : 0x3f400c9c A13 : 0x3ffb4140
A14 : 0x3ffb4120 A15 : 0x00000004 SAR : 0x00000015 EXCCAUSE: 0x00000002
EXCVADDR: 0x00000fe0 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff

Backtrace:0x400849c0:0x3ffb4110


ELF file SHA256: 9ca09f3ea1fea98f

Rebooting...

这里Double exception网上查到是双重异常,到时不知道是如何引发的。

vsf_simon
Posts: 20
Joined: Mon Nov 02, 2020 7:30 pm

Re: esp32/esp32s2 set_stack是如何实现的?

Postby vsf_simon » Wed Nov 04, 2020 6:34 pm

这个堆栈的地址,我也加了一些printf:

Code: Select all

ROOT void __post_vsf_kernel_init(void)
{
#if     VSF_OS_CFG_MAIN_MODE == VSF_OS_CFG_MAIN_MODE_THREAD                     \
    &&  VSF_KERNEL_CFG_SUPPORT_THREAD == ENABLED
    static NO_INIT app_main_thread_t __app_main;
    printf("main_thread: %p %d\r\n", &__app_main, sizeof(__app_main));
#   if VSF_KERNEL_CFG_EDA_SUPPORT_ON_TERMINATE == ENABLED
    __app_main  .use_as__vsf_thread_t
#       if VSF_KERNEL_CFG_EDA_SUPPORT_TIMER == ENABLED
                .use_as__vsf_teda_t
#       endif
                .use_as__vsf_eda_t
                .on_terminate = NULL;
#   endif
......
}
I (7146) cpu_start: ESP-IDF: v4.3-dev-1720-g494a124d9
I (7148) heap_init: Initializing. RAM available for dynamic allocation:
I (7155) heap_init: At 3FF80000 len 00002000 (8 KiB): RTCRAM
I (7157) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (7158) heap_init: At 3FFB4A10 len 0002B5F0 (173 KiB): DRAM
I (7160) heap_init: At 3FFE0440 len 0001FBC0 (126 KiB): D/IRAM
I (7165) heap_init: At 40078000 len 00008000 (32 KiB): IRAM
I (7167) heap_init: At 4008A844 len 000157BC (85 KiB): IRAM
I (7238) spi_flash: detected chip: gd
I (7254) spi_flash: flash io: dio
W (7268) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (7293) cpu_start: Starting scheduler on PRO CPU.
main_thread: 0x3ffb3110 4176
set_stack to 0x3FFB4160 4096
Guru Meditation Error: Core 0 panic'ed (Double exception).

Core 0 register dump:
PC : 0x400849c3 PS : 0x00040136 A0 : 0x00000000 A1 : 0x3ffb4110
A2 : 0x3f400cb4 A3 : 0x3ffafe24 A4 : 0x00001000 A5 : 0x3ffb8540
A6 : 0x3ffb84f0 A7 : 0x3ffb8540 A8 : 0x800d7974 A9 : 0x3ffb3e00
A10 : 0x00002889 A11 : 0x3ffb3e10 A12 : 0x3f400cb4 A13 : 0x3ffb4140
A14 : 0x3ffb4120 A15 : 0x00000004 SAR : 0x00000004 EXCCAUSE: 0x00000002
EXCVADDR: 0x00000fe0 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff

Backtrace:0x400849c0:0x3ffb4110

这里,main_thread的数据结构里,包含了堆栈

vsf_simon
Posts: 20
Joined: Mon Nov 02, 2020 7:30 pm

Re: esp32/esp32s2 set_stack是如何实现的?

Postby vsf_simon » Wed Nov 04, 2020 6:45 pm

Here is the image:
Attachments
esp32_debug.png
esp32_debug.png (295.89 KiB) Viewed 7255 times

vsf_simon
Posts: 20
Joined: Mon Nov 02, 2020 7:30 pm

Re: esp32/esp32s2 set_stack是如何实现的?

Postby vsf_simon » Wed Nov 04, 2020 7:18 pm

https://github.com/espressif/arduino-esp32/issues/1689

看到其他人提过类似的issue,也是基于setjmp实现的协程,但是貌似没解决

vsf_simon
Posts: 20
Joined: Mon Nov 02, 2020 7:30 pm

Re: esp32/esp32s2 set_stack是如何实现的?

Postby vsf_simon » Thu Nov 05, 2020 5:21 am

看了一下xtensa的架构,确实不是简单的一条指令就可以切换堆栈的,还有一些窗口相关的寄存器要处理。估计instr.h里的宏是对的。只是,会引发其他问题,比如类似堆栈检测等等

Who is online

Users browsing this forum: No registered users and 127 guests