mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-02 13:20:51 +00:00
Make tests work on public repo as well
PUBLISHED_FROM=78acb18d597b6f47f31da13087fa6685f21ce445
This commit is contained in:
1 parent
3eb4eb8074
commit
7bf5144e62
145 files changed
+30660
-16
No files matched your search
Executable
+2133
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,35 @@
|
||||
#include "rom_functions.h"
|
||||
|
||||
void SLIP_send(uint8_t *pkt, uint32_t size) {
|
||||
send_packet(pkt, size);
|
||||
}
|
||||
|
||||
uint32_t SLIP_recv(void *pkt, uint32_t max_len) {
|
||||
uint8_t c;
|
||||
uint32_t len = 0;
|
||||
uint8_t *p = (uint8_t *) pkt;
|
||||
do {
|
||||
c = uart_rx_one_char_block();
|
||||
} while (c != '\xc0');
|
||||
while (len < max_len) {
|
||||
c = uart_rx_one_char_block();
|
||||
if (c == '\xc0') return len;
|
||||
if (c == '\xdb') {
|
||||
c = uart_rx_one_char_block();
|
||||
if (c == '\xdc') {
|
||||
c = '\xc0';
|
||||
} else if (c == '\xdd') {
|
||||
c = '\xdb';
|
||||
} else {
|
||||
len = 0;
|
||||
break; /* Bad esc sequence. */
|
||||
}
|
||||
}
|
||||
*p++ = c;
|
||||
len++;
|
||||
}
|
||||
do {
|
||||
c = uart_rx_one_char_block();
|
||||
} while (c != '\xc0');
|
||||
return len;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef CS_COMMON_PLATFORMS_ESP8266_STUBS_SLIP_H_
|
||||
#define CS_COMMON_PLATFORMS_ESP8266_STUBS_SLIP_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
void SLIP_send(const void *pkt, uint32_t size);
|
||||
uint32_t SLIP_recv(void *pkt, uint32_t max_len);
|
||||
|
||||
#endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_SLIP_H_ */
|
||||
@@ -0,0 +1,559 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Cesanta Software Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* Spiffy flasher. Implements strong checksums (MD5) and can use higher
|
||||
* baud rates. Actual max baud rate will differe from device to device,
|
||||
* but 921K seems to be common.
|
||||
*
|
||||
* SLIP protocol is used for communication.
|
||||
* First packet is a single byte - command number.
|
||||
* After that, a packet with a variable number of 32-bit (LE) arguments,
|
||||
* depending on command.
|
||||
*
|
||||
* Then command produces variable number of packets of output, but first
|
||||
* packet of length 1 is the response code: 0 for success, non-zero - error.
|
||||
*
|
||||
* See individual command description below.
|
||||
*/
|
||||
|
||||
#include "stub_flasher.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rom_functions.h"
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include "eagle_soc.h"
|
||||
#include "ets_sys.h"
|
||||
#include "../../../miniz.c"
|
||||
#elif defined(ESP32)
|
||||
#include "rom/efuse.h"
|
||||
#include "rom/miniz.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "led.h"
|
||||
#endif
|
||||
|
||||
#include "slip.h"
|
||||
#include "uart.h"
|
||||
|
||||
/* Param: baud rate. */
|
||||
uint32_t params[1] __attribute__((section(".params")));
|
||||
|
||||
#define FLASH_BLOCK_SIZE 65536
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
#define FLASH_PAGE_SIZE 256
|
||||
|
||||
/* These consts should be in sync with flasher_client.go */
|
||||
#define NUM_BUFS 4
|
||||
#define BUF_SIZE 4096
|
||||
#define FLASH_WRITE_SIZE BUF_SIZE
|
||||
|
||||
#define UART_RX_INTS (UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA)
|
||||
|
||||
extern uint32_t _bss_start, _bss_end;
|
||||
|
||||
#ifdef ESP8266
|
||||
#define REG_SPI_BASE(i) (0x60000200 - i * 0x100)
|
||||
|
||||
#define SPI_CMD_REG(i) (REG_SPI_BASE(i) + 0x0)
|
||||
#define SPI_FLASH_WREN (BIT(30))
|
||||
#define SPI_FLASH_RDID (BIT(28))
|
||||
#define SPI_FLASH_SE (BIT(24))
|
||||
#define SPI_FLASH_BE (BIT(23))
|
||||
|
||||
#define SPI_ADDR_REG(i) (REG_SPI_BASE(i) + 0x4)
|
||||
|
||||
#define SPI_USER_REG(i) (REG_SPI_BASE(i) + 0x1C)
|
||||
|
||||
#define SPI_W0_REG(i) (REG_SPI_BASE(i) + 0x40)
|
||||
#endif
|
||||
|
||||
enum read_state {
|
||||
READ_WAIT_START = 0,
|
||||
READ_FLAGS,
|
||||
READ_DATA,
|
||||
READ_UNESCAPE,
|
||||
READ_ERROR,
|
||||
};
|
||||
|
||||
struct data_buf {
|
||||
uint32_t len;
|
||||
uint8_t data[BUF_SIZE];
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define FLAG_COMPRESSED 1
|
||||
|
||||
struct uart_buf {
|
||||
enum read_state state;
|
||||
struct data_buf bufs[NUM_BUFS];
|
||||
uint32_t bri, bwi;
|
||||
uint32_t ps;
|
||||
};
|
||||
|
||||
static inline uint32_t ccount(void) {
|
||||
uint32_t r;
|
||||
__asm volatile("rsr.ccount %0" : "=a"(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
struct write_progress {
|
||||
uint32_t num_written;
|
||||
uint32_t buf_level;
|
||||
uint8_t digest[16];
|
||||
};
|
||||
|
||||
struct write_result {
|
||||
uint32_t wait_time;
|
||||
uint32_t decomp_time;
|
||||
uint32_t write_time;
|
||||
uint32_t erase_time;
|
||||
uint32_t total_time;
|
||||
uint8_t digest[16];
|
||||
};
|
||||
|
||||
static struct uart_buf ub;
|
||||
static uint32_t inflate_buf[TINFL_LZ_DICT_SIZE / sizeof(uint32_t)];
|
||||
|
||||
static void next_write_buf(void) {
|
||||
ub.bwi++;
|
||||
if (ub.bwi == NUM_BUFS) ub.bwi = 0;
|
||||
ub.bufs[ub.bwi].len = 0;
|
||||
ub.bufs[ub.bwi].flags = 0;
|
||||
}
|
||||
|
||||
static void add_byte(uint8_t byte) {
|
||||
struct data_buf *buf = &ub.bufs[ub.bwi];
|
||||
if (buf->len < BUF_SIZE) {
|
||||
buf->data[buf->len++] = byte;
|
||||
ub.ps++;
|
||||
}
|
||||
}
|
||||
|
||||
void uart_isr(void *arg) {
|
||||
uint32_t int_st = READ_PERI_REG(UART_INT_ST_REG(0));
|
||||
uint8_t fifo_len, i;
|
||||
while ((fifo_len = READ_PERI_REG(UART_STATUS_REG(0))) > 0) {
|
||||
for (i = 0; i < fifo_len; i++) {
|
||||
uint8_t byte = READ_PERI_REG(UART_FIFO_REG(0));
|
||||
switch (ub.state) {
|
||||
case READ_WAIT_START: {
|
||||
if (byte == 0xc0) {
|
||||
ub.state = READ_FLAGS;
|
||||
ub.ps = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case READ_FLAGS:
|
||||
case READ_DATA: {
|
||||
struct data_buf *buf = &ub.bufs[ub.bwi];
|
||||
if (byte == 0xdb) {
|
||||
ub.state = READ_UNESCAPE;
|
||||
} else if (byte == 0xc0) {
|
||||
next_write_buf();
|
||||
if (ub.ps == 0) {
|
||||
/* Empty packet, sender aborted. */
|
||||
ub.state = READ_ERROR;
|
||||
SET_PERI_REG_MASK(UART_INT_ENA_REG(0), 0);
|
||||
goto out;
|
||||
} else {
|
||||
ub.state = READ_WAIT_START;
|
||||
}
|
||||
} else {
|
||||
if (ub.state == READ_FLAGS) {
|
||||
buf->flags = byte;
|
||||
ub.state = READ_DATA;
|
||||
} else {
|
||||
add_byte(byte);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case READ_UNESCAPE: {
|
||||
if (byte == 0xdc) {
|
||||
byte = 0xc0;
|
||||
} else if (byte == 0xdd) {
|
||||
byte = 0xdb;
|
||||
} else {
|
||||
ub.state = READ_ERROR;
|
||||
SET_PERI_REG_MASK(UART_INT_ENA_REG(0), 0);
|
||||
goto out;
|
||||
}
|
||||
add_byte(byte);
|
||||
ub.state = READ_DATA;
|
||||
break;
|
||||
}
|
||||
case READ_ERROR: {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
WRITE_PERI_REG(UART_INT_CLR_REG(0), int_st);
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
|
||||
const void *pSrc_buf, size_t src_buf_len,
|
||||
int flags);
|
||||
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
|
||||
#define TINFL_FLAG_PARSE_ZLIB_HEADER 1
|
||||
|
||||
#if defined(ESP8266)
|
||||
int esp_rom_spiflash_erase_start(uint32_t addr, uint32_t cmd) {
|
||||
SPI_write_enable(flashchip);
|
||||
WRITE_PERI_REG(SPI_ADDR_REG(0), addr);
|
||||
WRITE_PERI_REG(SPI_CMD_REG(0), cmd);
|
||||
while (READ_PERI_REG(SPI_CMD_REG(0)) & cmd) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#elif defined(ESP32)
|
||||
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip;
|
||||
|
||||
esp_rom_spiflash_result_t esp_rom_spiflash_erase_start(uint32_t addr,
|
||||
uint32_t cmd) {
|
||||
esp_rom_spiflash_chip_t *spi = &g_rom_spiflash_chip;
|
||||
esp_rom_spiflash_wait_idle(spi);
|
||||
|
||||
REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_USR_DUMMY);
|
||||
REG_SET_FIELD(PERIPHS_SPI_FLASH_USRREG1, SPI_USR_ADDR_BITLEN,
|
||||
ESP_ROM_SPIFLASH_W_SIO_ADDR_BITSLEN);
|
||||
|
||||
WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_WREN);
|
||||
while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0) {
|
||||
}
|
||||
|
||||
WRITE_PERI_REG(PERIPHS_SPI_FLASH_ADDR, addr);
|
||||
WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, cmd);
|
||||
|
||||
return ESP_ROM_SPIFLASH_RESULT_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) {
|
||||
int ret = 0;
|
||||
uint32_t num_erased = 0;
|
||||
struct MD5Context ctx;
|
||||
MD5Init(&ctx);
|
||||
|
||||
if (addr % FLASH_SECTOR_SIZE != 0) return 0x32;
|
||||
if (len % FLASH_SECTOR_SIZE != 0) return 0x33;
|
||||
if (esp_rom_spiflash_unlock() != 0) return 0x34;
|
||||
|
||||
memset(&ub, 0, sizeof(ub));
|
||||
memset(&inflate_buf, 0, sizeof(inflate_buf));
|
||||
ets_isr_attach(ETS_UART0_INUM, uart_isr, &ub);
|
||||
uint32_t saved_conf1 = READ_PERI_REG(UART_CONF1_REG(0));
|
||||
/* Reduce frequency of UART interrupts */
|
||||
WRITE_PERI_REG(UART_CONF1_REG(0), UART_RX_TOUT_EN |
|
||||
(20 << UART_RX_TOUT_THRHD_S) |
|
||||
(100 << UART_RXFIFO_FULL_THRHD_S));
|
||||
SET_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_RX_INTS);
|
||||
ets_isr_unmask(1 << ETS_UART0_INUM);
|
||||
|
||||
struct write_result wr;
|
||||
memset(&wr, 0, sizeof(wr));
|
||||
|
||||
struct write_progress wp = {.num_written = 0, .buf_level = 0};
|
||||
wp.buf_level = (uint32_t) &addr;
|
||||
SLIP_send(&wp, sizeof(wp));
|
||||
wr.total_time = ccount();
|
||||
while (wp.num_written < len) {
|
||||
/* Prepare the space ahead. */
|
||||
uint32_t start_count = ccount();
|
||||
while (erase && num_erased < wp.num_written + FLASH_WRITE_SIZE) {
|
||||
const uint32_t num_left = (len - num_erased);
|
||||
if (num_left >= FLASH_BLOCK_SIZE && addr % FLASH_BLOCK_SIZE == 0) {
|
||||
if (esp_rom_spiflash_erase_start(addr, SPI_FLASH_BE) != 0) {
|
||||
ret = 0x35;
|
||||
goto out;
|
||||
}
|
||||
num_erased += FLASH_BLOCK_SIZE;
|
||||
} else {
|
||||
/* len % FLASH_SECTOR_SIZE == 0 is enforced, no further checks needed */
|
||||
if (esp_rom_spiflash_erase_start(addr, SPI_FLASH_SE) != 0) {
|
||||
ret = 0x36;
|
||||
goto out;
|
||||
}
|
||||
num_erased += FLASH_SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
wr.erase_time += ccount() - start_count;
|
||||
start_count = ccount();
|
||||
/* Wait for data to arrive. */
|
||||
wp.buf_level = 0;
|
||||
for (int i = 0; i < NUM_BUFS; i++) wp.buf_level += ub.bufs[i].len;
|
||||
volatile uint32_t *bwi = &ub.bwi;
|
||||
while (*bwi == ub.bri && ub.state != READ_ERROR) {
|
||||
}
|
||||
struct data_buf *buf = &ub.bufs[ub.bri];
|
||||
if (ub.state == READ_ERROR) {
|
||||
ret = 0x37;
|
||||
goto out;
|
||||
}
|
||||
wr.wait_time += ccount() - start_count;
|
||||
start_count = ccount();
|
||||
uint32_t *data = (uint32_t *) buf->data;
|
||||
uint32_t write_len = buf->len;
|
||||
if (buf->flags & FLAG_COMPRESSED) {
|
||||
data = inflate_buf;
|
||||
write_len = tinfl_decompress_mem_to_mem(
|
||||
&inflate_buf[0], sizeof(inflate_buf), buf->data, write_len,
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER);
|
||||
if (write_len == TINFL_DECOMPRESS_MEM_TO_MEM_FAILED) {
|
||||
ret = 0x40;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
wr.decomp_time += ccount() - start_count;
|
||||
MD5Update(&ctx, (uint8_t *) data, write_len);
|
||||
start_count = ccount();
|
||||
wr.erase_time += ccount() - start_count;
|
||||
start_count = ccount();
|
||||
if (esp_rom_spiflash_write(addr, data, write_len) != 0) {
|
||||
ret = 0x38;
|
||||
goto out;
|
||||
}
|
||||
wr.write_time += ccount() - start_count;
|
||||
buf->len = 0;
|
||||
ub.bri++;
|
||||
if (ub.bri == NUM_BUFS) ub.bri = 0;
|
||||
addr += write_len;
|
||||
wp.num_written += write_len;
|
||||
struct MD5Context ctx2;
|
||||
memcpy(&ctx2, &ctx, sizeof(ctx));
|
||||
MD5Final(wp.digest, &ctx2);
|
||||
SLIP_send(&wp, sizeof(wp));
|
||||
}
|
||||
|
||||
MD5Final(wr.digest, &ctx);
|
||||
|
||||
wr.total_time = ccount() - wr.total_time;
|
||||
SLIP_send(&wr, sizeof(wr));
|
||||
|
||||
out:
|
||||
WRITE_PERI_REG(UART_CONF1_REG(0), saved_conf1);
|
||||
ets_isr_mask(1 << ETS_UART0_INUM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_flash_read(uint32_t addr, uint32_t len, uint32_t block_size,
|
||||
uint32_t max_in_flight) {
|
||||
uint8_t buf[FLASH_SECTOR_SIZE];
|
||||
uint8_t digest[16];
|
||||
struct MD5Context ctx;
|
||||
uint32_t num_sent = 0, num_acked = 0;
|
||||
if (block_size > sizeof(buf)) return 0x52;
|
||||
MD5Init(&ctx);
|
||||
while (num_acked < len) {
|
||||
while (num_sent < len && num_sent - num_acked < max_in_flight) {
|
||||
uint32_t n = len - num_sent;
|
||||
if (n > block_size) n = block_size;
|
||||
if (esp_rom_spiflash_read(addr, (uint32_t *) buf, n) != 0) return 0x53;
|
||||
send_packet(buf, n);
|
||||
MD5Update(&ctx, buf, n);
|
||||
addr += n;
|
||||
num_sent += n;
|
||||
}
|
||||
{
|
||||
if (SLIP_recv(&num_acked, sizeof(num_acked)) != 4) return 0x54;
|
||||
if (num_acked > num_sent) return 0x55;
|
||||
}
|
||||
}
|
||||
MD5Final(digest, &ctx);
|
||||
send_packet(digest, sizeof(digest));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_flash_digest(uint32_t addr, uint32_t len, uint32_t digest_block_size) {
|
||||
uint8_t buf[FLASH_SECTOR_SIZE];
|
||||
uint8_t digest[16];
|
||||
uint32_t read_block_size =
|
||||
digest_block_size ? digest_block_size : sizeof(buf);
|
||||
struct MD5Context ctx;
|
||||
if (digest_block_size > sizeof(buf)) return 0x62;
|
||||
MD5Init(&ctx);
|
||||
while (len > 0) {
|
||||
uint32_t n = len;
|
||||
struct MD5Context block_ctx;
|
||||
MD5Init(&block_ctx);
|
||||
if (n > read_block_size) n = read_block_size;
|
||||
if (esp_rom_spiflash_read(addr, (uint32_t *) buf, n) != 0) return 0x63;
|
||||
MD5Update(&ctx, buf, n);
|
||||
if (digest_block_size > 0) {
|
||||
MD5Update(&block_ctx, buf, n);
|
||||
MD5Final(digest, &block_ctx);
|
||||
send_packet(digest, sizeof(digest));
|
||||
}
|
||||
addr += n;
|
||||
len -= n;
|
||||
}
|
||||
MD5Final(digest, &ctx);
|
||||
send_packet(digest, sizeof(digest));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_flash_read_chip_id(void) {
|
||||
uint32_t chip_id = 0;
|
||||
WRITE_PERI_REG(SPI_CMD_REG(0), SPI_FLASH_RDID);
|
||||
while (READ_PERI_REG(SPI_CMD_REG(0)) & SPI_FLASH_RDID) {
|
||||
}
|
||||
chip_id = READ_PERI_REG(SPI_W0_REG(0)) & 0xFFFFFF;
|
||||
send_packet((uint8_t *) &chip_id, sizeof(chip_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t cmd_loop(void) {
|
||||
uint8_t cmd = 0x55;
|
||||
do {
|
||||
/* Reset FIFO to re-sync */
|
||||
SET_PERI_REG_MASK(UART_CONF0_REG(0), UART_RXFIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(UART_CONF0_REG(0), UART_RXFIFO_RST);
|
||||
uint32_t args[4];
|
||||
uint32_t len = SLIP_recv(&cmd, 1);
|
||||
if (len != 1) {
|
||||
continue;
|
||||
}
|
||||
uint8_t resp = 0xff;
|
||||
switch (cmd) {
|
||||
case CMD_FLASH_WRITE: {
|
||||
len = SLIP_recv(args, sizeof(args));
|
||||
if (len == 12) {
|
||||
resp = do_flash_write(args[0] /* addr */, args[1] /* len */,
|
||||
args[2] /* erase */);
|
||||
} else {
|
||||
resp = 0x41;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_FLASH_READ: {
|
||||
len = SLIP_recv(args, sizeof(args));
|
||||
if (len == 16) {
|
||||
resp = do_flash_read(args[0] /* addr */, args[1], /* len */
|
||||
args[2] /* block_size */,
|
||||
args[3] /* max_in_flight */);
|
||||
} else {
|
||||
resp = 0x51;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_FLASH_DIGEST: {
|
||||
len = SLIP_recv(args, sizeof(args));
|
||||
if (len == 12) {
|
||||
resp = do_flash_digest(args[0] /* addr */, args[1], /* len */
|
||||
args[2] /* digest_block_size */);
|
||||
} else {
|
||||
resp = 0x61;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_FLASH_READ_CHIP_ID: {
|
||||
resp = do_flash_read_chip_id();
|
||||
break;
|
||||
}
|
||||
case CMD_FLASH_ERASE_CHIP: {
|
||||
resp = esp_rom_spiflash_erase_chip();
|
||||
break;
|
||||
}
|
||||
case CMD_BOOT_FW:
|
||||
case CMD_REBOOT: {
|
||||
resp = 0;
|
||||
SLIP_send(&resp, 1);
|
||||
return cmd;
|
||||
}
|
||||
case CMD_ECHO: {
|
||||
len = SLIP_recv(args, sizeof(args));
|
||||
SLIP_send(args, len);
|
||||
resp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SLIP_send(&resp, 1);
|
||||
} while (cmd != CMD_BOOT_FW && cmd != CMD_REBOOT);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void stub_main1(void) {
|
||||
uint32_t baud_rate = params[0];
|
||||
uint32_t greeting = 0x4941484f; /* OHAI */
|
||||
uint8_t last_cmd;
|
||||
|
||||
/* This points at us right now, reset for next boot. */
|
||||
ets_set_user_start(0);
|
||||
|
||||
/* Selects SPI functions for flash pins. */
|
||||
#if defined(ESP8266)
|
||||
SelectSpiFunction();
|
||||
SET_PERI_REG_MASK(0x3FF00014, 1); /* Switch to 160 MHz */
|
||||
#elif defined(ESP32)
|
||||
esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), 0 /* legacy */);
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_config_param(
|
||||
0 /* deviceId */, 16 * 1024 * 1024 /* chip_size */, FLASH_BLOCK_SIZE,
|
||||
FLASH_SECTOR_SIZE, FLASH_PAGE_SIZE, 0xffff /* status_mask */);
|
||||
|
||||
if (baud_rate > 0) {
|
||||
ets_delay_us(10000);
|
||||
set_baud_rate(0, baud_rate);
|
||||
}
|
||||
|
||||
/* Give host time to get ready too. */
|
||||
ets_delay_us(50000);
|
||||
|
||||
#ifdef BAUD_TEST
|
||||
while (1) {
|
||||
WRITE_PERI_REG(UART_FIFO_REG(0), 0x55);
|
||||
}
|
||||
#else
|
||||
SLIP_send(&greeting, 4);
|
||||
#endif
|
||||
|
||||
last_cmd = cmd_loop();
|
||||
|
||||
ets_delay_us(10000);
|
||||
|
||||
if (last_cmd == CMD_BOOT_FW) {
|
||||
#if defined(ESP8266)
|
||||
/*
|
||||
* Find the return address in our own stack and change it.
|
||||
* "flash_finish" it gets to the same point, except it doesn't need to
|
||||
* patch up its RA: it returns from UartDwnLdProc, then from f_400011ac,
|
||||
* then jumps to 0x4000108a, then checks strapping bits again (which will
|
||||
* not have changed), and then proceeds to 0x400010a8.
|
||||
*/
|
||||
volatile uint32_t *sp = &baud_rate;
|
||||
while (*sp != (uint32_t) 0x40001100) sp++;
|
||||
*sp = 0x400010a8;
|
||||
/*
|
||||
* The following dummy asm fragment acts as a barrier, to make sure function
|
||||
* epilogue, including return address loading, is added after our stack
|
||||
* patching.
|
||||
*/
|
||||
__asm volatile("nop.n");
|
||||
return; /* To 0x400010a8 */
|
||||
#elif defined(ESP32)
|
||||
/* TODO(rojer) */
|
||||
#endif
|
||||
} else {
|
||||
software_reset();
|
||||
}
|
||||
/* Not reached */
|
||||
}
|
||||
|
||||
/* miniz requires at least 12K of stack */
|
||||
uint32_t stack[3071];
|
||||
uint32_t stack_end;
|
||||
|
||||
void stub_main(void) {
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start));
|
||||
__asm volatile("movi a1, stack_end\n");
|
||||
stub_main1();
|
||||
// Keep the stack vars alive.
|
||||
stack[0] = stack_end = 0xff;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#ifndef CS_COMMON_PLATFORMS_ESP8266_STUBS_STUB_FLASHER_H_
|
||||
#define CS_COMMON_PLATFORMS_ESP8266_STUBS_STUB_FLASHER_H_
|
||||
|
||||
enum stub_cmd {
|
||||
/*
|
||||
* Write to the SPI flash.
|
||||
*
|
||||
* Args: addr, len, erase; addr and len must be SECTOR_SIZE-aligned.
|
||||
* If erase != 0, perform erase before writing.
|
||||
* Input: Stream of data to be written, note: no SLIP encapsulation here.
|
||||
* Output: SLIP packets with number of bytes written after every write.
|
||||
* This can (and should) be used for flow control. Flasher will
|
||||
* write in 1K chunks but will buffer up to 4K of data
|
||||
* Use this feedback to keep buffer above 1K but below 4K.
|
||||
* Final packet will contain MD5 digest of the data written.
|
||||
*/
|
||||
CMD_FLASH_WRITE = 1,
|
||||
|
||||
/*
|
||||
* Read from the SPI flash.
|
||||
*
|
||||
* Args: addr, len, block_size; no alignment requirements, block_size <= 4K.
|
||||
* Input: None.
|
||||
* Output: Packets of up to block_size with data. An acknowledgement is
|
||||
*expected
|
||||
* after every packet, in the form of a packet with total number of
|
||||
* bytes received so far.
|
||||
* Last packet is the MD5 digest of the data sent.
|
||||
*
|
||||
* Note: No flow control is performed, it is assumed that the host can cope
|
||||
* with the inbound stream.
|
||||
*/
|
||||
CMD_FLASH_READ = 2,
|
||||
|
||||
/*
|
||||
* Compute MD5 digest of the specified flash region.
|
||||
*
|
||||
* Args: addr, len, digest_block_size; no alignment requirements.
|
||||
* Input: None.
|
||||
* Output: If block digests are not enabled (digest_block_size == 0),
|
||||
* only overall digest is produced.
|
||||
* Otherwise, there will be a separate digest for each block,
|
||||
* the remainder (if any) and the overall digest at the end.
|
||||
*/
|
||||
CMD_FLASH_DIGEST = 3,
|
||||
|
||||
/*
|
||||
* Read flash chip ID.
|
||||
* This is the JEDEC ID, containinf manufactirer, SPI mode and capacity.
|
||||
*
|
||||
* Args: None.
|
||||
* Input: None.
|
||||
* Output: 32 bit chip id (only 24 bits are meaningful).
|
||||
*/
|
||||
CMD_FLASH_READ_CHIP_ID = 4,
|
||||
|
||||
/*
|
||||
* Zap the whole chip at once.
|
||||
*
|
||||
* Args: None.
|
||||
* Input: None.
|
||||
* Output: None.
|
||||
*/
|
||||
CMD_FLASH_ERASE_CHIP = 5,
|
||||
|
||||
/*
|
||||
* Boots the firmware from flash.
|
||||
*
|
||||
* Args: None.
|
||||
* Input: None.
|
||||
* Output: None.
|
||||
*/
|
||||
CMD_BOOT_FW = 6,
|
||||
|
||||
/*
|
||||
* Reboot the CPU.
|
||||
* Since strapping settings are not reset, this will reboot into whatever mode
|
||||
* got us here, most likely UART loader.
|
||||
*
|
||||
* Args: None.
|
||||
* Input: None.
|
||||
* Output: None.
|
||||
*/
|
||||
CMD_REBOOT = 7,
|
||||
|
||||
/*
|
||||
* Echo the arguments back to the host.
|
||||
*
|
||||
* Args: variable.
|
||||
* Input: None.
|
||||
* Output: arguments.
|
||||
*/
|
||||
CMD_ECHO = 8,
|
||||
};
|
||||
|
||||
#endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_STUB_FLASHER_H_ */
|
||||
Reference in new issue
Block a user