1
0
mirror of https://github.com/SuperBFG7/ympd synced 2024-12-27 03:10:26 +00:00

Upgrade to mongoose-6.11

This commit is contained in:
jcorporation 2018-06-12 01:07:03 +01:00
parent 1ec430513f
commit 25fa58aa8c
196 changed files with 67213 additions and 147 deletions

1
src/mongoose Symbolic link
View File

@ -0,0 +1 @@
mongoose-6.11/

View File

@ -0,0 +1,9 @@
binary/
deps/
docker/
docs/
examples/
platforms/
src/
test/
multilingual/

View File

@ -0,0 +1,8 @@
People who have agreed to the
[Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml)
can make contributions. Note that the CLA isn't a copyright
_assigment_ but rather a copyright _license_.
You retain the copyright on your contributions.
We follow the Google C/C++ style guide: https://google.github.io/styleguide/cppguide.html
We'd appreciate if your contribution follows the same style guide.

16
src/mongoose-6.11/LICENSE Normal file
View File

@ -0,0 +1,16 @@
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
Copyright (c) 2013-2016 Cesanta Software Limited
All rights reserved
This software is dual-licensed: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation. For the terms of this
license, see <http://www.gnu.org/licenses/>.
You are free to use this software under the terms of the GNU General
Public License, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Alternatively, you can license this software under a commercial
license, as set out in <https://www.cesanta.com/license>.

View File

@ -0,0 +1,68 @@
# Mongoose - Embedded Web Server / Embedded Networking Library
![](https://img.shields.io/badge/license-GPL_2-green.svg "License")
Mongoose is ideal for embedded environments. It has been designed
for connecting devices and bringing them online. On the market since 2004,
used by vast number of open source and
commercial products - it even runs on the International Space station!
Mongoose makes embedded network programming fast, robust, and easy.
- [Download Mongoose Source Code here](https://www.cesanta.com/download.html)
Looking for a complete IoT firmware solution?
Check out [Mongoose OS](https://mongoose-os.com) - open source embedded operating system for low-power connected microcontrollers. Secure, designed for Internet of Things, complete environment for prototyping, development and managing.
# Support
- [Study mongoose example code](https://github.com/cesanta/mongoose/tree/master/examples)
- [Read User Guide and API reference](https://cesanta.com/docs/overview/intro.html)
- [Support Forum - ask your technical questions here](https://forum.mongoose-os.com/categories/mongoose)
- [Commercial licensing and support available](https://www.cesanta.com/licensing.html)
- [Check our latest releases](https://github.com/cesanta/mongoose/releases)
# Features
* Cross-platform: works on Linux/UNIX, MacOS, QNX, eCos, Windows, Android,
iPhone, FreeRTOS (TI CC3200, ESP8266), etc
* Supported hardware platforms: TI CC3200, TI MSP432, NRF52, STM32, PIC32, ESP8266, ESP32 and more
* Builtin protocols:
- plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way)
- HTTP client, HTTP server
- WebSocket client, WebSocket server
- MQTT client, MQTT broker
- CoAP client, CoAP server
- DNS client, DNS server, async DNS resolver
* Single-threaded, asynchronous, non-blocking core with simple event-based API
* Native support for [PicoTCP embedded TCP/IP stack](http://www.picotcp.com),
[LWIP embedded TCP/IP stack](https://en.wikipedia.org/wiki/LwIP)
* Tiny static and run-time footprint
* Source code is both ISO C and ISO C++ compliant
* Very easy to integrate: just copy
[mongoose.c](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.c) and
[mongoose.h](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.h)
files to your build tree
# Licensing
Mongoose is released under Commercial and [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open source licenses.
Commercial Projects: [Contact us for commercial license.](https://www.cesanta.com/contact.html)
# Dashboard Example
Mongoose is often used to implement device dashboards and real-time
data exchange over Websocket. Here is a dashboard example that illustrates
the functionality:
![](http://www.cesanta.com/images/dashboard.png)
[Developing a new product? Contact us today to discuss how Mongoose can help.](https://www.cesanta.com/contact.html)
# Contributions
To submit contributions, sign [Cesanta CLA](https://cesanta.com/cla.html)
and send GitHub pull request. You retain the copyright on your contributions.
# Looking for a pre-compiled Mongoose web server Windows or Mac binary?
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html)

View File

@ -0,0 +1,8 @@
LOCAL_PATH := $(call my-dir)/..
include $(CLEAR_VARS)
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(COPT)
LOCAL_MODULE := mongoose
LOCAL_SRC_FILES := examples/simplest_web_server/simplest_web_server.c mongoose.c
include $(BUILD_EXECUTABLE)

16132
src/mongoose-6.11/mongoose.c Normal file

File diff suppressed because it is too large Load Diff

6222
src/mongoose-6.11/mongoose.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
exclude_files=sha1\.c

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#include "common/cs_dbg.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "common/cs_time.h"
#include "common/str_util.h"
enum cs_log_level cs_log_threshold WEAK =
#if CS_ENABLE_DEBUG
LL_VERBOSE_DEBUG;
#else
LL_ERROR;
#endif
static char *s_filter_pattern = NULL;
static size_t s_filter_pattern_len;
void cs_log_set_filter(const char *pattern) WEAK;
#if CS_ENABLE_STDIO
FILE *cs_log_file WEAK = NULL;
#if CS_LOG_ENABLE_TS_DIFF
double cs_log_ts WEAK;
#endif
enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE;
void cs_log_set_filter(const char *pattern) {
free(s_filter_pattern);
if (pattern != NULL) {
s_filter_pattern = strdup(pattern);
s_filter_pattern_len = strlen(pattern);
} else {
s_filter_pattern = NULL;
s_filter_pattern_len = 0;
}
}
int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK;
int cs_log_print_prefix(enum cs_log_level level, const char *func,
const char *filename) {
char prefix[21];
if (level > cs_log_threshold) return 0;
if (s_filter_pattern != NULL &&
mg_match_prefix(s_filter_pattern, s_filter_pattern_len, func) == 0 &&
mg_match_prefix(s_filter_pattern, s_filter_pattern_len, filename) == 0) {
return 0;
}
strncpy(prefix, func, 20);
prefix[20] = '\0';
if (cs_log_file == NULL) cs_log_file = stderr;
cs_log_cur_msg_level = level;
fprintf(cs_log_file, "%-20s ", prefix);
#if CS_LOG_ENABLE_TS_DIFF
{
double now = cs_time();
fprintf(cs_log_file, "%7u ", (unsigned int) ((now - cs_log_ts) * 1000000));
cs_log_ts = now;
}
#endif
return 1;
}
void cs_log_printf(const char *fmt, ...) WEAK;
void cs_log_printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(cs_log_file, fmt, ap);
va_end(ap);
fputc('\n', cs_log_file);
fflush(cs_log_file);
cs_log_cur_msg_level = LL_NONE;
}
void cs_log_set_file(FILE *file) WEAK;
void cs_log_set_file(FILE *file) {
cs_log_file = file;
}
#else
void cs_log_set_filter(const char *pattern) {
(void) pattern;
}
#endif /* CS_ENABLE_STDIO */
void cs_log_set_level(enum cs_log_level level) WEAK;
void cs_log_set_level(enum cs_log_level level) {
cs_log_threshold = level;
#if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO
cs_log_ts = cs_time();
#endif
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_CS_DBG_H_
#define CS_COMMON_CS_DBG_H_
#include "common/platform.h"
#if CS_ENABLE_STDIO
#include <stdio.h>
#endif
#ifndef CS_ENABLE_DEBUG
#define CS_ENABLE_DEBUG 0
#endif
#ifndef CS_LOG_ENABLE_TS_DIFF
#define CS_LOG_ENABLE_TS_DIFF 0
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it.
*/
enum cs_log_level {
LL_NONE = -1,
LL_ERROR = 0,
LL_WARN = 1,
LL_INFO = 2,
LL_DEBUG = 3,
LL_VERBOSE_DEBUG = 4,
_LL_MIN = -2,
_LL_MAX = 5,
};
/*
* Set max log level to print; messages with the level above the given one will
* not be printed.
*/
void cs_log_set_level(enum cs_log_level level);
/*
* Set log filter. NULL (a default) logs everything.
* Otherwise, function name and file name will be tested against the given
* pattern, and only matching messages will be printed.
*
* For the pattern syntax, refer to `mg_match_prefix()` in `str_util.h`.
*
* Example:
* ```c
* void foo(void) {
* LOG(LL_INFO, ("hello from foo"));
* }
*
* void bar(void) {
* LOG(LL_INFO, ("hello from bar"));
* }
*
* void test(void) {
* cs_log_set_filter(NULL);
* foo();
* bar();
*
* cs_log_set_filter("f*");
* foo();
* bar(); // Will NOT print anything
*
* cs_log_set_filter("bar");
* foo(); // Will NOT print anything
* bar();
* }
* ```
*/
void cs_log_set_filter(const char *pattern);
/*
* Helper function which prints message prefix with the given `level`, function
* name `func` and `filename`. If message should be printed (accordingly to the
* current log level and filter), prints the prefix and returns 1, otherwise
* returns 0.
*
* Clients should typically just use `LOG()` macro.
*/
int cs_log_print_prefix(enum cs_log_level level, const char *func,
const char *filename);
extern enum cs_log_level cs_log_threshold;
#if CS_ENABLE_STDIO
/*
* Set file to write logs into. If `NULL`, logs go to `stderr`.
*/
void cs_log_set_file(FILE *file);
/*
* Prints log to the current log file, appends "\n" in the end and flushes the
* stream.
*/
void cs_log_printf(const char *fmt, ...)
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
;
/*
* Format and print message `x` with the given level `l`. Example:
*
* ```c
* LOG(LL_INFO, ("my info message: %d", 123));
* LOG(LL_DEBUG, ("my debug message: %d", 123));
* ```
*/
#define LOG(l, x) \
do { \
if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \
} while (0)
#ifndef CS_NDEBUG
/*
* Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))`
*/
#define DBG(x) LOG(LL_VERBOSE_DEBUG, x)
#else /* NDEBUG */
#define DBG(x)
#endif
#else /* CS_ENABLE_STDIO */
#define LOG(l, x)
#define DBG(x)
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CS_COMMON_CS_DBG_H_ */

View File

@ -0,0 +1,211 @@
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include "common/cs_md5.h"
#include "common/str_util.h"
#if !defined(EXCLUDE_COMMON)
#if !CS_DISABLE_MD5
#include "common/cs_endian.h"
static void byteReverse(unsigned char *buf, unsigned longs) {
/* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
#if BYTE_ORDER == BIG_ENDIAN
do {
uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32_t *) buf = t;
buf += 4;
} while (--longs);
#else
(void) buf;
(void) longs;
#endif
}
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
#define MD5STEP(f, w, x, y, z, data, s) \
(w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void cs_md5_init(cs_md5_ctx *ctx) {
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
register uint32_t a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len) {
uint32_t t;
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
ctx->bits[1] += (uint32_t) len >> 29;
t = (t >> 3) & 0x3f;
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
buf += t;
len -= t;
}
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
buf += 64;
len -= 64;
}
memcpy(ctx->in, buf, len);
}
void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx) {
unsigned count;
unsigned char *p;
uint32_t *a;
count = (ctx->bits[0] >> 3) & 0x3F;
p = ctx->in + count;
*p++ = 0x80;
count = 64 - 1 - count;
if (count < 8) {
memset(p, 0, count);
byteReverse(ctx->in, 16);
cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
memset(ctx->in, 0, 56);
} else {
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
a = (uint32_t *) ctx->in;
a[14] = ctx->bits[0];
a[15] = ctx->bits[1];
cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset((char *) ctx, 0, sizeof(*ctx));
}
#endif /* CS_DISABLE_MD5 */
#endif /* EXCLUDE_COMMON */

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_MD5_H_
#define CS_COMMON_MD5_H_
#include "common/platform.h"
#ifndef CS_DISABLE_MD5
#define CS_DISABLE_MD5 0
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t buf[4];
uint32_t bits[2];
unsigned char in[64];
} cs_md5_ctx;
void cs_md5_init(cs_md5_ctx *c);
void cs_md5_update(cs_md5_ctx *c, const unsigned char *data, size_t len);
void cs_md5_final(unsigned char *md, cs_md5_ctx *c);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CS_COMMON_MD5_H_ */

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#include "common/cs_time.h"
#ifndef _WIN32
#include <stddef.h>
/*
* There is no sys/time.h on ARMCC.
*/
#if !(defined(__ARMCC_VERSION) || defined(__ICCARM__)) && \
!defined(__TI_COMPILER_VERSION__) && \
(!defined(CS_PLATFORM) || CS_PLATFORM != CS_P_NXP_LPC)
#include <sys/time.h>
#endif
#else
#include <windows.h>
#endif
double cs_time(void) WEAK;
double cs_time(void) {
double now;
#ifndef _WIN32
struct timeval tv;
if (gettimeofday(&tv, NULL /* tz */) != 0) return 0;
now = (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0);
#else
SYSTEMTIME sysnow;
FILETIME ftime;
GetLocalTime(&sysnow);
SystemTimeToFileTime(&sysnow, &ftime);
/*
* 1. VC 6.0 doesn't support conversion uint64 -> double, so, using int64
* This should not cause a problems in this (21th) century
* 2. Windows FILETIME is a number of 100-nanosecond intervals since January
* 1, 1601 while time_t is a number of _seconds_ since January 1, 1970 UTC,
* thus, we need to convert to seconds and adjust amount (subtract 11644473600
* seconds)
*/
now = (double) (((int64_t) ftime.dwLowDateTime +
((int64_t) ftime.dwHighDateTime << 32)) /
10000000.0) -
11644473600;
#endif /* _WIN32 */
return now;
}
double cs_timegm(const struct tm *tm) {
/* Month-to-day offset for non-leap-years. */
static const int month_day[12] = {0, 31, 59, 90, 120, 151,
181, 212, 243, 273, 304, 334};
/* Most of the calculation is easy; leap years are the main difficulty. */
int month = tm->tm_mon % 12;
int year = tm->tm_year + tm->tm_mon / 12;
int year_for_leap;
int64_t rt;
if (month < 0) { /* Negative values % 12 are still negative. */
month += 12;
--year;
}
/* This is the number of Februaries since 1900. */
year_for_leap = (month > 1) ? year + 1 : year;
rt =
tm->tm_sec /* Seconds */
+
60 *
(tm->tm_min /* Minute = 60 seconds */
+
60 * (tm->tm_hour /* Hour = 60 minutes */
+
24 * (month_day[month] + tm->tm_mday - 1 /* Day = 24 hours */
+ 365 * (year - 70) /* Year = 365 days */
+ (year_for_leap - 69) / 4 /* Every 4 years is leap... */
- (year_for_leap - 1) / 100 /* Except centuries... */
+ (year_for_leap + 299) / 400))); /* Except 400s. */
return rt < 0 ? -1 : (double) rt;
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_CS_TIME_H_
#define CS_COMMON_CS_TIME_H_
#include <time.h>
#include "common/platform.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Sub-second granularity time(). */
double cs_time(void);
/*
* Similar to (non-standard) timegm, converts broken-down time into the number
* of seconds since Unix Epoch.
*/
double cs_timegm(const struct tm *tm);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CS_COMMON_CS_TIME_H_ */

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_MG_MEM_H_
#define CS_COMMON_MG_MEM_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MG_MALLOC
#define MG_MALLOC malloc
#endif
#ifndef MG_CALLOC
#define MG_CALLOC calloc
#endif
#ifndef MG_REALLOC
#define MG_REALLOC realloc
#endif
#ifndef MG_FREE
#define MG_FREE free
#endif
#ifdef __cplusplus
}
#endif
#endif /* CS_COMMON_MG_MEM_H_ */

View File

@ -0,0 +1,121 @@
#ifndef CS_COMMON_PLATFORM_H_
#define CS_COMMON_PLATFORM_H_
/*
* For the "custom" platform, includes and dependencies can be
* provided through mg_locals.h.
*/
#define CS_P_CUSTOM 0
#define CS_P_UNIX 1
#define CS_P_WINDOWS 2
#define CS_P_ESP32 15
#define CS_P_ESP8266 3
#define CS_P_CC3100 6
#define CS_P_CC3200 4
#define CS_P_CC3220 17
#define CS_P_MSP432 5
#define CS_P_TM4C129 14
#define CS_P_MBED 7
#define CS_P_WINCE 8
#define CS_P_NXP_LPC 13
#define CS_P_NXP_KINETIS 9
#define CS_P_NRF51 12
#define CS_P_NRF52 10
#define CS_P_PIC32 11
#define CS_P_STM32 16
/* Next id: 18 */
/* If not specified explicitly, we guess platform by defines. */
#ifndef CS_PLATFORM
#if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__)
#define CS_PLATFORM CS_P_MSP432
#elif defined(cc3200) || defined(TARGET_IS_CC3200)
#define CS_PLATFORM CS_P_CC3200
#elif defined(cc3220) || defined(TARGET_IS_CC3220)
#define CS_PLATFORM CS_P_CC3220
#elif defined(__unix__) || defined(__APPLE__)
#define CS_PLATFORM CS_P_UNIX
#elif defined(WINCE)
#define CS_PLATFORM CS_P_WINCE
#elif defined(_WIN32)
#define CS_PLATFORM CS_P_WINDOWS
#elif defined(__MBED__)
#define CS_PLATFORM CS_P_MBED
#elif defined(__USE_LPCOPEN)
#define CS_PLATFORM CS_P_NXP_LPC
#elif defined(FRDM_K64F) || defined(FREEDOM)
#define CS_PLATFORM CS_P_NXP_KINETIS
#elif defined(PIC32)
#define CS_PLATFORM CS_P_PIC32
#elif defined(ESP_PLATFORM)
#define CS_PLATFORM CS_P_ESP32
#elif defined(ICACHE_FLASH)
#define CS_PLATFORM CS_P_ESP8266
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \
defined(TARGET_IS_TM4C129_RA2)
#define CS_PLATFORM CS_P_TM4C129
#elif defined(STM32)
#define CS_PLATFORM CS_P_STM32
#endif
#ifndef CS_PLATFORM
#error "CS_PLATFORM is not specified and we couldn't guess it."
#endif
#endif /* !defined(CS_PLATFORM) */
#define MG_NET_IF_SOCKET 1
#define MG_NET_IF_SIMPLELINK 2
#define MG_NET_IF_LWIP_LOW_LEVEL 3
#define MG_NET_IF_PIC32 4
#define MG_SSL_IF_OPENSSL 1
#define MG_SSL_IF_MBEDTLS 2
#define MG_SSL_IF_SIMPLELINK 3
#include "common/platforms/platform_unix.h"
#include "common/platforms/platform_windows.h"
#include "common/platforms/platform_esp32.h"
#include "common/platforms/platform_esp8266.h"
#include "common/platforms/platform_cc3100.h"
#include "common/platforms/platform_cc3200.h"
#include "common/platforms/platform_cc3220.h"
#include "common/platforms/platform_mbed.h"
#include "common/platforms/platform_nrf51.h"
#include "common/platforms/platform_nrf52.h"
#include "common/platforms/platform_wince.h"
#include "common/platforms/platform_nxp_lpc.h"
#include "common/platforms/platform_nxp_kinetis.h"
#include "common/platforms/platform_pic32.h"
#include "common/platforms/platform_stm32.h"
/* Common stuff */
#if !defined(WEAK)
#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
#define WEAK __attribute__((weak))
#else
#define WEAK
#endif
#endif
#ifdef __GNUC__
#define NORETURN __attribute__((noreturn))
#define NOINLINE __attribute__((noinline))
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#define NOINSTR __attribute__((no_instrument_function))
#define DO_NOT_WARN_UNUSED __attribute__((unused))
#else
#define NORETURN
#define NOINLINE
#define WARN_UNUSED_RESULT
#define NOINSTR
#define DO_NOT_WARN_UNUSED
#endif /* __GNUC__ */
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#endif
#endif /* CS_COMMON_PLATFORM_H_ */

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* All rights reserved
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "FreeRTOS.h"
#include "common/platform.h"
#include "mgos_core_dump.h"
#include "mgos_hal.h"
struct arm_exc_frame {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t xpsr;
#ifdef ARM_HAVE_FPU
uint32_t s[16];
uint32_t fpscr;
uint32_t reserved;
#endif
} __attribute__((packed));
struct arm_gdb_reg_file {
uint32_t r[13];
uint32_t sp;
uint32_t lr;
uint32_t pc;
uint32_t cpsr;
uint64_t d[16];
uint32_t fpscr;
} __attribute__((packed));
#if ARM_HAVE_FPU
static void save_s16_s31(uint32_t *dst) {
__asm volatile(
"\
vmov r1, s16\n str r1, [%0, 0]\n\
vmov r1, s17\n str r1, [%0, 4]\n\
vmov r1, s18\n str r1, [%0, 8]\n\
vmov r1, s19\n str r1, [%0, 12]\n\
vmov r1, s20\n str r1, [%0, 16]\n\
vmov r1, s21\n str r1, [%0, 20]\n\
vmov r1, s22\n str r1, [%0, 24]\n\
vmov r1, s23\n str r1, [%0, 28]\n\
vmov r1, s24\n str r1, [%0, 32]\n\
vmov r1, s25\n str r1, [%0, 36]\n\
vmov r1, s26\n str r1, [%0, 40]\n\
vmov r1, s27\n str r1, [%0, 44]\n\
vmov r1, s28\n str r1, [%0, 48]\n\
vmov r1, s29\n str r1, [%0, 52]\n\
vmov r1, s30\n str r1, [%0, 56]\n\
vmov r1, s31\n str r1, [%0, 60]\n\
"
:
: "r"(dst)
: "r1");
}
static void print_fpu_regs(const uint32_t *regs, int off, int n) {
for (int i = 0, j = off; i < n; i++, j++) {
if (j % 4 == 0) mgos_cd_putc('\n');
mgos_cd_printf(" S%d: %s0x%08lx", j, (j < 10 ? " " : ""), regs[i]);
}
}
#endif
void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
struct arm_gdb_reg_file *rf) {
char buf[8];
const char *name;
portDISABLE_INTERRUPTS();
switch (isr_no) {
case 0:
name = "ThreadMode";
break;
case 1:
case 7:
case 8:
case 9:
case 10:
case 13:
name = "Reserved";
break;
case 2:
name = "NMI";
break;
case 3:
name = "HardFault";
break;
case 4:
name = "MemManage";
break;
case 5:
name = "BusFault";
break;
case 6:
name = "UsageFault";
break;
case 11:
name = "SVCall";
break;
case 12:
name = "ReservedDebug";
break;
case 14:
name = "PendSV";
break;
case 15:
name = "SysTick";
break;
default: {
sprintf(buf, "IRQ%u", isr_no - 16);
name = buf;
}
}
mgos_cd_printf("\n\n--- Exception %u (%s) ---\n", isr_no, name);
if (rf != NULL) {
mgos_cd_printf(" R0: 0x%08lx R1: 0x%08lx R2: 0x%08lx R3: 0x%08lx\n",
rf->r[0], rf->r[1], rf->r[2], rf->r[3]);
mgos_cd_printf(" R4: 0x%08lx R5: 0x%08lx R6: 0x%08lx R7: 0x%08lx\n",
rf->r[4], rf->r[5], rf->r[6], rf->r[7]);
mgos_cd_printf(" R8: 0x%08lx R9: 0x%08lx R10: 0x%08lx R11: 0x%08lx\n",
rf->r[8], rf->r[9], rf->r[10], rf->r[11]);
mgos_cd_printf(" R12: 0x%08lx SP: 0x%08lx LR: 0x%08lx PC: 0x%08lx\n",
rf->r[12], rf->sp, rf->lr, rf->pc);
mgos_cd_printf(" PSR: 0x%08lx\n", rf->cpsr);
}
memset(rf->d, 0, sizeof(rf->d));
#if ARM_HAVE_FPU
rf->fpscr = ef->fpscr;
memcpy((uint8_t *) rf->d, ef->s, sizeof(ef->s));
print_fpu_regs((uint32_t *) rf->d, 0, ARRAY_SIZE(ef->s));
save_s16_s31(ef->s);
memcpy(((uint8_t *) rf->d) + sizeof(ef->s), ef->s, sizeof(ef->s));
print_fpu_regs((uint32_t *) (((uint8_t *) rf->d) + sizeof(ef->s)), 16,
ARRAY_SIZE(ef->s));
mgos_cd_putc('\n');
mgos_cd_printf("FPSCR: 0x%08lx\n", rf->fpscr);
#else
rf->fpscr = 0;
#endif
mgos_cd_emit_header();
mgos_cd_emit_section(MGOS_CORE_DUMP_SECTION_REGS, rf, sizeof(*rf));
mgos_cd_emit_section("SRAM", (void *) SRAM_BASE_ADDR, SRAM_SIZE);
mgos_cd_emit_footer();
#ifdef MGOS_HALT_ON_EXCEPTION
mgos_cd_printf("Halting\n");
while (1) {
mgos_wdt_feed();
}
#else
mgos_cd_printf("Rebooting\n");
mgos_dev_system_restart();
#endif
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* All rights reserved
*/
.arch armv7e-m
.syntax unified
.thumb
/* These are required to satisfy TI linker. */
.eabi_attribute Tag_ABI_align_needed, 1
.eabi_attribute Tag_ABI_align_preserved, 1
.global arm_exc_handler_top
.global arm_exc_handler_bottom
/*
* Determines the stack pointer, populates most of the GDB frame
* and hands off to the C routine.
*/
.section .text.arm_exc_handler_top
.type arm_exc_handler_top, %function
.align 8
arm_exc_handler_top:
tst lr, #4
ite eq
mrseq r1, msp
mrsne r1, psp
// r1 -> arm_exc_frame prepared for us by the CPU
#if ARM_HAVE_FPU
add r0, r1, #104 // sizeof(arm_exc_frame)
sub sp, #328 // sizeof(arm_gdb_reg_file)
#else
add r0, r1, #32 // sizeof(arm_exc_frame)
sub sp, #328 // sizeof(arm_gdb_reg_file)
#endif
mov r2, sp
// r0 -> original sp, r2 -> arm_gdb_reg_file to fill
// r3 - scratch
ldr r3, [r1, #0] // r0
str r3, [r2, #0]
ldr r3, [r1, #4] // r2
str r3, [r2, #4]
ldr r3, [r1, #8] // r1
str r3, [r2, #8]
ldr r3, [r1, #12] // r3
str r3, [r2, #12]
str r4, [r2, #16] // r4
str r5, [r2, #20] // r5
str r6, [r2, #24] // r6
str r7, [r2, #28] // r7
str r8, [r2, #32] // r8
str r9, [r2, #36] // r9
str r10, [r2, #40] // r10
str r11, [r2, #44] // r11
ldr r3, [r1, #16] // r12
str r3, [r2, #48]
str r0, [r2, #52] // sp
ldr r3, [r1, #20] // lr
str r3, [r2, #56]
ldr r3, [r1, #24] // pc
str r3, [r2, #60]
ldr r3, [r1, #28] // xpsr
str r3, [r2, #64]
mrs r0, ipsr
b arm_exc_handler_bottom
.size arm_exc_handler_top, . - arm_exc_handler_top

View File

@ -0,0 +1,92 @@
/*****************************************************************************
*
* GCC Linker script for CC3200. Based on TI's example "blinky.ld".
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
ORG = DEFINED(ORG) ? ORG : 0x20004000;
RAM_SIZE = DEFINED(RAM_SIZE) ? RAM_SIZE : 0x3C000;
MEMORY
{
/* SRAM size of 240KB for cc3200 ES 1.33 device onward */
SRAM (rwx) : ORIGIN = ORG, LENGTH = RAM_SIZE
}
SECTIONS
{
.text :
{
_text = .;
KEEP(*(.intvecs))
*(.text*)
*(.rodata*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
_etext = .;
} > SRAM
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > SRAM
__init_data = .;
.data : AT(__init_data)
{
_data = .;
*(.data*)
. = ALIGN (8);
_edata = .;
} > SRAM
.bss :
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > SRAM
.heap :
{
_heap = .;
. = . + (LENGTH(SRAM) - SIZEOF(.text) - SIZEOF(.ARM) - SIZEOF(.data) - SIZEOF(.bss));
. = ALIGN(8);
_eheap = .;
} > SRAM
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#if CS_PLATFORM == CS_P_CC3200
#include "common/mg_mem.h"
#include <stdio.h>
#include <string.h>
#ifndef __TI_COMPILER_VERSION__
#include <reent.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#endif
#include <inc/hw_types.h>
#include <inc/hw_memmap.h>
#include <driverlib/prcm.h>
#include <driverlib/rom.h>
#include <driverlib/rom_map.h>
#include <driverlib/uart.h>
#include <driverlib/utils.h>
#define CONSOLE_UART UARTA0_BASE
#ifdef __TI_COMPILER_VERSION__
int asprintf(char **strp, const char *fmt, ...) {
va_list ap;
int len;
*strp = MG_MALLOC(BUFSIZ);
if (*strp == NULL) return -1;
va_start(ap, fmt);
len = vsnprintf(*strp, BUFSIZ, fmt, ap);
va_end(ap);
if (len > 0) {
*strp = MG_REALLOC(*strp, len + 1);
if (*strp == NULL) return -1;
}
if (len >= BUFSIZ) {
va_start(ap, fmt);
len = vsnprintf(*strp, len + 1, fmt, ap);
va_end(ap);
}
return len;
}
#if MG_TI_NO_HOST_INTERFACE
time_t HOSTtime() {
struct timeval tp;
gettimeofday(&tp, NULL);
return tp.tv_sec;
}
#endif
#endif /* __TI_COMPILER_VERSION__ */
void fprint_str(FILE *fp, const char *str) {
while (*str != '\0') {
if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
MAP_UARTCharPut(CONSOLE_UART, *str++);
}
}
void _exit(int status) {
fprint_str(stderr, "_exit\n");
/* cause an unaligned access exception, that will drop you into gdb */
*(int *) 1 = status;
while (1)
; /* avoid gcc warning because stdlib abort() has noreturn attribute */
}
void _not_implemented(const char *what) {
fprint_str(stderr, what);
fprint_str(stderr, " is not implemented\n");
_exit(42);
}
int _kill(int pid, int sig) {
(void) pid;
(void) sig;
_not_implemented("_kill");
return -1;
}
int _getpid() {
fprint_str(stderr, "_getpid is not implemented\n");
return 42;
}
int _isatty(int fd) {
/* 0, 1 and 2 are TTYs. */
return fd < 2;
}
#endif /* CS_PLATFORM == CS_P_CC3200 */

View File

@ -0,0 +1,82 @@
//*****************************************************************************
// cc3200v1p32.cmd
//
// CCS linker configuration file for cc3200 ES 1.32.
//
// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
--retain=g_pfnVectors
//*****************************************************************************
// The following command line options are set as part of the CCS project.
// If you are building using the command line, or for some reason want to
// define them here, you can uncomment and modify these lines as needed.
// If you are using CCS for building, it is probably better to make any such
// modifications in your CCS project and leave this file alone.
//*****************************************************************************
//*****************************************************************************
// The starting address of the application. Normally the interrupt vectors
// must be located at the beginning of the application.
//*****************************************************************************
#define RAM_BASE 0x20004000
/* System memory map */
MEMORY
{
/* Application uses internal RAM for program and data */
SRAM_CODE (RWX) : origin = 0x20004000, length = 0x2F000
SRAM_DATA (RWX) : origin = 0x20033000, length = 0xD000
}
/* Section allocation in memory */
SECTIONS
{
.intvecs: > RAM_BASE
.init_array : > SRAM_CODE
.vtable : > SRAM_CODE
.text : > SRAM_CODE
.const : > SRAM_CODE
.cinit : > SRAM_CODE
.pinit : > SRAM_CODE
.data : > SRAM_DATA
.bss : > SRAM_DATA
.sysmem : > SRAM_DATA
.stack : > SRAM_DATA(HIGH)
}

View File

@ -0,0 +1,52 @@
APP_LDFLAGS ?=
CC_WRAPPER ?=
GENFILES_LIST ?=
CC = arm-none-eabi-gcc
CXX = arm-none-eabi-g++
AR = arm-none-eabi-ar
NM = arm-none-eabi-nm
IPATH += $(SDK_PATH)/third_party/FreeRTOS/source/portable/GCC/ARM_CM4
VPATH += $(SDK_PATH)/third_party/FreeRTOS/source/portable/GCC/ARM_CM4
C_CXX_FLAGS = -mthumb -mcpu=cortex-m4 -ffunction-sections -fdata-sections \
-MD -Os -ggdb -Wall -Werror -Dgcc
CFLAGS += -std=c99 $(C_CXX_FLAGS)
CXXFLAGS += -std=g++11 $(C_CXX_FLAGS)
AR = arm-none-eabi-ar
LD = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
LIBGCC := ${shell ${CC} -mthumb ${CFLAGS} -print-libgcc-file-name}
LIBC := ${shell ${CC} ${CFLAGS} -print-file-name=libc.a}
LIBM := ${shell ${CC} ${CFLAGS} -print-file-name=libm.a}
# Disable certain warnings on SDK sources, we have no control over them anyway.
# We also force-include platform.h which resolves some symbol conflicts
# between system includes and simplelink.h
$(SDK_OBJS): CFLAGS += -Wno-missing-braces -Wno-strict-aliasing -Wno-parentheses -Wno-unused-variable -Wno-builtin-macro-redefined
$(SDK_OBJS): CFLAGS += -include common/platform.h
# cc flags,file
define cc
$(vecho) "GCC $2 -> $@"
$(Q) $(CC_WRAPPER) $(CC) -c $1 -o $@ $2
endef
define cxx
$(vecho) "G++ $2 -> $@"
$(Q) $(CC_WRAPPER) $(CXX) -c $1 -o $@ $2
endef
# ar files
define ar
$(vecho) "AR $@"
$(Q) $(AR) cru $@ $1
endef
# link script,flags,objs
define link
$(vecho) "LD $@"
$(Q) $(CC_WRAPPER) $(LD) \
--gc-sections -o $@ -T $1 $2 $3 \
$(LIBM) $(LIBC) $(LIBGCC)
endef

View File

@ -0,0 +1,52 @@
IPATH += $(SDK_PATH)/third_party/FreeRTOS/source/portable/CCS/ARM_CM3
VPATH += $(SDK_PATH)/third_party/FreeRTOS/source/portable/CCS/ARM_CM3
CC_WRAPPER ?=
CC = $(TOOLCHAIN)/bin/armcl
AR = $(TOOLCHAIN)/bin/armar
NM = nm
GENFILES_LIST ?=
C_CXX_FLAGS = -Dccs -I$(TOOLCHAIN)/include
TI_C_CXX_FLAGS = -mv7M4 --little_endian --code_state=16 --float_support=vfplib --abi=eabi \
-O4 --opt_for_speed=0 --unaligned_access=on --small_enum \
--gen_func_subsections=on --diag_wrap=off --display_error_number \
--emit_warnings_as_errors
CFLAGS += --c99 $(TI_C_CXX_FLAGS) $(C_CXX_FLAGS)
CXXFLAGS += $(TI_C_CXX_FLAGS) $(C_CXX_FLAGS)
# cc flags,file
define cc
$(vecho) "TICC $2 -> $@"
$(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2
endef
define cxx
$(vecho) "TICXX $2 -> $@"
$(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2
endef
# asm flags,file
define asm
$(vecho) "TIASM $2 -> $@"
$(Q) $(CC_WRAPPER) $(CC) -c $1 --output_file=$@ $2
endef
# ar files
define ar
$(vecho) "TIAR $@"
$(Q) $(AR) qru $@ $1
endef
# link script,flags,objs
define link
$(vecho) "TILD $@"
$(Q) $(CC_WRAPPER) $(CC) \
-mv7M4 --code_state=16 --float_support=vfplib --abi=eabi --little_endian \
--run_linker \
--generate_dead_funcs_list=$@.garbage.xml \
-i $(TOOLCHAIN)/lib \
--reread_libs --warn_sections --display_error_number \
--unused_section_elimination=on \
-o $@ --map_file=$@.map --xml_link_info=$@.map.xml \
$2 $1 $3
endef

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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_ */

View File

@ -0,0 +1 @@
rom.bin -nodiff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
#!/bin/bash
xtensa-esp108-elf-gcc -Wl,-N,-Ttext,0x40000000 -nostdlib rom.S -o rom.elf && \
xtensa-esp108-elf-objdump -d rom.elf > ESP31B_ROM.txt

View File

@ -0,0 +1,163 @@
/* Just some notes scribbled while disassembling */
/*
* RTC = 0x60008000
* RTC+0x18: ??c????? ???????? ???????? ????????
* RTC+0x34: ???????? ??bbbbbb bbbb???? ??aaaaaa
*/
int _X_get_rst_cause(void) {
int ret;
int a = GET_PERI_REG_BITS(RTC_STATE1, 6, 0);
if (a == 5) {
int b = (RTC_STATE1 >> 12) && 0xfff;
if (b != 1) {
ret = (b == 8 ? a : 0);
} else {
ret = 20;
}
} else {
ret = a;
}
CLEAR_PERI_REG_MASK(RTC_STATE0, RTC_CNTL_SLP_WAKEUP);
return ret;
}
/*
* RTC = 0x60008000
* RTC+0x38: ???????? ???????? ???????? ??cccccc
* RTC+0x74: ???????? ???????? ???????? dddddddd
* RTC+0x80: ???????? ??????a? ???b???? ????????
*/
void main(void) {
uint32_t rst_cause = _X_get_rst_cause();
CLEAR_PERI_REG_MASK(RTC+0x80, BIT(17)); // a
SET_PERI_REG_MASK(RTC+0x80, BIT(12)); // b
uint32_t boot_mode = GET_PERI_REG_BITS(GPIO_STRAP, 6, 0); // c
if (boot_mode & (BIT(5) | BIT(4)) == (BIT(5) | BIT(4)) || boot_mode == 24 || boot_mode == 26) {
CLEAR_PERI_REG_MASK(RTC+0x74, 0xff);
}
if (boot_mode & (BIT(5) | BIT(4)) == BIT(5)) {
CLEAR_PERI_REG_MASK(RTC+0x94, BIT(31));
CLEAR_PERI_REG_MASK(RTC+0x98, BIT(31));
CLEAR_PERI_REG_MASK(RTC+0x9c, BIT(31));
CLEAR_PERI_REG_MASK(RTC+0xa0, BIT(31));
CLEAR_PERI_REG_MASK(RTC+0xa4, BIT(31));
CLEAR_PERI_REG_MASK(RTC+0xa8, BIT(31));
CLEAR_PERI_REG_MASK(RTC+0xac, BIT(31));
}
if (boot_mode & (BIT(5) | BIT(3)) == 0) {
// ... 1405
}
CLEAR_PERI_REG_MASK(RTC+0x74, 0xff);
_X_uart_attach();
_X_uart_init(0);
// GPIO_STRAP ...
ets_printf(boot_banner, fw_build, rst_cause, boot_mode);
// rst_cause
if (rst_cause == 1 || rst_cause == 2) {
} else {
// ...
}
ets_printf("%s %u", "ets_main.c", 305);
while(1) {}
}
/*
* GPIO strap mapping:
*
* 0011 1111 1011 0011
* || |||| |||| ||||
* || |||| |||| |||`- IO5
* || |||| |||| ||`-- IO15
* || |||| |||| |`--- IO4
* || |||| |||| `---- IO2
* || |||| |||`------ ?
* || |||| ||`------- IO0
* || |||| |`-------- IO12
* || |||| `--------- ?
* || |||`----------- CLK
* || ||`------------ ?
* || |`------------- SD0
* || `-------------- SD1
* |`---------------- ? SD2
* `----------------- SD3
*/
struct uartdev {
uint32_t baud_rate; // 0
uint32_t ud4;
uint32_t ud8;
uint32_t ud12;
uint32_t ud16;
uint32_t ud20;
uint8_t ud24;
uint8_t ud25;
uint32_t ud28;
uint32_t ud32;
uint32_t ud36;
uint8_t ud40;
uint32_t ud48;
uint32_t ud52;
};
void _X_uart_attach(void) {
// zero uartdev
uartdev.baud_rate = 115200;
_X_xtos_ints_off(1 << ETS_UART_INUM);
// INTR_MAP_REG_C
// 11111111 11111111 11111100 00011111 &
// 00000000 00000000 00000000 10100000 |
// PRODPORT_INTR_MAP_13 -> 5 = ETS_UART_INUM
// 11111111 11111111 10000011 11111111 &
// 00000000 00000000 00010100 11111111 |
// PRODPORT_INTR_MAP_14 -> 5 = ETS_UART_INUM
_xtos_set_interrupt_handler_arg(ETS_UART_INUM, uart_int_handler, _c_0x3fffdb2c_uart_int_handler_arg);
}
void _X_uart_init(uint32_t a) {
// GPIO_FUNC_IN_SEL3
// xx999999 88888877 77776666 66555555
// 11111111 11111100 00001111 11111111 = 0xfffc0fff
// 00000000 00000000 10010000 00000000 = 0x00009000
// GPIO17 func => 9
// 00000000 00000010 00000000 00000000
uart_div_modify(13000000 / uartdev.baud_rate);
// ...
}
struct _st_0x3fffdc90 {
};
struct _st_0x3fffdf70 {
void *fp1; // 20
void *fp2; // 24
uint32_t d28;
uint32_t d32;
uint32_t d36;
struct _st_0x3fffdc90 *st; // 44
} stdf70;
void _X_slc_init_attach(void *fp1, void *fp2, struct _st_0x3fffdc90 *st, uint32_t gpio_mode) {
stdf70.fp1 = fp1;
stdf70.fp2 = fp2;
stdf70.st = st;
d28 = d32 = d36 = 0;
SET_PERI_REG_MASK(WIFI_RST_EN, PRODPORT_SDIO_RST);
CLEAR_PERI_REG_MASK(WIFI_RST_EN, PRODPORT_SDIO_RST);
if (gpio_mode == 4) {
SET_PERI_REG((READ_PERI_REG(PERIPHS_HINF_BASEADDR+4) & 0xf0000000) | 0x01110013);
} else {
SET_PERI_REG((READ_PERI_REG(PERIPHS_HINF_BASEADDR+4) & 0xf0000000) | 0x02320017);
}
SET_PERI_REG(PERIPHS_HINF_BASEADDR, 0x11116666);
_X_slc_set_host_io_max_window();
...
}
#define SLC_TOKEN1 (PERIPHS_SLC_BASEADDR + 0x54)
#define SLC_BRIDGE_CONF (PERIPHS_SLC_BASEADDR + 0x74)
void _X_slc_set_host_io_max_window(void) {
SET_PERI_REG(SLC_BRIDGE_CONF, (READ_PERI_REG(SLC_BRIDGE_CONF) & 0xfffff0c0) | 0x720);
}

View File

@ -0,0 +1,16 @@
.text
.org 0
.globl _start
// xtensa-esp108-elf-gcc -Wl,-N,-Ttext,0x40000000 -nostdlib rom.S -o rom.elf
here = .
#define PROVIDE(name, addr) name = here + addr - 0x40000000
#include "rom_functions.S"
.text
_start:
.incbin "rom.bin"
_end:

View File

@ -0,0 +1,294 @@
// These come from linker script
PROVIDE ( Cache_Read_Disable , 0x4000444c );
PROVIDE ( Cache_Read_Enable , 0x4000438c );
PROVIDE ( ets_delay_us , 0x40002db4 );
PROVIDE ( bzero , 0x40002a54 );
PROVIDE ( memcmp , 0x400068ec );
PROVIDE ( memcpy , 0x40006974 );
PROVIDE ( memmove , 0x40006a6c );
PROVIDE ( memset , 0x40006be4 );
PROVIDE ( strcmp , 0x40005bb8 );
PROVIDE ( strcpy , 0x40005cdc );
PROVIDE ( strlen , 0x40005d6c );
PROVIDE ( strncmp , 0x40005dd0 );
PROVIDE ( strncpy , 0x40005e90 );
PROVIDE ( strstr , 0x40005f6c );
PROVIDE ( ets_install_putc1 , 0x40002774 );
PROVIDE ( ets_printf , 0x40002804 );
PROVIDE ( ets_putc , 0x40002b14 );
PROVIDE ( ets_str2macaddr , 0x40002a64 );
PROVIDE ( gpio_output_set , 0x400049d8 );
PROVIDE ( gpio_output_set_high , 0x400049f8 );
PROVIDE ( ets_get_cpu_frequency , 0x40002de8 );
PROVIDE ( ets_update_cpu_frequency , 0x40002ddc );
PROVIDE ( lldesc_build_chain , 0x40004c8c );
PROVIDE ( multofup , 0x400068a0 );
PROVIDE ( roundup2 , 0x40006890 );
PROVIDE (software_reset_cpu , 0x40002998 );
PROVIDE ( SPIEraseSector , 0x40004708 );
PROVIDE ( SPIRead , 0x40004898 );
PROVIDE ( SPIWrite , 0x40004738 );
PROVIDE ( uart_div_modify , 0x400034e8 );
PROVIDE ( uart_tx_one_char , 0x4000362c );
PROVIDE ( __divsi3 , 0x40006888 );
PROVIDE ( __udivdi3 , 0x40006c30 );
PROVIDE ( __umoddi3 , 0x40006e64 );
PROVIDE ( _xtos_set_intlevel , 0x40006670 );
// These have been reverse-engineered.
PROVIDE(_XX_Vec40, 0x40000040)
PROVIDE(_XX_ExcVec50, 0x40000050)
PROVIDE(_XX_ExcVec80, 0x40000080)
PROVIDE(_XX_Vec400, 0x40000300)
PROVIDE(_WindowOverflowHandler, 0x40000100)
PROVIDE(_WindowUnderflowHandler, 0x40000140)
PROVIDE(_X_ResetVector, 0x40000500)
PROVIDE(_c_stack, 0x40000700)
PROVIDE(_c_bss_start, 0x40000708)
PROVIDE(_c_bss_end, 0x4000070c)
PROVIDE(_c_0x3fffc210, 0x40000734)
PROVIDE(_c_0x80000000, 0x40000738)
PROVIDE(_c_0x40000000, 0x40000760)
PROVIDE(_c_0x7fffffff, 0x40000780)
PROVIDE(_c_0x00ff0000, 0x40000798)
PROVIDE(_X_start, 0x400007ac)
PROVIDE(_c_0x3fffd820, 0x40000f50)
PROVIDE(_X_ets_task, 0x40000f54)
PROVIDE(_XX_unk0f84, 0x40000f84)
PROVIDE(_XX_unk0f96, 0x40000f98)
PROVIDE(_c_ets_critical_level, 0x400010a4)
PROVIDE(_X_ets_enter_critical, 0x400010a8)
PROVIDE(_X_ets_exit_critical, 0x400010bc)
PROVIDE(_X_ets_exit_critical_and_wait_int, 0x400010d4)
PROVIDE(_X_ets_isr_attach, 0x400010e8) // 3 args
PROVIDE(_X_ets_isr_mask, 0x400010f8) // 1 arg
PROVIDE(_X_ets_isr_unmask, 0x40001104) // 1 arg
PROVIDE(_c_0x3fffda30, 0x40001110)
PROVIDE(_XX_set_0x3fffda30_0, 0x40001114)
PROVIDE(_XX_set_0x3fffda30_4, 0x40001120)
PROVIDE(_c_0xfffdffff, 0x4000112c)
PROVIDE(_c_0x60003e00, 0x40001130)
PROVIDE(_c_0x60008200, 0x40001134)
PROVIDE(_c_0x60007e00, 0x40001138)
PROVIDE(_c_0x1000, 0x4000113c)
PROVIDE(_s_fw_build, 0x40001140)
PROVIDE(_s_boot_banner, 0x40001144)
PROVIDE(_s_pct_s_pct_u, 0x40001148)
PROVIDE(_s_ets_main_c, 0x4000114c)
PROVIDE(_X_main, 0x4000115c)
PROVIDE(_l_strap_0x0xxx, 0x4000125a)
PROVIDE(_l_strap_init_uart0, 0x40001269)
PROVIDE(_l_strap_0x0x00, 0x400012e2)
PROVIDE(_l_boot, 0x400012ea)
PROVIDE(_l_rst_cause_345, 0x40001336)
PROVIDE(_l_rst_cause_12, 0x40001342)
PROVIDE(_l_strap_NxNxxx, 0x40001405)
PROVIDE(_l_strap_0010xx, 0x4000144c)
PROVIDE(_l_strap_001000_0x110x, 0x400014b0)
PROVIDE(_l_strap_0x0x11_loader, 0x400014c9) // loader
PROVIDE(_l_strap_0x0x01, 0x400014d4)
PROVIDE(_l_strap_0x0x10, 0x400014e6)
PROVIDE(_c_0xffff8fff, 0x400014f0)
PROVIDE(_c_0x60008e00, 0x400014f4)
PROVIDE(_s_waiting_for_host, 0x4000152c)
PROVIDE(_s_mem_banner, 0x40001cdc)
PROVIDE(_c_stack_sentry, 0x40001ce0)
PROVIDE(_XX_unk153c, 0x4000153c)
PROVIDE(_c_data_end, 0x40001cd8)
PROVIDE(_c_data_start, 0x40001ce4)
PROVIDE(_X_print_mem_banner, 0x40001ce8)
PROVIDE(_s_exc_sp_fmt, 0x40001d0c)
PROVIDE(_s_exc_sf_dump_fmt, 0x40001d10)
PROVIDE(_s_exc_regs_fmt, 0x40001d14)
PROVIDE(_X_exc_handler, 0x40001d18)
PROVIDE(_XX_unk1d90, 0x40001d90)
PROVIDE(_X_ets_memset, 0x40001db4)
PROVIDE(_X_ets_memcpy, 0x40001dc4)
PROVIDE(_X_ets_memmove, 0x40001dd4)
PROVIDE(_X_ets_memcmp, 0x40001de4)
PROVIDE(_st_0x3fffda9c, 0x40002150) // struct
PROVIDE(_X_ets_uart_putc, 0x4000223c)
PROVIDE(_X_ets_unk225c, 0x4000225c)
PROVIDE(_c_0x4000223c_ets_uart_putc, 0x40002780)
PROVIDE(_X_ets_install_uart_printf, 0x40002784)
PROVIDE(_c_0x400027dc, 0x40002790)
PROVIDE(_X_ets_install_external_printf, 0x40002794)
PROVIDE(_X_ets_install_putc2, 0x400027b4)
PROVIDE(_X_ets_get_printf_buf_remain_len, 0x400027c0)
PROVIDE(_X_ets_reset_printf_buf_len, 0x400027cc)
PROVIDE(_X_ets_putc, 0x400027dc)
PROVIDE(_c_0xdfffffff, 0x400028d4)
PROVIDE(_X_get_rst_cause, 0x400028d8)
PROVIDE(_XX_unk2948, 0x40002948)
PROVIDE(_l_2970, 0x40002970)
PROVIDE(_X_sw_sys_rst, 0x4000297c)
PROVIDE(_c_0x00400000, 0x400029b4)
PROVIDE(_c_0xffbfffff, 0x400029b8)
PROVIDE(_XX_apb_bridge_toggle, 0x400029bc) // turns RTC_CNTL_APB2RTC_BRIDGE_SEL on and off
PROVIDE(_X_ets_strcpy, 0x400029ec)
PROVIDE(_X_ets_strncpy, 0x40002a00)
PROVIDE(_X_ets_strcmp, 0x40002a10)
PROVIDE(_X_ets_strncmp, 0x40002a24)
PROVIDE(_X_ets_strlen, 0x40002a34)
PROVIDE(_X_ets_strstr, 0x40002a40)
PROVIDE(_st_0x3fffdb10_uartdev, 0x40002e4c) // some struct - uartdev?
PROVIDE(_c_0x3fffdb00, 0x40002e50)
PROVIDE(_c_0x3fffdb04, 0x40002f64)
PROVIDE(_XX_unk2e58, 0x40002e58)
PROVIDE(_X_UartDwnLdProc, 0x40002f6c)
PROVIDE(_c_0x00001800, 0x400030ec)
PROVIDE(_X_FlashDwnLdStartMsgProc, 0x400030f0)
PROVIDE(_XX_unk313c, 0x4000313c)
PROVIDE(_XX_unk31bc, 0x400031bc)
PROVIDE(_XX_unk31e4, 0x400031e4)
PROVIDE(_XX_unk3210, 0x40003210)
PROVIDE(_XX_unk3240, 0x40003240)
PROVIDE(_X_MemDwnLdStopReqMsgProc, 0x4000329c)
PROVIDE(_X_UartConnectProc, 0x400032c4)
PROVIDE(_X_UartRegWriteProc, 0x400032d4)
PROVIDE(_X_UartRegReadProc, 0x40003318)
PROVIDE(_c_115200, 0x4000332c)
PROVIDE(_c_0x3feffe00, 0x40003330)
PROVIDE(_c_0xffff83ff, 0x40003334)
PROVIDE(_c_0x00001400, 0x40003338)
PROVIDE(_c_0x40003728_uart_int_handler, 0x4000333c)
PROVIDE(_c_0x3fffdb2c_uart_int_handler_arg, 0x40003340)
PROVIDE(_X_uart_attach, 0x40003344)
PROVIDE(_XX_uart_set_unk33c0, 0x400033c0)
PROVIDE(_c_0x5ffffe00, 0x400033cc)
PROVIDE(_c_0x0000ffff, 0x400033d0)
PROVIDE(_c_0x000fffff, 0x40003448)
PROVIDE(_c_0x00060000, 0x400034e0)
PROVIDE(_c_0xfff9ffff, 0x400034e4)
PROVIDE(_c_0xfffc0fff, 0x40003520)
PROVIDE(_c_0x00009000, 0x40003524)
PROVIDE(_c_0x00020000, 0x40003528)
PROVIDE(_c_13000000, 0x4000352c)
PROVIDE(_c_0x08000000, 0x40003530)
PROVIDE(_X_uart_init, 0x40003534)
PROVIDE(_l_35f4, 0x400035f4)
PROVIDE(_X_uart_wait_tx_empty, 0x4000369c)
PROVIDE(_X_uart_int_handler, 0x40003728)
PROVIDE(_X_uart_tx_one_char2, 0x40003664)
PROVIDE(_X_send_packet, 0x400037d4)
PROVIDE(_X_SendMsg, 0x40003828)
PROVIDE(_X_recv_packet, 0x4000383c)
PROVIDE(_X_RcvMsg, 0x40003988)
PROVIDE(_X_uart_rx_readbuff, 0x400039a0)
PROVIDE(_c_0x60004e00, 0x40003a18)
PROVIDE(_X_SelectSpiFunction, 0x40003a1c) // 1 arg - SPI number
PROVIDE(_c_0x60002e00, 0x40003c78)
PROVIDE(_X_SPI_chip_erase, 0x40003c7c)
PROVIDE(_c_0x00ffffff, 0x40003cb4)
PROVIDE(_c_0x01000000, 0x40003cb8)
PROVIDE(_XX_unk3cbc, 0x40003cbc)
PROVIDE(_c_0x00800000, 0x40003d00)
PROVIDE(_c_0x02000000, 0x40003d4c)
PROVIDE(_XX_unk3e24, 0x40003e24)
PROVIDE(_X_SPI_read_status, 0x40003efc)
PROVIDE(_c_0x90000000, 0x40003f48)
PROVIDE(_c_0x70000035, 0x40003f4c)
PROVIDE(_c_0x00040000, 0x40003f50)
PROVIDE(_XX_unk3f54, 0x40003f54)
PROVIDE(_c_0x04000000, 0x40003fcc)
PROVIDE(_XX_unk4010, 0x40004010)
PROVIDE(_X_SPI_write_enable, 0x400041bc)
PROVIDE(_X_Wait_SPI_Idle, 0x40004208)
PROVIDE(_l_4228, 0x40004228)
PROVIDE(_l_4234, 0x40004234)
PROVIDE(_XX_unk4238, 0x40004238)
PROVIDE(_X_SPIFlashModeConfig, 0x400042d8)
PROVIDE(_X_spi_flash_attach, 0x40004370) // 2 args: SPI num, ???
PROVIDE(_X_SPIReadModeConfig, 0x40004538)
PROVIDE(_X_SPIEraseArea, 0x400048b4)
PROVIDE(_XX_unk4940, 0x40004940)
PROVIDE(_st_0x3fffdc90, 0x40004d80)
PROVIDE(_XX_unk4d88, 0x40004d88)
PROVIDE(_XX_unk4f6c, 0x40004f6c)
PROVIDE(_XX_unk4fc8, 0x40004fc8)
PROVIDE(_c_0xbfffffff, 0x40004c80)
PROVIDE(_c_0xff000fff, 0x40004c88)
PROVIDE(_XX_unk4f14, 0x40004f14)
PROVIDE(_s_no_rds, 0x40005008)
PROVIDE(_XX_unk500c, 0x4000500c)
PROVIDE(_fp_0x40004f6c, 0x40005164)
PROVIDE(_fp_0x40004fc8, 0x40005168)
PROVIDE(_X_sip_init_attach, 0x40005170) // 1 arg, boot_mode?
PROVIDE(_XX_unk51ac, 0x400051ac)
PROVIDE(_c_0x60017e00, 0x40005478)
PROVIDE(_st_0x3fffdf70, 0x400054a4)
PROVIDE(_c_0x6000ae00, 0x400054b8)
PROVIDE(_c_0xf0000000, 0x400054bc)
PROVIDE(_c_0x02320017, 0x400054c0)
PROVIDE(_c_0x11116666, 0x400054c4)
PROVIDE(_c_0x01110013, 0x400054e4)
PROVIDE(_X_slc_init_attach, 0x400054e8) // 4 args - fp, fp, st, boot_mode; PRODPORT_SDIO_RST
PROVIDE(_l_slc_boot_mode_4, 0x40005654)
PROVIDE(_X_slc_enable, 0x40005678)
PROVIDE(_X_slc_select_tohost_gpio_mode, 0x400056fc)
PROVIDE(_X_slc_select_tohost_gpio, 0x40005708)
PROVIDE(_c_0xff300000, 0x40005730)
PROVIDE(_XX_unk5734, 0x40005734)
PROVIDE(_XX_unk57b8, 0x400057b8)
PROVIDE(_XX_unk57f4, 0x400057f4)
PROVIDE(_XX_unk5848, 0x40005848)
PROVIDE(_c_0xfffff0c0, 0x40005988)
PROVIDE(_X_slc_set_host_io_max_window, 0x4000598c)
PROVIDE(_X_slc_init_credit, 0x400059ac)
PROVIDE(_X_slc_add_credits, 0x400059c4)
PROVIDE(_X_xtos_set_interrupt_handler_arg, 0x400059d8)
PROVIDE(_X_xtos_set_interrupt_handler, 0x40005a24)
PROVIDE(_X_xtos_ints_on, 0x40005a34)
PROVIDE(_X_xtos_ints_off, 0x40005a58)
PROVIDE(_XX_xtos_exc_unk5a80, 0x40005a80)
PROVIDE(_XX_xtos_exc_unk5b94, 0x40005b94)

View File

@ -0,0 +1,2 @@
rom.bin -nodiff
rom.elf -nodiff

View File

@ -0,0 +1,4 @@
#!/bin/bash
xtensa-esp32-elf-gcc -Wl,-N,-Ttext,0x40000000 -nostdlib rom.S -o rom.elf && \
xtensa-esp32-elf-objdump -d rom.elf > ESP32_ROM.txt

View File

@ -0,0 +1,28 @@
.text
.org 0
.globl _start
// xtensa-esp32-elf-gcc -Wl,-N,-Ttext,0x40000000 -nostdlib rom.S -o rom.elf
here = .
#define PROVIDE(name, addr) name = here + addr - 0x40000000
#include "rom_functions.S"
PROVIDE ( _x_unk_40061b88, 0x40061b88 )
PROVIDE ( _x_unk_spi_400622c0, 0x400622c0 )
PROVIDE ( _c_3ff000c8, 0x40062df0 )
PROVIDE ( _c_3ff5b024, 0x40062e0c )
PROVIDE ( _c_3ff5b000, 0x40062e10 )
PROVIDE ( _c_3ff5b020, 0x40062e14 )
PROVIDE ( _c_3ff5b028, 0x40062e18 )
PROVIDE ( _l_40062e90, 0x40062e90 )
PROVIDE ( _l_SPI_Prepare_Encrypt_Data_loop, 0x40062e34 )
PROVIDE ( _l_SPI_Prepare_Encrypt_Data_wait, 0x40062e54 )
PROVIDE ( _l_SPI_Prepare_Encrypt_Data_out, 0x40062e5e )
.text
_start:
.incbin "rom.bin"
_end:

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
#
# Copyright (c) 2015 Cesanta Software Limited
# All rights reserved
#
STUB = stub_hello.c
LIBS =
PARAMS =
PORT = /dev/ttyUSB0
BUILD_DIR = .build
COMMON_STUB_DIR = ../../esp
STUB_ELF = $(BUILD_DIR)/$(patsubst %.c,%.elf,$(notdir $(STUB)))
STUB_JSON ?= $(BUILD_DIR)/$(patsubst %.c,%.json,$(notdir $(STUB)))
SDK = $(shell cat ../../../../fw/platforms/esp32/sdk.version)
XT_CC = xtensa-esp32-elf-gcc
.PHONY: all clean run wrap
all: $(STUB_ELF)
$(STUB_ELF): $(STUB) $(LIBS)
@echo " CC $^ -> $@"
@[ -d $(BUILD_DIR) ] || mkdir $(BUILD_DIR)
@docker run --rm -i -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \
"cd /src/common/platforms/esp32/stubs && \
$(XT_CC) -std=c99 -Wall -Werror -Os -DESP32 \
-mtext-section-literals -mlongcalls -nostdlib -fno-builtin \
-I. -I/src/common/platforms/esp \
-I/opt/Espressif/esp-idf/components/esp32/include \
-I/opt/Espressif/esp-idf/components/soc/esp32/include \
-L/opt/Espressif/esp-idf -Wl,-static \
-ffunction-sections -Wl,--gc-sections \
-Tstub.ld -o $@ $^"
wrap: $(STUB_JSON)
$(STUB_JSON): $(STUB_ELF) $(COMMON_STUB_DIR)/esptool.py
@echo " WRAP $< -> $@"
@docker run --rm -i -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \
"cd /src/common/platforms/esp32/stubs && \
$(COMMON_STUB_DIR)/esptool.py wrap_stub $<" > $@
run: $(STUB_JSON)
@echo " RUN $< $(PARAMS) -> $(PORT)"
@docker run --rm -i --privileged -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \
"cd /src/common/platforms/esp32/stubs && \
$(COMMON_STUB_DIR)/esptool.py --port $(PORT) run_stub $< $(PARAMS)"
clean:
@rm -rf $(BUILD_DIR)

View File

@ -0,0 +1,13 @@
This is a ESP boot loader stub development environment.
Code produced in this environment can be loaded and executed
in the bootloader environment. Usually it is used to implement
functionality not found in the bootloader.
Stubs can be executed using the `run_stub` command of the modified esptool.py provided.
`wrap_stub` produces a JSON represenattion of the stub that can later be reused
or built into other tools.
Example usage:
$ make run STUB=stub_flash_size.c PORT=/dev/ttyUSB0
$ make run STUB=stub_md5.c PORT=/dev/ttyUSB0 PARAMS="0x11000 10000 1"

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* All rights reserved
*/
#include "soc/gpio_reg.h"
void led_setup(int io) {
if (io < 32) {
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, 1 << io);
} else {
WRITE_PERI_REG(GPIO_ENABLE1_W1TS_REG, 1 << (io - 32));
}
}
void led_on(int io) {
if (io < 32) {
WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << io);
} else {
WRITE_PERI_REG(GPIO_OUT1_W1TS_REG, 1 << (io - 32));
}
}
void led_off(int io) {
if (io < 32) {
WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << io);
} else {
WRITE_PERI_REG(GPIO_OUT1_W1TC_REG, 1 << (io - 32));
}
}
void led_toggle(int io) {
if (READ_PERI_REG(GPIO_OUT_REG & (1 << io))) {
WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << io);
} else {
WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << io);
}
}

View File

@ -0,0 +1,11 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* All rights reserved
*/
#pragma once
void led_setup(int io);
void led_on(int io);
void led_off(int io);
void led_toggle(int io);

View File

@ -0,0 +1,10 @@
#ifndef CS_COMMON_PLATFORMS_ESP32_STUBS_ROM_FUNCTIONS_H_
#define CS_COMMON_PLATFORMS_ESP32_STUBS_ROM_FUNCTIONS_H_
#include "rom/ets_sys.h"
#include "rom/spi_flash.h"
#include "rom/md5_hash.h"
#include "rom/uart.h"
#include "rom/rtc.h"
#endif /* CS_COMMON_PLATFORMS_ESP32_STUBS_ROM_FUNCTIONS_H_ */

View File

@ -0,0 +1 @@
#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2016 Cesanta Software Limited
* All rights reserved
*/
MEMORY {
iram : org = 0x40090000, len = 0x10000
/* DRAM startin at 0x3FFC0000 gets stomped by something before mem_finish
* and is thus not suitable for initialized data, but works fine for BSS. */
dram_bss : org = 0x3FFC0000, len = 0x10000
dram : org = 0x3FFD0000, len = 0x10000
}
ENTRY(stub_main)
SECTIONS {
.params 0x40090000 : {
_params_start = ABSOLUTE(.);
*(.params)
_params_end = ABSOLUTE(.);
} > iram
.text : ALIGN(4) {
_code_start = ABSOLUTE(.);
*(.literal)
*(.text .text.*)
} > iram
.bss : ALIGN(4) {
_bss_start = ABSOLUTE(.);
*(.bss)
_bss_end = ABSOLUTE(.);
} > dram
.data : ALIGN(4) {
_data_start = ABSOLUTE(.);
*(.data)
*(.rodata .rodata.*)
} > dram
}
INCLUDE "components/esp32/ld/esp32.rom.ld"
INCLUDE "components/esp32/ld/esp32.rom.spiram_incompatible_fns.ld"
PROVIDE(esp_rom_spiflash_attach = 0x40062a6c);
PROVIDE(esp_rom_spiflash_config_clk = 0x40062bc8);

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*
*
* Stub template.
*/
#include <inttypes.h>
#include <string.h>
#include "slip.h"
/* Define the args vector and put it into the ".params" section. */
uint32_t params[3] __attribute__((section(".params")));
/* Define a function called stub_main. Do not return or reboot.
* Use send_packet to communicate to the host. */
const char *hello = "Hello";
static char buf[1024];
extern uint32_t _bss_start, _bss_end;
void stub_main(void) {
uint32_t greeting = 0x4941484f;
SLIP_send(&greeting, 4);
memset(&_bss_start, 0, (&_bss_end - &_bss_start));
buf[1] = 123;
SLIP_send(hello, 5);
while (1) {
}
}

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#include "uart.h"
#include "rom_functions.h"
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate) {
uint32_t master_freq = ets_get_detected_xtal_freq() << 4;
master_freq += (baud_rate / 2);
uint32_t div = master_freq / baud_rate;
uart_div_modify(uart_no, div);
}

View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_PLATFORMS_ESP32_STUBS_UART_H_
#define CS_COMMON_PLATFORMS_ESP32_STUBS_UART_H_
#include <stdint.h>
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate);
#endif /* CS_COMMON_PLATFORMS_ESP32_STUBS_UART_H_ */

View File

@ -0,0 +1,76 @@
CFLAGS_EXTRA ?=
XTENSA_TOOLS_ROOT ?= /opt/Espressif/crosstool-NG/builds/xtensa-lx106-elf/bin
SDK_PATH ?= /opt/Espressif/ESP8266_SDK
ESPTOOL ?= esptool.py
ESPPORT ?= /dev/ttyACM0
ESPSPEED ?= 230400
# For flash = > 16Mbit
ESPFLASHARGS = --flash_mode dio --flash_size 32m
VERBOSE ?= 0
CC := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
CXX := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-g++
AR := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-ar
LD := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-gcc
OBJCOPY := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-objcopy
NM := $(XTENSA_TOOLS_ROOT)/xtensa-lx106-elf-nm
CC_WRAPPER ?=
define link
$(vecho) "LD $@"
$(Q) $(CC_WRAPPER) $(LD) $(LIBDIRS) -T$(LD_SCRIPT) $(LDFLAGS) -o $@ \
-Wl,-Map=$@.map -Wl,--start-group $1 -Wl,--end-group
endef
define compile_params
$(vecho) "$5 $1 -> $2"
$(Q) $(CC_WRAPPER) $3 -MD -MP $(INCDIRS) $4 -c $1 -o $2
endef
define compile
$(call compile_params,$<,$@, $(CC), $(CFLAGS),"CC")
endef
define compile_cxx
$(call compile_params,$<,$@, $(CXX), $(CXXFLAGS),"CXX")
endef
# some of these flags works around for gdb 7.5.x stacktrace issue
# while still allowing -Os to remove padding between data in .rodata
# section, allowing us to gain about 1k of ram.
# text section is 4k bigger, but we care more about ram at the moment.
# TODO(mkm): figure out which flag(s).
NO_Os_FLAGS= -fno-expensive-optimizations -fno-thread-jumps \
-fno-align-functions -fno-align-jumps \
-fno-align-loops -fno-align-labels -fno-caller-saves \
-fno-crossjumping -fno-cse-follow-jumps -fno-cse-skip-blocks \
-fno-delete-null-pointer-checks -fno-devirtualize \
-fno-gcse -fno-gcse-lm -fno-hoist-adjacent-loads \
-fno-inline-small-functions -fno-indirect-inlining -fno-partial-inlining \
-fno-ipa-cp -fno-ipa-sra -fno-peephole2 -fno-optimize-sibling-calls -fno-optimize-strlen \
-fno-reorder-blocks -fno-reorder-blocks-and-partition -fno-reorder-functions \
-fno-sched-interblock -fno-sched-spec -fno-rerun-cse-after-loop \
-fno-schedule-insns -fno-schedule-insns2 -fno-strict-aliasing -fno-strict-overflow \
-fno-tree-builtin-call-dce -fno-tree-switch-conversion -fno-tree-tail-merge \
-fno-tree-pre -fno-tree-vrp
C_CXX_FLAGS = -W -Wall -Werror -Wundef -Wno-comment -Wno-variadic-macros -Wpointer-arith \
-Os $(NO_Os_FLAGS) -g3 \
-Wl,-EL -fno-inline-functions \
-D_XOPEN_SOURCE=500 \
-nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DSTATIC=static \
-Wno-parentheses \
-DIRAM='__attribute__((section(".fast.text")))' \
-DICACHE_RAM_ATTR=IRAM \
-DNOINSTR='__attribute__((no_instrument_function))' \
-DCS_PLATFORM=3 \
-ffunction-sections -fdata-sections
CFLAGS = -std=c99 $(C_CXX_FLAGS)
CXXFLAGS = -std=gnu++11 -fno-exceptions $(C_CXX_FLAGS)
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start \
-Wl,-static -Wl,--gc-sections

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "mongoose/mongoose.h"
#ifdef RTOS_SDK
#include "esp_libc.h"
#else
#include "osapi.h"
#endif
extern int sha1_vector(size_t num_msgs, const uint8_t *msgs[],
const size_t *msg_lens, uint8_t *digest);
extern int md5_vector(size_t num_msgs, const uint8_t *msgs[],
const size_t *msg_lens, uint8_t *digest);
/* For digest auth. */
void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
const size_t *msg_lens, uint8_t *digest) {
(void) md5_vector(num_msgs, msgs, msg_lens, digest);
}
/* For WebSocket handshake. */
void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
const size_t *msg_lens, uint8_t *digest) {
(void) sha1_vector(num_msgs, msgs, msg_lens, digest);
}
#if MG_ENABLE_SSL
#include "mbedtls/aes.h"
#include "mbedtls/sha256.h"
#define AES_PRIV_NR_POS (4 * 15)
/*
* Crypto functions in ROM/SDK.
* They come from wpa_supplicant, you can find them here https://w1.fi/cgit/
*
* Note that ROM version of the key setup function is older, does not take the
* number of bits argument and only supports AES-128. This prototype doesn't
* suit it, but since the difference is in the last aegument, it doesn't matter.
*/
extern void rijndaelKeySetupDec(void *ctx, const uint8_t *key, int bits);
extern int rijndaelKeySetupEnc(void *ctx, const uint8_t *key, int bits);
void aes_encrypt(void *ctx, const uint8_t *plain, uint8_t *crypt);
void aes_decrypt(void *ctx, const uint8_t *crypt, uint8_t *plain);
/*
* AES that comes with wpa_supplicant allocates its own AES context in
* aes_{encrypt,decrypt}_init. Ideally, we'd take that pointer and store it in
* our mbedtls_aes_context, but then a lot of space would be wasted.
* We do not call _init and go directly to key setup functions and poke number
* of rounds into the right place too. This is a bit hacky, but works fine.
* There is also a difference between older function in ROM and the one coming
* with SDK which is newer: the older one actually takes two arguments, not 3.
* But it doesn't matter, extra argument doesn't hurt and this works with both.
*/
int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits) {
if (keybits != 128) return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
((uint32_t *) ctx)[AES_PRIV_NR_POS] = 10;
rijndaelKeySetupEnc(ctx, key, 128);
return 0;
}
int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits) {
if (keybits != 128) return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
((uint32_t *) ctx)[AES_PRIV_NR_POS] = 10;
rijndaelKeySetupDec(ctx, key, 128);
return 0;
}
int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16]) {
aes_encrypt(ctx, input, output);
return 0;
}
int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16]) {
aes_decrypt(ctx, input, output);
return 0;
}
/* os_get_random uses hardware RNG, so it's cool. */
int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
os_get_random(buf, len);
(void) ctx;
return 0;
}
/* For CryptoAuthLib host crypto. */
int atcac_sw_sha2_256(const uint8_t *data, size_t data_size,
uint8_t digest[32]) {
mbedtls_sha256(data, data_size, digest, false /* is_224 */);
return 0;
}
#endif /* MG_ENABLE_SSL */

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2014-2017 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_HW_WDT_REGISTER_H_
#define CS_COMMON_PLATFORMS_ESP8266_ESP_HW_WDT_REGISTER_H_
#ifdef RTOS_SDK
#include <esp_common.h>
#else
#include <user_interface.h>
#endif
#define REG_WDT_BASE 0x60000900
#define WDT_CTL (REG_WDT_BASE + 0x0)
#define WDT_CTL_ENABLE (BIT(0))
#define WDT_CTL_STAGE1_NO_RESET (BIT(1))
#define WDT_CTL_STAGE1_DISABLE (BIT(2))
#define WDT_CTL_UNK3 (BIT(3))
#define WDT_CTL_UNK4 (BIT(4))
#define WDT_CTL_UNK5 (BIT(5))
/* Bits 3, 4, 5 - ???; set to 1 by ROM. */
#define WDT_RELOAD_STAGE0 (REG_WDT_BASE + 0x4)
#define WDT_RELOAD_STAGE0_V (0xf)
#define WDT_RELOAD_STAGE0_S (0)
#define WDT_RELOAD_STAGE1 (REG_WDT_BASE + 0x8)
#define WDT_RELOAD_STAGE1_V (0xf)
#define WDT_RELOAD_STAGE1_S (0)
#define WDT_COUNT (REG_WDT_BASE + 0xc) /* Counts at CPU_CLK (80 MHz) */
#define WDT_COUNT_V (0xffffffff)
#define WDT_COUNT_S (0)
#define WDT_STAGE (REG_WDT_BASE + 0x10)
#define WDT_STAGE_V (1)
#define WDT_STAGE_S (0)
#define WDT_RESET (REG_WDT_BASE + 0x14)
#define WDT_RESET_V (0xff)
#define WDT_RESET_S (0)
#define WDT_RESET_STAGE (REG_WDT_BASE + 0x18)
#define WDT_RESET_STAGE_V (0xff)
#define WDT_RESET_STAGE_S (0)
#define WDT_RESET_VALUE 0x73
#endif /* CS_COMMON_PLATFORMS_ESP8266_ESP_HW_WDT_REGISTER_H_ */

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_MISSING_INCLUDES_H_
#define CS_COMMON_PLATFORMS_ESP8266_ESP_MISSING_INCLUDES_H_
#include <stdint.h>
#include <stdlib.h>
void pp_soft_wdt_init(void);
void pp_soft_wdt_stop(void);
void pp_soft_wdt_feed(void);
void pp_soft_wdt_restart(void);
void system_soft_wdt_stop(void); /* Alias for pp_soft_wdt_stop */
void Cache_Read_Disable(void);
void Cache_Read_Enable(uint32_t, uint32_t, uint32_t);
void Cache_Read_Disable_2(void);
void Cache_Read_Enable_2(void);
void Cache_Read_Enable_New(void);
int SPIEraseBlock(uint32_t block);
uint32_t SPIRead(uint32_t addr, void *dst, uint32_t size);
#ifndef RTOS_SDK
#include <ets_sys.h>
/* There are no declarations for these anywhere in the SDK (as of 1.2.0). */
void ets_isr_mask(unsigned intr);
void ets_isr_unmask(unsigned intr);
void system_restart_local(void);
int os_printf_plus(const char *format, ...);
void ets_wdt_init(void);
void ets_wdt_enable(uint32_t mode, uint32_t arg1, uint32_t arg2);
void ets_wdt_disable(void);
void ets_wdt_restore(uint32_t mode);
uint32_t ets_wdt_get_mode(void);
void _xtos_l1int_handler(void);
void _xtos_set_exception_handler();
void xthal_set_intenable(unsigned);
/* These are present in mem.h but are commented out. */
void *pvPortMalloc(size_t xWantedSize, const char *file, int line);
void vPortFree(void *pv, const char *file, int line);
void *pvPortZalloc(size_t size, const char *file, int line);
void *pvPortRealloc(void *pv, size_t size, const char *file, int line);
#else /* !RTOS_SDK */
#define BIT(nr) (1UL << (nr))
void system_soft_wdt_feed(void);
void system_soft_wdt_restart(void);
void ets_putc(char c);
#endif /* RTOS_SDK */
void _ResetVector(void);
#endif /* CS_COMMON_PLATFORMS_ESP8266_ESP_MISSING_INCLUDES_H_ */

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_SSL_KRYPTON_H_
#define CS_COMMON_PLATFORMS_ESP8266_ESP_SSL_KRYPTON_H_
#include "krypton/krypton.h"
struct mg_connection;
void mg_lwip_ssl_do_hs(struct mg_connection *nc);
void mg_lwip_ssl_send(struct mg_connection *nc);
void mg_lwip_ssl_recv(struct mg_connection *nc);
#endif /* CS_COMMON_PLATFORMS_ESP8266_ESP_SSL_KRYPTON_H_ */

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#include <string.h>
#include <stdio.h>
#include "common/umm_malloc/umm_malloc.h"
#include "esp_umm_malloc.h"
#if ESP_UMM_ENABLE
/*
* ESP-specific glue for the `umm_malloc`.
*
* In SDK (https://github.com/cesanta/esp-open-sdk), there is an archive
* `sdk/lib/libmain.a` which contains some files, including `mem_manager.o`.
*
* The `mem_manager.o` contains all the heap-related functions: `pvPortMalloc`,
* etc. We have weaken all symbols from `mem_manager.o` by
* `xtensa-lx106-elf-objcopy` (see exact commands in Dockerfile:
* `docker/esp8266/Dockerfile-esp8266-build-oss`), and provide our own
* implementations in this file.
*
* ------------------------------------
*
* NOTE that not all public functions from `mem_manager.o` need to be replaced:
* some of them are used only internally:
*
* - system_show_malloc()
* - pvShowMalloc()
* - prvInsertBlockIntoUsedList()
* - prvRemoveBlockFromUsedList()
* - check_memleak_debug_enable()
* - vPortInitialiseBlocks()
*
* So when we replace all the rest (`pvPortMalloc`, etc), we can check with
* `objdump` that resulting binary (for SJ, it's `fw.out`) doesn't contain
* any of the "internal" functions.
*
* ------------------------------------
*
* NOTE that to make linker actually consider implementations in this file,
* you should explicitly reference some function from it. This is what
* `esp_umm_init()` is for: it is a dummy no-op function that must be called
* from somewhere outside.
*
* If you don't do this, linker will merely garbage-collect this file, and
* will use heap implementation from SDK.
*/
void *pvPortMalloc(size_t size, const char *file, unsigned line) {
(void) file;
(void) line;
return umm_malloc(size);
}
void *pvPortCalloc(size_t num, size_t size, const char *file, unsigned line) {
(void) file;
(void) line;
return umm_calloc(num, size);
}
void *pvPortZalloc(size_t size, const char *file, unsigned line) {
void *ret;
(void) file;
(void) line;
ret = umm_malloc(size);
if (ret != NULL) memset(ret, 0, size);
return ret;
}
void *pvPortRealloc(void *ptr, size_t size, const char *file, unsigned line) {
(void) file;
(void) line;
return umm_realloc(ptr, size);
}
void vPortFree(void *ptr, const char *file, unsigned line) {
(void) file;
(void) line;
umm_free(ptr);
}
size_t xPortGetFreeHeapSize(void) {
return umm_free_heap_size();
}
size_t xPortWantedSizeAlign(void) {
return 4;
}
void esp_umm_init(void) {
/* Nothing to do, see header for details */
}
void esp_umm_oom_cb(size_t size, size_t blocks_cnt) {
fprintf(stderr, "E:M %u (%u blocks)\n", (unsigned int) size,
(unsigned int) blocks_cnt);
}
#endif /* ESP_UMM_ENABLE */

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#if ESP_UMM_ENABLE
/*
* This is a no-op dummy function that is merely needed because we have to
* reference any function from the file `esp_umm_malloc.c`, so that linker
* won't garbage-collect the whole compilation unit.
*/
void esp_umm_init(void);
/*
* Callback that gets called by umm_malloc in case of Out-of-memory error.
*
* `size` is the size requested by user, and `block_cnt` is a number of heap
* blocks that umm_malloc failed to allocate
*/
void esp_umm_oom_cb(size_t size, size_t blocks_cnt);
#endif /* CS_COMMON_PLATFORMS_ESP8266_ESP_UMM_MALLOC_H_ */

View File

@ -0,0 +1,26 @@
#
# Makefile for esptool2
# https://github.com/raburton/esp8266
#
CFLAGS = -O2 -Wall
CC = gcc
LD = gcc
BUILD_DIR = ../../build
all: $(BUILD_DIR) $(BUILD_DIR)/esptool2
$(BUILD_DIR):
@mkdir -p $(BUILD_DIR)
$(BUILD_DIR)/esptool2.o: esptool2.c esptool2.h esptool2_elf.h elf.h
@echo "CC $<"
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/esptool2_elf.o: esptool2_elf.c esptool2.h esptool2_elf.h elf.h
@echo "CC $<"
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/esptool2: $(BUILD_DIR)/esptool2.o $(BUILD_DIR)/esptool2_elf.o
@echo "LD $@"
$(LD) -o $@ $^

View File

@ -0,0 +1,76 @@
// Based on a small portion of ELF.h from LLVM
//===-- llvm/Support/ELF.h - ELF constants and data structures --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License.
//
//===----------------------------------------------------------------------===//
//
// This header contains common, non-processor-specific data structures and
// constants for the ELF file format.
//
// The details of the ELF32 bits in this file are largely based on the Tool
// Interface Standard (TIS) Executable and Linking Format (ELF) Specification
// Version 1.2, May 1995. The ELF64 stuff is based on ELF-64 Object File Format
// Version 1.5, Draft 2, May 1998 as well as OpenBSD header files.
//
//===----------------------------------------------------------------------===//
#ifndef CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ELF_H_
#define CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ELF_H_
typedef uint32_t Elf32_Addr; // Program address
typedef uint32_t Elf32_Off; // File offset
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Word;
typedef int32_t Elf32_Sword;
// e_ident size and indices
enum {
EI_MAG0 = 0, // File identification index.
EI_MAG1 = 1, // File identification index.
EI_MAG2 = 2, // File identification index.
EI_MAG3 = 3, // File identification index.
EI_CLASS = 4, // File class.
EI_DATA = 5, // Data encoding.
EI_VERSION = 6, // File version.
EI_OSABI = 7, // OS/ABI identification.
EI_ABIVERSION = 8, // ABI version.
EI_PAD = 9, // Start of padding bytes.
EI_NIDENT = 16 // Number of bytes in e_ident.
};
typedef struct {
unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes
Elf32_Half e_type; // Type of file (see ET_* below)
Elf32_Half e_machine; // Required architecture for this file (see EM_*)
Elf32_Word e_version; // Must be equal to 1
Elf32_Addr e_entry; // Address to jump to in order to start program
Elf32_Off e_phoff; // Program header table's file offset, in bytes
Elf32_Off e_shoff; // Section header table's file offset, in bytes
Elf32_Word e_flags; // Processor-specific flags
Elf32_Half e_ehsize; // Size of ELF header, in bytes
Elf32_Half e_phentsize; // Size of an entry in the program header table
Elf32_Half e_phnum; // Number of entries in the program header table
Elf32_Half e_shentsize; // Size of an entry in the section header table
Elf32_Half e_shnum; // Number of entries in the section header table
Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table
} Elf32_Ehdr;
typedef struct {
Elf32_Word sh_name; // Section name (index into string table)
Elf32_Word sh_type; // Section type (SHT_*)
Elf32_Word sh_flags; // Section flags (SHF_*)
Elf32_Addr sh_addr; // Address where section is to be loaded
Elf32_Off sh_offset; // File offset of section data, in bytes
Elf32_Word sh_size; // Size of section, in bytes
Elf32_Word sh_link; // Section type-specific header table index link
Elf32_Word sh_info; // Section type-specific extra information
Elf32_Word sh_addralign; // Section address alignment
Elf32_Word sh_entsize; // Size of records contained within the section
} Elf32_Shdr;
#endif /* CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ELF_H_ */

View File

@ -0,0 +1,561 @@
/**********************************************************************************
*
* Copyright (c) 2015 Richard A Burton <richardaburton@gmail.com>
*
* This file is part of esptool2.
*
* esptool2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* esptool2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with esptool2. If not, see <http://www.gnu.org/licenses/>.
*
**********************************************************************************/
/* clang-format off */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "esptool2.h"
#include "esptool2_elf.h"
#define IMAGE_PADDING 16
#define SECTION_PADDING 4
#define IROM_SECTION_PADDING 4096
#define CHECKSUM_INIT 0xEF
#define BIN_MAGIC_IROM 0xEA
#define BIN_MAGIC_FLASH 0xE9
typedef struct {
Elf32_Addr addr;
Elf32_Word size;
} Section_Header;
typedef struct {
unsigned char magic;
unsigned char count;
unsigned char byte2;
unsigned char byte3;
Elf32_Addr entry;
} Image_Header;
static const char PADDING[IROM_SECTION_PADDING] = {0};
static bool debugon = false;
static bool quieton = false;
// Print a standard info message (unless quiet mode)
void print(const char* format, ...) {
va_list args;
if (!quieton) {
va_start(args, format);
vprintf(format, args);
va_end(args);
}
}
// Print a debug message (if debug mode)
void debug(const char* format, ...) {
va_list args;
if (debugon) {
va_start(args, format);
vprintf(format, args);
va_end(args);
}
}
// Print an error message (always)
void error(const char* format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
}
// Write an elf section (by name) to an existing file.
// Parameters:
// headed - add a header to the output
// zeroaddr - force zero entry point in header (default is the real entry point)
// padded - output will be padded to multiple of SECTION_PADDING bytes
// chksum - pointer to existing checksum to add this data to (zero if not needed)
// Produces error message on failure (so caller doesn't need to).
bool WriteElfSection(MyElf_File *elf, FILE *outfile, char* name, bool headed,
bool zeroaddr, int padto, unsigned char *chksum) {
int i, pad = 0;
bool ret = false;
unsigned char *bindata = 0;
Section_Header sechead;
MyElf_Section *sect;
// get elf section header
sect = GetElfSection(elf, name);
if(!sect) {
error("Error: Section '%s' not found in elf file.\r\n", name);
goto end_function;
}
// create image section header
sechead.addr = (zeroaddr ? 0 : sect->address);
sechead.size = sect->size;
// do we need to pad the section?
if (padto) {
pad = sechead.size % padto;
if (pad > 0) {
pad = padto - pad;
sechead.size += pad;
}
}
debug("Adding section '%s', addr: 0x%08x, size: %d (+%d bytes(s) padding).\r\n",
name, sect->address, sect->size, pad);
// get elf section binary data
bindata = GetElfSectionData(elf, sect);
if (!bindata) {
goto end_function;
}
// write section (and pad if required)
if((headed && fwrite(&sechead, 1, sizeof(sechead), outfile) != sizeof(sechead))
|| fwrite(bindata, 1, sect->size, outfile) != sect->size
|| (pad > 0 && fwrite(PADDING, 1, pad, outfile) != pad)) {
error("Error: Failed to write section '%s' to image file.\r\n", name);
goto end_function;
}
// include section data in the checksum
if(chksum) {
for(i = 0; i < (int)sect->size; i++) {
*chksum ^= bindata[i];
}
}
ret = true;
end_function:
if (bindata) free(bindata);
return ret;
}
// Load an elf file and export a section of it to a new file, without
// header, padding or checksum. For exporting the .irom0.text library.
// Produces error message on failure (so caller doesn't need to).
bool ExportElfSection(char *infile, char *outfile, char *name) {
bool ret = false;
FILE *fd = 0;
MyElf_File *elf = 0;
// load elf file
elf = LoadElf(infile);
if (!elf) {
goto end_function;
}
// open output file
fd = fopen(outfile, "wb");
if(!fd) {
error("Error: Can't open output file '%s' for writing.\r\n", outfile);
goto end_function;
}
// actually do the export
ret = WriteElfSection(elf, fd, name, false, false, false, 0);
end_function:
// clean up
if (fd) fclose(fd);
UnloadElf(elf);
return ret;
}
// Create the main binary firmware image, from specified elf sections.
// Can produce for standard standalone app (separate .irom0.text)
// or sdk bootloaded apps (integrated .irom0.text).
// Choice of type requires appropriately linked elf file.
// Produces error message on failure (so caller doesn't need to).
bool CreateHeaderFile(char *elffile, char *imagefile, char *sections[], int numsec) {
bool ret = false;
int i;
unsigned int j, len;
FILE *outfile = 0;
MyElf_File *elf = 0;
MyElf_Section *sect;
unsigned char *bindata = 0;
char name[31];
// load elf file
elf = LoadElf(elffile);
if (!elf) {
goto end_function;
}
// open output file
outfile = fopen(imagefile, "wb");
if(outfile == NULL) {
error("Error: Failed to open output file '%s' for writing.\r\n", imagefile);
goto end_function;
}
// add entry point
fprintf(outfile, "const uint32 entry_addr = 0x%08x;\r\n", elf->header.e_entry);
// add sections
for (i = 0; i < numsec; i++) {
// get elf section header
sect = GetElfSection(elf, sections[i]);
if(!sect) {
error("Error: Section '%s' not found in elf file.\r\n", sections[i]);
goto end_function;
}
// simple name fix name
strncpy(name, sect->name, 31);
len = strlen(name);
for (j = 0; j < len; j++) {
if (name[j] == '.') name[j] = '_';
}
// add address, length and start the data block
debug("Adding section '%s', addr: 0x%08x, size: %d.\r\n", sections[i], sect->address, sect->size);
fprintf(outfile, "\r\nconst uint32 %s_addr = 0x%08x;\r\nconst uint32 %s_len = %d;\r\nconst uint8 %s_data[] = {",
name, sect->address, name, sect->size, name);
// get elf section binary data
bindata = GetElfSectionData(elf, sect);
if (!bindata) {
goto end_function;
}
// add the data and finish off the block
for (j = 0; j < sect->size; j++) {
if (j % 16 == 0) fprintf(outfile, "\r\n 0x%02x,", bindata[j]);
else fprintf(outfile, " 0x%02x,", bindata[j]);
}
fprintf(outfile, "\r\n};\r\n");
free(bindata);
bindata = 0;
}
// if we got this far everything worked!
ret = true;
end_function:
// clean up
if (outfile) fclose(outfile);
if (elf) UnloadElf(elf);
if (bindata) free(bindata);
return ret;
}
// Create the main binary firmware image, from specified elf sections.
// Can produce for standard standalone app (separate .irom0.text)
// or sdk bootloaded apps (integrated .irom0.text).
// Choice of type requires appropriately linked elf file.
// Produces error message on failure (so caller doesn't need to).
bool CreateBinFile(char *elffile, char *imagefile, int bootver, unsigned char mode,
unsigned char clock, unsigned char size, bool iromchksum, char *sections[], int numsec) {
bool ret = false;
int i, pad, len;
unsigned char chksum = CHECKSUM_INIT;
unsigned char *data = 0;
FILE *outfile = 0;
MyElf_File *elf = 0;
Image_Header imghead;
// load elf file
elf = LoadElf(elffile);
if (!elf) {
goto end_function;
}
// open output file
outfile = fopen(imagefile, "wb");
if(outfile == NULL) {
error("Error: Failed to open output file '%s' for writing.\r\n", imagefile);
goto end_function;
}
// set options common to standard and boot v1.2+ headers
imghead.byte2 = mode;
//imghead.byte3 = (int)((int)size << 4 | clock) && 0xff;
imghead.byte3 = ((size << 4) | clock) & 0xff;
imghead.entry = elf->header.e_entry;
debug("Size = %02x\r\n", size);
debug("Byte2 = %02x\r\n", imghead.byte2);
debug("Byte3 = %02x\r\n", imghead.byte3);
debug("Entry = %08x\r\n", imghead.entry);
// boot v1.2+ header
if (bootver == 2) {
// extra header
imghead.magic = BIN_MAGIC_IROM;
imghead.count = 4; // probably a version number here, not a count
if(fwrite(&imghead, 1, sizeof(imghead), outfile) != sizeof(imghead)) {
error("Error: Failed to write header to image file.\r\n");
goto end_function;
}
if(!WriteElfSection(elf, outfile, ".irom0.text", true, true, IROM_SECTION_PADDING, (iromchksum ? &chksum : 0))) {
goto end_function;
}
}
// standard header
imghead.magic = BIN_MAGIC_FLASH;
imghead.count = numsec;
// write header
if(fwrite(&imghead, 1, sizeof(imghead), outfile) != sizeof(imghead)) {
error("Error: Failed to write header to image file.\r\n");
goto end_function;
}
// add sections
for (i = 0; i < numsec; i++) {
if(!WriteElfSection(elf, outfile, sections[i], true, false, SECTION_PADDING, &chksum)) {
goto end_function;
}
}
// get image length (plus a byte for the checksum)
len = ftell(outfile) + 1;
// do we need to pad the image?
pad = len % IMAGE_PADDING;
if (pad > 0) {
pad = IMAGE_PADDING - pad;
debug("Padding image with %d byte(s).\r\n", pad);
if(fwrite(PADDING, 1, pad, outfile) != pad) {
error("Error: Failed to write padding to image file.\r\n");
goto end_function;
}
}
// write checksum
if(fwrite(&chksum, 1, 1, outfile) != 1) {
error("Error: Failed to write checksum to image file.\r\n");
goto end_function;
}
// boot v1.1
if(bootver == 1) {
// write 'ff' padding up to the position of the library
len = 0x10000 - ftell(outfile);
debug("Adding boot v1.1 padding, %d bytes of '0xff'.\r\n", len);
data = (unsigned char*)malloc(len);
memset(data, 0xff, len);
if(fwrite(data, 1, len, outfile) != len) {
error("Error: Failed to write boot v1.1 spacer.\r\n");
goto end_function;
}
// write the library
if(!WriteElfSection(elf, outfile, ".irom0.text", false, false, 0, 0)) {
goto end_function;
}
}
// if we got this far everything worked!
ret = true;
end_function:
// clean up
if (outfile) fclose(outfile);
if (data) free(data);
if (elf) UnloadElf(elf);
return ret;
}
int main(int argc, char *argv[]) {
int i;
char *infile;
char *outfile;
int numstr;
bool binfile = false;
bool libfile = false;
bool headerfile = false;
bool paramerror = false;
bool iromchksum = false;
int bootver = 0;
/* Overwrite-friendly by default */
unsigned char mode = 0xff;
unsigned char size = 0xff;
unsigned char clock = 0;
int opts = 0;
// parse options
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-bin")) {
binfile = true;
opts++;
} else if (!strcmp(argv[i], "-lib")) {
libfile = true;
opts++;
} else if (!strcmp(argv[i], "-header")) {
headerfile = true;
opts++;
} else if (!strcmp(argv[i], "-quiet")) {
quieton = true;
} else if (!strcmp(argv[i], "-debug")) {
debugon = true;
} else if (!strcmp(argv[i], "-boot0")) {
bootver = 0;
} else if (!strcmp(argv[i], "-boot1")) {
bootver = 1;
} else if (!strcmp(argv[i], "-boot2")) {
bootver = 2;
} else if (!strcmp(argv[i], "-qio")) {
mode = 0;
} else if (!strcmp(argv[i], "-qout")) {
mode = 1;
} else if (!strcmp(argv[i], "-dio")) {
mode = 2;
} else if (!strcmp(argv[i], "-dout")) {
mode = 3;
} else if (!strcmp(argv[i], "-256")) {
size = 1;
} else if (!strcmp(argv[i], "-512")) {
size = 0;
} else if (!strcmp(argv[i], "-1024")) {
size = 2;
} else if (!strcmp(argv[i], "-2048")) {
size = 3;
} else if (!strcmp(argv[i], "-4096")) {
size = 4;
} else if (!strcmp(argv[i], "-20")) {
clock = 2;
} else if (!strcmp(argv[i], "-26.7")) {
clock = 1;
} else if (!strcmp(argv[i], "-40")) {
clock = 0;
} else if (!strcmp(argv[i], "-80")) {
clock = 15;
} else if (!strcmp(argv[i], "-iromchksum")) {
iromchksum = true;
} else if (!strcmp(argv[i], "--")) {
i++;
break;
} else if (argv[i][0] == '-') {
paramerror = true;
break;
} else {
break;
}
}
print("esptool2 v2.0.0 - (c) 2015 Richard A Burton <richardaburton@gmail.com>\r\n");
print("This program is licensed under the GPL v3.\r\n");
print("See the file LICENSE for details.\r\n\r\n");
if (paramerror) {
error("Error: Unrecognised option '%s'.\r\n", argv[i]);
return -1;
}
if (argc < 2) {
print("Usage:\r\n");
print("esptool2 -lib [options] <input_file> <output_file>\r\n");
print("esptool2 -bin [options] <input_file> <output_file> <elf_section>...\r\n");
print("esptool2 -header [options] <input_file> <output_file> <elf_section>...\r\n");
print("\r\n");
print(" -lib\r\n");
print(" Export the sdk library (.irom0.text), for a standalone app.\r\n");
print(" e.g. esptool2 -elf esp8266_iot.out out.bin\r\n");
print("\r\n");
print(" -header\r\n");
print(" Export elf sections as bytes to a C header file.\r\n");
print(" e.g. esptool2 -elf esp8266_iot.out out.h .text .data .rodata\r\n");
print("\r\n");
print(" -bin\r\n");
print(" Create binary program image, for standalone and bootloaded apps, with\r\n");
print(" specified elf sections. Includes sdk library for bootloaded apps.\r\n");
print(" e.g. esptool2 -bin esp8266_iot.out out.bin .text .data .rodata\r\n");
print(" Options:\r\n");
print(" bootloader: -boot0 -boot1 -boot2 (default -boot0)\r\n");
print(" -boot0 = standalone app, not built for bootloader use\r\n");
print(" -boot1 = built for bootloader v1.1\r\n");
print(" -boot2 = built for bootloader v1.2+ (use for rBoot roms)\r\n");
print(" (elf file must have been linked appropriately for chosen option)\r\n");
print(" spi size (kb): -256 -512 -1024 -2048 -4096 (default -512)\r\n");
print(" spi mode: -qio -qout -dio -dout (default -qio)\r\n");
print(" spi speed: -20 -26.7 -40 -80 (default -40)\r\n");
print(" include irom in checksum: -iromchksum (also needs enabling in rBoot)\r\n");
print("\r\n");
print("General options:\r\n");
print(" -quiet prints only error messages\r\n");
print(" -debug print extra debug information\r\n");
print(" -- no more options follow (needed if your elf file starts with a '-')\r\n");
print("\r\n");
print("Returns:\r\n");
print(" 0 on success\r\n");
print(" -1 on failure\r\n");
print("\r\n");
return -1;
}
// validate command line options
if (opts != 1) {
error("Error: You must specify -bin OR -lib OR -header for build type.\r\n");
return -1;
}
if (quieton && debugon) {
error("Error: You cannot specify -quiet and -debug.\r\n");
return -1;
}
// check enough parameters
if ((libfile && i + 2 > argc) || ((binfile | headerfile) && i + 3 > argc)) {
error("Error: Not enough arguments supplied.\r\n");
return -1;
} else if (libfile && i + 2 < argc) {
error("Error: Too many arguments supplied.\r\n");
return -1;
}
// get parameters
infile = argv[i++];
outfile = argv[i++];
numstr = argc - i;
// do it
if (binfile) {
if (!CreateBinFile(infile, outfile, bootver, mode, clock, size, iromchksum, &argv[i], numstr)) {
remove(outfile);
return -1;
}
} else if (headerfile) {
if (!CreateHeaderFile(infile, outfile, &argv[i], numstr)) {
remove(outfile);
return -1;
}
} else {
if (!ExportElfSection(infile, outfile, ".irom0.text")) {
remove(outfile);
return -1;
}
}
print("Successfully created '%s'.\r\n", outfile);
return 0;
}

View File

@ -0,0 +1,44 @@
/**********************************************************************************
*
* Copyright (c) 2015 Richard A Burton <richardaburton@gmail.com>
*
* This file is part of esptool2.
*
* esptool2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* esptool2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with esptool2. If not, see <http://www.gnu.org/licenses/>.
*
**********************************************************************************/
#ifndef CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ESPTOOL2_H_
#define CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ESPTOOL2_H_
#ifdef WIN32
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#else
#include <stdint.h>
#endif
#define true 1
#define false 0
#define bool char
void debug( const char* format, ... );
void print( const char* format, ... );
void error( const char* format, ... );
#endif /* CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ESPTOOL2_H_ */

View File

@ -0,0 +1,183 @@
/**********************************************************************************
*
* Copyright (c) 2015 Richard A Burton <richardaburton@gmail.com>
*
* This file is part of esptool2.
*
* esptool2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* esptool2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with esptool2. If not, see <http://www.gnu.org/licenses/>.
*
**********************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "esptool2.h"
#include "esptool2_elf.h"
// Find a section in an elf file by name.
// Returns pointer to section if found, else returns zero.
// Does not produce any messages.
MyElf_Section* GetElfSection(MyElf_File *elf, char *name) {
int i;
for(i = 0; i < elf->header.e_shnum - 1; i++) {
if(!strcmp(name, elf->sections[i].name)) {
debug("Found section '%s'.\r\n", name);
return &elf->sections[i];
}
}
debug("Could not find section '%s'.\r\n", name);
return 0;
}
// Reads an elf section (actual data) from the elf file.
// Returns a pointer to newly allocated memory (or zero on error),
// which should be freed by the caller when finished with.
// Produces error message on failure (so caller doesn't need to).
unsigned char* GetElfSectionData(MyElf_File *elf, MyElf_Section *section) {
unsigned char *data = 0;
if (section->size && section->offset) {
data = (unsigned char*)malloc(section->size);
if(!data) {
error("Error: Out of memory!\r\n");
return 0;
}
if(fseek(elf->fd, section->offset, SEEK_SET) ||
fread(data, 1, section->size, elf->fd) != section->size) {
error("Error: Can't read section '%s' data from elf file.\r\n", section->name);
free(data);
return 0;
}
} else {
error("Error: Section '%s' has no data to read.\r\n", section->name);
}
return data;
}
// Opens an elf file and reads the string table and file & section headers.
// Returns a pointer to a MyElf_File structure (or zero on error).
// UnloadElf should be called to dispose of the MyElf_File structure.
// Produces error message on failure (so caller doesn't need to).
MyElf_File* LoadElf(char *infile) {
int i;
MyElf_File *elf;
Elf32_Shdr temp;
// allocate the elf structure
elf = (MyElf_File*)malloc(sizeof(MyElf_File));
if(!elf) {
error("Error: Out of memory!\r\n");
goto error_exit;
}
memset(elf, 0, sizeof(MyElf_File));
// open the file
elf->fd = fopen(infile, "rb");
if(!elf->fd) {
error("Error: Can't open elf file '%s'.\r\n", infile);
goto error_exit;
}
// read the header
if(fread(&elf->header, 1, sizeof(Elf32_Ehdr), elf->fd) != sizeof(Elf32_Ehdr)) {
error("Error: Can't read elf file header.\r\n");
goto error_exit;
}
// check the file header
if (memcmp(elf->header.e_ident, "\x7f" "ELF", 4)) {
error("Error: Input files doesn't look like an elf file (bad header).\r\n");
goto error_exit;
}
// is there a string table section (we need one)
if(!elf->header.e_shstrndx) {
error("Error: Elf file does not contain a string table.\r\n");
goto error_exit;
}
// get the string table section header
if(fseek(elf->fd, elf->header.e_shoff + (elf->header.e_shentsize * elf->header.e_shstrndx), SEEK_SET) ||
fread(&temp, 1, sizeof(Elf32_Shdr), elf->fd) != sizeof(Elf32_Shdr)) {
error("Error: Can't read string table section from elf file.\r\n");
goto error_exit;
}
// read the actual string table
if(!temp.sh_size) {
error("Error: Elf file contains an empty string table.\r\n");
goto error_exit;
}
elf->strings = (char*)malloc(temp.sh_size);
if(!elf->strings) {
error("Error: Out of memory!\r\n");
goto error_exit;
}
if(fseek(elf->fd, temp.sh_offset, SEEK_SET) ||
fread(elf->strings, 1, temp.sh_size, elf->fd) != temp.sh_size) {
error("Error: Failed to read string stable from elf file.\r\n");
goto error_exit;
}
// read section headers
elf->sections = (MyElf_Section*)malloc(sizeof(MyElf_Section) * elf->header.e_shnum);
if(!elf->sections) {
error("Error: Out of memory!\r\n");
goto error_exit;
}
for(i = 1; i < elf->header.e_shnum; i++) {
if(fseek(elf->fd, elf->header.e_shoff + (elf->header.e_shentsize * i), SEEK_SET)
|| fread(&temp, 1, sizeof(Elf32_Shdr), elf->fd) != sizeof(Elf32_Shdr)) {
error("Error: Can't read section %d from elf file.\r\n", i);
break;
}
debug("Read section %d '%s'.\r\n", i, elf->strings + temp.sh_name);
elf->sections[i-1].address = temp.sh_addr;
elf->sections[i-1].offset = temp.sh_offset;
elf->sections[i-1].size = temp.sh_size;
elf->sections[i-1].name = elf->strings + temp.sh_name;
}
return elf;
error_exit:
if (elf) {
if (elf->fd) fclose(elf->fd);
if (elf->strings) free(elf->strings);
free(elf);
}
return 0;
}
// Close an elf file and dispose of the MyElf_File structure.
void UnloadElf(MyElf_File *elf) {
if (elf) {
debug("Unloading elf file.\r\n");
if(elf->fd) fclose(elf->fd);
if(elf->strings) free(elf->strings);
if(elf->sections) free(elf->sections);
free(elf);
}
}

View File

@ -0,0 +1,48 @@
/**********************************************************************************
*
* Copyright (c) 2015 Richard A Burton <richardaburton@gmail.com>
*
* This file is part of esptool2.
*
* esptool2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* esptool2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with esptool2. If not, see <http://www.gnu.org/licenses/>.
*
**********************************************************************************/
#ifndef CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ESPTOOL2_ELF_H_
#define CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ESPTOOL2_ELF_H_
#include <stdio.h>
#include "elf.h"
typedef struct {
Elf32_Off offset;
Elf32_Addr address;
Elf32_Word size;
char *name;
} MyElf_Section;
typedef struct {
FILE *fd;
Elf32_Ehdr header;
char *strings;
MyElf_Section *sections;
} MyElf_File;
MyElf_File* LoadElf(char *infile);
void UnloadElf(MyElf_File *e_object);
MyElf_Section* GetElfSection(MyElf_File *e_object, char *name);
unsigned char* GetElfSectionData(MyElf_File *e_object, MyElf_Section *section);
#endif /* CS_COMMON_PLATFORMS_ESP8266_RBOOT_ESPTOOL2_ESPTOOL2_ELF_H_ */

View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,19 @@
Esptool2
richardaburton@gmail.com
http://richard.burtons.org/
Esptool2 is a tool for creating rom images for the ESP8266. It is an alternative
to using the SDK supplied shell script/Makefile/python script combo, which is a
mess. It was inspired by the windows esptool v0.0.2 by mamalala and found on
www.esp8266.com but made somewhat simpler in code and usage. It also adds
support for boot loader v1.2+ rom types, which was the main reason I wrote it.
It was written for my own use and the name was simply to distinguish it for the
other version on my system. The 2 is not intended to imply it is better than the
original. The original has since been updated to v0.0.3 which can write to the
flash, but I currently have no intention to add that to esptool2, it is purely a
rom creating utility. It has become an integral part of my build process now and
has added functionality needed for building the rBoot boot loader. Since I have
released rBoot I needed to release this as well.
Run tool for full usage instructions, or look at the code.

View File

@ -0,0 +1,152 @@
//////////////////////////////////////////////////
// rBoot OTA and config API for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
// OTA code based on SDK sample from Espressif.
//////////////////////////////////////////////////
#ifdef RBOOT_INTEGRATION
#include <rboot-integration.h>
#endif
#include <c_types.h>
#include <stdlib.h>
#include <string.h>
#ifdef RTOS_SDK
#include "spi_flash.h"
#else
#include <user_interface.h>
#endif
#include "rboot-api.h"
#include "../rboot-private.h"
#include "esp_missing_includes.h"
#ifdef __cplusplus
extern "C" {
#endif
// get the rboot config
rboot_config ICACHE_FLASH_ATTR rboot_get_config(void) {
rboot_config conf;
spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32*)&conf, sizeof(rboot_config));
return conf;
}
// write the rboot config
// preserves the contents of the rest of the sector,
// so the rest of the sector can be used to store user data
// updates checksum automatically (if enabled)
bool ICACHE_FLASH_ATTR rboot_set_config(rboot_config *conf) {
uint32_t buffer[sizeof(*conf) / sizeof(uint32_t) + 1];
#ifdef BOOT_CONFIG_CHKSUM
uint8 chksum;
uint8 *ptr;
#endif
#ifdef BOOT_CONFIG_CHKSUM
chksum = CHKSUM_INIT;
for (ptr = (uint8*)conf; ptr < &conf->chksum; ptr++) {
chksum ^= *ptr;
}
conf->chksum = chksum;
#endif
memset(buffer, 0xff, sizeof(buffer));
memcpy(buffer, conf, sizeof(*conf));
if (spi_flash_erase_sector(BOOT_CONFIG_SECTOR) != SPI_FLASH_RESULT_OK ||
spi_flash_write(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, sizeof(buffer)) != SPI_FLASH_RESULT_OK) {
return false;
}
return true;
}
// get current boot rom
uint8 ICACHE_FLASH_ATTR rboot_get_current_rom(void) {
rboot_config conf;
conf = rboot_get_config();
return conf.current_rom;
}
// set current boot rom
bool ICACHE_FLASH_ATTR rboot_set_current_rom(uint8 rom) {
rboot_config conf;
conf = rboot_get_config();
if (rom >= conf.count) return false;
conf.current_rom = rom;
return rboot_set_config(&conf);
}
// create the write status struct, based on supplied start address
rboot_write_status ICACHE_FLASH_ATTR rboot_write_init(uint32 start_addr) {
rboot_write_status status = {0};
status.start_addr = start_addr;
status.start_sector = start_addr / SECTOR_SIZE;
//status.max_sector_count = 200;
//os_printf("init addr: 0x%08x\r\n", start_addr);
return status;
}
// function to do the actual writing to flash
// call repeatedly with more data (max len per write is the flash sector size (4k))
bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, uint8 *data, uint16 len) {
bool ret = false;
uint8 *buffer;
if (data == NULL || len == 0) {
return true;
}
// get a buffer
buffer = (uint8 *) calloc(1, len + status->extra_count);
if (!buffer) {
//os_printf("No ram!\r\n");
return false;
}
// copy in any remaining bytes from last chunk
memcpy(buffer, status->extra_bytes, status->extra_count);
// copy in new data
memcpy(buffer + status->extra_count, data, len);
// calculate length, must be multiple of 4
// save any remaining bytes for next go
len += status->extra_count;
status->extra_count = len % 4;
len -= status->extra_count;
memcpy(status->extra_bytes, buffer + len, status->extra_count);
// check data will fit
//if (status->start_addr + len < (status->start_sector + status->max_sector_count) * SECTOR_SIZE) {
if (len > SECTOR_SIZE) {
// to support larger writes we would need to erase current
// (if not already done), next and possibly later sectors too
} else {
// check if the sector the write finishes in has been erased yet,
// this is fine as long as data len < sector size
if (status->last_sector_erased != (status->start_addr + len) / SECTOR_SIZE) {
status->last_sector_erased = (status->start_addr + len) / SECTOR_SIZE;
spi_flash_erase_sector(status->last_sector_erased);
}
}
// write current chunk
//os_printf("write addr: 0x%08x, len: 0x%04x\r\n", status->start_addr, len);
if (spi_flash_write(status->start_addr, (uint32 *)buffer, len) == SPI_FLASH_RESULT_OK) {
ret = true;
status->start_addr += len;
}
//}
free(buffer);
return ret;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,38 @@
#ifndef CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_APPCODE_RBOOT_API_H_
#define CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_APPCODE_RBOOT_API_H_
//////////////////////////////////////////////////
// rBoot OTA and config API for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
// OTA code based on SDK sample from Espressif.
//////////////////////////////////////////////////
#include "../rboot.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint32 start_addr;
uint32 start_sector;
//uint32 max_sector_count;
uint32 last_sector_erased;
uint8 extra_count;
uint8 extra_bytes[4];
} rboot_write_status;
rboot_config ICACHE_FLASH_ATTR rboot_get_config(void);
bool ICACHE_FLASH_ATTR rboot_set_config(rboot_config *conf);
uint8 ICACHE_FLASH_ATTR rboot_get_current_rom(void);
bool ICACHE_FLASH_ATTR rboot_set_current_rom(uint8 rom);
rboot_write_status ICACHE_FLASH_ATTR rboot_write_init(uint32 start_addr);
bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, uint8 *data, uint16 len);
#ifdef __cplusplus
}
#endif
#endif /* CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_APPCODE_RBOOT_API_H_ */

View File

@ -0,0 +1,61 @@
//////////////////////////////////////////////////
// rBoot open source boot loader for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
//////////////////////////////////////////////////
/* clang-format off */
#ifdef RBOOT_INTEGRATION
#include <rboot-integration.h>
#endif
typedef unsigned int uint32;
typedef unsigned char uint8;
#include <rboot.h>
#if 0 //def BOOT_BIG_FLASH
// plain sdk defaults to iram
#ifndef IRAM_ATTR
#define IRAM_ATTR
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern void Cache_Read_Disable();
extern uint32 SPIRead(uint32, void*, uint32);
extern void Cache_Read_Enable(uint32, uint32, uint32);
uint8 rBoot_mmap_1 = 0xff;
uint8 rBoot_mmap_2 = 0xff;
// this function must remain in iram
IRAM NOINSTR void __wrap_Cache_Read_Enable_New(void) {
if (rBoot_mmap_1 == 0xff) {
uint32 addr;
rboot_config conf;
Cache_Read_Disable();
SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, &conf, sizeof(rboot_config));
addr = conf.roms[conf.current_rom];
addr /= 0x100000;
rBoot_mmap_2 = addr / 2;
rBoot_mmap_1 = addr % 2;
}
Cache_Read_Enable(rBoot_mmap_1, rBoot_mmap_2, 1);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Richard A Burton (richardaburton@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,74 @@
#ifndef CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_RBOOT_PRIVATE_H_
#define CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_RBOOT_PRIVATE_H_
//////////////////////////////////////////////////
// rBoot open source boot loader for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
//////////////////////////////////////////////////
typedef int int32;
typedef unsigned int uint32;
typedef unsigned char uint8;
#include "rboot.h"
#define NOINLINE __attribute__ ((noinline))
#define ROM_MAGIC 0xe9
#define ROM_MAGIC_NEW1 0xea
#define ROM_MAGIC_NEW2 0x04
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
// buffer size, must be at least 0x10 (size of rom_header_new structure)
#define BUFFER_SIZE 0x100
// esp8266 built in rom functions
extern void ets_printf(const char*, ...);
extern uint32 SPIRead(uint32 addr, void *outptr, uint32 len);
extern uint32 SPIEraseSector(int);
extern uint32 SPIWrite(uint32 addr, void *inptr, uint32 len);
// functions we'll call by address
typedef void stage2a(uint32);
typedef void usercode(void);
// standard rom header
typedef struct {
// general rom header
uint8 magic;
uint8 count;
uint8 flags1;
uint8 flags2;
usercode* entry;
} rom_header;
typedef struct {
uint8* address;
uint32 length;
} section_header;
// new rom header (irom section first) there is
// another 8 byte header straight afterward the
// standard header
typedef struct {
// general rom header
uint8 magic;
uint8 count; // second magic for new header
uint8 flags1;
uint8 flags2;
uint32 entry;
// new type rom, lib header
uint32 add; // zero
uint32 len; // length of irom section
} rom_header_new;
#endif /* CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_RBOOT_PRIVATE_H_ */

View File

@ -0,0 +1,80 @@
//////////////////////////////////////////////////
// rBoot open source boot loader for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
//////////////////////////////////////////////////
#ifdef RBOOT_INTEGRATION
#include <rboot-integration.h>
#endif
#include "rboot-private.h"
usercode* NOINLINE load_rom(uint32 readpos) {
uint8 buffer[BUFFER_SIZE];
uint8 sectcount;
uint8 *writepos;
uint32 remaining;
usercode* usercode;
rom_header *header = (rom_header*)buffer;
section_header *section = (section_header*)buffer;
// read rom header
SPIRead(readpos, header, sizeof(rom_header));
readpos += sizeof(rom_header);
// create function pointer for entry point
usercode = header->entry;
// copy all the sections
for (sectcount = header->count; sectcount > 0; sectcount--) {
// read section header
SPIRead(readpos, section, sizeof(section_header));
readpos += sizeof(section_header);
// get section address and length
writepos = section->address;
remaining = section->length;
while (remaining > 0) {
// work out how much to read, up to 16 bytes at a time
uint32 readlen = (remaining < BUFFER_SIZE) ? remaining : BUFFER_SIZE;
// read the block
SPIRead(readpos, buffer, readlen);
readpos += readlen;
// copy the block
ets_memcpy(writepos, buffer, readlen);
// increment next write position
writepos += readlen;
// decrement remaining count
remaining -= readlen;
}
}
return usercode;
}
#ifdef BOOT_NO_ASM
void call_user_start(uint32 readpos) {
usercode* user;
user = load_rom(readpos);
user();
}
#else
void call_user_start(uint32 readpos) {
__asm volatile (
"mov a15, a0\n" // store return addr, we already splatted a15!
"call0 load_rom\n" // load the rom
"mov a0, a15\n" // restore return addr
"jx a2\n" // now jump to the rom code
);
}
#endif

View File

@ -0,0 +1,211 @@
/* This linker script generated from xt-genldscripts.tpp for LSP . */
/* Linker Script for ld -N */
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x4010FC00, len = 0x400
irom0_0_seg : org = 0x40240000, len = 0x3C000
}
PHDRS
{
dport0_0_phdr PT_LOAD;
dram0_0_phdr PT_LOAD;
dram0_0_bss_phdr PT_LOAD;
iram1_0_phdr PT_LOAD;
irom0_0_phdr PT_LOAD;
}
/* Default entry point: */
ENTRY(call_user_start)
EXTERN(_DebugExceptionVector)
EXTERN(_DoubleExceptionVector)
EXTERN(_KernelExceptionVector)
EXTERN(_NMIExceptionVector)
EXTERN(_UserExceptionVector)
PROVIDE(_memmap_vecbase_reset = 0x40000000);
/* Various memory-map dependent cache attribute settings: */
_memmap_cacheattr_wb_base = 0x00000110;
_memmap_cacheattr_wt_base = 0x00000110;
_memmap_cacheattr_bp_base = 0x00000220;
_memmap_cacheattr_unused_mask = 0xFFFFF00F;
_memmap_cacheattr_wb_trapnull = 0x2222211F;
_memmap_cacheattr_wba_trapnull = 0x2222211F;
_memmap_cacheattr_wbna_trapnull = 0x2222211F;
_memmap_cacheattr_wt_trapnull = 0x2222211F;
_memmap_cacheattr_bp_trapnull = 0x2222222F;
_memmap_cacheattr_wb_strict = 0xFFFFF11F;
_memmap_cacheattr_wt_strict = 0xFFFFF11F;
_memmap_cacheattr_bp_strict = 0xFFFFF22F;
_memmap_cacheattr_wb_allvalid = 0x22222112;
_memmap_cacheattr_wt_allvalid = 0x22222112;
_memmap_cacheattr_bp_allvalid = 0x22222222;
PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
SECTIONS
{
.dport0.rodata : ALIGN(4)
{
_dport0_rodata_start = ABSOLUTE(.);
*(.dport0.rodata)
*(.dport.rodata)
_dport0_rodata_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.dport0.literal : ALIGN(4)
{
_dport0_literal_start = ABSOLUTE(.);
*(.dport0.literal)
*(.dport.literal)
_dport0_literal_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.dport0.data : ALIGN(4)
{
_dport0_data_start = ABSOLUTE(.);
*(.dport0.data)
*(.dport.data)
_dport0_data_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.data : ALIGN(4)
{
_data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.data1)
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
*(.jcr)
_data_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_phdr
.rodata : ALIGN(4)
{
_rodata_start = ABSOLUTE(.);
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
*(.eh_frame)
/* C++ constructor and destructor tables, properly ordered: */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
/* C++ exception handlers table: */
__XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
*(.xt_except_desc)
*(.gnu.linkonce.h.*)
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
*(.xt_except_desc_end)
*(.dynamic)
*(.gnu.version_d)
. = ALIGN(4); /* this table MUST be 4-byte aligned */
_bss_table_start = ABSOLUTE(.);
LONG(_bss_start)
LONG(_bss_end)
_bss_table_end = ABSOLUTE(.);
_rodata_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_phdr
.bss ALIGN(8) (NOLOAD) : ALIGN(4)
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
_heap_start = ABSOLUTE(.);
/* _stack_sentry = ALIGN(0x8); */
} >dram0_0_seg :dram0_0_bss_phdr
/* __stack = 0x3ffc8000; */
.text : ALIGN(4)
{
_stext = .;
_text_start = ABSOLUTE(.);
*(.UserEnter.text)
. = ALIGN(16);
*(.DebugExceptionVector.text)
. = ALIGN(16);
*(.NMIExceptionVector.text)
. = ALIGN(16);
*(.KernelExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.UserExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.DoubleExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN (16);
*(.entry.text)
*(.init.literal)
*(.init)
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.fini.literal)
*(.fini)
*(.gnu.version)
_text_end = ABSOLUTE(.);
_etext = .;
} >iram1_0_seg :iram1_0_phdr
.lit4 : ALIGN(4)
{
_lit4_start = ABSOLUTE(.);
*(*.lit4)
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
} >iram1_0_seg :iram1_0_phdr
.irom0.text : ALIGN(4)
{
_irom0_text_start = ABSOLUTE(.);
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
_irom0_text_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr
}
/* get ROM code address */
INCLUDE "rboot_rom.ld"

View File

@ -0,0 +1,414 @@
//////////////////////////////////////////////////
// rBoot open source boot loader for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
//////////////////////////////////////////////////
/* clang-format off */
#ifdef RBOOT_INTEGRATION
#include <rboot-integration.h>
#endif
#include "rboot-private.h"
#include <rboot-hex2a.h>
static uint32 check_image(uint32 readpos) {
uint8 buffer[BUFFER_SIZE];
uint8 sectcount;
uint8 sectcurrent;
uint8 *writepos;
uint8 chksum = CHKSUM_INIT;
uint32 loop;
uint32 remaining;
uint32 romaddr;
rom_header_new *header = (rom_header_new*)buffer;
section_header *section = (section_header*)buffer;
if (readpos == 0 || readpos == 0xffffffff) {
return 0;
}
// read rom header
if (SPIRead(readpos, header, sizeof(rom_header_new)) != 0) {
return 0;
}
// check header type
if (header->magic == ROM_MAGIC) {
// old type, no extra header or irom section to skip over
romaddr = readpos;
readpos += sizeof(rom_header);
sectcount = header->count;
} else if (header->magic == ROM_MAGIC_NEW1 && header->count == ROM_MAGIC_NEW2) {
// new type, has extra header and irom section first
romaddr = readpos + header->len + sizeof(rom_header_new);
#ifdef BOOT_IROM_CHKSUM
// we will set the real section count later, when we read the header
sectcount = 0xff;
// just skip the first part of the header
// rest is processed for the chksum
readpos += sizeof(rom_header);
#else
// skip the extra header and irom section
readpos = romaddr;
// read the normal header that follows
if (SPIRead(readpos, header, sizeof(rom_header)) != 0) {
return 0;
}
sectcount = header->count;
readpos += sizeof(rom_header);
#endif
} else {
return 0;
}
// test each section
for (sectcurrent = 0; sectcurrent < sectcount; sectcurrent++) {
// read section header
if (SPIRead(readpos, section, sizeof(section_header)) != 0) {
return 0;
}
readpos += sizeof(section_header);
// get section address and length
writepos = section->address;
remaining = section->length;
while (remaining > 0) {
// work out how much to read, up to BUFFER_SIZE
uint32 readlen = (remaining < BUFFER_SIZE) ? remaining : BUFFER_SIZE;
// read the block
if (SPIRead(readpos, buffer, readlen) != 0) {
return 0;
}
// increment next read and write positions
readpos += readlen;
writepos += readlen;
// decrement remaining count
remaining -= readlen;
// add to chksum
for (loop = 0; loop < readlen; loop++) {
chksum ^= buffer[loop];
}
}
#ifdef BOOT_IROM_CHKSUM
if (sectcount == 0xff) {
// just processed the irom section, now
// read the normal header that follows
if (SPIRead(readpos, header, sizeof(rom_header)) != 0) {
return 0;
}
sectcount = header->count + 1;
readpos += sizeof(rom_header);
}
#endif
}
// round up to next 16 and get checksum
readpos = readpos | 0x0f;
if (SPIRead(readpos, buffer, 1) != 0) {
return 0;
}
// compare calculated and stored checksums
if (buffer[0] != chksum) {
return 0;
}
return romaddr;
}
#define ETS_UNCACHED_ADDR(addr) (addr)
#define READ_PERI_REG(addr) (*((volatile uint32 *)ETS_UNCACHED_ADDR(addr)))
#define WRITE_PERI_REG(addr, val) (*((volatile uint32 *)ETS_UNCACHED_ADDR(addr))) = (uint32)(val)
#define PERIPHS_RTC_BASEADDR 0x60000700
#define REG_RTC_BASE PERIPHS_RTC_BASEADDR
#define RTC_GPIO_OUT (REG_RTC_BASE + 0x068)
#define RTC_GPIO_ENABLE (REG_RTC_BASE + 0x074)
#define RTC_GPIO_IN_DATA (REG_RTC_BASE + 0x08C)
#define RTC_GPIO_CONF (REG_RTC_BASE + 0x090)
#define PAD_XPD_DCDC_CONF (REG_RTC_BASE + 0x0A0)
static uint32 get_gpio16(void) {
// set output level to 1
WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)(1));
// read level
WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection
WRITE_PERI_REG(RTC_GPIO_CONF, (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE, READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe); //out disable
uint32 x = (READ_PERI_REG(RTC_GPIO_IN_DATA) & 1);
return x;
}
#ifdef BOOT_CONFIG_CHKSUM
// calculate checksum for block of data
// from start up to (but excluding) end
static uint8 calc_chksum(uint8 *start, uint8 *end) {
uint8 chksum = CHKSUM_INIT;
while(start < end) {
chksum ^= *start;
start++;
}
return chksum;
}
#endif
#define UART_CLKDIV_26MHZ(B) (52000000 + B / 2) / B
// prevent this function being placed inline with main
// to keep main's stack size as small as possible
// don't mark as static or it'll be optimised out when
// using the assembler stub
uint32 NOINLINE find_image(void) {
uint8 flag;
uint32 runAddr;
uint32 flashsize;
int32 romToBoot;
uint8 gpio_boot = FALSE;
uint8 updateConfig = FALSE;
uint8 buffer[SECTOR_SIZE];
rboot_config *romconf = (rboot_config*)buffer;
rom_header *header = (rom_header*)buffer;
// delay to slow boot (help see messages when debugging)
//ets_delay_us(2000000);
uart_div_modify(0, UART_CLKDIV_26MHZ(115200));
ets_delay_us(1000);
ets_printf("\r\nrBoot v1.2.1 - richardaburton@gmail.com\r\n");
// read rom header
SPIRead(0, header, sizeof(rom_header));
// print and get flash size
ets_printf("Flash Size: ");
flag = header->flags2 >> 4;
if (flag == 0) {
ets_printf("4 Mbit\r\n");
flashsize = 0x80000;
} else if (flag == 1) {
ets_printf("2 Mbit\r\n");
flashsize = 0x40000;
} else if (flag == 2) {
ets_printf("8 Mbit\r\n");
flashsize = 0x100000;
} else {
#ifdef BOOT_BIG_FLASH
if (flag == 3) {
ets_printf("16 Mbit\r\n");
flashsize = 0x200000;
} else if (flag == 4) {
ets_printf("32 Mbit\r\n");
flashsize = 0x400000;
} else if (flag == 8) {
ets_printf("64 Mbit\r\n");
flashsize = 0x800000;
} else if (flag == 9) {
ets_printf("128 Mbit\r\n");
flashsize = 0x1000000;
} else {
ets_printf("unknown\r\n");
flashsize = 0x100000; // assume 8Mbit
}
#else
ets_printf("8 Mbit\r\n");
flashsize = 0x100000; // limit to 8Mbit
#endif
}
// print spi mode
ets_printf("Flash Mode: ");
if (header->flags1 == 0) {
ets_printf("QIO\r\n");
} else if (header->flags1 == 1) {
ets_printf("QOUT\r\n");
} else if (header->flags1 == 2) {
ets_printf("DIO\r\n");
} else if (header->flags1 == 3) {
ets_printf("DOUT\r\n");
} else {
ets_printf("unknown\r\n");
}
// print spi speed
ets_printf("Flash Speed: ");
flag = header->flags2 & 0x0f;
if (flag == 0) ets_printf("40 MHz\r\n");
else if (flag == 1) ets_printf("26.7 MHz\r\n");
else if (flag == 2) ets_printf("20 MHz\r\n");
else if (flag == 0x0f) ets_printf("80 MHz\r\n");
else ets_printf("unknown\r\n");
// print enabled options
#ifdef BOOT_BIG_FLASH
ets_printf("rBoot Option: Big flash\r\n");
#endif
#ifdef BOOT_CONFIG_CHKSUM
ets_printf("rBoot Option: Config chksum\r\n");
#endif
#ifdef BOOT_IROM_CHKSUM
ets_printf("rBoot Option: irom chksum\r\n");
#endif
ets_printf("\r\n");
// read boot config
SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE);
// fresh install or old version?
if (romconf->magic != BOOT_CONFIG_MAGIC || romconf->version != BOOT_CONFIG_VERSION
#ifdef BOOT_CONFIG_CHKSUM
|| romconf->chksum != calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum)
#endif
) {
/* Modified by Cesanta */
ets_printf("Writing default boot config @ 0x%x.\r\n", BOOT_CONFIG_SECTOR * SECTOR_SIZE);
ets_memset(romconf, 0x00, sizeof(rboot_config));
romconf->magic = BOOT_CONFIG_MAGIC;
romconf->version = BOOT_CONFIG_VERSION;
romconf->count = 2;
romconf->mode = MODE_STANDARD;
/* FWx_ADDR, FWx_FS_ADDR and FS_SIZE, FW_SIZE must be defined by -D */
romconf->roms[0] = FW1_ADDR;
romconf->roms[1] = FW2_ADDR;
romconf->fs_addresses[0] = FW1_FS_ADDR;
romconf->fs_addresses[1] = FW2_FS_ADDR;
romconf->fs_sizes[0] = romconf->fs_sizes[1] = FS_SIZE;
romconf->roms_sizes[0] = romconf->roms_sizes[1] = FW_SIZE;
#ifdef BOOT_CONFIG_CHKSUM
romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum);
#endif
// write new config sector
SPIEraseSector(BOOT_CONFIG_SECTOR);
SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE);
}
// if gpio mode enabled check status of the gpio
if ((romconf->mode & MODE_GPIO_ROM) && (get_gpio16() == 0)) {
ets_printf("Booting GPIO-selected.\r\n");
romToBoot = romconf->previous_rom;
/*
* Modified by Cesanta
* Make FD current
*/
updateConfig = TRUE;
romconf->fw_updated = 0;
romconf->is_first_boot = 0;
gpio_boot = TRUE;
} else if (romconf->current_rom >= romconf->count) {
// if invalid rom selected try rom 0
ets_printf("Invalid rom selected, defaulting.\r\n");
romToBoot = 0;
romconf->current_rom = 0;
romconf->fw_updated = 0;
romconf->is_first_boot = 0;
updateConfig = TRUE;
} else {
/* Modified by Cesanta */
if (romconf->is_first_boot != 0) {
ets_printf("First boot, attempt %d\n", romconf->boot_attempts);
/* boot is unconfirmed */
if (romconf->boot_attempts == 0) {
/* haven't try to load yes */
ets_printf("Boot is unconfirmed\r\n");
romconf->boot_attempts++;
} else {
ets_printf("Boot failed, fallback to fw #%d\r\n",
romconf->previous_rom);
romconf->current_rom = romconf->previous_rom;
/* clear fw update flag, to avoid post-update acttions */
romconf->fw_updated = 0;
romconf->boot_attempts = 0;
}
updateConfig = TRUE;
}
/* End of Cesanta modifications */
// try rom selected in the config
romToBoot = romconf->current_rom;
}
// try to find a good rom
do {
runAddr = check_image(romconf->roms[romToBoot]);
if (runAddr == 0) {
ets_printf("Rom %d is bad.\r\n", romToBoot);
if (gpio_boot) {
// don't switch to backup for gpio-selected rom
ets_printf("GPIO boot failed.\r\n");
return 0;
} else {
// for normal mode try each previous rom
// until we find a good one or run out
updateConfig = TRUE;
romToBoot--;
if (romToBoot < 0) romToBoot = romconf->count - 1;
if (romToBoot == romconf->current_rom) {
// tried them all and all are bad!
ets_printf("No good rom available.\r\n");
return 0;
}
}
}
} while (runAddr == 0);
// re-write config, if required
if (updateConfig) {
romconf->current_rom = romToBoot;
#ifdef BOOT_CONFIG_CHKSUM
romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum);
#endif
SPIEraseSector(BOOT_CONFIG_SECTOR);
SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE);
}
ets_printf("Booting rom %d (0x%x).\r\n", romToBoot, romconf->roms[romToBoot]);
// copy the loader to top of iram
ets_memcpy((void*)_text_addr, _text_data, _text_len);
// return address to load from
return runAddr;
}
#ifdef BOOT_NO_ASM
// small stub method to ensure minimum stack space used
void call_user_start(void) {
uint32 addr;
stage2a *loader;
addr = find_image();
if (addr != 0) {
loader = (stage2a*)entry_addr;
loader(addr);
}
}
#else
// assembler stub uses no stack space
// works with gcc
void call_user_start(void) {
__asm volatile (
"mov a15, a0\n" // store return addr, hope nobody wanted a15!
"call0 find_image\n" // find a good rom to boot
"mov a0, a15\n" // restore return addr
"bnez a2, 1f\n" // ?success
"ret\n" // no, return
"1:\n" // yes...
"movi a3, entry_addr\n" // actually gives us a pointer to entry_addr
"l32i a3, a3, 0\n" // now really load entry_addr
"jx a3\n" // now jump to it
);
}
#endif

View File

@ -0,0 +1,82 @@
#ifndef CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_RBOOT_H_
#define CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_RBOOT_H_
//////////////////////////////////////////////////
// rBoot open source boot loader for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
//////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
// uncomment to use only c code
// if you aren't using gcc you may need to do this
//#define BOOT_NO_ASM
// uncomment to have a checksum on the boot config
//#define BOOT_CONFIG_CHKSUM
// uncomment to enable big flash support (>1MB)
//#define BOOT_BIG_FLASH
// uncomment to include .irom0.text section in the checksum
// roms must be built with esptool2 using -iromchksum option
//#define BOOT_IROM_CHKSUM
// increase if required
#define MAX_ROMS 4
#define CHKSUM_INIT 0xef
#define SECTOR_SIZE 0x1000
#ifndef BOOT_CONFIG_ADDR
#define BOOT_CONFIG_ADDR 0x1000
#endif
#define BOOT_CONFIG_SECTOR (BOOT_CONFIG_ADDR / SECTOR_SIZE)
#define BOOT_CONFIG_MAGIC 0xe1
#define BOOT_CONFIG_VERSION 0x01
#define MODE_STANDARD 0x00
#define MODE_GPIO_ROM 0x01
// boot config structure
// rom addresses must be multiples of 0x1000 (flash sector aligned)
// without BOOT_BIG_FLASH only the first 8Mbit of the chip will be memory mapped
// so rom slots containing .irom0.text sections must remain below 0x100000
// slots beyond this will only be accessible via spi read calls, so
// use these for stored resources, not code
// with BOOT_BIG_FLASH the flash will be mapped in chunks of 8MBit, so roms can
// be anywhere, but must not straddle two 8MBit blocks
typedef struct {
uint8 magic; // our magic
uint8 version; // config struct version
uint8 mode; // boot loader mode
uint8 current_rom; // currently selected rom
uint8 gpio_rom; // rom to use for gpio boot
uint8 count; // number of roms in use
uint8 previous_rom; // previously selected rom
uint8 is_first_boot;
uint8 boot_attempts;
uint8 fw_updated;
uint8 padding[2];
uint32 roms[MAX_ROMS]; // flash addresses of the roms
uint32 roms_sizes[MAX_ROMS]; // sizes of the roms
uint32 fs_addresses[MAX_ROMS]; // file system addresses
uint32 fs_sizes[MAX_ROMS]; // file system sizes
uint32 user_flags;
#ifdef BOOT_CONFIG_CHKSUM
uint8 chksum; // config chksum
#endif
} rboot_config;
#ifdef __cplusplus
}
#endif
#endif /* CS_COMMON_PLATFORMS_ESP8266_RBOOT_RBOOT_RBOOT_H_ */

View File

@ -0,0 +1,2 @@
INCLUDE "eagle.app.v6.ld"
INCLUDE "rboot_rom.ld"

View File

@ -0,0 +1,89 @@
#
# Makefile for rBoot
# https://github.com/raburton/esp8266
#
ESPTOOL2 ?= ../../build/esptool2
SDK_BASE ?= /opt/Espressif/ESP8266_SDK
SPI_SIZE ?=
RBOOT_INTEGRATION ?=
RBOOT_EXTRA_INCDIR ?=
# RBOOT_BUILD_BASE and RBOOT_GEN_BASE should be provided via makefile parameters
RBOOT_BUILD_BASE ?=
# RBOOT_GEN_BASE is the directory for generated inputs
RBOOT_GEN_BASE ?=
ifndef XTENSA_BINDIR
CC := xtensa-lx106-elf-gcc
LD := xtensa-lx106-elf-gcc
else
CC := $(addprefix $(XTENSA_BINDIR)/,xtensa-lx106-elf-gcc)
LD := $(addprefix $(XTENSA_BINDIR)/,xtensa-lx106-elf-gcc)
endif
CC_WRAPPER ?=
CFLAGS = -Os -O3 -Wpointer-arith -Wundef -Werror -Wl,-EL \
-fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals \
-D__ets__ -DIRAM='__attribute__((section(".fast.text")))' \
-DNOINSTR='__attribute__((no_instrument_function))' \
-DICACHE_FLASH $(CFLAGS_EXTRA)
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static -L $(SDK_BASE)/ld/
LD_SCRIPT = rboot.ld
E2_OPTS = -quiet -bin -boot0
ifeq ($(RBOOT_BIG_FLASH),1)
CFLAGS += -DBOOT_BIG_FLASH
endif
ifeq ($(RBOOT_INTEGRATION),1)
CFLAGS += -DRBOOT_INTEGRATION
endif
ifeq ($(SPI_SIZE), 256K)
E2_OPTS += -256
else ifeq ($(SPI_SIZE), 512K)
E2_OPTS += -512
else ifeq ($(SPI_SIZE), 1M)
E2_OPTS += -1024
else ifeq ($(SPI_SIZE), 2M)
E2_OPTS += -2048
else ifeq ($(SPI_SIZE), 4M)
E2_OPTS += -4096
endif
RBOOT_EXTRA_INCDIR := $(addprefix -I,$(RBOOT_EXTRA_INCDIR))
.SECONDARY:
all: $(RBOOT_BUILD_BASE)/rboot.bin
$(RBOOT_BUILD_BASE)/rboot-stage2a.o: rboot-stage2a.c rboot-private.h rboot.h
@echo "CC $<"
@$(CC_WRAPPER) $(CC) $(CFLAGS) $(RBOOT_EXTRA_INCDIR) -c $< -o $@
$(RBOOT_BUILD_BASE)/rboot-stage2a.elf: $(RBOOT_BUILD_BASE)/rboot-stage2a.o
@echo "LD $@"
@$(CC_WRAPPER) $(LD) -Trboot-stage2a.ld $(LDFLAGS) -Wl,--start-group $^ -Wl,--end-group -o $@
$(RBOOT_GEN_BASE)/rboot-hex2a.h: $(RBOOT_BUILD_BASE)/rboot-stage2a.elf
@echo "E2 $@"
@$(ESPTOOL2) -quiet -header $< $@ .text
$(RBOOT_BUILD_BASE)/rboot.o: rboot.c rboot-private.h rboot.h $(RBOOT_GEN_BASE)/rboot-hex2a.h
@echo "CC $<"
@$(CC) $(CFLAGS) -I$(RBOOT_GEN_BASE) $(RBOOT_EXTRA_INCDIR) -c $< -o $@
$(RBOOT_BUILD_BASE)/%.o: %.c %.h
@echo "CC $<"
@$(CC) $(CFLAGS) $(RBOOT_EXTRA_INCDIR) -c $< -o $@
$(RBOOT_BUILD_BASE)/%.elf: $(RBOOT_BUILD_BASE)/%.o
@echo "LD $@"
@$(LD) -T$(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $^ -Wl,--end-group -o $@
$(RBOOT_BUILD_BASE)/%.bin: $(RBOOT_BUILD_BASE)/%.elf
@echo "E2 $@"
@$(ESPTOOL2) $(E2_OPTS) $< $@ .text .rodata

View File

@ -0,0 +1,8 @@
PROVIDE ( ets_delay_us = 0x40002ecc );
PROVIDE ( ets_memcpy = 0x400018b4 );
PROVIDE ( ets_memset = 0x400018a4 );
PROVIDE ( ets_printf = 0x400024cc );
PROVIDE ( SPIEraseSector = 0x40004a00 );
PROVIDE ( SPIRead = 0x40004b1c );
PROVIDE ( SPIWrite = 0x40004a4c );
PROVIDE ( uart_div_modify = 0x400039d8 );

View File

@ -0,0 +1,40 @@
rBoot - User API for rBoot on the ESP8266
------------------------------------------
by Richard A Burton, richardaburton@gmail.com
http://richard.burtons.org/
This provides a few simple APIs for getting & setting rBoot config and for
writing data from OTA updates. API source files are in the appcode directory.
Actual OTA network code is implementation specific and no longer included in
rBoot itself, see the rBoot sample projects for this code (which you can then
use in your own projects).
rboot_config rboot_get_config();
Returns rboot_config (defined in rboot.h) allowing you to modify any values
in it, including the rom layout.
bool rboot_set_config(rboot_config *conf);
Saves the rboot_config structure back to sector 2 of the flash, while
maintaining the contents of the rest of the sector. You can use the rest of
this sector for your app settings, as long as you protect this structure
when you do so.
uint8 rboot_get_current_rom();
Get the currently selected boot rom (the currently running rom, as long as
you haven't changed it since boot).
bool rboot_set_current_rom(uint8 rom);
Set the current boot rom, which will be used when next restarted.
rboot_write_status rboot_write_init(uint32 start_addr);
Call once before starting to pass data to write to the flash. start_addr is
the address on the SPI flash to write from. Returns a status structure which
must be passed back on each write. The contents of the structure should not
be modified by the calling code.
bool rboot_write_flash(rboot_write_status *status, uint8 *data, uint16 len);
Call repeatedly to write data to the flash, starting at the address
specified on the prior call to rboot_write_init. Current write position is
tracked automatically. This method is likely to be called each time a packet
of OTA data is received over the network.

View File

@ -0,0 +1,218 @@
rBoot - An open source boot loader for the ESP8266
--------------------------------------------------
by Richard A Burton, richardaburton@gmail.com
http://richard.burtons.org/
rBoot is designed to be a flexible open source boot loader, a replacement for
the binary blob supplied with the SDK. It has the following advantages over the
Espressif loader:
- Open source (written in C).
- Supports up to 256 roms.
- Roms can be variable size.
- Able to test multiple roms to find a valid backup (without resetting).
- Flash layout can be changed on the fly (with care and appropriately linked
rom images).
- GPIO support for rom selection.
- Wastes no stack space (SDK boot loader uses 144 bytes).
- Documented config structure to allow easy editing from user code.
- Can validate .irom0.text section with checksum.
Limitations
-----------
The ESP8266 can only map 8Mbits (1MB) of flash to memory, but which 8Mbits to
map is selectable. This allows individual roms to be up to 1MB in size, so long
as they do not straddle an 8Mbit boundary on the flash. This means you could
have four 1MB roms or 8 512KB roms on a 32Mbit flash (such as on the ESP-12), or
a combination. Note, however, that you could not have, for example, a 512KB rom
followed immediately by a 1MB rom because the 2nd rom would then straddle an
8MBit boundary. By default support for using more than the first 8Mbit of the
flash is disabled, because it requires several steps to get it working. See
below for instructions.
Building
--------
A Makefile is included, which should work with the gcc xtensa cross compiler.
There are two source files, the first is compiled and included as data in the
second. When run this code is copied to memory and executed (there is a good
reason for this, see my blog for an explanation). The make file will handle this
for you, but you'll need my esptool2 (see github).
To use the Makefile set SDK_BASE to point to the root of the Espressif SDK and
either set XTENSA_BINDIR to the gcc xtensa bin directory or include it in your
PATH. These can be set as environment variables or by editing the Makefile.
Two small assembler stub functions allow the bootloader to launch the user code
without reserving any space on the stack (while the SDK boot loader uses 144
bytes). This compiles fine with GCC, but if you use another compiler and it
will not compile/work for you then uncomment the #define BOOT_NO_ASM in rboot.h
to use a C version of these functions (this uses 32 bytes).
Tested with SDK v1.3 and GCC v4.8.2.
Installation
------------
Simply write rboot.bin to the first sector of the flash. Remember to set your
flash size correctly with your chosen flash tool (e.g. for esptool.py use the
-fs option). When run rBoot will create it's own config at the start of sector
two for a simple two rom system. You can can then write your two roms to flash
addresses 0x2000 and (half chip size + 0x2000). E.g. for 8Mbit flash:
esptool.py -fs 8m 0x0000 rboot.bin 0x2000 user1.bin 0x82000 user2.bin
Note: your device may need other options specified. E.g. The nodemcu devkit v1.0
(commonly, but incorrectly, sold as v2) also needs the "-fm dio" option.
For more interesting rom layouts you'll need to write an rBoot config sector
manually, see next step.
The two testload bin files can be flashed in place of normal user roms for
testing rBoot. You do not need these for normal use.
rBoot Config
------------
typedef struct {
uint8 magic; // our magic
uint8 version; // config struct version
uint8 mode; // boot loader mode
uint8 current_rom; // currently selected rom
uint8 gpio_rom; // rom to use for gpio boot
uint8 count; // number of roms in use
uint8 unused[2]; // padding
uint32 roms[MAX_ROMS]; // flash addresses of the roms
#ifdef BOOT_CONFIG_CHKSUM
uint8 chksum; // boot config chksum
#endif
} rboot_config;
Write a config structure as above to address 0x1000 on the flash. If you want
more than 4 roms (default) just increase MAX_ROMS when you compile rBoot.
Think about how you intend to layout your flash before you start!
Rom addresses must be sector aligned i.e start on a multiple of 4096.
- magic should have value 0xe1 (defined as BOOT_CONFIG_MAGIC).
- version is used in case the config structure changes after deployment. It is
defined as 0x01 (BOOT_CONFIG_VERSION). I don't intend to increase this, but
you should if you choose to reflash the bootloader after deployment and
the config structure has changed.
- mode can be 0x00 (MODE_STANDARD) or 0x01 (MODE_GPIO_ROM). If you set GPIO
you will need to set gpio_rom as well. The sample GPIO code uses GPIO 16 on
a nodemcu dev board, if you want to use a different GPIO you'll need to
adapt the code in rBoot slightly.
- current_rom is the rom to boot, numbered 0 to count-1.
- gpio_rom is the rom to boot when the GPIO is triggered at boot.
- count is the number of roms available (may be less than MAX_ROMS, but not
more).
- unused[2] is padding so the uint32 rom addresses are 4 bytes aligned.
- roms is the array of flash address for the roms. The default generated
config will contain two entries: 0x00002000 and 0x00082000.
- chksum (if enabled, not by deafult) should be the xor of 0xef followed by
each of the bytes of the config structure up to (but obviously not
including) the chksum byte itself.
Linking user code
-----------------
Each rom will need to be linked with an appropriate linker file, specifying
where it will reside on the flash. If you are only flashing one rom to multiple
places on the flash it must be linked multiple times to produce the set of rom
images. This is the same as with the SDK loader.
Because there are endless possibilities for layout with this loader I don't
supply sample linker files. Instead I'll tell you how to make them.
For each rom slot on the flash take a copy of the eagle.app.v6.ld linker script
from the sdk. You then need to modify just one line in it for each rom:
irom0_0_seg : org = 0x40240000, len = 0x3C000
Change the org address to be 0x40200000 (base memory mapped location of the
flash) + flash address + 0x10 (offset of data after the header).
The logical place for your first rom is the third sector, address 0x2000.
0x40200000 + 0x2000 + 0x10 = 0x40202010
If you use the default generated config the loader will expect to find the
second rom at flash address half-chip-size + 0x2000 (e.g. 0x82000 on an 8MBit
flash) so the irom0_0_seg should be:
0x40200000 + 0x82000 + 0x10 = 0x40282010
Due to the limitation of mapped flash (max 8MBit) if you use a larger chip and
do not have big flash support enabled the second rom in the default config will
still be placed at 0x082000, not truly half-chip-size + 0x2000.
Ideally you should also adjust the len to help detect over sized sections at
link time, but more important is the overall size of the rom which you need to
ensure fits in the space you have allocated for it in your flash layout plan.
Then simply compile and link as you would normally for OTA updates with the SDK
boot loader, except using the linker scripts you've just prepared rather than
the ones supplied with the SDK. Remember when building roms to create them as
'new' type roms (for use with SDK boot loader v1.2+). Or if using my esptool2
use the -boot2 option. Note: the test loads included with rBoot are built with
-boot0 because they do not contain a .irom0.text section (and so the value of
irom0_0_seg in the linker file is irrelevant to them) but 'normal' user apps
always do.
irom checksum
-------------
The SDK boot loader checksum only covers sections loaded into ram (data and some
code). Most of the SDK and user code remains on the flash and that is not
included in the checksum. This means you could attempt to boot a corrupt rom
and, because it looks ok to the boot loader, there will be no attempt to switch
to a backup rom. rBoot improves on this by allowing the .irom0.text section to
be included in the checksum. To enable this uncomment #define BOOT_IROM_CHKSUM
in rboot.h and build your roms with esptool2 using the -iromchksum option.
Big flash support
-----------------
This only needs to be enabled if you wish to be able to memory map more than the
first 8MBit of the flash. Note you can still only map 8Mbit at a time. Use this
if you want to have multiple 1MB roms, or more smaller roms than will fit in
8Mbits. If you have a large flash but only need, for example, two 512KB roms you
do not need to enable this mode.
Support in rBoot is enabled by uncommenting the #define BOOT_BIG_FLASH in
rboot.h.
Thinking about your linker files is either simpler or more complicated,
depending on your usage of the flash. If you intend to use multiple 1MB roms you
will only need one linker file and you only need to link once for OTA updates.
Although when you perform an OTA update the rom will be written to a different
position on the flash, each 8Mbit of flash is mapped (separately) to 0x40200000.
So when any given rom is run the code will appear at the same place in memory
regardless of where it is on the flash. Your base address for the linker would
be 0x40202010. (Actually all but the first rom could base at 0x40200010 (because
they don't need to leave space for rBoot and config) but then you're just making
it more complicated again!)
If you wanted eight 512KB roms you would need two linker files - one for the
first half of any given 8Mbits of flash and another for the second half. Just
remember you are really laying out within a single 8MBit area, which can then be
replicated multiple times on the flash.
Now the clever bit - rBoot needs to hijack the memory mapping code to select
which 8Mbits gets mapped. There is no API for this, but we can override the SDK
function. First we need to slightly modify the SDK library libmain.a, like so:
xtensa-lx106-elf-objcopy -W Cache_Read_Enable_New libmain.a libmain2.a
This produces a version of libmain with a 'weakened' Cache_Read_Enable_New
function, which we can then override with our own. Modify your Makefile to link
against the library main2 instead of main.
Next add rboot-bigflash.c (from the appcode directory) & rboot.h to your project
- this adds the replacement Cache_Read_Enable_New to your code.
Getting gcc to apply the override correctly can be slightly tricky (I'm not sure
why, it shouldn't be). One option is to add "-u Cache_Read_Enable_New" to your
LD_FLAGS and change the order of objects on the LD command so your objects/.a
file is before the libraries. Another way that seems easier was to #include
rboot-bigflash.c into the main .c file, rather than compiling it to a separate
object file. I can't make any sense of that, but I suggest you uncomment the
message in the Cache_Read_Enable_New function when you first build with it, to
make sure you are getting your version into the rom.
Now when rBoot starts your rom, the SDK code linked in it that normally performs
the memory mapping will delegate part of that task to rBoot code (linked in your
rom, not in rBoot itself) to choose which part of the flash to map.
Integration into other frameworks
---------------------------------
If you wish to integrate rBoot into a development framework (e.g. Sming) you
can set the define RBOOT_INTEGRATION and at compile time the file
rboot-integration.h will be included into the source. This should allow you to
set some platform specific options without having to modify the source of rBoot
which makes it easier to integrate and maintain.

View File

@ -0,0 +1,2 @@
rom.bin -nodiff
rom.elf -nodiff

View File

@ -0,0 +1,4 @@
#!/bin/bash
xtensa-lx106-elf-gcc -Wl,-N,-Ttext,0x40000000 -nostdlib rom.S -o rom.elf && \
xtensa-lx106-elf-objdump -d rom.elf > ESP8266_ROM.txt

View File

@ -0,0 +1,101 @@
.text
.org 0
.globl _start
// xtensa-esp108-elf-gcc -Wl,-N,-Ttext,0x40000000 -nostdlib rom.S -o rom.elf
here = .
#define PROVIDE(name, addr) name = here + addr - 0x40000000
#include "rom_functions.S"
PROVIDE(SPI_chip_erase, 0x40004080)
PROVIDE(SPIFlashModeConfig, 0x40004568)
PROVIDE(_c_0x80000000, 0x400003a4)
PROVIDE(_c_0x00400000, 0x40000414)
PROVIDE(_c_0x00ffffff, 0x40000418)
PROVIDE(_p_user_start, 0x40000fb8) // 0x3fffdcd0
PROVIDE(_c_0x60000200, 0x40000fc4)
PROVIDE(_s_ets_build, 0x40000fc8) // Jan 8 2013
PROVIDE(_s_ets_banner, 0x40000fcc) // ets %s,rst cause:%d, boot mode:(%d,%d)
PROVIDE(_s_format_s_s, 0x40000fd0) // %s %s
PROVIDE(_s_ets_main_c, 0x40000fd4) // ets_main.c
PROVIDE(_s_user_code_done, 0x40000fe0) // user code done
PROVIDE(_s_wdt_reset, 0x40000fe4) // wdt reset
PROVIDE(_s_unk_reset, 0x40000fe8) // unknown reset
PROVIDE(_l_boot_mode_6, 0x40001044)
PROVIDE(_l_boot_mode_0_1_2_3, 0x4000104a)
PROVIDE(_l_rst_cause_ge_3, 0x40001075)
PROVIDE(_l_rst_cause_ge_3_lt_7, 0x40001084)
PROVIDE(_l_rst_cause_3_soft_wdt, 0x4000108a)
PROVIDE(_l_load_from_flash, 0x400010a8)
PROVIDE(_l_run_user_code, 0x400010be)
PROVIDE(_l_wdt_reset, 0x40001118)
PROVIDE(_l_rst_cause_1_2, 0x40001121)
PROVIDE(_l_rst_cause_unknown, 0x40001130)
PROVIDE(_l_boot_mode_7, 0x40001148)
PROVIDE(_l_boot_mode_4, 0x40001150)
PROVIDE(_c_0x60000600, 0x4000115c)
PROVIDE(_s_waiting_for_host, 0x4000119c) // waiting for host
PROVIDE(_x_unk1160, 0x40001160)
PROVIDE(_c_0x3fffa000_uart_buf, 0x400011a0)
PROVIDE(_c_0x2000, 0x400011a4)
PROVIDE(_c_0x40100000, 0x400011a8) // default user_start
PROVIDE(_x_boot2, 0x400011ac) // arg: 0x3fffdcd0 (&user_start)
PROVIDE(_l_strapping_2_eq_0, 0x400011d2)
PROVIDE(_l_124d, 0x4000124d)
PROVIDE(_l_boot_mode2_eq_2, 0x40001265)
PROVIDE(_l_boot_mode_eq_2, 0x40001268)
PROVIDE(_l_boot_mode_eq_1, 0x4000127a)
PROVIDE(_l_setup_uart, 0x40001291)
PROVIDE(_l_boot_mode_eq_3, 0x400012b0)
PROVIDE(_x_load_from_flash, 0x40001308)
PROVIDE(_c_0x00001000, 0x40001994)
PROVIDE(_c_0xffdfffff, 0x400025dc)
PROVIDE(_l_rr_not_dsleep, 0x40002624)
PROVIDE(_c_100000, 0x40002664)
PROVIDE(_c_0x3feffe00, 0x40002e5c)
PROVIDE(_p_cpu_freq, 0x40002ec8)
PROVIDE(_x_wdt_interval, 0x40002f14) // arg: 3 -> 11, 6 -> 12, 12 -> 13
PROVIDE(_p_wdt_cfg, 0x40002f30)
PROVIDE(_wdt_soft_timer_fn2, 0x40002f3c)
PROVIDE(_l_wdt_soft_timer_fn2_exit, 0x40002f59)
PROVIDE(_l_wdt_soft_timer_fn2_feed, 0x40002f60)
PROVIDE(_l_wdt_soft_timer_fn2_mode2_stage1_feed, 0x40002f74)
PROVIDE(_wdt_soft_timer_fn, 0x40002f88)
PROVIDE(_p_wdt_soft_timer_fn, 0x40002f98)
PROVIDE(_p_wdt_soft_timer, 0x40002f9c) // 0x3fffdde0
PROVIDE(_l_skip_wdt_imask, 0x40002fc4)
PROVIDE(_l_wdt_enable_and_exit, 0x40002fea)
PROVIDE(_l_wdt_mode_1, 0x4000309c)
PROVIDE(_l_wdt_mode_2_4, 0x4000300a)
PROVIDE(_l_wdt_mode_3, 0x40003060)
PROVIDE(_l_recv_req, 0x400033a1)
PROVIDE(_l_send_response, 0x400033be)
PROVIDE(_l_send_resp_pkt, 0x400033da)
PROVIDE(_l_process_req, 0x40003424)
PROVIDE(_l_34a3, 0x400034a3)
PROVIDE(_l_34b9, 0x400034b9)
PROVIDE(_c_0x00001800, 0x40003534)
PROVIDE(_c_0x60000a00, 0x40003f54)
PROVIDE(_c_0x01000000, 0x400040bc)
PROVIDE(_x_SPI_erase_sector, 0x400040c0)
PROVIDE(_l_SPI_erase_sector_align_ok, 0x400040dc)
PROVIDE(_c_0x00800000, 0x4000411c)
PROVIDE(_x_SPI_erase_block, 0x40004120)
PROVIDE(_c_0x20000000, 0x4000416c)
PROVIDE(_c_0x08000000, 0x400043c4)
PROVIDE(_c_0x04000000, 0x400043fc)
PROVIDE(_c_0x40000000, 0x40004438)
PROVIDE(_p_flashchip, 0x40004874)
PROVIDE(_s_bootup, 0x400054cc) // bootup , addr 0x%08x
PROVIDE(_p_sip_ctx, 0x40005130)
PROVIDE(_l_sip_cmd_out, 0x4000550a)
PROVIDE(_c_0x00010000, 0x40005de0)
.text
_start:
.incbin "rom.bin"
_end:

Binary file not shown.

View File

@ -0,0 +1,347 @@
PROVIDE ( Cache_Read_Disable , 0x400047f0 );
PROVIDE ( Cache_Read_Enable , 0x40004678 );
PROVIDE ( FilePacketSendReqMsgProc , 0x400035a0 );
PROVIDE ( FlashDwnLdParamCfgMsgProc , 0x4000368c );
PROVIDE ( FlashDwnLdStartMsgProc , 0x40003538 );
PROVIDE ( FlashDwnLdStopReqMsgProc , 0x40003658 );
PROVIDE ( GetUartDevice , 0x40003f4c );
PROVIDE ( MD5Final , 0x40009900 );
PROVIDE ( MD5Init , 0x40009818 );
PROVIDE ( MD5Update , 0x40009834 );
PROVIDE ( MemDwnLdStartMsgProc , 0x400036c4 );
PROVIDE ( MemDwnLdStopReqMsgProc , 0x4000377c );
PROVIDE ( MemPacketSendReqMsgProc , 0x400036f0 );
PROVIDE ( RcvMsg , 0x40003eac );
PROVIDE ( SHA1Final , 0x4000b648 );
PROVIDE ( SHA1Init , 0x4000b584 );
PROVIDE ( SHA1Transform , 0x4000a364 );
PROVIDE ( SHA1Update , 0x4000b5a8 );
PROVIDE ( SPI_read_status , 0x400043c8 );
PROVIDE ( SPI_write_status , 0x40004400 );
PROVIDE ( SPI_write_enable , 0x4000443c );
PROVIDE ( Wait_SPI_Idle , 0x4000448c );
PROVIDE ( SPIEraseArea , 0x40004b44 );
PROVIDE ( SPIEraseBlock , 0x400049b4 );
PROVIDE ( SPIEraseChip , 0x40004984 );
PROVIDE ( SPIEraseSector , 0x40004a00 );
PROVIDE ( SPILock , 0x400048a8 );
PROVIDE ( SPIParamCfg , 0x40004c2c );
PROVIDE ( SPIRead , 0x40004b1c );
PROVIDE ( SPIReadModeCnfig , 0x400048ec );
PROVIDE ( SPIUnlock , 0x40004878 );
PROVIDE ( SPIWrite , 0x40004a4c );
PROVIDE ( SelectSpiFunction , 0x40003f58 );
PROVIDE ( SendMsg , 0x40003cf4 );
PROVIDE ( UartConnCheck , 0x40003230 );
PROVIDE ( UartConnectProc , 0x400037a0 );
PROVIDE ( UartDwnLdProc , 0x40003368 );
PROVIDE ( UartGetCmdLn , 0x40003ef4 );
PROVIDE ( UartRegReadProc , 0x4000381c );
PROVIDE ( UartRegWriteProc , 0x400037ac );
PROVIDE ( UartRxString , 0x40003c30 );
PROVIDE ( Uart_Init , 0x40003a14 );
PROVIDE ( _DebugExceptionVector , 0x40000010 );
PROVIDE ( _DoubleExceptionVector , 0x40000070 );
PROVIDE ( _KernelExceptionVector , 0x40000030 );
PROVIDE ( _NMIExceptionVector , 0x40000020 );
PROVIDE ( _ResetHandler , 0x400000a4 );
PROVIDE ( _ResetVector , 0x40000080 );
PROVIDE ( _UserExceptionVector , 0x40000050 );
PROVIDE ( __adddf3 , 0x4000c538 );
PROVIDE ( __addsf3 , 0x4000c180 );
PROVIDE ( __divdf3 , 0x4000cb94 );
PROVIDE ( __divdi3 , 0x4000ce60 );
PROVIDE ( __divsi3 , 0x4000dc88 );
PROVIDE ( __extendsfdf2 , 0x4000cdfc );
PROVIDE ( __fixdfsi , 0x4000ccb8 );
PROVIDE ( __fixunsdfsi , 0x4000cd00 );
PROVIDE ( __fixunssfsi , 0x4000c4c4 );
PROVIDE ( __floatsidf , 0x4000e2f0 );
PROVIDE ( __floatsisf , 0x4000e2ac );
PROVIDE ( __floatunsidf , 0x4000e2e8 );
PROVIDE ( __floatunsisf , 0x4000e2a4 );
PROVIDE ( __muldf3 , 0x4000c8f0 );
PROVIDE ( __muldi3 , 0x40000650 );
PROVIDE ( __mulsf3 , 0x4000c3dc );
PROVIDE ( __subdf3 , 0x4000c688 );
PROVIDE ( __subsf3 , 0x4000c268 );
PROVIDE ( __truncdfsf2 , 0x4000cd5c );
PROVIDE ( __udivdi3 , 0x4000d310 );
PROVIDE ( __udivsi3 , 0x4000e21c );
PROVIDE ( __umoddi3 , 0x4000d770 );
PROVIDE ( __umodsi3 , 0x4000e268 );
PROVIDE ( __umulsidi3 , 0x4000dcf0 );
PROVIDE ( _rom_store , 0x4000e388 );
PROVIDE ( _rom_store_table , 0x4000e328 );
PROVIDE ( _start , 0x4000042c );
PROVIDE ( _xtos_alloca_handler , 0x4000dbe0 );
PROVIDE ( _xtos_c_wrapper_handler , 0x40000598 );
PROVIDE ( _xtos_cause3_handler , 0x40000590 );
PROVIDE ( _xtos_ints_off , 0x4000bda4 );
PROVIDE ( _xtos_ints_on , 0x4000bd84 );
PROVIDE ( _xtos_l1int_handler , 0x4000048c );
PROVIDE ( _xtos_p_none , 0x4000dbf8 );
PROVIDE ( _xtos_restore_intlevel , 0x4000056c );
PROVIDE ( _xtos_return_from_exc , 0x4000dc54 );
PROVIDE ( _xtos_set_exception_handler , 0x40000454 );
PROVIDE ( _xtos_set_interrupt_handler , 0x4000bd70 );
PROVIDE ( _xtos_set_interrupt_handler_arg , 0x4000bd28 );
PROVIDE ( _xtos_set_intlevel , 0x4000dbfc );
PROVIDE ( _xtos_set_min_intlevel , 0x4000dc18 );
PROVIDE ( _xtos_set_vpri , 0x40000574 );
PROVIDE ( _xtos_syscall_handler , 0x4000dbe4 );
PROVIDE ( _xtos_unhandled_exception , 0x4000dc44 );
PROVIDE ( _xtos_unhandled_interrupt , 0x4000dc3c );
PROVIDE ( aes_decrypt , 0x400092d4 );
PROVIDE ( aes_decrypt_deinit , 0x400092e4 );
PROVIDE ( aes_decrypt_init , 0x40008ea4 );
PROVIDE ( aes_unwrap , 0x40009410 );
PROVIDE ( base64_decode , 0x40009648 );
PROVIDE ( base64_encode , 0x400094fc );
PROVIDE ( bzero , 0x4000de84 );
PROVIDE ( cmd_parse , 0x40000814 );
PROVIDE ( conv_str_decimal , 0x40000b24 );
PROVIDE ( conv_str_hex , 0x40000cb8 );
PROVIDE ( convert_para_str , 0x40000a60 );
PROVIDE ( dtm_get_intr_mask , 0x400026d0 );
PROVIDE ( dtm_params_init , 0x4000269c );
PROVIDE ( dtm_set_intr_mask , 0x400026c8 );
PROVIDE ( dtm_set_params , 0x400026dc );
PROVIDE ( eprintf , 0x40001d14 );
PROVIDE ( eprintf_init_buf , 0x40001cb8 );
PROVIDE ( eprintf_to_host , 0x40001d48 );
PROVIDE ( est_get_printf_buf_remain_len , 0x40002494 );
PROVIDE ( est_reset_printf_buf_len , 0x4000249c );
PROVIDE ( ets_bzero , 0x40002ae8 );
PROVIDE ( ets_char2xdigit , 0x40002b74 );
PROVIDE ( ets_delay_us , 0x40002ecc );
PROVIDE ( ets_enter_sleep , 0x400027b8 );
PROVIDE ( ets_external_printf , 0x40002578 );
PROVIDE ( ets_get_cpu_frequency , 0x40002f0c );
PROVIDE ( ets_getc , 0x40002bcc );
PROVIDE ( ets_install_external_printf , 0x40002450 );
PROVIDE ( ets_install_putc1 , 0x4000242c );
PROVIDE ( ets_install_putc2 , 0x4000248c );
PROVIDE ( ets_install_uart_printf , 0x40002438 );
PROVIDE ( ets_intr_lock , 0x40000f74 );
PROVIDE ( ets_intr_unlock , 0x40000f80 );
PROVIDE ( ets_isr_attach , 0x40000f88 );
PROVIDE ( ets_isr_mask , 0x40000f98 );
PROVIDE ( ets_isr_unmask , 0x40000fa8 );
PROVIDE ( ets_memcmp , 0x400018d4 );
PROVIDE ( ets_memcpy , 0x400018b4 );
PROVIDE ( ets_memmove , 0x400018c4 );
PROVIDE ( ets_memset , 0x400018a4 );
PROVIDE ( ets_post , 0x40000e24 );
PROVIDE ( ets_printf , 0x400024cc );
PROVIDE ( ets_putc , 0x40002be8 );
PROVIDE ( ets_rtc_int_register , 0x40002a40 );
PROVIDE ( ets_run , 0x40000e04 );
PROVIDE ( ets_set_idle_cb , 0x40000dc0 );
PROVIDE ( ets_set_user_start , 0x40000fbc );
PROVIDE ( ets_str2macaddr , 0x40002af8 );
PROVIDE ( ets_strcmp , 0x40002aa8 );
PROVIDE ( ets_strcpy , 0x40002a88 );
PROVIDE ( ets_strlen , 0x40002ac8 );
PROVIDE ( ets_strncmp , 0x40002ab8 );
PROVIDE ( ets_strncpy , 0x40002a98 );
PROVIDE ( ets_strstr , 0x40002ad8 );
PROVIDE ( ets_task , 0x40000dd0 );
PROVIDE ( ets_timer_arm , 0x40002cc4 );
PROVIDE ( ets_timer_disarm , 0x40002d40 );
PROVIDE ( ets_timer_done , 0x40002d80 );
PROVIDE ( ets_timer_handler_isr , 0x40002da8 );
PROVIDE ( ets_timer_init , 0x40002e68 );
PROVIDE ( ets_timer_setfn , 0x40002c48 );
PROVIDE ( ets_uart_printf , 0x40002544 );
PROVIDE ( ets_update_cpu_frequency , 0x40002f04 );
PROVIDE ( ets_vprintf , 0x40001f00 );
PROVIDE ( ets_wdt_disable , 0x400030f0 );
PROVIDE ( ets_wdt_enable , 0x40002fa0 );
PROVIDE ( ets_wdt_get_mode , 0x40002f34 );
PROVIDE ( ets_wdt_init , 0x40003170 );
PROVIDE ( ets_wdt_restore , 0x40003158 );
PROVIDE ( ets_write_char , 0x40001da0 );
PROVIDE ( get_first_seg , 0x4000091c );
PROVIDE ( gpio_init , 0x40004c50 );
PROVIDE ( gpio_input_get , 0x40004cf0 );
PROVIDE ( gpio_intr_ack , 0x40004dcc );
PROVIDE ( gpio_intr_handler_register , 0x40004e28 );
PROVIDE ( gpio_intr_pending , 0x40004d88 );
PROVIDE ( gpio_intr_test , 0x40004efc );
PROVIDE ( gpio_output_set , 0x40004cd0 );
PROVIDE ( gpio_pin_intr_state_set , 0x40004d90 );
PROVIDE ( gpio_pin_wakeup_disable , 0x40004ed4 );
PROVIDE ( gpio_pin_wakeup_enable , 0x40004e90 );
PROVIDE ( gpio_register_get , 0x40004d5c );
PROVIDE ( gpio_register_set , 0x40004d04 );
PROVIDE ( hmac_md5 , 0x4000a2cc );
PROVIDE ( hmac_md5_vector , 0x4000a160 );
PROVIDE ( hmac_sha1 , 0x4000ba28 );
PROVIDE ( hmac_sha1_vector , 0x4000b8b4 );
PROVIDE ( lldesc_build_chain , 0x40004f40 );
PROVIDE ( lldesc_num2link , 0x40005050 );
PROVIDE ( lldesc_set_owner , 0x4000507c );
PROVIDE ( main , 0x40000fec );
PROVIDE ( md5_vector , 0x400097ac );
PROVIDE ( mem_calloc , 0x40001c2c );
PROVIDE ( mem_free , 0x400019e0 );
PROVIDE ( mem_init , 0x40001998 );
PROVIDE ( mem_malloc , 0x40001b40 );
PROVIDE ( mem_realloc , 0x40001c6c );
PROVIDE ( mem_trim , 0x40001a14 );
PROVIDE ( mem_zalloc , 0x40001c58 );
PROVIDE ( memcmp , 0x4000dea8 );
PROVIDE ( memcpy , 0x4000df48 );
PROVIDE ( memmove , 0x4000e04c );
PROVIDE ( memset , 0x4000e190 );
PROVIDE ( multofup , 0x400031c0 );
PROVIDE ( pbkdf2_sha1 , 0x4000b840 );
PROVIDE ( phy_get_romfuncs , 0x40006b08 );
PROVIDE ( rand , 0x40000600 );
PROVIDE ( rc4_skip , 0x4000dd68 );
PROVIDE ( recv_packet , 0x40003d08 );
PROVIDE ( remove_head_space , 0x40000a04 );
PROVIDE ( rijndaelKeySetupDec , 0x40008dd0 );
PROVIDE ( rijndaelKeySetupEnc , 0x40009300 );
PROVIDE ( rom_abs_temp , 0x400060c0 );
PROVIDE ( rom_ana_inf_gating_en , 0x40006b10 );
PROVIDE ( rom_cal_tos_v50 , 0x40007a28 );
PROVIDE ( rom_chip_50_set_channel , 0x40006f84 );
PROVIDE ( rom_chip_v5_disable_cca , 0x400060d0 );
PROVIDE ( rom_chip_v5_enable_cca , 0x400060ec );
PROVIDE ( rom_chip_v5_rx_init , 0x4000711c );
PROVIDE ( rom_chip_v5_sense_backoff , 0x4000610c );
PROVIDE ( rom_chip_v5_tx_init , 0x4000718c );
PROVIDE ( rom_dc_iq_est , 0x4000615c );
PROVIDE ( rom_en_pwdet , 0x400061b8 );
PROVIDE ( rom_get_bb_atten , 0x40006238 );
PROVIDE ( rom_get_corr_power , 0x40006260 );
PROVIDE ( rom_get_fm_sar_dout , 0x400062dc );
PROVIDE ( rom_get_noisefloor , 0x40006394 );
PROVIDE ( rom_get_power_db , 0x400063b0 );
PROVIDE ( rom_i2c_readReg , 0x40007268 );
PROVIDE ( rom_i2c_readReg_Mask , 0x4000729c );
PROVIDE ( rom_i2c_writeReg , 0x400072d8 );
PROVIDE ( rom_i2c_writeReg_Mask , 0x4000730c );
PROVIDE ( rom_iq_est_disable , 0x40006400 );
PROVIDE ( rom_iq_est_enable , 0x40006430 );
PROVIDE ( rom_linear_to_db , 0x40006484 );
PROVIDE ( rom_mhz2ieee , 0x400065a4 );
PROVIDE ( rom_pbus_dco___SA2 , 0x40007bf0 );
PROVIDE ( rom_pbus_debugmode , 0x4000737c );
PROVIDE ( rom_pbus_enter_debugmode , 0x40007410 );
PROVIDE ( rom_pbus_exit_debugmode , 0x40007448 );
PROVIDE ( rom_pbus_force_test , 0x4000747c );
PROVIDE ( rom_pbus_rd , 0x400074d8 );
PROVIDE ( rom_pbus_set_rxgain , 0x4000754c );
PROVIDE ( rom_pbus_set_txgain , 0x40007610 );
PROVIDE ( rom_pbus_workmode , 0x40007648 );
PROVIDE ( rom_pbus_xpd_rx_off , 0x40007688 );
PROVIDE ( rom_pbus_xpd_rx_on , 0x400076cc );
PROVIDE ( rom_pbus_xpd_tx_off , 0x400076fc );
PROVIDE ( rom_pbus_xpd_tx_on , 0x40007740 );
PROVIDE ( rom_pbus_xpd_tx_on__low_gain , 0x400077a0 );
PROVIDE ( rom_phy_reset_req , 0x40007804 );
PROVIDE ( rom_restart_cal , 0x4000781c );
PROVIDE ( rom_rfcal_pwrctrl , 0x40007eb4 );
PROVIDE ( rom_rfcal_rxiq , 0x4000804c );
PROVIDE ( rom_rfcal_rxiq_set_reg , 0x40008264 );
PROVIDE ( rom_rfcal_txcap , 0x40008388 );
PROVIDE ( rom_rfcal_txiq , 0x40008610 );
PROVIDE ( rom_rfcal_txiq_cover , 0x400088b8 );
PROVIDE ( rom_rfcal_txiq_set_reg , 0x40008a70 );
PROVIDE ( rom_rfpll_reset , 0x40007868 );
PROVIDE ( rom_rfpll_set_freq , 0x40007968 );
PROVIDE ( rom_rxiq_cover_mg_mp , 0x40008b6c );
PROVIDE ( rom_rxiq_get_mis , 0x40006628 );
PROVIDE ( rom_sar_init , 0x40006738 );
PROVIDE ( rom_set_ana_inf_tx_scale , 0x4000678c );
PROVIDE ( rom_set_channel_freq , 0x40006c50 );
PROVIDE ( rom_set_loopback_gain , 0x400067c8 );
PROVIDE ( rom_set_noise_floor , 0x40006830 );
PROVIDE ( rom_set_rxclk_en , 0x40006550 );
PROVIDE ( rom_set_txbb_atten , 0x40008c6c );
PROVIDE ( rom_set_txclk_en , 0x4000650c );
PROVIDE ( rom_set_txiq_cal , 0x40008d34 );
PROVIDE ( rom_start_noisefloor , 0x40006874 );
PROVIDE ( rom_start_tx_tone , 0x400068b4 );
PROVIDE ( rom_stop_tx_tone , 0x4000698c );
PROVIDE ( rom_tx_mac_disable , 0x40006a98 );
PROVIDE ( rom_tx_mac_enable , 0x40006ad4 );
PROVIDE ( rom_txtone_linear_pwr , 0x40006a1c );
PROVIDE ( rom_write_rfpll_sdm , 0x400078dc );
PROVIDE ( roundup2 , 0x400031b4 );
PROVIDE ( rtc_enter_sleep , 0x40002870 );
PROVIDE ( rtc_get_reset_reason , 0x400025e0 );
PROVIDE ( rtc_intr_handler , 0x400029ec );
PROVIDE ( rtc_set_sleep_mode , 0x40002668 );
PROVIDE ( save_rxbcn_mactime , 0x400027a4 );
PROVIDE ( save_tsf_us , 0x400027ac );
PROVIDE ( send_packet , 0x40003c80 );
PROVIDE ( sha1_prf , 0x4000ba48 );
PROVIDE ( sha1_vector , 0x4000a2ec );
PROVIDE ( sip_alloc_to_host_evt , 0x40005180 );
PROVIDE ( sip_get_ptr , 0x400058a8 );
PROVIDE ( sip_get_state , 0x40005668 );
PROVIDE ( sip_init_attach , 0x4000567c );
PROVIDE ( sip_install_rx_ctrl_cb , 0x4000544c );
PROVIDE ( sip_install_rx_data_cb , 0x4000545c );
PROVIDE ( sip_post , 0x400050fc );
PROVIDE ( sip_post_init , 0x400056c4 );
PROVIDE ( sip_reclaim_from_host_cmd , 0x4000534c );
PROVIDE ( sip_reclaim_tx_data_pkt , 0x400052c0 );
PROVIDE ( sip_send , 0x40005808 );
PROVIDE ( sip_to_host_chain_append , 0x40005864 );
PROVIDE ( sip_to_host_evt_send_done , 0x40005234 );
PROVIDE ( slc_add_credits , 0x400060ac );
PROVIDE ( slc_enable , 0x40005d90 );
PROVIDE ( slc_from_host_chain_fetch , 0x40005f24 );
PROVIDE ( slc_from_host_chain_recycle , 0x40005e94 );
PROVIDE ( slc_init_attach , 0x40005c50 );
PROVIDE ( slc_init_credit , 0x4000608c );
PROVIDE ( slc_pause_from_host , 0x40006014 );
PROVIDE ( slc_reattach , 0x40005c1c );
PROVIDE ( slc_resume_from_host , 0x4000603c );
PROVIDE ( slc_select_tohost_gpio , 0x40005dc0 );
PROVIDE ( slc_select_tohost_gpio_mode , 0x40005db8 );
PROVIDE ( slc_send_to_host_chain , 0x40005de4 );
PROVIDE ( slc_set_host_io_max_window , 0x40006068 );
PROVIDE ( slc_to_host_chain_recycle , 0x40005f10 );
PROVIDE ( software_reset , 0x4000264c );
PROVIDE ( spi_flash_attach , 0x40004644 );
PROVIDE ( srand , 0x400005f0 );
PROVIDE ( strcmp , 0x4000bdc8 );
PROVIDE ( strcpy , 0x4000bec8 );
PROVIDE ( strlen , 0x4000bf4c );
PROVIDE ( strncmp , 0x4000bfa8 );
PROVIDE ( strncpy , 0x4000c0a0 );
PROVIDE ( strstr , 0x4000e1e0 );
PROVIDE ( timer_insert , 0x40002c64 );
PROVIDE ( uartAttach , 0x4000383c );
PROVIDE ( uart_baudrate_detect , 0x40003924 );
PROVIDE ( uart_buff_switch , 0x400038a4 );
PROVIDE ( uart_div_modify , 0x400039d8 );
PROVIDE ( uart_rx_intr_handler , 0x40003bbc );
PROVIDE ( uart_rx_one_char , 0x40003b8c );
PROVIDE ( uart_rx_one_char_block , 0x40003b64 );
PROVIDE ( uart_rx_readbuff , 0x40003ec8 );
PROVIDE ( uart_tx_one_char , 0x40003b30 );
PROVIDE ( wepkey_128 , 0x4000bc40 );
PROVIDE ( wepkey_64 , 0x4000bb3c );
PROVIDE ( xthal_bcopy , 0x40000688 );
PROVIDE ( xthal_copy123 , 0x4000074c );
PROVIDE ( xthal_get_ccompare , 0x4000dd4c );
PROVIDE ( xthal_get_ccount , 0x4000dd38 );
PROVIDE ( xthal_get_interrupt , 0x4000dd58 );
PROVIDE ( xthal_get_intread , 0x4000dd58 );
PROVIDE ( xthal_memcpy , 0x400006c4 );
PROVIDE ( xthal_set_ccompare , 0x4000dd40 );
PROVIDE ( xthal_set_intclear , 0x4000dd60 );
PROVIDE ( xthal_spill_registers_into_stack_nw , 0x4000e320 );
PROVIDE ( xthal_window_spill , 0x4000e324 );
PROVIDE ( xthal_window_spill_nw , 0x4000e320 );
PROVIDE ( Te0 , 0x3fffccf0 );
PROVIDE ( UartDev , 0x3fffde10 );
PROVIDE ( flashchip , 0x3fffc714);

View File

@ -0,0 +1,50 @@
#
# Copyright (c) 2015 Cesanta Software Limited
# All rights reserved
#
STUB = stub_hello.c
LIBS =
PARAMS =
CFLAGS =
PORT = /dev/ttyUSB0
BUILD_DIR = .build
COMMON_STUB_DIR = ../../esp
STUB_ELF = $(BUILD_DIR)/$(patsubst %.c,%.elf,$(notdir $(STUB)))
STUB_JSON ?= $(BUILD_DIR)/$(patsubst %.c,%.json,$(notdir $(STUB)))
SDK = $(shell cat ../../../../fw/platforms/esp8266/sdk.version)
XT_CC = xtensa-lx106-elf-gcc
.PHONY: all clean run wrap
all: $(STUB_ELF)
$(STUB_ELF): $(STUB) $(LIBS)
@echo " CC $^ -> $@"
@[ -d $(BUILD_DIR) ] || mkdir $(BUILD_DIR)
@docker run --rm -i -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \
"cd /src/common/platforms/esp8266/stubs && \
$(XT_CC) -std=c99 -Wall -Werror -Os -DESP8266 \
-mtext-section-literals -mlongcalls -nostdlib -fno-builtin \
-I. -I/src/common/platforms/esp \
-I/opt/Espressif/ESP8266_SDK \
-Wl,-static -ffunction-sections -Wl,--gc-sections \
-Tstub.ld $(CFLAGS) -o $@ $^"
wrap: $(STUB_JSON)
$(STUB_JSON): $(STUB_ELF) $(COMMON_STUB_DIR)/esptool.py
@echo " WRAP $< -> $@"
@docker run --rm -i -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \
"cd /src/common/platforms/esp8266/stubs && \
$(COMMON_STUB_DIR)/esptool.py wrap_stub $<" > $@
run: $(STUB_JSON)
@echo " RUN $< $(PARAMS) -> $(PORT)"
@docker run --rm -i --privileged -v $(CURDIR)/../../../..:/src $(SDK) //bin/bash -c \
"cd /src/common/platforms/esp8266/stubs && \
$(COMMON_STUB_DIR)/esptool.py --port $(PORT) run_stub $< $(PARAMS)"
clean:
@rm -rf $(BUILD_DIR)

View File

@ -0,0 +1,13 @@
This is a ESP boot loader stub development environment.
Code produced in this environment can be loaded and executed
in the bootloader environment. Usually it is used to implement
functionality not found in the bootloader.
Stubs can be executed using the `run_stub` command of the modified esptool.py provided.
`wrap_stub` produces a JSON represenattion of the stub that can later be reused
or built into other tools.
Example usage:
$ make run STUB=stub_flash_size.c PORT=/dev/ttyUSB0
$ make run STUB=stub_md5.c PORT=/dev/ttyUSB0 PARAMS="0x11000 10000 1"

View File

@ -0,0 +1,14 @@
#!/usr/bin/python
import sys
for line in open(sys.argv[1]):
i = 0
while i < len(line):
n = len(line) - i
if n > 80: n = 80
l = line[i:i+n]
if n == 80:
l += '\\'
print l
i += n

View File

@ -0,0 +1,91 @@
#ifndef CS_COMMON_PLATFORMS_ESP8266_STUBS_ROM_FUNCTIONS_H_
#define CS_COMMON_PLATFORMS_ESP8266_STUBS_ROM_FUNCTIONS_H_
#include <inttypes.h>
#include "/opt/Espressif/ESP8266_NONOS_SDK/include/c_types.h"
#include "/opt/Espressif/ESP8266_NONOS_SDK/include/spi_flash.h"
int uart_rx_one_char(uint8_t *ch);
uint8_t uart_rx_one_char_block();
int uart_tx_one_char(char ch);
void uart_div_modify(uint32_t uart_no, uint32_t baud_div);
int SendMsg(uint8_t *msg, uint8_t size);
int send_packet(uint8_t *packet, uint32_t size);
// recv_packet depends on global UartDev, better to avoid it.
// uint32_t recv_packet(void *packet, uint32_t len, uint8_t no_sync);
void _putc1(char *ch);
void ets_delay_us(uint32_t us);
uint32_t SPILock();
uint32_t SPIUnlock();
uint32_t SPIRead(uint32_t addr, void *dst, uint32_t size);
uint32_t SPIWrite(uint32_t addr, const uint32_t *src, uint32_t size);
uint32_t SPIEraseChip();
uint32_t SPIEraseBlock(uint32_t block_num);
uint32_t SPIEraseSector(uint32_t sector_num);
extern SpiFlashChip *flashchip;
uint32_t Wait_SPI_Idle(SpiFlashChip *spi);
uint32_t SPI_chip_erase(SpiFlashChip *spi);
uint32_t SPI_read_status(SpiFlashChip *spi);
uint32_t SPI_write_enable(SpiFlashChip *spi);
void spi_flash_attach();
/* ESP32 API compatibility */
#define esp_rom_spiflash_unlock SPIUnlock
#define esp_rom_spiflash_erase_sector SPIEraseSector
#define esp_rom_spiflash_erase_block SPIEraseBlock
#define esp_rom_spiflash_erase_chip SPIEraseChip
#define esp_rom_spiflash_read SPIRead
#define esp_rom_spiflash_write SPIWrite
#define esp_rom_spiflash_config_param SPIParamCfg
void SelectSpiFunction();
void SPIFlashModeConfig(uint32_t a, uint32_t b);
void SPIReadModeCnfig(uint32_t a);
uint32_t SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t block_size,
uint32_t sector_size, uint32_t page_size,
uint32_t status_mask);
void Cache_Read_Disable();
void ets_delay_us(uint32_t delay_micros);
void ets_isr_mask(uint32_t ints);
void ets_isr_unmask(uint32_t ints);
typedef void (*int_handler_t)(void *arg);
void ets_intr_lock();
void ets_intr_unlock();
void ets_set_user_start(void (*user_start_fn)());
uint32_t rtc_get_reset_reason();
void software_reset();
void rom_phy_reset_req();
void uart_rx_intr_handler(void *arg);
void _ResetVector();
/* Crypto functions are from wpa_supplicant. */
int md5_vector(uint32_t num_msgs, const uint8_t *msgs[],
const uint32_t *msg_lens, uint8_t *digest);
int sha1_vector(uint32_t num_msgs, const uint8_t *msgs[],
const uint32_t *msg_lens, uint8_t *digest);
struct MD5Context {
uint32_t buf[4];
uint32_t bits[2];
uint8_t in[64];
};
void MD5Init(struct MD5Context *ctx);
void MD5Update(struct MD5Context *ctx, void *buf, uint32_t len);
void MD5Final(uint8_t digest[16], struct MD5Context *ctx);
#endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_ROM_FUNCTIONS_H_ */

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*/
MEMORY {
iram : org = 0x40100000, len = 0x8000
dram : org = 0x3FFE8000, len = 0x14000
}
ENTRY(stub_main)
SECTIONS {
.params 0x40100000 : {
_params_start = ABSOLUTE(.);
*(.params)
_params_end = ABSOLUTE(.);
} > iram
.text : ALIGN(4) {
_code_start = ABSOLUTE(.);
*(.literal)
*(.text .text.*)
} > iram
.bss : ALIGN(4) {
_bss_start = ABSOLUTE(.);
*(.bss)
_bss_end = ABSOLUTE(.);
} > dram
.data : ALIGN(4) {
_data_start = ABSOLUTE(.);
*(.data)
*(.rodata .rodata.*)
} > dram
}
INCLUDE "eagle.rom.addr.v6.ld"
PROVIDE(SPIFlashModeConfig = 0x40004568);
PROVIDE(SPI_erase_sector = 0x400040c0);
PROVIDE(SPI_erase_block = 0x40004120);

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*
*
* Stub template.
*/
#include <inttypes.h>
#include "rom_functions.h"
/* Define the args vector and put it into the ".params" section. */
uint32_t params[3] __attribute__((section(".params")));
/* Define a function called stub_main. Do not return or reboot.
* Use send_packet to communicate to the host. */
const char *hello = "Hello";
void stub_main(void) {
send_packet(hello, 5);
_ResetVector();
}

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#include "uart.h"
#include "ets_sys.h"
#define UART_CLKDIV_26MHZ(B) (52000000 + B / 2) / B
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate) {
uint32_t div = UART_CLKDIV_26MHZ(baud_rate);
WRITE_PERI_REG(UART_CLKDIV_REG(uart_no), div & 0xfffff);
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_PLATFORMS_ESP8266_STUBS_UART_H_
#define CS_COMMON_PLATFORMS_ESP8266_STUBS_UART_H_
#include <stdint.h>
void set_baud_rate(uint32_t uart_no, uint32_t baud_rate);
#define REG_UART_BASE(i) (0x60000000 + (i) *0xf00)
#define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0)
#define UART_CONF1_REG(i) (REG_UART_BASE(i) + 0x24)
#define UART_RX_TOUT_EN (BIT(31))
#define UART_RX_TOUT_THRHD_S 24
#define UART_RXFIFO_FULL_THRHD_S 0
#define UART_INT_ST_REG(i) (REG_UART_BASE(i) + 0x8)
#define UART_INT_ENA_REG(i) (REG_UART_BASE(i) + 0xC)
#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
#define UART_INT_CLR_REG(i) (REG_UART_BASE(i) + 0x10)
#define UART_CLKDIV_REG(i) (REG_UART_BASE(i) + 0x14)
#define UART_STATUS_REG(i) (REG_UART_BASE(i) + 0x1C)
#define UART_CONF0_REG(i) (REG_UART_BASE(i) + 0x20)
#define UART_RXFIFO_RST (BIT(17))
#define ETS_UART0_INUM ETS_UART_INUM
#endif /* CS_COMMON_PLATFORMS_ESP8266_STUBS_UART_H_ */

View File

@ -0,0 +1,23 @@
#!/usr/bin/python
# Analyzers output of firmware compiler with -DESP_ENABLE_MALLOC_TRACES
import re
import sys
allocs = {}
for l in sys.stdin:
m = re.match(r'(ca|ma|re|fr) (\S+)\s*(\S*)\s*(\S*)', l)
if not m: continue
op = m.group(1)
if op in ('ca', 'ma'):
allocs[m.group(2)] = long(m.group(3))
else:
if m.group(2) in allocs:
del allocs[m.group(2)]
if op == 're':
allocs[m.group(3)] = long(m.group(4))
for k, v in sorted(allocs.iteritems()):
print k, v

View File

@ -0,0 +1,136 @@
/* clang-format off */
/*
* Copyright (c) 2010 - 2011 Espressif System
*
*/
#ifndef CS_COMMON_PLATFORMS_ESP8266_UART_REGISTER_H_
#define CS_COMMON_PLATFORMS_ESP8266_UART_REGISTER_H_
#define REG_UART_BASE(i) (0x60000000 + (i)*0xf00)
//version value:32'h062000
#define UART_FIFO(i) (REG_UART_BASE(i) + 0x0)
#define UART_RXFIFO_RD_BYTE 0x000000FF
#define UART_RXFIFO_RD_BYTE_S 0
#define UART_INT_RAW(i) (REG_UART_BASE(i) + 0x4)
#define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
#define UART_BRK_DET_INT_RAW (BIT(7))
#define UART_CTS_CHG_INT_RAW (BIT(6))
#define UART_DSR_CHG_INT_RAW (BIT(5))
#define UART_RXFIFO_OVF_INT_RAW (BIT(4))
#define UART_FRM_ERR_INT_RAW (BIT(3))
#define UART_PARITY_ERR_INT_RAW (BIT(2))
#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
#define UART_RXFIFO_FULL_INT_RAW (BIT(0))
#define UART_INT_ST(i) (REG_UART_BASE(i) + 0x8)
#define UART_RXFIFO_TOUT_INT_ST (BIT(8))
#define UART_BRK_DET_INT_ST (BIT(7))
#define UART_CTS_CHG_INT_ST (BIT(6))
#define UART_DSR_CHG_INT_ST (BIT(5))
#define UART_RXFIFO_OVF_INT_ST (BIT(4))
#define UART_FRM_ERR_INT_ST (BIT(3))
#define UART_PARITY_ERR_INT_ST (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
#define UART_RXFIFO_FULL_INT_ST (BIT(0))
#define UART_INT_ENA(i) (REG_UART_BASE(i) + 0xC)
#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
#define UART_BRK_DET_INT_ENA (BIT(7))
#define UART_CTS_CHG_INT_ENA (BIT(6))
#define UART_DSR_CHG_INT_ENA (BIT(5))
#define UART_RXFIFO_OVF_INT_ENA (BIT(4))
#define UART_FRM_ERR_INT_ENA (BIT(3))
#define UART_PARITY_ERR_INT_ENA (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
#define UART_INT_CLR(i) (REG_UART_BASE(i) + 0x10)
#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
#define UART_BRK_DET_INT_CLR (BIT(7))
#define UART_CTS_CHG_INT_CLR (BIT(6))
#define UART_DSR_CHG_INT_CLR (BIT(5))
#define UART_RXFIFO_OVF_INT_CLR (BIT(4))
#define UART_FRM_ERR_INT_CLR (BIT(3))
#define UART_PARITY_ERR_INT_CLR (BIT(2))
#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
#define UART_CLKDIV(i) (REG_UART_BASE(i) + 0x14)
#define UART_CLKDIV_CNT 0x000FFFFF
#define UART_CLKDIV_S 0
#define UART_AUTOBAUD(i) (REG_UART_BASE(i) + 0x18)
#define UART_GLITCH_FILT 0x000000FF
#define UART_GLITCH_FILT_S 8
#define UART_AUTOBAUD_EN (BIT(0))
#define UART_STATUS(i) (REG_UART_BASE(i) + 0x1C)
#define UART_TXD (BIT(31))
#define UART_RTSN (BIT(30))
#define UART_DTRN (BIT(29))
#define UART_TXFIFO_CNT 0x000000FF
#define UART_TXFIFO_CNT_S 16
#define UART_RXD (BIT(15))
#define UART_CTSN (BIT(14))
#define UART_DSRN (BIT(13))
#define UART_RXFIFO_CNT 0x000000FF
#define UART_RXFIFO_CNT_S 0
#define UART_CONF0(i) (REG_UART_BASE(i) + 0x20)
#define UART_DTR_INV (BIT(24))
#define UART_RTS_INV (BIT(23))
#define UART_TXD_INV (BIT(22))
#define UART_DSR_INV (BIT(21))
#define UART_CTS_INV (BIT(20))
#define UART_RXD_INV (BIT(19))
#define UART_TXFIFO_RST (BIT(18))
#define UART_RXFIFO_RST (BIT(17))
#define UART_IRDA_EN (BIT(16))
#define UART_TX_FLOW_EN (BIT(15))
#define UART_LOOPBACK (BIT(14))
#define UART_IRDA_RX_INV (BIT(13))
#define UART_IRDA_TX_INV (BIT(12))
#define UART_IRDA_WCTL (BIT(11))
#define UART_IRDA_TX_EN (BIT(10))
#define UART_IRDA_DPLX (BIT(9))
#define UART_TXD_BRK (BIT(8))
#define UART_SW_DTR (BIT(7))
#define UART_SW_RTS (BIT(6))
#define UART_STOP_BIT_NUM 0x00000003
#define UART_STOP_BIT_NUM_S 4
#define UART_BIT_NUM 0x00000003
#define UART_BIT_NUM_S 2
#define UART_PARITY_EN (BIT(1))
#define UART_PARITY (BIT(0))
#define UART_CONF1(i) (REG_UART_BASE(i) + 0x24)
#define UART_RX_TOUT_EN (BIT(31))
#define UART_RX_TOUT_THRHD 0x0000007F
#define UART_RX_TOUT_THRHD_S 24
#define UART_RX_FLOW_EN (BIT(23))
#define UART_RX_FLOW_THRHD 0x0000007F
#define UART_RX_FLOW_THRHD_S 16
#define UART_TXFIFO_EMPTY_THRHD 0x0000007F
#define UART_TXFIFO_EMPTY_THRHD_S 8
#define UART_RXFIFO_FULL_THRHD 0x0000007F
#define UART_RXFIFO_FULL_THRHD_S 0
#define UART_LOWPULSE(i) (REG_UART_BASE(i) + 0x28)
#define UART_LOWPULSE_MIN_CNT 0x000FFFFF
#define UART_LOWPULSE_MIN_CNT_S 0
#define UART_HIGHPULSE(i) (REG_UART_BASE(i) + 0x2C)
#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
#define UART_HIGHPULSE_MIN_CNT_S 0
#define UART_PULSE_NUM(i) (REG_UART_BASE(i) + 0x30)
#define UART_PULSE_NUM_CNT 0x0003FF
#define UART_PULSE_NUM_CNT_S 0
#define UART_DATE(i) (REG_UART_BASE(i) + 0x78)
#define UART_ID(i) (REG_UART_BASE(i) + 0x7C)
#endif /* CS_COMMON_PLATFORMS_ESP8266_UART_REGISTER_H_ */

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_
#define CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_
#ifndef MG_LWIP
#define MG_LWIP 0
#endif
#if MG_LWIP
/*
* When compiling for nRF5x chips with arm-none-eabi-gcc, it has BYTE_ORDER
* already defined, so in order to avoid warnings in lwip, we have to undefine
* it.
*
* TODO: Check if in the future versions of nRF5 SDK that changes.
* Current version of nRF51 SDK: 0.8.0
* nRF5 SDK: 0.9.0
*/
#if CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52
#undef BYTE_ORDER
#endif
#include <lwip/opt.h>
#include <lwip/err.h>
#include <lwip/ip_addr.h>
#include <lwip/inet.h>
#include <lwip/netdb.h>
#include <lwip/dns.h>
#ifndef LWIP_PROVIDE_ERRNO
#include <errno.h>
#endif
#if LWIP_SOCKET
#include <lwip/sockets.h>
#else
/* We really need the definitions from sockets.h. */
#undef LWIP_SOCKET
#define LWIP_SOCKET 1
#include <lwip/sockets.h>
#undef LWIP_SOCKET
#define LWIP_SOCKET 0
#endif
#define INVALID_SOCKET (-1)
#define SOMAXCONN 10
typedef int sock_t;
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
struct mg_mgr;
struct mg_connection;
uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr);
void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle,
int interval, int count);
#endif
/* For older version of LWIP */
#ifndef ipX_2_ip
#define ipX_2_ip(x) (x)
#endif
#endif /* MG_LWIP */
#endif /* CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ */

View File

@ -0,0 +1,243 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
#ifndef MG_SIG_QUEUE_LEN
#define MG_SIG_QUEUE_LEN 32
#endif
struct mg_ev_mgr_lwip_signal {
int sig;
struct mg_connection *nc;
};
struct mg_ev_mgr_lwip_data {
struct mg_ev_mgr_lwip_signal sig_queue[MG_SIG_QUEUE_LEN];
int sig_queue_len;
int start_index;
};
void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc) {
struct mg_ev_mgr_lwip_data *md =
(struct mg_ev_mgr_lwip_data *) nc->iface->data;
mgos_lock();
if (md->sig_queue_len >= MG_SIG_QUEUE_LEN) {
mgos_unlock();
return;
}
int end_index = (md->start_index + md->sig_queue_len) % MG_SIG_QUEUE_LEN;
md->sig_queue[end_index].sig = sig;
md->sig_queue[end_index].nc = nc;
md->sig_queue_len++;
mg_lwip_mgr_schedule_poll(nc->mgr);
mgos_unlock();
}
void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
struct mg_ev_mgr_lwip_data *md =
(struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data;
while (md->sig_queue_len > 0) {
mgos_lock();
int sig = md->sig_queue[md->start_index].sig;
struct mg_connection *nc = md->sig_queue[md->start_index].nc;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
md->start_index = (md->start_index + 1) % MG_SIG_QUEUE_LEN;
md->sig_queue_len--;
mgos_unlock();
if (nc->iface == NULL || nc->mgr == NULL) continue;
switch (sig) {
case MG_SIG_CONNECT_RESULT: {
#if MG_ENABLE_SSL
if (cs->err == 0 && (nc->flags & MG_F_SSL) &&
!(nc->flags & MG_F_SSL_HANDSHAKE_DONE)) {
mg_lwip_ssl_do_hs(nc);
} else
#endif
{
mg_if_connect_cb(nc, cs->err);
}
break;
}
case MG_SIG_CLOSE_CONN: {
nc->flags |= MG_F_SEND_AND_CLOSE;
mg_close_conn(nc);
break;
}
case MG_SIG_RECV: {
cs->recv_pending = 0;
if (nc->flags & MG_F_UDP) {
mg_lwip_handle_recv_udp(nc);
} else {
mg_lwip_handle_recv_tcp(nc);
}
break;
}
case MG_SIG_TOMBSTONE: {
break;
}
case MG_SIG_ACCEPT: {
mg_lwip_handle_accept(nc);
break;
}
}
}
}
void mg_lwip_if_init(struct mg_iface *iface) {
LOG(LL_INFO, ("%p Mongoose init", iface));
iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
}
void mg_lwip_if_free(struct mg_iface *iface) {
MG_FREE(iface->data);
iface->data = NULL;
}
void mg_lwip_if_add_conn(struct mg_connection *nc) {
(void) nc;
}
void mg_lwip_if_remove_conn(struct mg_connection *nc) {
struct mg_ev_mgr_lwip_data *md =
(struct mg_ev_mgr_lwip_data *) nc->iface->data;
/* Walk the queue and null-out further signals for this conn. */
for (int i = 0; i < MG_SIG_QUEUE_LEN; i++) {
if (md->sig_queue[i].nc == nc) {
md->sig_queue[i].sig = MG_SIG_TOMBSTONE;
}
}
}
time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
struct mg_mgr *mgr = iface->mgr;
int n = 0;
double now = mg_time();
struct mg_connection *nc, *tmp;
double min_timer = 0;
int num_timers = 0;
#if 0
DBG(("begin poll @%u", (unsigned int) (now * 1000)));
#endif
mg_ev_mgr_lwip_process_signals(mgr);
for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
tmp = nc->next;
n++;
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
((nc->flags & MG_F_SEND_AND_CLOSE) && (nc->flags & MG_F_UDP) &&
(nc->send_mbuf.len == 0))) {
mg_close_conn(nc);
continue;
}
mg_if_poll(nc, now);
mg_if_timer(nc, now);
#if MG_ENABLE_SSL
if ((nc->flags & MG_F_SSL) && cs != NULL && cs->pcb.tcp != NULL &&
cs->pcb.tcp->state == ESTABLISHED) {
if (((nc->flags & MG_F_WANT_WRITE) ||
((nc->send_mbuf.len > 0) &&
(nc->flags & MG_F_SSL_HANDSHAKE_DONE))) &&
cs->pcb.tcp->snd_buf > 0) {
/* Can write more. */
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
}
if (cs->rx_chain != NULL || (nc->flags & MG_F_WANT_READ)) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
}
} else
#endif /* MG_ENABLE_SSL */
{
if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) {
mg_lwip_send_more(nc);
}
}
if (nc->sock != INVALID_SOCKET &&
!(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
cs->pcb.tcp->unsent != NULL) {
tcpip_callback(tcp_output_tcpip, cs->pcb.tcp);
}
if (nc->ev_timer_time > 0) {
if (num_timers == 0 || nc->ev_timer_time < min_timer) {
min_timer = nc->ev_timer_time;
}
num_timers++;
}
if (nc->sock != INVALID_SOCKET) {
/* Try to consume data from cs->rx_chain */
mg_lwip_consume_rx_chain_tcp(nc);
/*
* If the connection is about to close, and rx_chain is finally empty,
* send the MG_SIG_CLOSE_CONN signal
*/
if (cs->draining_rx_chain && cs->rx_chain == NULL) {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
}
}
#if 0
DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms",
(unsigned int) (now * 1000), n, num_timers,
(unsigned int) (min_timer * 1000), timeout_ms));
#endif
(void) timeout_ms;
return now;
}
uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) {
struct mg_connection *nc;
double now;
double min_timer = 0;
int num_timers = 0;
mg_ev_mgr_lwip_process_signals(mgr);
for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (nc->ev_timer_time > 0) {
if (num_timers == 0 || nc->ev_timer_time < min_timer) {
min_timer = nc->ev_timer_time;
}
num_timers++;
}
if (nc->send_mbuf.len > 0
#if MG_ENABLE_SSL
|| (nc->flags & MG_F_WANT_WRITE)
#endif
) {
int can_send = 0;
/* We have stuff to send, but can we? */
if (nc->flags & MG_F_UDP) {
/* UDP is always ready for sending. */
can_send = (cs->pcb.udp != NULL);
} else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
}
/* We want and can send, request a poll immediately. */
if (can_send) return 0;
}
}
uint32_t timeout_ms = ~0;
now = mg_time();
if (num_timers > 0) {
/* If we have a timer that is past due, do a poll ASAP. */
if (min_timer < now) return 0;
double timer_timeout_ms = (min_timer - now) * 1000 + 1 /* rounding */;
if (timer_timeout_ms < timeout_ms) {
timeout_ms = timer_timeout_ms;
}
}
return timeout_ms;
}
#endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */

Some files were not shown because too many files have changed in this diff Show More