如何将esp8266 / Arduino的yield()移植到esp-open-sdk?

时间:2019-04-04 16:46:27

标签: assembly esp8266 arduino-esp8266

我正在尝试让HTTPS与我的端点一起使用;可以与esp8266 / Arduino堆栈配合使用,但是HW WDT可以通过esp-open-sdk堆栈触发,因此HTTPS连接失败。

我已经重建了mbedtls库,并发现我陷入了以下代码中。喂食SW看门狗(而不是完全停止SW看门狗)没有什么区别。

这是ESP所卡住的部分代码:

int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error)
{
...
            // Getting stuck in this loop!
            system_soft_wdt_stop();
            while ((ret = mbedtls_ssl_handshake(&TLSmsg->ssl)) != 0) {

                if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
                    ret = ESPCONN_OK;
                    break;
                } else{
                    break;
                }
            }
            system_soft_wdt_restart();
...
}

以上循环运行了很长时间,并且在触发HW WDT之前没有完成。然后,ESP重新启动,我发现RST原因为4,这对应于WDT故障。

相同的端点可以在Arduino堆栈上正常工作(尽管使用BearSSL / axTLS)。但是,我怀疑是因为它具有神奇的yield()函数,该函数允许后台任务每隔一段时间运行一次:

size_t WiFiClientSecure::_write(const uint8_t *buf, size_t size, bool pmem) {
  size_t sent_bytes = 0;

  if (!connected() || !size || !_handshake_done) {
    return 0;
  }

  do {
    // Ensure we yield if we need multiple fragments to avoid WDT
    if (sent_bytes) {
      //*** MAGIC YIELD FUNCTION TO ALLOW BACKGROUND TASKS TO RUN ***
      optimistic_yield(1000);
    }

    // Get BearSSL to a state where we can send
    if (_run_until(BR_SSL_SENDAPP) < 0) {
      break;
    }

    if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) {
      size_t sendapp_len;
      unsigned char *sendapp_buf = br_ssl_engine_sendapp_buf(_eng, &sendapp_len);
      int to_send = size > sendapp_len ? sendapp_len : size;
      if (pmem) {
        memcpy_P(sendapp_buf, buf, to_send);
      } else {
        memcpy(sendapp_buf, buf, to_send);
      }
      br_ssl_engine_sendapp_ack(_eng, to_send);
      br_ssl_engine_flush(_eng, 0);
      flush();
      buf += to_send;
      sent_bytes += to_send;
      size -= to_send;
    } else {
      break;
    }
  } while (size);

  return sent_bytes;
}

yield()函数就是这样的汇编,由于我缺乏汇编技巧,因此我很难理解:

    .text
    .align    4
    .literal_position
    .global   cont_yield
    .type     cont_yield, @function
cont_yield:
    /* a1: sp */
    /* a2: void* cont_ctx */
    /* adjust stack and save registers */
    addi    a1,  a1, -24
    s32i    a12, a1, 0
    s32i    a13, a1, 4
    s32i    a14, a1, 8
    s32i    a15, a1, 12
    s32i    a0,  a1, 16
    s32i    a2,  a1, 20

    /* &cont_continue -> cont_ctx.pc_yield */
    movi    a3, cont_continue
    s32i    a3, a2, 8
    /* sp -> cont_ctx.sp_yield */
    s32i    a1, a2, 12

    /* a0 <- cont_ctx.pc_ret */
    l32i    a0, a2, 0
    /* sp <- cont_ctx.sp_ret */
    l32i    a1, a2, 4
    jx      a0

cont_continue:
    l32i    a12, a1, 0
    l32i    a13, a1, 4
    l32i    a14, a1, 8
    l32i    a15, a1, 12
    l32i    a0,  a1, 16
    l32i    a2,  a1, 20
    addi    a1,  a1, 24
    ret
    .size    cont_yield, . - cont_yield

////////////////////////////////////////////////////

/*
  The purpose of cont_wrapper is to signal to xtensa-gdb
  that we want to treat this function as the outermost one.

  From: binutils-gdb-xtensa/gdb/xtensa-tdep.c:2677 <https://git.io/vA8Ps>
    "Special case for terminating backtrace at a function that wants to
    be seen as the outermost one.  Such a function will clear it's RA (A0)
    register to 0 in the prologue instead of saving its original value."
*/

    .text
    .align   4
    .literal_position
    .global  cont_wrapper
    .type    cont_wrapper, @function
cont_wrapper:
    movi    a0, 0
    callx0  a3
    movi    a2, cont_norm
    jx      a2
    .size   cont_wrapper, . - cont_wrapper

////////////////////////////////////////////////////

    .text
    .align   4
    .literal_position
    .global  cont_run
    .type    cont_run, @function
cont_run:
    /* a1: sp */
    /* a2: void* cont_ctx */
    /* a3: void (*pfn) */

    /* adjust stack and save registers */
    addi    a1,  a1, -20
    s32i    a12, a1, 0
    s32i    a13, a1, 4
    s32i    a14, a1, 8
    s32i    a15, a1, 12
    s32i    a0,  a1, 16

    /* cont_ret -> a4 -> cont_ctx.pc_ret*/
    movi    a4, cont_ret
    s32i    a4, a2, 0
    /* sp -> cont_ctx.sp_ret */
    s32i    a1, a2, 4

    /* if cont_ctx.pc_yield != 0, goto cont_resume */
    l32i    a4, a2, 8
    bnez    a4, cont_resume
    /* else */
    /* set new stack*/
    l32i    a1, a2, 16;
    /* goto pfn */
    movi    a2, cont_wrapper
    jx      a2

cont_resume:
    /* a1 <- cont_ctx.sp_yield */
    l32i    a1, a2, 12
    /* reset yield flag, 0 -> cont_ctx.pc_yield */
    movi    a3, 0
    s32i    a3, a2, 8
    /* jump to saved cont_ctx.pc_yield */
    movi    a0, cont_ret
    jx       a4

cont_norm:
    /* calculate pointer to cont_ctx.struct_start from sp */
    l32i    a2,    a1, 4
    /* sp <- cont_ctx.sp_ret */
    l32i    a1, a2, 4
    /* 0 -> cont_ctx.pc_ret */
    movi    a4, 0
    s32i    a4, a2, 0

cont_ret:
    /* restore registers */
    l32i    a12, a1, 0
    l32i    a13, a1, 4
    l32i    a14, a1, 8
    l32i    a15, a1, 12
    l32i    a0,  a1, 16
    /* adjust stack and return */
    addi    a1,  a1, 20
    ret
    .size   cont_run, . - cont_run

所以,我对ESP8266 / Arduino专家的问题是是否可以将上述代码移植到esp-open-sdk堆栈中。或者,如果ESP8266 / Arduino堆栈有一些特殊之处,导致无法使用该端口。

0 个答案:

没有答案