Merge branch 'feature/mbedtls'
This commit is contained in:
commit
65307aed75
33 changed files with 4571 additions and 822 deletions
7
.gitmodules
vendored
7
.gitmodules
vendored
|
@ -1,7 +1,6 @@
|
|||
[submodule "lwip/lwip"]
|
||||
path = lwip/lwip
|
||||
url = https://github.com/SuperHouse/esp-lwip.git
|
||||
[submodule "axtls/axtls"]
|
||||
path = axtls/axtls
|
||||
url = https://github.com/SuperHouse/axtls.git
|
||||
|
||||
[submodule "extras/mbedtls/mbedtls"]
|
||||
path = extras/mbedtls/mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls.git
|
||||
|
|
10
README.md
10
README.md
|
@ -69,18 +69,18 @@ Current status is alpha quality, actively developed. AP STATION mode (ie wifi cl
|
|||
* `include` contains header files from Espressif RTOS SDK, relating to the binary libraries & Xtensa core.
|
||||
* `core` contains source & headers for low-level ESP8266 functions & peripherals. `core/include/esp` contains useful headers for peripheral access, etc. Minimal to no FreeRTOS dependencies.
|
||||
* `extras` is a directory that contains optional components that can be added to your project. Most 'extras' components will have a corresponding example in the `examples` directory. Extras include:
|
||||
- mbedtls - [mbedTLS](https://tls.mbed.org/) is a TLS/SSL library providing up to date secure connectivity and encryption support.
|
||||
- i2c - software i2c driver ([upstream project](https://github.com/kanflo/esp-open-rtos-driver-i2c))
|
||||
- rboot-ota - OTA support (over-the-air updates) including a TFTP server for receiving updates ([for rboot by @raburton](http://richard.burtons.org/2015/05/18/rboot-a-new-boot-loader-for-esp8266/))
|
||||
- bmp180 driver for digital pressure sensor ([upstream project](https://github.com/Angus71/esp-open-rtos-driver-bmp180))
|
||||
* `FreeRTOS` contains FreeRTOS implementation, subdirectory structure is the standard FreeRTOS structure. `FreeRTOS/source/portable/esp8266/` contains the ESP8266 port.
|
||||
* `lwip` and `axtls` contain the lwIP TCP/IP library and the axTLS TLS library ('libssl' in the esp8266 SDKs), respectively. See [Third Party Libraries](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries) wiki page for details.
|
||||
* `lwip` contains the lwIP TCP/IP library. See [Third Party Libraries](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries) wiki page for details.
|
||||
* `libc` contains the newlib libc. [Libc details here](https://github.com/SuperHouse/esp-open-rtos/wiki/libc-configuration).
|
||||
|
||||
## Open Source Components
|
||||
|
||||
* [FreeRTOS](http://freertos.org) V7.5.2
|
||||
* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v1.4.1, modified via the [esp-lwip project](https://github.com/kadamski/esp-lwip) by @kadamski.
|
||||
* [axTLS](http://axtls.sourceforge.net/) compiled from development version v1.5.3, plus modifications for low memory devices.
|
||||
* [newlib](https://github.com/projectgus/newlib-xtensa) v2.2.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
|
||||
|
||||
For details of how third party libraries are integrated, [see the wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries).
|
||||
|
@ -91,6 +91,8 @@ Binary libraries (inside the `lib` dir) are all supplied by Espressif as part of
|
|||
|
||||
As part of the esp-open-rtos build process, all binary SDK symbols are prefixed with `sdk_`. This makes it easier to differentiate binary & open source code, and also prevents namespace conflicts.
|
||||
|
||||
Espressif's RTOS SDK provided a "libssl" based on axTLS. This has been replaced with the more up to date mbedTLS library (see below).
|
||||
|
||||
Some binary libraries appear to contain unattributed open source code:
|
||||
|
||||
* libnet80211.a & libwpa.a appear to be based on FreeBSD net80211/wpa, or forks of them. ([See this issue](https://github.com/SuperHouse/esp-open-rtos/issues/4)).
|
||||
|
@ -98,7 +100,7 @@ Some binary libraries appear to contain unattributed open source code:
|
|||
|
||||
## Licensing
|
||||
|
||||
* BSD license (as described in LICENSE) applies to original source files, [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki), and [axTLS](http://axtls.sourceforge.net/). lwIP is Copyright (C) Swedish Institute of Computer Science. axTLS is Copyright (C) Cameron Rich.
|
||||
* BSD license (as described in LICENSE) applies to original source files, [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki). lwIP is Copyright (C) Swedish Institute of Computer Science.
|
||||
|
||||
* FreeRTOS is provided under the GPL with the FreeRTOS linking exception, allowing non-GPL firmwares to be produced using FreeRTOS as the RTOS core. License details in files under FreeRTOS dir. FreeRTOS is Copyright (C) Real Time Engineers Ltd.
|
||||
|
||||
|
@ -106,6 +108,8 @@ Some binary libraries appear to contain unattributed open source code:
|
|||
|
||||
* Newlib is covered by several copyrights and licenses, as per the files in the `libc` directory.
|
||||
|
||||
* [mbedTLS](https://tls.mbed.org/) is provided under the Apache 2.0 license as described in the file extras/mbedtls/mbedtls/apache-2.0.txt. mbedTLS is Copyright (C) ARM Limited.
|
||||
|
||||
Components under `extras/` may contain different licenses, please see those directories for details.
|
||||
|
||||
## Contributions
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit a4860ef68d7f5d98a8731f99787d51cc44c433c9
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Stub time-related functions for TLS time-related operations
|
||||
*
|
||||
* ESPTODO: Revisit these ASAP as gettimeofday() is used for entropy
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
time_t time(time_t *t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t mktime(struct tm *tm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gettimeofday(struct timeval *tv, void *tz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
printf("abort() was called.\r\n");
|
||||
while(1) {}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
# Component makefile for axTLS
|
||||
|
||||
# axTLS has its own configure and build system, but it's not particularly
|
||||
# designed for embedded systems. For now we're just imposing the ESP Open RTOS
|
||||
# build system over the top.
|
||||
|
||||
# We supply our own hand tweaked config.h in the external 'include' dir.
|
||||
|
||||
AXTLS_DIR = $(axtls_ROOT)axtls/
|
||||
INC_DIRS += $(axtls_ROOT)include $(AXTLS_DIR)ssl $(AXTLS_DIR)crypto
|
||||
|
||||
# args for passing into compile rule generation
|
||||
axtls_INC_DIR = $(AXTLS_DIR)include $(AXTLS_DIR)
|
||||
axtls_SRC_DIR = $(AXTLS_DIR)crypto $(AXTLS_DIR)ssl $(axtls_ROOT)
|
||||
|
||||
#axtls_CFLAGS = $(CFLAGS) -Wno-address
|
||||
|
||||
$(eval $(call component_compile_rules,axtls))
|
||||
|
||||
# Helpful error if git submodule not initialised
|
||||
$(axtls_SRC_DIR):
|
||||
$(error "axtls git submodule not installed. Please run 'git submodule init' then 'git submodule update'")
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
* Automatically generated header file: don't edit
|
||||
*/
|
||||
#define HAVE_DOT_CONFIG 0
|
||||
#undef CONFIG_PLATFORM_LINUX
|
||||
#undef CONFIG_PLATFORM_CYGWIN
|
||||
#undef CONFIG_PLATFORM_WIN32
|
||||
|
||||
/*
|
||||
* General Configuration
|
||||
*/
|
||||
#define PREFIX "/usr/local"
|
||||
#define CROSS "xtensa-lx106-elf-"
|
||||
#undef CONFIG_DEBUG
|
||||
#define CONFIG_STRIP_UNWANTED_SECTIONS 1
|
||||
#undef CONFIG_VISUAL_STUDIO_7_0
|
||||
#undef CONFIG_VISUAL_STUDIO_8_0
|
||||
#undef CONFIG_VISUAL_STUDIO_10_0
|
||||
#define CONFIG_VISUAL_STUDIO_7_0_BASE ""
|
||||
#define CONFIG_VISUAL_STUDIO_8_0_BASE ""
|
||||
#define CONFIG_VISUAL_STUDIO_10_0_BASE ""
|
||||
#define CONFIG_EXTRA_CFLAGS_OPTIONS ""
|
||||
#define CONFIG_EXTRA_LDFLAGS_OPTIONS ""
|
||||
|
||||
/*
|
||||
* Embedded System Options (added for ESP RTOS SDK, don't have config entries yetr)
|
||||
*/
|
||||
#define CONFIG_NO_FILESYSTEM 1
|
||||
#define CONFIG_USE_RAND 1
|
||||
#define CONFIG_MAX_PLAIN_LENGTH 1024
|
||||
#define CONFIG_MAX_KEY_BYTE_SIZE 256 /* for max 2048 bit keys (untested with >1024 bit keys) */
|
||||
|
||||
/*
|
||||
* SSL Library
|
||||
*/
|
||||
#undef CONFIG_SSL_SERVER_ONLY
|
||||
#undef CONFIG_SSL_CERT_VERIFICATION
|
||||
#define CONFIG_SSL_ENABLE_CLIENT 1
|
||||
#undef CONFIG_SSL_FULL_MODE
|
||||
#undef CONFIG_SSL_SKELETON_MODE
|
||||
#undef CONFIG_SSL_PROT_LOW
|
||||
#define CONFIG_SSL_PROT_MEDIUM 1
|
||||
#undef CONFIG_SSL_PROT_HIGH
|
||||
#undef CONFIG_SSL_USE_DEFAULT_KEY
|
||||
#define CONFIG_SSL_PRIVATE_KEY_LOCATION ""
|
||||
#define CONFIG_SSL_PRIVATE_KEY_PASSWORD ""
|
||||
#define CONFIG_SSL_X509_CERT_LOCATION ""
|
||||
#undef CONFIG_SSL_GENERATE_X509_CERT
|
||||
#define CONFIG_SSL_X509_COMMON_NAME ""
|
||||
#define CONFIG_SSL_X509_ORGANIZATION_NAME ""
|
||||
#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME ""
|
||||
#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE
|
||||
#undef CONFIG_SSL_HAS_PEM
|
||||
#undef CONFIG_SSL_USE_PKCS12
|
||||
#define CONFIG_SSL_EXPIRY_TIME 24
|
||||
#define CONFIG_X509_MAX_CA_CERTS 1
|
||||
#define CONFIG_SSL_MAX_CERTS 3
|
||||
#undef CONFIG_SSL_CTX_MUTEXING
|
||||
#undef CONFIG_USE_DEV_URANDOM
|
||||
#undef CONFIG_WIN32_USE_CRYPTO_LIB
|
||||
#undef CONFIG_OPENSSL_COMPATIBLE
|
||||
#undef CONFIG_PERFORMANCE_TESTING
|
||||
#undef CONFIG_SSL_TEST
|
||||
#undef CONFIG_AXTLSWRAP
|
||||
#undef CONFIG_AXHTTPD
|
||||
#undef CONFIG_HTTP_STATIC_BUILD
|
||||
#define CONFIG_HTTP_PORT
|
||||
#define CONFIG_HTTP_HTTPS_PORT
|
||||
#define CONFIG_HTTP_SESSION_CACHE_SIZE
|
||||
#define CONFIG_HTTP_WEBROOT ""
|
||||
#define CONFIG_HTTP_TIMEOUT
|
||||
#undef CONFIG_HTTP_HAS_CGI
|
||||
#define CONFIG_HTTP_CGI_EXTENSIONS ""
|
||||
#undef CONFIG_HTTP_ENABLE_LUA
|
||||
#define CONFIG_HTTP_LUA_PREFIX ""
|
||||
#undef CONFIG_HTTP_BUILD_LUA
|
||||
#define CONFIG_HTTP_CGI_LAUNCHER ""
|
||||
#undef CONFIG_HTTP_DIRECTORIES
|
||||
#undef CONFIG_HTTP_HAS_AUTHORIZATION
|
||||
#undef CONFIG_HTTP_HAS_IPV6
|
||||
#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER
|
||||
#define CONFIG_HTTP_USER ""
|
||||
#undef CONFIG_HTTP_VERBOSE
|
||||
#undef CONFIG_HTTP_IS_DAEMON
|
||||
|
||||
/*
|
||||
* Language Bindings
|
||||
*/
|
||||
#undef CONFIG_BINDINGS
|
||||
#undef CONFIG_CSHARP_BINDINGS
|
||||
#undef CONFIG_VBNET_BINDINGS
|
||||
#define CONFIG_DOT_NET_FRAMEWORK_BASE ""
|
||||
#undef CONFIG_JAVA_BINDINGS
|
||||
#define CONFIG_JAVA_HOME ""
|
||||
#undef CONFIG_PERL_BINDINGS
|
||||
#define CONFIG_PERL_CORE ""
|
||||
#define CONFIG_PERL_LIB ""
|
||||
#undef CONFIG_LUA_BINDINGS
|
||||
#define CONFIG_LUA_CORE ""
|
||||
|
||||
/*
|
||||
* Samples
|
||||
*/
|
||||
#undef CONFIG_SAMPLES
|
||||
#undef CONFIG_C_SAMPLES
|
||||
#undef CONFIG_CSHARP_SAMPLES
|
||||
#undef CONFIG_VBNET_SAMPLES
|
||||
#undef CONFIG_JAVA_SAMPLES
|
||||
#undef CONFIG_PERL_SAMPLES
|
||||
#undef CONFIG_LUA_SAMPLES
|
||||
|
||||
/*
|
||||
* BigInt Options
|
||||
*/
|
||||
#undef CONFIG_BIGINT_CLASSICAL
|
||||
#undef CONFIG_BIGINT_MONTGOMERY
|
||||
#define CONFIG_BIGINT_BARRETT 1
|
||||
#define CONFIG_BIGINT_CRT 1
|
||||
#undef CONFIG_BIGINT_KARATSUBA
|
||||
#define MUL_KARATSUBA_THRESH
|
||||
#define SQU_KARATSUBA_THRESH
|
||||
#define CONFIG_BIGINT_SLIDING_WINDOW 1
|
||||
#define CONFIG_BIGINT_SQUARE 1
|
||||
#define CONFIG_BIGINT_CHECK_ON 1
|
||||
#define CONFIG_INTEGER_32BIT 1
|
||||
#undef CONFIG_INTEGER_16BIT
|
||||
#undef CONFIG_INTEGER_8BIT
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef _OS_INT_H
|
||||
#define _OS_INT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#endif
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2015, Cameron Rich
|
||||
* Modifications Copyright (c) 2015 Superhouse Automation Pty Ltd
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 the axTLS project 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file os_port.h
|
||||
*
|
||||
* Some stuff to minimise the differences between windows and linux/unix
|
||||
*/
|
||||
|
||||
#ifndef _HEADER_OS_PORT_H
|
||||
#define _HEADER_OS_PORT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "os_int.h"
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <netdb.h>
|
||||
//#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <posix/sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <ipv4/lwip/inet.h>
|
||||
#if defined(CONFIG_SSL_CTX_MUTEXING)
|
||||
#include "semphr.h"
|
||||
#endif
|
||||
|
||||
#define SOCKET_READ(A,B,C) read(A,B,C)
|
||||
#define SOCKET_WRITE(A,B,C) write(A,B,C)
|
||||
#define SOCKET_CLOSE(A) if (A >= 0) close(A)
|
||||
#define TTY_FLUSH()
|
||||
|
||||
static inline uint64_t be64toh(uint64_t x) {
|
||||
return ntohl(x>>32) | ((uint64_t)(ntohl(x)) << 32);
|
||||
}
|
||||
|
||||
void exit_now(const char *format, ...) __attribute((noreturn));
|
||||
|
||||
#define EXP_FUNC
|
||||
#define STDCALL
|
||||
|
||||
/* Mutex definitions */
|
||||
#if defined(CONFIG_SSL_CTX_MUTEXING)
|
||||
#define SSL_CTX_MUTEX_TYPE xSemaphoreHandle
|
||||
#define SSL_CTX_MUTEX_INIT(A) vSemaphoreCreateBinaryCreateMutex(A)
|
||||
#define SSL_CTX_MUTEX_DESTROY(A) vSemaphoreDelete(A)
|
||||
#define SSL_CTX_LOCK(A) xSemaphoreTakeRecursive(A, portMAX_DELAY)
|
||||
#define SSL_CTX_UNLOCK(A) xSemaphoreGiveRecursive(A)
|
||||
#else
|
||||
#define SSL_CTX_MUTEX_TYPE
|
||||
#define SSL_CTX_MUTEX_INIT(A)
|
||||
#define SSL_CTX_MUTEX_DESTROY(A)
|
||||
#define SSL_CTX_LOCK(A)
|
||||
#define SSL_CTX_UNLOCK(A)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||
/* axTLS version header
|
||||
|
||||
We need this because we're using axTLS from source repo, not from a release.
|
||||
*/
|
||||
|
||||
#ifndef _VERSION_H
|
||||
|
||||
#define AXTLS_VERSION "esp-open-rtos axTLS " GITSHORTREV
|
||||
|
||||
#endif
|
16
common.mk
16
common.mk
|
@ -80,7 +80,7 @@ OBJDUMP = $(CROSS)objdump
|
|||
|
||||
# Source components to compile and link. Each of these are subdirectories
|
||||
# of the root, with a 'component.mk' file.
|
||||
COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip axtls core
|
||||
COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core
|
||||
|
||||
# binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking.
|
||||
SDK_LIBS ?= main net80211 phy pp wpa
|
||||
|
@ -94,14 +94,25 @@ OWN_LIBC ?= 1
|
|||
# Note: you will need a recent esp
|
||||
ENTRY_SYMBOL ?= call_user_start
|
||||
|
||||
# Set this to zero if you don't want individual function & data sections
|
||||
# (some code may be slightly slower, linking will be slighty slower,
|
||||
# but compiled code size will come down a small amount.)
|
||||
SPLIT_SECTIONS ?= 1
|
||||
|
||||
# Common flags for both C & C++_
|
||||
C_CXX_FLAGS = -Wall -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals $(CPPFLAGS)
|
||||
# Flags for C only
|
||||
CFLAGS = $(C_CXX_FLAGS) -std=gnu99
|
||||
# Flags for C++ only
|
||||
CXXFLAGS = $(C_CXX_FLAGS) -fno-exceptions -fno-rtti
|
||||
|
||||
LDFLAGS = -nostdlib -Wl,--no-check-sections -Wl,-L$(BUILD_DIR)sdklib -Wl,-L$(ROOT)lib -u $(ENTRY_SYMBOL) -Wl,-static -Wl,-Map=build/${PROGRAM}.map $(EXTRA_LDFLAGS)
|
||||
|
||||
ifeq ($(SPLIT_SECTIONS),1)
|
||||
C_CXX_FLAGS += -ffunction-sections -fdata-sections
|
||||
LDFLAGS += -Wl,-gc-sections
|
||||
endif
|
||||
|
||||
ifeq ($(FLAVOR),debug)
|
||||
C_CXX_FLAGS += -g -O0
|
||||
LDFLAGS += -g -O0
|
||||
|
@ -159,7 +170,7 @@ ifeq ($(OTA),0)
|
|||
# for non-OTA, we create two different files for uploading into the flash
|
||||
# these are the names and options to generate them
|
||||
FW_ADDR_1 = 0x00000
|
||||
FW_ADDR_2 = 0x40000
|
||||
FW_ADDR_2 = 0x20000
|
||||
FW_FILE_1 = $(addprefix $(FW_BASE),$(FW_ADDR_1).bin)
|
||||
FW_FILE_2 = $(addprefix $(FW_BASE),$(FW_ADDR_2).bin)
|
||||
else
|
||||
|
@ -263,6 +274,7 @@ $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.S $$($(1)_MAKEFILE) $(wildcard $(ROOT)*
|
|||
$(vecho) "AS $$<"
|
||||
$(Q) mkdir -p $$(dir $$@)
|
||||
$$($(1)_CC_ARGS) -c $$< -o $$@
|
||||
$$($(1)_CC_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$<
|
||||
|
||||
# the component is shown to depend on both obj and source files so we get a meaningful error message
|
||||
# for missing explicitly named source files
|
||||
|
|
27
core/esp_hwrand.c
Normal file
27
core/esp_hwrand.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* Hardware Random Number Generator Functions
|
||||
*
|
||||
* For documentation, see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Angus Gratton
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <esp/hwrand.h>
|
||||
#include <esp/wdev_regs.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Return a random 32-bit number */
|
||||
uint32_t hwrand(void)
|
||||
{
|
||||
return WDEV.HWRNG;
|
||||
}
|
||||
|
||||
/* Fill a variable size buffer with data from the Hardware RNG */
|
||||
void hwrand_fill(uint8_t *buf, size_t len)
|
||||
{
|
||||
for(size_t i = 0; i < len; i+=4) {
|
||||
uint32_t random = WDEV.HWRNG;
|
||||
/* using memcpy here in case 'buf' is unaligned */
|
||||
memcpy(buf + i, &random, (i+4 <= len) ? 4 : (len % 4));
|
||||
}
|
||||
}
|
|
@ -1,120 +1,408 @@
|
|||
/* Xtensa Exception (ie interrupt) Vectors & low-level handler code
|
||||
|
||||
Core exception handler code is placed in the .vecbase section,
|
||||
which gets picked up specially in the linker script and placed
|
||||
at beginning of IRAM.
|
||||
|
||||
The actual VecBase symbol should be the first thing in .vecbase
|
||||
(this is not strictly important as it gets set by symbol lookup not
|
||||
by hardcoded address, but having it at 0x40100000 means that the
|
||||
exception vectors have memorable offsets, which match the default
|
||||
Boot ROM vector offsets. So convenient for human understanding.
|
||||
|
||||
Part of esp-open-rtos
|
||||
Original vector contents Copyright (C) 2014-2015 Espressif Systems
|
||||
Additions Copyright (C) Superhouse Automation Pty Ltd
|
||||
BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
.text
|
||||
.section .vecbase.text, "x"
|
||||
.align 256
|
||||
.global VecBase
|
||||
.type VecBase, @function /* it's not really a function, but treat it like one */
|
||||
VecBase:
|
||||
/* IMPORTANT: exception vector literals will go here, but we
|
||||
can't have more than 4 otherwise we push DebugExceptionVector past
|
||||
offset 0x10 relative to VecBase. There should be ways to avoid this,
|
||||
and also keep the VecBase offsets easy to read, but this works for now.
|
||||
*
|
||||
* Core exception handler code is placed in the .vecbase section, which gets
|
||||
* picked up specially in the linker script and placed at beginning of IRAM.
|
||||
*
|
||||
* The actual VecBase symbol should be the first thing in .vecbase (this is not
|
||||
* strictly important as it gets set by symbol lookup not by hardcoded address,
|
||||
* but having it at 0x40100000 means that the exception vectors have memorable
|
||||
* offsets, which match the default Boot ROM vector offsets. So convenient for
|
||||
* human understanding.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Original vector contents Copyright (C) 2014-2015 Espressif Systems
|
||||
* Additions Copyright (C) Superhouse Automation Pty Ltd and Angus Gratton
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
#include "led_debug.s"
|
||||
|
||||
/* Some UserException causes, see table Table 4–64 in ISA reference */
|
||||
|
||||
#define CAUSE_SYSCALL 1
|
||||
#define CAUSE_LOADSTORE 3
|
||||
#define CAUSE_LVL1INT 4
|
||||
|
||||
.section .bss
|
||||
|
||||
NMIHandlerStack: # stack space for NMI handler
|
||||
.skip 4*0x100
|
||||
.LNMIHandlerStackTop:
|
||||
NMIRegisterSaved: # register space for saving NMI registers
|
||||
.skip 4*(16 + 6)
|
||||
|
||||
LoadStoreErrorHandlerStack:
|
||||
.word 0 # a0
|
||||
.word 0 # (unused)
|
||||
.word 0 # a2
|
||||
.word 0 # a3
|
||||
.word 0 # a4
|
||||
|
||||
/***************************** Exception Vectors *****************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Note: Exception vectors must be aligned on a 256-byte (0x100) boundary or
|
||||
* they will not function properly. (This is taken care of in the linker
|
||||
* script by ensuring .vecbase.text is aligned properly, and putting VecBase
|
||||
* right at the beginning of .vecbase.text) */
|
||||
.org 0
|
||||
VecBase:
|
||||
.global VecBase
|
||||
/* IMPORTANT: exception vector literals will go here, but we
|
||||
* can't have more than 4 otherwise we push DebugExceptionVector past
|
||||
* offset 0x10 relative to VecBase. There should be ways to avoid this,
|
||||
* and also keep the VecBase offsets easy to read, but this works for
|
||||
* now. */
|
||||
.literal_position
|
||||
.align 16
|
||||
|
||||
.org VecBase + 0x10
|
||||
DebugExceptionVector:
|
||||
wsr.excsave2 a0
|
||||
.type DebugExceptionVector, @function
|
||||
|
||||
wsr a0, excsave2
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
rfi 2
|
||||
.align 16
|
||||
|
||||
.org VecBase + 0x20
|
||||
NMIExceptionVector:
|
||||
wsr.excsave3 a0
|
||||
.type NMIExceptionVector, @function
|
||||
|
||||
wsr a0, excsave3
|
||||
call0 CallNMIExceptionHandler
|
||||
rfi 3 /* CallNMIExceptionHandler should call rfi itself */
|
||||
.align 16
|
||||
rfi 3 # Should never be reached
|
||||
|
||||
.org VecBase + 0x30
|
||||
KernelExceptionVector:
|
||||
.type KernelExceptionVector, @function
|
||||
|
||||
break 1, 0
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
rfe
|
||||
.align 16
|
||||
.L_EmptyVectorEntry:
|
||||
nop
|
||||
.align 16
|
||||
|
||||
.org VecBase + 0x50
|
||||
UserExceptionVector:
|
||||
wsr.excsave1 a0
|
||||
call0 CallUserExceptionHandler
|
||||
rfe /* CallUserExceptionHandler should call rfe itself */
|
||||
.align 16
|
||||
.L_EmptyVectorEntry2:
|
||||
nop
|
||||
.align 16
|
||||
.type UserExceptionVector, @function
|
||||
|
||||
wsr a1, excsave1
|
||||
rsr a1, exccause
|
||||
beqi a1, CAUSE_LOADSTORE, LoadStoreErrorHandler
|
||||
j UserExceptionHandler
|
||||
|
||||
.org VecBase + 0x70
|
||||
DoubleExceptionVector:
|
||||
.type DoubleExceptionVector, @function
|
||||
|
||||
break 1, 4
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
.align 16
|
||||
.L_UnusedResetVector:
|
||||
/* reset vector slot doesn't get used, as vecbase goes back to mask ROM on reset */
|
||||
nop
|
||||
|
||||
.section .bss
|
||||
NMIHandlerStack: /* stack space for NMI handler */
|
||||
.skip 4*0x100
|
||||
NMIRegisterSaved: /* register space for saving NMI registers */
|
||||
.skip 4*(0x16 + 6)
|
||||
/* Reset vector at offset 0x80 is unused, as vecbase gets reset to mask ROM
|
||||
* vectors on chip reset. */
|
||||
|
||||
/* this symbol is _Pri_3_HandlerAddress in the RTOS SDK, appears totally
|
||||
unused (stays zero at all times) */
|
||||
.global NMIHandlerAddress
|
||||
NMIHandlerAddress:
|
||||
.long 0
|
||||
/*************************** LoadStoreError Handler **************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Xtensa "Load/Store Exception" handler:
|
||||
* Completes L8/L16 load instructions from Instruction address space, for which
|
||||
* the architecture only supports 32-bit reads.
|
||||
*
|
||||
* Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause
|
||||
*
|
||||
* (Fast path (no branches) is for L8UI)
|
||||
*/
|
||||
.literal_position
|
||||
|
||||
.balign 4
|
||||
LoadStoreErrorHandler:
|
||||
.type LoadStoreErrorHandler, @function
|
||||
|
||||
/* Registers are saved in the address corresponding to their register
|
||||
* number times 4. This allows a quick and easy mapping later on when
|
||||
* needing to store the value to a particular register number. */
|
||||
movi sp, LoadStoreErrorHandlerStack
|
||||
s32i a0, sp, 0
|
||||
s32i a2, sp, 0x08
|
||||
s32i a3, sp, 0x0c
|
||||
s32i a4, sp, 0x10
|
||||
rsr a0, sar # Save SAR in a0 to restore later
|
||||
|
||||
/* Examine the opcode which generated the exception */
|
||||
/* Note: Instructions are in this order to avoid pipeline stalls. */
|
||||
rsr a2, epc1
|
||||
movi a3, ~3
|
||||
ssa8l a2 # sar is now correct shift for aligned read
|
||||
and a2, a2, a3 # a2 now 4-byte aligned address of instruction
|
||||
l32i a4, a2, 0
|
||||
l32i a2, a2, 4
|
||||
movi a3, 0x00700F # opcode mask for l8ui/l16si/l16ui
|
||||
src a2, a2, a4 # a2 now instruction that failed
|
||||
and a3, a2, a3 # a3 is masked instruction
|
||||
bnei a3, 0x000002, .LSE_check_l16
|
||||
|
||||
/* Note: At this point, opcode could technically be one of two things:
|
||||
* xx0xx2 (L8UI)
|
||||
* xx8xx2 (Reserved (invalid) opcode)
|
||||
* It is assumed that we'll never get to this point from an illegal
|
||||
* opcode, so we don't bother to check for that case and presume this
|
||||
* is always an L8UI. */
|
||||
|
||||
movi a4, ~3
|
||||
rsr a3, excvaddr # read faulting address
|
||||
and a4, a3, a4 # a4 now word aligned read address
|
||||
|
||||
l32i a4, a4, 0 # perform the actual read
|
||||
ssa8l a3 # sar is now shift to extract a3's byte
|
||||
srl a3, a4 # shift right correct distance
|
||||
extui a4, a3, 0, 8 # mask off bits we need for an l8
|
||||
|
||||
.LSE_post_fetch:
|
||||
/* We jump back here after either the L8UI or the L16*I routines do the
|
||||
* necessary work to read the value from memory.
|
||||
* At this point, a2 holds the faulting instruction and a4 holds the
|
||||
* correctly read value.
|
||||
|
||||
* Restore original SAR value (saved in a0) and update EPC so we'll
|
||||
* return back to the instruction following the one we just emulated */
|
||||
|
||||
/* Note: Instructions are in this order to avoid pipeline stalls */
|
||||
rsr a3, epc1
|
||||
wsr a0, sar
|
||||
addi a3, a3, 0x3
|
||||
wsr a3, epc1
|
||||
|
||||
/* Stupid opcode tricks: The jumptable we use later on needs 16 bytes
|
||||
* per entry (so we can avoid a second jump by just doing a RFE inside
|
||||
* each entry). Unfortunately, however, Xtensa doesn't have an addx16
|
||||
* operation to make that easy for us. Luckily, all of the faulting
|
||||
* opcodes we're processing are guaranteed to have bit 3 be zero, which
|
||||
* means if we just shift the register bits of the opcode down by 3
|
||||
* instead of 4, we will get the register number multiplied by 2. This
|
||||
* combined with an addx8 will give us an effective addx16 without
|
||||
* needing any extra shift operations. */
|
||||
extui a2, a2, 3, 5 # a2 is now destination register 0-15 times 2
|
||||
|
||||
bgei a2, 10, .LSE_assign_reg # a5..a15 use jumptable
|
||||
beqi a2, 2, .LSE_assign_a1 # a1 uses a special routine
|
||||
|
||||
/* We're storing into a0 or a2..a4, which are all saved in our "stack"
|
||||
* area. Calculate the correct address and stick the value in there,
|
||||
* then just do our normal restore and RFE (no jumps required, which
|
||||
* actually makes a0..a4 substantially faster). */
|
||||
addx2 a2, a2, sp
|
||||
s32i a4, a2, 0
|
||||
|
||||
/* Restore all regs and return */
|
||||
l32i a0, sp, 0
|
||||
l32i a2, sp, 0x08
|
||||
l32i a3, sp, 0x0c
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1 # restore a1 saved by UserExceptionVector
|
||||
rfe
|
||||
|
||||
.LSE_assign_reg:
|
||||
/* At this point, a2 contains the register number times 2, a4 is the
|
||||
* read value. */
|
||||
|
||||
/* Calculate the jumptable address, and restore all regs except a2 and
|
||||
* a4 so we have less to do after jumping. */
|
||||
/* Note: Instructions are in this order to avoid pipeline stalls. */
|
||||
movi a3, .LSE_jumptable_base
|
||||
l32i a0, sp, 0
|
||||
addx8 a2, a2, a3 # a2 is now the address to jump to
|
||||
l32i a3, sp, 0x0c
|
||||
|
||||
jx a2
|
||||
|
||||
.balign 4
|
||||
.LSE_check_l16:
|
||||
/* At this point, a2 contains the opcode, a3 is masked opcode */
|
||||
movi a4, 0x001002 # l16si or l16ui opcode after masking
|
||||
bne a3, a4, .LSE_wrong_opcode
|
||||
|
||||
/* Note: At this point, the opcode could be one of two things:
|
||||
* xx1xx2 (L16UI)
|
||||
* xx9xx2 (L16SI)
|
||||
* Both of these we can handle. */
|
||||
|
||||
movi a4, ~3
|
||||
rsr a3, excvaddr # read faulting address
|
||||
and a4, a3, a4 # a4 now word aligned read address
|
||||
|
||||
l32i a4, a4, 0 # perform the actual read
|
||||
ssa8l a3 # sar is now shift to extract a3's bytes
|
||||
srl a3, a4 # shift right correct distance
|
||||
extui a4, a3, 0, 16 # mask off bits we need for an l16
|
||||
|
||||
bbci a2, 15, .LSE_post_fetch # Not a signed op
|
||||
bbci a4, 15, .LSE_post_fetch # Value does not need sign-extension
|
||||
|
||||
movi a3, 0xFFFF0000
|
||||
or a4, a3, a4 # set 32-bit sign bits
|
||||
j .LSE_post_fetch
|
||||
|
||||
.LSE_wrong_opcode:
|
||||
/* If we got here it's not an opcode we can try to fix, so bomb out.
|
||||
* Restore registers so any dump the fatal exception routine produces
|
||||
* will have correct values */
|
||||
wsr a0, sar
|
||||
l32i a0, sp, 0
|
||||
l32i a2, sp, 0x08
|
||||
l32i a3, sp, 0x0c
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
|
||||
.balign 4
|
||||
.LSE_assign_a1:
|
||||
/* a1 is saved in excsave1, so just update that with the value, */
|
||||
wsr a4, excsave1
|
||||
/* Then restore all regs and return */
|
||||
l32i a0, sp, 0
|
||||
l32i a2, sp, 0x08
|
||||
l32i a3, sp, 0x0c
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.balign 4
|
||||
.LSE_jumptable:
|
||||
/* The first 5 entries (80 bytes) of this table are unused (registers
|
||||
* a0..a4 are handled separately above). Rather than have a whole bunch
|
||||
* of wasted space, we just pretend that the table starts 80 bytes
|
||||
* earlier in memory. */
|
||||
.set .LSE_jumptable_base, .LSE_jumptable - (16 * 5)
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 5)
|
||||
mov a5, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 6)
|
||||
mov a6, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 7)
|
||||
mov a7, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 8)
|
||||
mov a8, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 9)
|
||||
mov a9, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 10)
|
||||
mov a10, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 11)
|
||||
mov a11, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 12)
|
||||
mov a12, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 13)
|
||||
mov a13, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 14)
|
||||
mov a14, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 15)
|
||||
mov a15, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
/****************************** call_user_start ******************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* This is the first entrypoint called from the ROM after loading the image
|
||||
* into IRAM. It just sets up the VECBASE register to point at our own
|
||||
* exception vectors and then calls sdk_user_start() */
|
||||
|
||||
.literal_position
|
||||
|
||||
.balign 4
|
||||
call_user_start:
|
||||
.global call_user_start
|
||||
.type call_user_start, @function
|
||||
|
||||
movi a2, VecBase
|
||||
wsr a2, vecbase
|
||||
call0 sdk_user_start
|
||||
|
||||
/*************************** NMI Exception Handler ***************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Save register relative to a0 */
|
||||
.macro SAVE_REG register, regnum
|
||||
s32i \register, a0, (0x20 + 4 * \regnum)
|
||||
s32i \register, a0, (4 * (\regnum + 6))
|
||||
.endm
|
||||
|
||||
/* Load register relative to sp */
|
||||
.macro LOAD_REG register, regnum
|
||||
l32i \register, sp, (0x20 + 4 * \regnum)
|
||||
l32i \register, sp, (4 * (\regnum + 6))
|
||||
.endm
|
||||
|
||||
.text
|
||||
.section .vecbase.text
|
||||
.literal_position
|
||||
.align 4
|
||||
.global call_user_start
|
||||
.type call_user_start, @function
|
||||
call_user_start:
|
||||
movi a2, VecBase
|
||||
wsr.vecbase a2
|
||||
call0 sdk_user_start
|
||||
|
||||
.literal_position
|
||||
.align 16
|
||||
.type CallNMIExceptionHandler, @function
|
||||
.balign 16
|
||||
CallNMIExceptionHandler:
|
||||
.type CallNMIExceptionHandler, @function
|
||||
|
||||
movi a0, NMIRegisterSaved
|
||||
SAVE_REG a2, 2
|
||||
movi a2, NMIHandlerAddress
|
||||
l32i a2, a2, 0
|
||||
SAVE_REG sp, 1
|
||||
SAVE_REG a3, 3
|
||||
xsr.excsave3 a2 /* excsave3 is now NMIHandlerAddress, a2 is former a0 */
|
||||
rsr a2, excsave3 # a2 is now former a0
|
||||
SAVE_REG a4, 4
|
||||
SAVE_REG a2, 0
|
||||
rsr.epc1 a3
|
||||
rsr.exccause a4
|
||||
rsr a3, epc1
|
||||
rsr a4, exccause
|
||||
SAVE_REG a3, -5
|
||||
SAVE_REG a4, -4
|
||||
rsr.excvaddr a3
|
||||
rsr a3, excvaddr
|
||||
SAVE_REG a3, -3
|
||||
rsr.excsave1 a3
|
||||
rsr a3, excsave1
|
||||
SAVE_REG a3, -2
|
||||
SAVE_REG a5, 5
|
||||
SAVE_REG a6, 6
|
||||
|
@ -127,18 +415,18 @@ CallNMIExceptionHandler:
|
|||
SAVE_REG a13, 13
|
||||
SAVE_REG a14, 14
|
||||
SAVE_REG a15, 15
|
||||
movi sp, NMIRegisterSaved /* also top of NMIHandlerStack */
|
||||
movi sp, .LNMIHandlerStackTop
|
||||
movi a0, 0
|
||||
movi a2, 0x23 /* argument for handler */
|
||||
wsr.ps a2
|
||||
movi a2, 0x23 # argument for handler
|
||||
wsr a2, ps
|
||||
rsync
|
||||
rsr.sar a14
|
||||
s32i a14, sp, 0 /* this is also NMIRegisterSaved+0 */
|
||||
rsr a14, sar
|
||||
s32i a14, sp, 0 # this is also NMIRegisterSaved+0
|
||||
call0 sdk_wDev_ProcessFiq
|
||||
l32i a15, sp, 0
|
||||
wsr.sar a15
|
||||
wsr a15, sar
|
||||
movi a2, 0x33
|
||||
wsr.ps a2
|
||||
wsr a2, ps
|
||||
rsync
|
||||
LOAD_REG a4, 4
|
||||
LOAD_REG a5, 5
|
||||
|
@ -154,101 +442,98 @@ CallNMIExceptionHandler:
|
|||
LOAD_REG a15, 15
|
||||
LOAD_REG a2, -5
|
||||
LOAD_REG a3, -4
|
||||
wsr.epc1 a2
|
||||
wsr.exccause a3
|
||||
wsr a2, epc1
|
||||
wsr a3, exccause
|
||||
LOAD_REG a2, -3
|
||||
LOAD_REG a3, -2
|
||||
wsr.excvaddr a2
|
||||
wsr.excsave1 a3
|
||||
wsr a2, excvaddr
|
||||
wsr a3, excsave1
|
||||
LOAD_REG a0, 0
|
||||
/* set dport nmi status bit 0 (wDev_ProcessFiq clears & verifies this bit stays cleared,
|
||||
see http://esp8266-re.foogod.com/wiki/WDev_ProcessFiq_%28IoT_RTOS_SDK_0.9.9%29) */
|
||||
/* set dport nmi status bit 0 (wDev_ProcessFiq clears & verifies this
|
||||
* bit stays cleared, see
|
||||
* http://esp8266-re.foogod.com/wiki/WDev_ProcessFiq_%28IoT_RTOS_SDK_0.9.9%29)
|
||||
*/
|
||||
movi a2, 0x3ff00000
|
||||
movi a3, 0x1
|
||||
s32i a3, a2, 0
|
||||
LOAD_REG a2, 2
|
||||
LOAD_REG a3, 3
|
||||
LOAD_REG a1, 1
|
||||
rfi 0x3
|
||||
rfi 3
|
||||
|
||||
/* Some UserException causes, see table Table 4–64 in ISA reference */
|
||||
#define CAUSE_SYSCALL 1
|
||||
#define CAUSE_LVL1INT 4
|
||||
/*********************** General UserException Handler ***********************/
|
||||
|
||||
.type CallUserExceptionHandler, @function
|
||||
CallUserExceptionHandler:
|
||||
rsr.exccause a0
|
||||
beqi a0, CAUSE_SYSCALL, UserSyscallHandler
|
||||
mov a0, sp
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Called by UserExceptionVector if EXCCAUSE is anything other than
|
||||
* LoadStoreCause. */
|
||||
|
||||
.literal_position
|
||||
|
||||
.balign 4
|
||||
UserExceptionHandler:
|
||||
.type UserExceptionHandler, @function
|
||||
xsr a0, excsave1 # a0 now contains sp
|
||||
mov sp, a0
|
||||
addi sp, sp, -0x50
|
||||
s32i a0, sp, 0x10
|
||||
rsr.ps a0
|
||||
rsr a0, ps
|
||||
s32i a0, sp, 0x08
|
||||
rsr.epc1 a0
|
||||
rsr a0, epc1
|
||||
s32i a0, sp, 0x04
|
||||
rsr.excsave1 a0 /* a0 was saved in UserExceptionVector */
|
||||
rsr a0, excsave1
|
||||
s32i a0, sp, 0x0c
|
||||
movi a0, _xt_user_exit
|
||||
s32i a0, sp, 0x0
|
||||
call0 sdk__xt_int_enter
|
||||
movi a0, 0x23
|
||||
wsr.ps a0
|
||||
wsr a0, ps
|
||||
rsync
|
||||
rsr.exccause a2
|
||||
rsr a2, exccause
|
||||
beqi a2, CAUSE_LVL1INT, UserHandleInterrupt
|
||||
/* Any UserException cause other than level 1 interrupt triggers a panic */
|
||||
/* Any UserException cause other than level 1 interrupt should panic */
|
||||
UserFailOtherExceptionCause:
|
||||
break 1, 1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
UserHandleInterrupt:
|
||||
rsil a0, 1
|
||||
rsr.intenable a2
|
||||
rsr.interrupt a3
|
||||
rsr a2, intenable
|
||||
rsr a3, interrupt
|
||||
movi a4, 0x3fff
|
||||
and a2, a2, a3
|
||||
and a2, a2, a4 /* a2 = 0x3FFF & INTENABLE & INTERRUPT */
|
||||
and a2, a2, a4 # a2 = 0x3FFF & INTENABLE & INTERRUPT
|
||||
UserHandleTimer:
|
||||
movi a3, 0xffbf
|
||||
and a3, a2, a3 /* a3 = a2 & 0xFFBF, ie remove 0x40 from a2 if set */
|
||||
bnez a3, UserTimerDone /* bits other than 0x40 are set */
|
||||
and a3, a2, a3 # a3 = a2 with bit 6 cleared
|
||||
bnez a3, UserTimerDone # If any non-timer interrupt bits set
|
||||
movi a3, 0x40
|
||||
sub a12, a2, a3 /* a12 - a2 - 0x40 - I think a12 _must_ be zero here? */
|
||||
call0 sdk__xt_timer_int /* tick timer interrupt */
|
||||
mov a2, a12 /* restore a2 from a12, ie zero */
|
||||
sub a12, a2, a3 # a12 = a2 - 0x40 -- Will be zero if bit 6 set
|
||||
call0 sdk__xt_timer_int # tick timer interrupt
|
||||
mov a2, a12 # restore a2 from a12, ie zero
|
||||
beqz a2, UserIntDone
|
||||
UserTimerDone:
|
||||
call0 _xt_isr_handler
|
||||
bnez a2, UserHandleTimer
|
||||
UserIntDone:
|
||||
beqz a2, UserIntExit
|
||||
break 1, 1 /* non-zero remnant in a2 means fail */
|
||||
/* FIXME: this code will never be reached */
|
||||
break 1, 1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
UserIntExit:
|
||||
call0 sdk__xt_int_exit /* calls rfi */
|
||||
call0 sdk__xt_int_exit # jumps to _xt_user_exit. Never returns here
|
||||
|
||||
/* As far as I can tell, the syscall handler is basically a no-op */
|
||||
UserSyscallHandler:
|
||||
addi sp, sp, -0x10
|
||||
s32i a2, sp, 0x08
|
||||
s32i a2, sp, 0x0c
|
||||
rsr.epc1 a2
|
||||
addi a3, a2, 0x3
|
||||
wsr.epc1 a3
|
||||
l32i a2, sp, 0x8
|
||||
l32i a3, sp, 0xc
|
||||
addi sp, sp, 0x10
|
||||
movi a0, 0x7f
|
||||
movnez a2, a0, a2
|
||||
rsr.excsave1 a0
|
||||
rfe
|
||||
.section .text
|
||||
|
||||
/* _xt_user_exit is used to exit interrupt context. */
|
||||
/* TODO: Find a better place for this to live. */
|
||||
_xt_user_exit:
|
||||
.global _xt_user_exit
|
||||
.type _xt_user_exit, @function
|
||||
_xt_user_exit:
|
||||
|
||||
l32i a0, sp, 0x8
|
||||
wsr.ps a0
|
||||
wsr a0, ps
|
||||
l32i a0, sp, 0x4
|
||||
wsr.epc1 a0
|
||||
wsr a0, epc1
|
||||
l32i a0, sp, 0xc
|
||||
l32i sp, sp, 0x10
|
||||
rsync
|
||||
|
|
22
core/include/esp/hwrand.h
Normal file
22
core/include/esp/hwrand.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/** esp/hwrand.h
|
||||
*
|
||||
* Hardware Random Number Generator functions.
|
||||
*
|
||||
* For documentation, see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Angus Gratton
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _ESP_RNG_H
|
||||
#define _ESP_RNG_H
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Return a random 32-bit number */
|
||||
uint32_t hwrand(void);
|
||||
|
||||
/* Fill a variable size buffer with data from the Hardware RNG */
|
||||
void hwrand_fill(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
|
@ -2,6 +2,9 @@
|
|||
*
|
||||
* ESP8266 register definitions for the "wdev" region (0x3FF2xxx)
|
||||
*
|
||||
* In the DPORT memory space, alongside DPORT regs. However mostly
|
||||
* concerned with the WiFi hardware interface.
|
||||
*
|
||||
* Not compatible with ESP SDK register access code.
|
||||
*/
|
||||
|
||||
|
@ -21,10 +24,19 @@
|
|||
*/
|
||||
|
||||
struct WDEV_REGS {
|
||||
uint32_t volatile _unknown[768]; // 0x0000 - 0x0bfc
|
||||
uint32_t volatile _unknown0[768]; // 0x0000 - 0x0bfc
|
||||
uint32_t volatile SYS_TIME; // 0x0c00
|
||||
uint32_t volatile _unknown1[144]; // 0x0c04 - 0x0e40
|
||||
uint32_t volatile HWRNG; // 0xe44 HW RNG, see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
_Static_assert(sizeof(struct WDEV_REGS) == 0xc04, "WDEV_REGS is the wrong size");
|
||||
_Static_assert(sizeof(struct WDEV_REGS) == 0xe48, "WDEV_REGS is the wrong size");
|
||||
|
||||
/* Extra paranoid check about the HWRNG address, as if this becomes
|
||||
wrong there will be no obvious symptoms apart from a lack of
|
||||
entropy.
|
||||
*/
|
||||
_Static_assert(&WDEV.HWRNG == (void*)0x3FF20E44, "HWRNG register is at wrong address");
|
||||
|
||||
#endif /* _ESP_WDEV_REGS_H */
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
*
|
||||
* To have this work from initial reset, without needing an iomux call
|
||||
* first, choose a pin where iomux defaults to GPIO (ie 0,2,4,5)
|
||||
*
|
||||
* Current sets on=LOW, as the GPIO2 pin is active low
|
||||
*/
|
||||
LED_GPIO=2
|
||||
GPIO_DIR_SET = 0x6000030c
|
||||
|
@ -19,11 +21,11 @@ GPIO_OUT_CLEAR = 0x60000308
|
|||
.endm
|
||||
|
||||
// Turn LED on. rega, regb will be clobbered
|
||||
.macro led_on rega, regb
|
||||
.macro led_off rega, regb
|
||||
led_op \rega, \regb, GPIO_OUT_SET
|
||||
.endm
|
||||
|
||||
// Turn LED off. rega, regb will be clobbered
|
||||
.macro led_off rega, regb
|
||||
// Turn LED on. rega, regb will be clobbered
|
||||
.macro led_on rega, regb
|
||||
led_op \rega, \regb, GPIO_OUT_CLEAR
|
||||
.endm
|
||||
|
|
2
examples/experiments/unaligned_load/Makefile
Normal file
2
examples/experiments/unaligned_load/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
PROGRAM=unaligned_load
|
||||
include ../../../common.mk
|
432
examples/experiments/unaligned_load/unaligned_load.c
Normal file
432
examples/experiments/unaligned_load/unaligned_load.c
Normal file
|
@ -0,0 +1,432 @@
|
|||
/* Very basic example that just demonstrates we can run at all!
|
||||
*/
|
||||
#include "esp/rom.h"
|
||||
#include "esp/timer.h"
|
||||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include "string.h"
|
||||
#include "strings.h"
|
||||
|
||||
#define TESTSTRING "O hai there! %d %d %d"
|
||||
|
||||
const char *dramtest = TESTSTRING;
|
||||
const __attribute__((section(".iram1.notrodata"))) char iramtest[] = TESTSTRING;
|
||||
const __attribute__((section(".text.notrodata"))) char iromtest[] = TESTSTRING;
|
||||
|
||||
INLINED uint32_t get_ccount (void)
|
||||
{
|
||||
uint32_t ccount;
|
||||
asm volatile ("rsr.ccount %0" : "=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
typedef void (* test_with_fn_t)(const char *string);
|
||||
|
||||
char buf[64];
|
||||
|
||||
void test_memcpy_aligned(const char *string)
|
||||
{
|
||||
memcpy(buf, string, 16);
|
||||
}
|
||||
|
||||
void test_memcpy_unaligned(const char *string)
|
||||
{
|
||||
memcpy(buf, string, 15);
|
||||
}
|
||||
|
||||
void test_memcpy_unaligned2(const char *string)
|
||||
{
|
||||
memcpy(buf, string+1, 15);
|
||||
}
|
||||
|
||||
void test_strcpy(const char *string)
|
||||
{
|
||||
strcpy(buf, string);
|
||||
}
|
||||
|
||||
void test_sprintf(const char *string)
|
||||
{
|
||||
sprintf(buf, string, 1, 2, 3);
|
||||
}
|
||||
|
||||
void test_sprintf_arg(const char *string)
|
||||
{
|
||||
sprintf(buf, "%s", string);
|
||||
}
|
||||
|
||||
void test_naive_strcpy(const char *string)
|
||||
{
|
||||
char *to = buf;
|
||||
while((*to++ = *string++))
|
||||
;
|
||||
}
|
||||
|
||||
void test_naive_strcpy_a0(const char *string)
|
||||
{
|
||||
asm volatile (
|
||||
" mov a8, %0 \n"
|
||||
" mov a9, %1 \n"
|
||||
"tns_loop%=: l8ui a0, a9, 0 \n"
|
||||
" addi.n a9, a9, 1 \n"
|
||||
" s8i a0, a8, 0 \n"
|
||||
" addi.n a8, a8, 1 \n"
|
||||
" bnez a0, tns_loop%=\n"
|
||||
: : "r" (buf), "r" (string) : "a0", "a8", "a9");
|
||||
}
|
||||
|
||||
void test_naive_strcpy_a2(const char *string)
|
||||
{
|
||||
asm volatile (
|
||||
" mov a8, %0 \n"
|
||||
" mov a9, %1 \n"
|
||||
"tns_loop%=: l8ui a2, a9, 0 \n"
|
||||
" addi.n a9, a9, 1 \n"
|
||||
" s8i a2, a8, 0 \n"
|
||||
" addi.n a8, a8, 1 \n"
|
||||
" bnez a2, tns_loop%=\n"
|
||||
: : "r" (buf), "r" (string) : "a2", "a8", "a9");
|
||||
}
|
||||
|
||||
void test_naive_strcpy_a3(const char *string)
|
||||
{
|
||||
asm volatile (
|
||||
" mov a8, %0 \n"
|
||||
" mov a9, %1 \n"
|
||||
"tns_loop%=: l8ui a3, a9, 0 \n"
|
||||
" addi.n a9, a9, 1 \n"
|
||||
" s8i a3, a8, 0 \n"
|
||||
" addi.n a8, a8, 1 \n"
|
||||
" bnez a3, tns_loop%=\n"
|
||||
: : "r" (buf), "r" (string) : "a3", "a8", "a9");
|
||||
}
|
||||
|
||||
void test_naive_strcpy_a4(const char *string)
|
||||
{
|
||||
asm volatile (
|
||||
" mov a8, %0 \n"
|
||||
" mov a9, %1 \n"
|
||||
"tns_loop%=: l8ui a4, a9, 0 \n"
|
||||
" addi.n a9, a9, 1 \n"
|
||||
" s8i a4, a8, 0 \n"
|
||||
" addi.n a8, a8, 1 \n"
|
||||
" bnez a4, tns_loop%=\n"
|
||||
: : "r" (buf), "r" (string) : "a4", "a8", "a9");
|
||||
}
|
||||
|
||||
void test_naive_strcpy_a5(const char *string)
|
||||
{
|
||||
asm volatile (
|
||||
" mov a8, %0 \n"
|
||||
" mov a9, %1 \n"
|
||||
"tns_loop%=: l8ui a5, a9, 0 \n"
|
||||
" addi.n a9, a9, 1 \n"
|
||||
" s8i a5, a8, 0 \n"
|
||||
" addi.n a8, a8, 1 \n"
|
||||
" bnez a5, tns_loop%=\n"
|
||||
: : "r" (buf), "r" (string) : "a5", "a8", "a9");
|
||||
}
|
||||
|
||||
void test_naive_strcpy_a6(const char *string)
|
||||
{
|
||||
asm volatile (
|
||||
" mov a8, %0 \n"
|
||||
" mov a9, %1 \n"
|
||||
"tns_loop%=: l8ui a6, a9, 0 \n"
|
||||
" addi.n a9, a9, 1 \n"
|
||||
" s8i a6, a8, 0 \n"
|
||||
" addi.n a8, a8, 1 \n"
|
||||
" bnez a6, tns_loop%=\n"
|
||||
: : "r" (buf), "r" (string) : "a6", "a8", "a9");
|
||||
}
|
||||
|
||||
void test_l16si(const char *string)
|
||||
{
|
||||
/* This follows most of the l16si path, but as the
|
||||
values in the string are all 7 bit none of them get sign extended.
|
||||
|
||||
See separate test_sign_extension function which validates
|
||||
sign extension works as expected.
|
||||
*/
|
||||
int16_t *src_int16 = (int16_t *)string;
|
||||
int32_t *dst_int32 = (int32_t *)buf;
|
||||
dst_int32[0] = src_int16[0];
|
||||
dst_int32[1] = src_int16[1];
|
||||
dst_int32[2] = src_int16[2];
|
||||
}
|
||||
|
||||
#define TEST_REPEATS 1000
|
||||
|
||||
void test_noop(const char *string)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t IRAM run_test(const char *string, test_with_fn_t testfn, const char *testfn_label, uint32_t nullvalue, bool evict_cache)
|
||||
{
|
||||
printf(" .. against %30s: ", testfn_label);
|
||||
vPortEnterCritical();
|
||||
uint32_t before = get_ccount();
|
||||
for(int i = 0; i < TEST_REPEATS; i++) {
|
||||
testfn(string);
|
||||
if(evict_cache) {
|
||||
Cache_Read_Disable();
|
||||
Cache_Read_Enable(0,0,1);
|
||||
}
|
||||
}
|
||||
uint32_t after = get_ccount();
|
||||
vPortExitCritical();
|
||||
uint32_t instructions = (after-before)/TEST_REPEATS - nullvalue;
|
||||
printf("%5d instructions\r\n", instructions);
|
||||
return instructions;
|
||||
}
|
||||
|
||||
void test_string(const char *string, char *label, bool evict_cache)
|
||||
{
|
||||
printf("Testing %s (%p) '%s'\r\n", label, string, string);
|
||||
printf("Formats as: '");
|
||||
printf(string, 1, 2, 3);
|
||||
printf("'\r\n");
|
||||
uint32_t nullvalue = run_test(string, test_noop, "null op", 0, evict_cache);
|
||||
run_test(string, test_memcpy_aligned, "memcpy - aligned len", nullvalue, evict_cache);
|
||||
run_test(string, test_memcpy_unaligned, "memcpy - unaligned len", nullvalue, evict_cache);
|
||||
run_test(string, test_memcpy_unaligned2, "memcpy - unaligned start&len", nullvalue, evict_cache);
|
||||
run_test(string, test_strcpy, "strcpy", nullvalue, evict_cache);
|
||||
run_test(string, test_naive_strcpy, "naive strcpy", nullvalue, evict_cache);
|
||||
run_test(string, test_naive_strcpy_a0, "naive strcpy (a0)", nullvalue, evict_cache);
|
||||
run_test(string, test_naive_strcpy_a2, "naive strcpy (a2)", nullvalue, evict_cache);
|
||||
run_test(string, test_naive_strcpy_a3, "naive strcpy (a3)", nullvalue, evict_cache);
|
||||
run_test(string, test_naive_strcpy_a4, "naive strcpy (a4)", nullvalue, evict_cache);
|
||||
run_test(string, test_naive_strcpy_a5, "naive strcpy (a5)", nullvalue, evict_cache);
|
||||
run_test(string, test_naive_strcpy_a6, "naive strcpy (a6)", nullvalue, evict_cache);
|
||||
run_test(string, test_sprintf, "sprintf", nullvalue, evict_cache);
|
||||
run_test(string, test_sprintf_arg, "sprintf format arg", nullvalue, evict_cache);
|
||||
run_test(string, test_l16si, "load as l16si", nullvalue, evict_cache);
|
||||
}
|
||||
|
||||
static void test_isr();
|
||||
static void test_sign_extension();
|
||||
static void test_system_interaction();
|
||||
void sanity_tests(void);
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
|
||||
|
||||
gpio_enable(2, GPIO_OUTPUT); /* used for LED debug */
|
||||
gpio_write(2, 1); /* active low */
|
||||
|
||||
printf("\r\n\r\nSDK version:%s\r\n", sdk_system_get_sdk_version());
|
||||
sanity_tests();
|
||||
test_string(dramtest, "DRAM", 0);
|
||||
test_string(iramtest, "IRAM", 0);
|
||||
test_string(iromtest, "Cached flash", 0);
|
||||
test_string(iromtest, "'Uncached' flash", 1);
|
||||
|
||||
test_isr();
|
||||
test_sign_extension();
|
||||
|
||||
xTaskHandle taskHandle;
|
||||
xTaskCreate(test_system_interaction, (signed char *)"interactionTask", 256, &taskHandle, 2, NULL);
|
||||
}
|
||||
|
||||
static volatile bool frc1_ran;
|
||||
static volatile bool frc1_finished;
|
||||
static volatile char frc1_buf[80];
|
||||
|
||||
static void frc1_interrupt_handler(void)
|
||||
{
|
||||
frc1_ran = true;
|
||||
timer_set_run(FRC1, false);
|
||||
strcpy((char *)frc1_buf, iramtest);
|
||||
frc1_finished = true;
|
||||
}
|
||||
|
||||
static void test_isr()
|
||||
{
|
||||
printf("Testing behaviour inside ISRs...\r\n");
|
||||
timer_set_interrupts(FRC1, false);
|
||||
timer_set_run(FRC1, false);
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
||||
timer_set_frequency(FRC1, 1000);
|
||||
timer_set_interrupts(FRC1, true);
|
||||
timer_set_run(FRC1, true);
|
||||
sdk_os_delay_us(2000);
|
||||
|
||||
if(!frc1_ran)
|
||||
printf("ERROR: FRC1 timer exception never fired.\r\n");
|
||||
else if(!frc1_finished)
|
||||
printf("ERROR: FRC1 timer exception never finished.\r\n");
|
||||
else if(strcmp((char *)frc1_buf, iramtest))
|
||||
printf("ERROR: FRC1 strcpy from IRAM failed.\r\n");
|
||||
else
|
||||
printf("PASSED\r\n");
|
||||
}
|
||||
|
||||
const volatile __attribute__((section(".iram1.notliterals"))) int16_t unsigned_shorts[] = { -3, -4, -5, -32767, 44 };
|
||||
|
||||
static void test_sign_extension()
|
||||
{
|
||||
/* this step seems to be necessary so the compiler will actually generate l16si */
|
||||
int16_t *shorts_p = (int16_t *)unsigned_shorts;
|
||||
if(shorts_p[0] == -3 && shorts_p[1] == -4 && shorts_p[2] == -5 && shorts_p[3] == -32767 && shorts_p[4] == 44)
|
||||
{
|
||||
printf("l16si sign extension PASSED.\r\n");
|
||||
} else {
|
||||
printf("ERROR: l16si sign extension failed. Got values %d %d %d %d %d\r\n", shorts_p[0], shorts_p[1], shorts_p[2], shorts_p[3], shorts_p[4]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* test that running unaligned loads in a running FreeRTOS system doesn't break things
|
||||
|
||||
The following tests run inside a FreeRTOS task, after everything else.
|
||||
*/
|
||||
static void test_system_interaction()
|
||||
{
|
||||
uint32_t start = xTaskGetTickCount();
|
||||
printf("Starting system/timer interaction test (takes approx 30 seconds)...\n");
|
||||
for(int i = 0; i < 200*1000; i++) {
|
||||
test_naive_strcpy_a0(iromtest);
|
||||
test_naive_strcpy_a2(iromtest);
|
||||
test_naive_strcpy_a3(iromtest);
|
||||
test_naive_strcpy_a4(iromtest);
|
||||
test_naive_strcpy_a5(iromtest);
|
||||
test_naive_strcpy_a6(iromtest);
|
||||
/*
|
||||
const volatile char *string = iromtest;
|
||||
volatile char *to = dest;
|
||||
while((*to++ = *string++))
|
||||
;
|
||||
*/
|
||||
}
|
||||
uint32_t ticks = xTaskGetTickCount() - start;
|
||||
printf("Timer interaction test PASSED after %dms.\n", ticks*portTICK_RATE_MS);
|
||||
while(1) {}
|
||||
}
|
||||
|
||||
/* The following "sanity tests" are designed to try to execute every code path
|
||||
* of the LoadStoreError handler, with a variety of offsets and data values
|
||||
* designed to catch any mask/shift errors, sign-extension bugs, etc */
|
||||
|
||||
/* (Contrary to expectations, 'mov a15, a15' in Xtensa is not technically a
|
||||
* no-op, but is officially "undefined and reserved for future use", so we need
|
||||
* a special case in the case where reg == "a15" so we don't end up generating
|
||||
* those opcodes. GCC is smart enough to optimize away the whole conditional
|
||||
* and just insert the correct asm block, since `reg` is a static argument.) */
|
||||
#define LOAD_VIA_REG(op, reg, addr, var) \
|
||||
if (strcmp(reg, "a15")) { \
|
||||
asm volatile ( \
|
||||
"mov a15, " reg "\n\t" \
|
||||
op " " reg ", %1, 0\n\t" \
|
||||
"mov %0, " reg "\n\t" \
|
||||
"mov " reg ", a15\n\t" \
|
||||
: "=r" (var) : "r" (addr) : "a15" ); \
|
||||
} else { \
|
||||
asm volatile ( \
|
||||
op " " reg ", %1, 0\n\t" \
|
||||
"mov %0, " reg "\n\t" \
|
||||
: "=r" (var) : "r" (addr) : "a15" ); \
|
||||
}
|
||||
|
||||
#define TEST_LOAD(op, reg, addr, value) \
|
||||
{ \
|
||||
int32_t result; \
|
||||
LOAD_VIA_REG(op, reg, addr, result); \
|
||||
if (result != value) sanity_test_failed(op, reg, addr, value, result); \
|
||||
}
|
||||
|
||||
void sanity_test_failed(const char *testname, const char *reg, const void *addr, int32_t value, int32_t result) {
|
||||
uint32_t actual_data = *(uint32_t *)((uint32_t)addr & 0xfffffffc);
|
||||
|
||||
printf("*** SANITY TEST FAILED: '%s %s' from %p (underlying 32-bit value: 0x%x): Expected 0x%08x (%d), got 0x%08x (%d)\n", testname, reg, addr, actual_data, value, value, result, result);
|
||||
}
|
||||
|
||||
const __attribute__((section(".iram1.notrodata"))) char sanity_test_data[] = {
|
||||
0x01, 0x55, 0x7e, 0x2a, 0x81, 0xd5, 0xfe, 0xaa
|
||||
};
|
||||
|
||||
void sanity_test_l8ui(const void *addr, int32_t value) {
|
||||
TEST_LOAD("l8ui", "a0", addr, value);
|
||||
TEST_LOAD("l8ui", "a1", addr, value);
|
||||
TEST_LOAD("l8ui", "a2", addr, value);
|
||||
TEST_LOAD("l8ui", "a3", addr, value);
|
||||
TEST_LOAD("l8ui", "a4", addr, value);
|
||||
TEST_LOAD("l8ui", "a5", addr, value);
|
||||
TEST_LOAD("l8ui", "a6", addr, value);
|
||||
TEST_LOAD("l8ui", "a7", addr, value);
|
||||
TEST_LOAD("l8ui", "a8", addr, value);
|
||||
TEST_LOAD("l8ui", "a9", addr, value);
|
||||
TEST_LOAD("l8ui", "a10", addr, value);
|
||||
TEST_LOAD("l8ui", "a11", addr, value);
|
||||
TEST_LOAD("l8ui", "a12", addr, value);
|
||||
TEST_LOAD("l8ui", "a13", addr, value);
|
||||
TEST_LOAD("l8ui", "a14", addr, value);
|
||||
TEST_LOAD("l8ui", "a15", addr, value);
|
||||
}
|
||||
|
||||
void sanity_test_l16ui(const void *addr, int32_t value) {
|
||||
TEST_LOAD("l16ui", "a0", addr, value);
|
||||
TEST_LOAD("l16ui", "a1", addr, value);
|
||||
TEST_LOAD("l16ui", "a2", addr, value);
|
||||
TEST_LOAD("l16ui", "a3", addr, value);
|
||||
TEST_LOAD("l16ui", "a4", addr, value);
|
||||
TEST_LOAD("l16ui", "a5", addr, value);
|
||||
TEST_LOAD("l16ui", "a6", addr, value);
|
||||
TEST_LOAD("l16ui", "a7", addr, value);
|
||||
TEST_LOAD("l16ui", "a8", addr, value);
|
||||
TEST_LOAD("l16ui", "a9", addr, value);
|
||||
TEST_LOAD("l16ui", "a10", addr, value);
|
||||
TEST_LOAD("l16ui", "a11", addr, value);
|
||||
TEST_LOAD("l16ui", "a12", addr, value);
|
||||
TEST_LOAD("l16ui", "a13", addr, value);
|
||||
TEST_LOAD("l16ui", "a14", addr, value);
|
||||
TEST_LOAD("l16ui", "a15", addr, value);
|
||||
}
|
||||
|
||||
void sanity_test_l16si(const void *addr, int32_t value) {
|
||||
TEST_LOAD("l16si", "a0", addr, value);
|
||||
TEST_LOAD("l16si", "a1", addr, value);
|
||||
TEST_LOAD("l16si", "a2", addr, value);
|
||||
TEST_LOAD("l16si", "a3", addr, value);
|
||||
TEST_LOAD("l16si", "a4", addr, value);
|
||||
TEST_LOAD("l16si", "a5", addr, value);
|
||||
TEST_LOAD("l16si", "a6", addr, value);
|
||||
TEST_LOAD("l16si", "a7", addr, value);
|
||||
TEST_LOAD("l16si", "a8", addr, value);
|
||||
TEST_LOAD("l16si", "a9", addr, value);
|
||||
TEST_LOAD("l16si", "a10", addr, value);
|
||||
TEST_LOAD("l16si", "a11", addr, value);
|
||||
TEST_LOAD("l16si", "a12", addr, value);
|
||||
TEST_LOAD("l16si", "a13", addr, value);
|
||||
TEST_LOAD("l16si", "a14", addr, value);
|
||||
TEST_LOAD("l16si", "a15", addr, value);
|
||||
}
|
||||
|
||||
void sanity_tests(void) {
|
||||
printf("== Performing sanity tests (sanity_test_data @ %p)...\n", sanity_test_data);
|
||||
|
||||
sanity_test_l8ui(sanity_test_data + 0, 0x01);
|
||||
sanity_test_l8ui(sanity_test_data + 1, 0x55);
|
||||
sanity_test_l8ui(sanity_test_data + 2, 0x7e);
|
||||
sanity_test_l8ui(sanity_test_data + 3, 0x2a);
|
||||
sanity_test_l8ui(sanity_test_data + 4, 0x81);
|
||||
sanity_test_l8ui(sanity_test_data + 5, 0xd5);
|
||||
sanity_test_l8ui(sanity_test_data + 6, 0xfe);
|
||||
sanity_test_l8ui(sanity_test_data + 7, 0xaa);
|
||||
|
||||
sanity_test_l16ui(sanity_test_data + 0, 0x5501);
|
||||
sanity_test_l16ui(sanity_test_data + 2, 0x2a7e);
|
||||
sanity_test_l16ui(sanity_test_data + 4, 0xd581);
|
||||
sanity_test_l16ui(sanity_test_data + 6, 0xaafe);
|
||||
|
||||
sanity_test_l16si(sanity_test_data + 0, 0x5501);
|
||||
sanity_test_l16si(sanity_test_data + 2, 0x2a7e);
|
||||
sanity_test_l16si(sanity_test_data + 4, -10879);
|
||||
sanity_test_l16si(sanity_test_data + 6, -21762);
|
||||
|
||||
printf("== Sanity tests completed.\n");
|
||||
}
|
4
examples/http_get_mbedtls/Makefile
Normal file
4
examples/http_get_mbedtls/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
PROGRAM=http_get_mbedtls
|
||||
COMPONENTS = FreeRTOS lwip core extras/mbedtls
|
||||
|
||||
include ../../common.mk
|
39
examples/http_get_mbedtls/cert.c
Normal file
39
examples/http_get_mbedtls/cert.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* This is the root certificate for the CA trust chain of
|
||||
www.howsmyssl.com in PEM format, as dumped via:
|
||||
|
||||
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
|
||||
|
||||
The root cert is the last cert in the chain output by the server.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n"
|
||||
"MIIEWTCCA0GgAwIBAgIDAjpjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\r\n"
|
||||
"MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\r\n"
|
||||
"YWwgQ0EwHhcNMTIwODI3MjA0MDQwWhcNMjIwNTIwMjA0MDQwWjBEMQswCQYDVQQG\r\n"
|
||||
"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg\r\n"
|
||||
"U1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5J/lP\r\n"
|
||||
"2Pa3FT+Pzc7WjRxr/X/aVCFOA9jK0HJSFbjJgltYeYT/JHJv8ml/vJbZmnrDPqnP\r\n"
|
||||
"UCITDoYZ2+hJ74vm1kfy/XNFCK6PrF62+J589xD/kkNm7xzU7qFGiBGJSXl6Jc5L\r\n"
|
||||
"avDXHHYaKTzJ5P0ehdzgMWUFRxasCgdLLnBeawanazpsrwUSxLIRJdY+lynwg2xX\r\n"
|
||||
"HNil78zs/dYS8T/bQLSuDxjTxa9Akl0HXk7+Yhc3iemLdCai7bgK52wVWzWQct3Y\r\n"
|
||||
"TSHUQCNcj+6AMRaraFX0DjtU6QRN8MxOgV7pb1JpTr6mFm1C9VH/4AtWPJhPc48O\r\n"
|
||||
"bxoj8cnI2d+87FLXAgMBAAGjggFUMIIBUDAfBgNVHSMEGDAWgBTAephojYn7qwVk\r\n"
|
||||
"DBF9qn1luMrMTjAdBgNVHQ4EFgQUEUrQcznVW2kIXLo9v2SaqIscVbwwEgYDVR0T\r\n"
|
||||
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2gK4Yp\r\n"
|
||||
"aHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYB\r\n"
|
||||
"BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20w\r\n"
|
||||
"TAYDVR0gBEUwQzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93\r\n"
|
||||
"d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwKgYDVR0RBCMwIaQfMB0xGzAZ\r\n"
|
||||
"BgNVBAMTElZlcmlTaWduTVBLSS0yLTI1NDANBgkqhkiG9w0BAQUFAAOCAQEAPOU9\r\n"
|
||||
"WhuiNyrjRs82lhg8e/GExVeGd0CdNfAS8HgY+yKk3phLeIHmTYbjkQ9C47ncoNb/\r\n"
|
||||
"qfixeZeZ0cNsQqWSlOBdDDMYJckrlVPg5akMfUf+f1ExRF73Kh41opQy98nuwLbG\r\n"
|
||||
"mqzemSFqI6A4ZO6jxIhzMjtQzr+t03UepvTp+UJrYLLdRf1dVwjOLVDmEjIWE4ry\r\n"
|
||||
"lKKbR6iGf9mY5ffldnRk2JG8hBYo2CVEMH6C2Kyx5MDkFWzbtiQnAioBEoW6MYhY\r\n"
|
||||
"R3TjuNJkpsMyWS4pS0XxW4lJLoKaxhgVRNAuZAEVaDj59vlmAwxVG52/AECu8Egn\r\n"
|
||||
"TOCAXi25KhV6vGb4NQ==\r\n"
|
||||
"-----END CERTIFICATE-----\r\n";
|
||||
|
||||
|
347
examples/http_get_mbedtls/http_get_mbedtls.c
Normal file
347
examples/http_get_mbedtls/http_get_mbedtls.c
Normal file
|
@ -0,0 +1,347 @@
|
|||
/* http_get_mbedtls - HTTPS version of the http_get example, using mbed TLS.
|
||||
*
|
||||
* Retrieves a JSON response from the howsmyssl.com API via HTTPS over TLS v1.2.
|
||||
*
|
||||
* Validates the server's certificate using the root CA loaded (in PEM format) in cert.c.
|
||||
*
|
||||
* Adapted from the ssl_client1 example in mbedtls.
|
||||
*
|
||||
* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved, Apache 2.0 License.
|
||||
* Additions Copyright (C) 2015 Angus Gratton, Apache 2.0 License.
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
#include "ssid_config.h"
|
||||
|
||||
/* mbedtls/config.h MUST appear before all other mbedtls headers, or
|
||||
you'll get the default config.
|
||||
|
||||
(Although mostly that isn't a big problem, you just might get
|
||||
errors at link time if functions don't exist.) */
|
||||
#include "mbedtls/config.h"
|
||||
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/certs.h"
|
||||
|
||||
#define WEB_SERVER "howsmyssl.com"
|
||||
#define WEB_PORT "443"
|
||||
#define WEB_URL "https://www.howsmyssl.com/a/check"
|
||||
|
||||
#define GET_REQUEST "GET "WEB_URL" HTTP/1.1\n\n"
|
||||
|
||||
/* Root cert for howsmyssl.com, stored in cert.c */
|
||||
extern const char *server_root_cert;
|
||||
|
||||
/* MBEDTLS_DEBUG_C disabled by default to save substantial bloating of
|
||||
* firmware, define it in
|
||||
* examples/http_get_mbedtls/include/mbedtls/config.h if you'd like
|
||||
* debugging output.
|
||||
*/
|
||||
#ifdef MBEDTLS_DEBUG_C
|
||||
|
||||
|
||||
/* Increase this value to see more TLS debug details,
|
||||
0 prints nothing, 1 will print any errors, 4 will print _everything_
|
||||
*/
|
||||
#define DEBUG_LEVEL 4
|
||||
|
||||
static void my_debug(void *ctx, int level,
|
||||
const char *file, int line,
|
||||
const char *str)
|
||||
{
|
||||
((void) level);
|
||||
|
||||
/* Shorten 'file' from the whole file path to just the filename
|
||||
|
||||
This is a bit wasteful because the macros are compiled in with
|
||||
the full _FILE_ path in each case, so the firmware is bloated out
|
||||
by a few kb. But there's not a lot we can do about it...
|
||||
*/
|
||||
char *file_sep = rindex(file, '/');
|
||||
if(file_sep)
|
||||
file = file_sep+1;
|
||||
|
||||
printf("%s:%04d: %s", file, line, str);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
|
||||
void http_get_task(void *pvParameters)
|
||||
{
|
||||
int successes = 0, failures = 0, ret;
|
||||
printf("HTTP get task starting...\n");
|
||||
|
||||
uint32_t flags;
|
||||
unsigned char buf[1024];
|
||||
const char *pers = "ssl_client1";
|
||||
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_x509_crt cacert;
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_net_context server_fd;
|
||||
|
||||
/*
|
||||
* 0. Initialize the RNG and the session data
|
||||
*/
|
||||
mbedtls_ssl_init(&ssl);
|
||||
mbedtls_x509_crt_init(&cacert);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
printf("\n . Seeding the random number generator...");
|
||||
fflush(stdout);
|
||||
|
||||
mbedtls_ssl_config_init(&conf);
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||
(const unsigned char *) pers,
|
||||
strlen(pers))) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
||||
while(1) {} /* todo: replace with abort() */
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
/*
|
||||
* 0. Initialize certificates
|
||||
*/
|
||||
printf(" . Loading the CA root certificate ...");
|
||||
fflush(stdout);
|
||||
|
||||
ret = mbedtls_x509_crt_parse(&cacert, (uint8_t*)server_root_cert, strlen(server_root_cert)+1);
|
||||
if(ret < 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
||||
while(1) {} /* todo: replace with abort() */
|
||||
}
|
||||
|
||||
printf(" ok (%d skipped)\n", ret);
|
||||
|
||||
/* Hostname set here should match CN in server certificate */
|
||||
if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
|
||||
while(1) {} /* todo: replace with abort() */
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. Setup stuff
|
||||
*/
|
||||
printf(" . Setting up the SSL/TLS structure...");
|
||||
fflush(stdout);
|
||||
|
||||
if((ret = mbedtls_ssl_config_defaults(&conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
/* OPTIONAL is not optimal for security, in this example it will print
|
||||
a warning if CA verification fails but it will continue to connect.
|
||||
*/
|
||||
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
|
||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
#ifdef MBEDTLS_DEBUG_C
|
||||
mbedtls_debug_set_threshold(DEBUG_LEVEL);
|
||||
mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
|
||||
#endif
|
||||
|
||||
if((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Wait until we can resolve the DNS for the server, as an indication
|
||||
our network is probably working...
|
||||
*/
|
||||
printf("Waiting for server DNS to resolve... ");
|
||||
fflush(stdout);
|
||||
err_t dns_err;
|
||||
ip_addr_t host_ip;
|
||||
do {
|
||||
vTaskDelay(500 / portTICK_RATE_MS);
|
||||
dns_err = netconn_gethostbyname(WEB_SERVER, &host_ip);
|
||||
} while(dns_err != ERR_OK);
|
||||
printf("done.\n");
|
||||
|
||||
while(1) {
|
||||
mbedtls_net_init(&server_fd);
|
||||
printf("top of loop, free heap = %u\n", xPortGetFreeHeapSize());
|
||||
/*
|
||||
* 1. Start the connection
|
||||
*/
|
||||
printf(" . Connecting to %s:%s...", WEB_SERVER, WEB_PORT);
|
||||
fflush(stdout);
|
||||
|
||||
if((ret = mbedtls_net_connect(&server_fd, WEB_SERVER,
|
||||
WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
/*
|
||||
* 4. Handshake
|
||||
*/
|
||||
printf(" . Performing the SSL/TLS handshake...");
|
||||
fflush(stdout);
|
||||
|
||||
while((ret = mbedtls_ssl_handshake(&ssl)) != 0)
|
||||
{
|
||||
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
/*
|
||||
* 5. Verify the server certificate
|
||||
*/
|
||||
printf(" . Verifying peer X.509 certificate...");
|
||||
|
||||
/* In real life, we probably want to bail out when ret != 0 */
|
||||
if((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0)
|
||||
{
|
||||
char vrfy_buf[512];
|
||||
|
||||
printf(" failed\n");
|
||||
|
||||
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
|
||||
|
||||
printf("%s\n", vrfy_buf);
|
||||
}
|
||||
else
|
||||
printf(" ok\n");
|
||||
|
||||
/*
|
||||
* 3. Write the GET request
|
||||
*/
|
||||
printf(" > Write to server:");
|
||||
fflush(stdout);
|
||||
|
||||
int len = sprintf((char *) buf, GET_REQUEST);
|
||||
|
||||
while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0)
|
||||
{
|
||||
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
len = ret;
|
||||
printf(" %d bytes written\n\n%s", len, (char *) buf);
|
||||
|
||||
/*
|
||||
* 7. Read the HTTP response
|
||||
*/
|
||||
printf(" < Read from server:");
|
||||
fflush(stdout);
|
||||
|
||||
do
|
||||
{
|
||||
len = sizeof(buf) - 1;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ret = mbedtls_ssl_read(&ssl, buf, len);
|
||||
|
||||
if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
continue;
|
||||
|
||||
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if(ret < 0)
|
||||
{
|
||||
printf("failed\n ! mbedtls_ssl_read returned %d\n\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
if(ret == 0)
|
||||
{
|
||||
printf("\n\nEOF\n\n");
|
||||
break;
|
||||
}
|
||||
|
||||
len = ret;
|
||||
printf(" %d bytes read\n\n%s", len, (char *) buf);
|
||||
} while(1);
|
||||
|
||||
mbedtls_ssl_close_notify(&ssl);
|
||||
|
||||
exit:
|
||||
mbedtls_ssl_session_reset(&ssl);
|
||||
mbedtls_net_free(&server_fd);
|
||||
|
||||
if(ret != 0)
|
||||
{
|
||||
char error_buf[100];
|
||||
mbedtls_strerror(ret, error_buf, 100);
|
||||
printf("\n\nLast error was: %d - %s\n\n", ret, error_buf);
|
||||
failures++;
|
||||
} else {
|
||||
successes++;
|
||||
}
|
||||
|
||||
printf("\n\nsuccesses = %d failures = %d\n", successes, failures);
|
||||
for(int countdown = successes ? 10 : 5; countdown >= 0; countdown--) {
|
||||
printf("%d... ", countdown);
|
||||
fflush(stdout);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
}
|
||||
printf("\nStarting again!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
struct sdk_station_config config = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASS,
|
||||
};
|
||||
|
||||
/* required to call wifi_set_opmode before station_set_config */
|
||||
sdk_wifi_set_opmode(STATION_MODE);
|
||||
sdk_wifi_station_set_config(&config);
|
||||
|
||||
xTaskCreate(&http_get_task, (signed char *)"get_task", 2048, NULL, 2, NULL);
|
||||
}
|
27
examples/http_get_mbedtls/include/mbedtls/config.h
Normal file
27
examples/http_get_mbedtls/include/mbedtls/config.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* Special mbedTLS config file for http_get_mbedtls example,
|
||||
overrides supported cipher suite list.
|
||||
|
||||
Overriding the set of cipher suites saves small amounts of ROM and
|
||||
RAM, and is a good practice in general if you know what server(s)
|
||||
you want to connect to.
|
||||
|
||||
However it's extra important here because the howsmyssl API sends
|
||||
back the list of ciphers we send it as a JSON list in the, and we
|
||||
only have a 4096kB receive buffer. If the server supported maximum
|
||||
fragment length option then we wouldn't have this problem either,
|
||||
but we do so this is a good workaround.
|
||||
|
||||
The ciphers chosen below are common ECDHE ciphers, the same ones
|
||||
Firefox uses when connecting to a TLSv1.2 server.
|
||||
*/
|
||||
#ifndef MBEDTLS_CONFIG_H
|
||||
|
||||
/* include_next picks up default config from extras/mbedtls/include/mbedtls/config.h */
|
||||
#include_next<mbedtls/config.h>
|
||||
|
||||
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
||||
|
||||
/* uncomment next line to include debug output from example */
|
||||
//#define MBEDTLS_DEBUG_C
|
||||
|
||||
#endif
|
|
@ -1,2 +0,0 @@
|
|||
PROGRAM=http_get_ssl
|
||||
include ../../common.mk
|
|
@ -1,223 +0,0 @@
|
|||
/* http_get_ssl - HTTPS version of the http_get example.
|
||||
*
|
||||
* Retrieves a web page over HTTPS (TLS) using GET.
|
||||
*
|
||||
* Does not validate server certificate.
|
||||
*
|
||||
* This sample code is in the public domain.,
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include "ssl.h"
|
||||
|
||||
#include "ssid_config.h"
|
||||
|
||||
#define WEB_SERVER "192.168.0.18"
|
||||
#define WEB_PORT "8000"
|
||||
#define WEB_URL "/test"
|
||||
|
||||
static void display_cipher(SSL *ssl);
|
||||
static void display_session_id(SSL *ssl);
|
||||
|
||||
void http_get_task(void *pvParameters)
|
||||
{
|
||||
int successes = 0, failures = 0;
|
||||
SSL_CTX *ssl_ctx;
|
||||
uint32_t options = SSL_SERVER_VERIFY_LATER|SSL_DISPLAY_CERTS;
|
||||
printf("HTTP get task starting...\r\n");
|
||||
|
||||
printf("free heap = %u\r\n", xPortGetFreeHeapSize());
|
||||
if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL)
|
||||
{
|
||||
printf("Error: SSL Client context is invalid\n");
|
||||
while(1) {}
|
||||
}
|
||||
printf("Got SSL context.");
|
||||
|
||||
while(1) {
|
||||
const struct addrinfo hints = {
|
||||
.ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
};
|
||||
struct addrinfo *res;
|
||||
|
||||
printf("top of loop, free heap = %u\r\n", xPortGetFreeHeapSize());
|
||||
|
||||
printf("Running DNS lookup for %s...\r\n", WEB_SERVER);
|
||||
int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
|
||||
|
||||
if(err != 0 || res == NULL) {
|
||||
printf("DNS lookup failed err=%d res=%p\r\n", err, res);
|
||||
if(res)
|
||||
freeaddrinfo(res);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
failures++;
|
||||
continue;
|
||||
}
|
||||
/* Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
|
||||
struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
|
||||
printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr));
|
||||
|
||||
int s = socket(res->ai_family, res->ai_socktype, 0);
|
||||
if(s < 0) {
|
||||
printf("... Failed to allocate socket.\r\n");
|
||||
freeaddrinfo(res);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
failures++;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("... allocated socket\r\n");
|
||||
|
||||
if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
|
||||
close(s);
|
||||
freeaddrinfo(res);
|
||||
printf("... socket connect failed.\r\n");
|
||||
vTaskDelay(4000 / portTICK_RATE_MS);
|
||||
failures++;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("... connected. starting TLS session...\r\n");
|
||||
freeaddrinfo(res);
|
||||
|
||||
SSL *ssl = ssl_client_new(ssl_ctx, s, NULL, 0);
|
||||
printf("initial status %p %d\r\n", ssl, ssl_handshake_status(ssl));
|
||||
if((err = ssl_handshake_status(ssl)) != SSL_OK) {
|
||||
ssl_free(ssl);
|
||||
close(s);
|
||||
printf("SSL handshake failed. :( %d\r\n", err);
|
||||
vTaskDelay(4000 / portTICK_RATE_MS);
|
||||
failures++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *common_name = ssl_get_cert_dn(ssl,
|
||||
SSL_X509_CERT_COMMON_NAME);
|
||||
if (common_name)
|
||||
{
|
||||
printf("Common Name:\t\t\t%s\n", common_name);
|
||||
}
|
||||
|
||||
display_session_id(ssl);
|
||||
display_cipher(ssl);
|
||||
|
||||
const char *req =
|
||||
"GET "WEB_URL"\r\n"
|
||||
"User-Agent: esp-open-rtos/0.1 esp8266\r\n"
|
||||
"\r\n";
|
||||
if (ssl_write(ssl, (uint8_t *)req, strlen(req)) < 0) {
|
||||
printf("... socket send failed\r\n");
|
||||
ssl_free(ssl);
|
||||
close(s);
|
||||
vTaskDelay(4000 / portTICK_RATE_MS);
|
||||
failures++;
|
||||
continue;
|
||||
}
|
||||
printf("... socket send success\r\n");
|
||||
|
||||
uint8_t *recv_buf;
|
||||
int r;
|
||||
do {
|
||||
r = ssl_read(ssl, &recv_buf);
|
||||
for(int i = 0; i < r; i++)
|
||||
printf("%c", recv_buf[i]);
|
||||
} while(r > 0);
|
||||
|
||||
printf("... done reading from socket. Last read return=%d errno=%d\r\n", r, errno);
|
||||
if(r != 0)
|
||||
failures++;
|
||||
else
|
||||
successes++;
|
||||
ssl_free(ssl);
|
||||
close(s);
|
||||
printf("successes = %d failures = %d\r\n", successes, failures);
|
||||
for(int countdown = 10; countdown >= 0; countdown--) {
|
||||
printf("%d... ", countdown);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
}
|
||||
printf("\r\nStarting again!\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
struct sdk_station_config config = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASS,
|
||||
};
|
||||
|
||||
/* required to call wifi_set_opmode before station_set_config */
|
||||
sdk_wifi_set_opmode(STATION_MODE);
|
||||
sdk_wifi_station_set_config(&config);
|
||||
|
||||
xTaskCreate(&http_get_task, (signed char *)"get_task", 2048, NULL, 2, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display what session id we have.
|
||||
*/
|
||||
static void display_session_id(SSL *ssl)
|
||||
{
|
||||
int i;
|
||||
const uint8_t *session_id = ssl_get_session_id(ssl);
|
||||
int sess_id_size = ssl_get_session_id_size(ssl);
|
||||
|
||||
if (sess_id_size > 0)
|
||||
{
|
||||
printf("-----BEGIN SSL SESSION PARAMETERS-----\n");
|
||||
for (i = 0; i < sess_id_size; i++)
|
||||
{
|
||||
printf("%02x", session_id[i]);
|
||||
}
|
||||
|
||||
printf("\n-----END SSL SESSION PARAMETERS-----\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display what cipher we are using
|
||||
*/
|
||||
static void display_cipher(SSL *ssl)
|
||||
{
|
||||
printf("CIPHER is ");
|
||||
switch (ssl_get_cipher_id(ssl))
|
||||
{
|
||||
case SSL_AES128_SHA:
|
||||
printf("AES128-SHA");
|
||||
break;
|
||||
|
||||
case SSL_AES256_SHA:
|
||||
printf("AES256-SHA");
|
||||
break;
|
||||
|
||||
case SSL_RC4_128_SHA:
|
||||
printf("RC4-SHA");
|
||||
break;
|
||||
|
||||
case SSL_RC4_128_MD5:
|
||||
printf("RC4-MD5");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown - %d", ssl_get_cipher_id(ssl));
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
PROGRAM=hmac_test
|
||||
EXTRA_COMPONENTS=extras/mbedtls
|
||||
include ../../../common.mk
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "ssl.h"
|
||||
#include "mbedtls/md.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -31,9 +31,7 @@ static const uint8_t aa_80_times[] = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x
|
|||
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
||||
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa};
|
||||
|
||||
/* NOTE: Vectors 6 & 7 currently cause a fault as the axTLS
|
||||
routines don't support keys longer than the block size. */
|
||||
const uint8_t NUM_MD5_VECTORS = 5;
|
||||
const uint8_t NUM_MD5_VECTORS = 7;
|
||||
|
||||
static const struct test_vector md5_vectors[] = {
|
||||
{ /* vector 1*/
|
||||
|
@ -88,15 +86,30 @@ static const struct test_vector md5_vectors[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static void print_blob(const char *label, const uint8_t *data, const uint32_t len)
|
||||
{
|
||||
printf("%s:", label);
|
||||
for(int i = 0; i < len; i++) {
|
||||
if(i % 16 == 0)
|
||||
printf("\n%02x:", i);
|
||||
printf(" %02x", data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_md5(void)
|
||||
{
|
||||
printf("\r\nTesting MD5 vectors...\r\n");
|
||||
uint8_t test_digest[16];
|
||||
|
||||
const mbedtls_md_info_t *md5_hmac = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
|
||||
|
||||
for(int i = 0; i < NUM_MD5_VECTORS; i++) {
|
||||
const struct test_vector *vector = &md5_vectors[i];
|
||||
printf("Test case %d: ", i+1);
|
||||
hmac_md5(vector->data, vector->data_len, vector->key, vector->key_len, test_digest);
|
||||
if(memcmp(test_digest, vector->digest, 16)) {
|
||||
|
||||
uint8_t test_digest[16];
|
||||
mbedtls_md_hmac(md5_hmac, vector->key, vector->key_len, vector->data, vector->data_len, test_digest);
|
||||
|
||||
if(memcmp(vector->digest, test_digest, 16)) {
|
||||
uint8_t first = 0;
|
||||
for(first = 0; first < 16; first++) {
|
||||
if(test_digest[first] != vector->digest[first]) {
|
||||
|
|
56
extras/mbedtls/component.mk
Normal file
56
extras/mbedtls/component.mk
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Component makefile for mbedtls
|
||||
|
||||
# mbedtls by default builds into 3 libraries not one. We just use one for now (doesn't make a huge difference when static linking)
|
||||
|
||||
# Config:
|
||||
# We supply our own hand tweaked mbedtls/config.h in our 'include' dir, the rest of upstream mbedtls is not changed.
|
||||
|
||||
MBEDTLS_DIR = $(mbedtls_ROOT)mbedtls/
|
||||
INC_DIRS += $(mbedtls_ROOT)include $(MBEDTLS_DIR)include
|
||||
|
||||
# these OBJS_xxx variables are copied directly from mbedtls/mbedtls/Makefile,
|
||||
# minus a few values (noted in comments)
|
||||
#
|
||||
# If updating to a future mbedtls version you can just copy these in.
|
||||
OBJS_CRYPTO= aes.o aesni.o arc4.o \
|
||||
asn1parse.o asn1write.o base64.o \
|
||||
bignum.o blowfish.o camellia.o \
|
||||
ccm.o cipher.o cipher_wrap.o \
|
||||
ctr_drbg.o des.o dhm.o \
|
||||
ecdh.o ecdsa.o ecp.o \
|
||||
ecp_curves.o entropy.o entropy_poll.o \
|
||||
error.o gcm.o havege.o \
|
||||
hmac_drbg.o md.o md2.o \
|
||||
md4.o md5.o md_wrap.o \
|
||||
memory_buffer_alloc.o oid.o \
|
||||
padlock.o pem.o pk.o \
|
||||
pk_wrap.o pkcs12.o pkcs5.o \
|
||||
pkparse.o pkwrite.o platform.o \
|
||||
ripemd160.o rsa.o sha1.o \
|
||||
sha256.o sha512.o threading.o \
|
||||
timing.o version.o \
|
||||
version_features.o xtea.o
|
||||
# minus net.o
|
||||
|
||||
OBJS_X509= certs.o pkcs11.o x509.o \
|
||||
x509_create.o x509_crl.o x509_crt.o \
|
||||
x509_csr.o x509write_crt.o x509write_csr.o
|
||||
|
||||
OBJS_TLS= debug.o ssl_cache.o \
|
||||
ssl_ciphersuites.o ssl_cli.o \
|
||||
ssl_cookie.o ssl_srv.o ssl_ticket.o \
|
||||
ssl_tls.o
|
||||
|
||||
# args for passing into compile rule generation
|
||||
mbedtls_INC_DIR =
|
||||
mbedtls_SRC_DIR = $(mbedtls_ROOT)
|
||||
mbedtls_EXTRA_SRC_FILES = $(patsubst %.o,$(MBEDTLS_DIR)library/%.c,$(OBJS_CRYPTO) $(OBJS_X509) $(OBJS_TLS))
|
||||
|
||||
# depending on cipher configuration, some mbedTLS variables are unused
|
||||
mbedtls_CFLAGS = -Wno-error=unused-but-set-variable -Wno-error=unused-variable $(CFLAGS)
|
||||
|
||||
$(eval $(call component_compile_rules,mbedtls))
|
||||
|
||||
# Helpful error if git submodule not initialised
|
||||
$(MBEDTLS_DIR):
|
||||
$(error "mbedtls git submodule not installed. Please run 'git submodule update --init'")
|
22
extras/mbedtls/hardware_entropy.c
Normal file
22
extras/mbedtls/hardware_entropy.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* ESP8266 "Hardware RNG" (validity still being confirmed) support for ESP8266
|
||||
*
|
||||
* Based on research done by @foogod.
|
||||
*
|
||||
* Please don't rely on this too much as an entropy source, quite yet...
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Angus Gratton
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <mbedtls/entropy_poll.h>
|
||||
#include <esp/hwrand.h>
|
||||
|
||||
int mbedtls_hardware_poll( void *data,
|
||||
unsigned char *output, size_t len, size_t *olen )
|
||||
{
|
||||
(void)(data);
|
||||
hwrand_fill(output, len);
|
||||
if(olen)
|
||||
*olen = len;
|
||||
return 0;
|
||||
}
|
2446
extras/mbedtls/include/mbedtls/config.h
Normal file
2446
extras/mbedtls/include/mbedtls/config.h
Normal file
File diff suppressed because it is too large
Load diff
1
extras/mbedtls/mbedtls
Submodule
1
extras/mbedtls/mbedtls
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 0a0c22e0efcf2f8f71d7e16712f80b8f77326f72
|
510
extras/mbedtls/net_lwip.c
Normal file
510
extras/mbedtls/net_lwip.c
Normal file
|
@ -0,0 +1,510 @@
|
|||
/*
|
||||
* TCP/IP or UDP/IP networking functions
|
||||
* modified for LWIP support on ESP8266
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* Additions Copyright (C) 2015 Angus Gratton
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||
*/
|
||||
|
||||
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||
#include "mbedtls/config.h"
|
||||
#else
|
||||
#include MBEDTLS_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_NET_C)
|
||||
|
||||
#include "mbedtls/net.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Prepare for using the sockets interface
|
||||
*/
|
||||
static int net_prepare( void )
|
||||
{
|
||||
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
|
||||
!defined(EFI32)
|
||||
WSADATA wsaData;
|
||||
|
||||
if( wsa_init_done == 0 )
|
||||
{
|
||||
if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 )
|
||||
return( MBEDTLS_ERR_NET_SOCKET_FAILED );
|
||||
|
||||
wsa_init_done = 1;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a context
|
||||
*/
|
||||
void mbedtls_net_init( mbedtls_net_context *ctx )
|
||||
{
|
||||
ctx->fd = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate a TCP connection with host:port and the given protocol
|
||||
*/
|
||||
int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto )
|
||||
{
|
||||
int ret;
|
||||
struct addrinfo hints, *addr_list, *cur;
|
||||
|
||||
if( ( ret = net_prepare() ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/* Do name resolution with both IPv6 and IPv4 */
|
||||
memset( &hints, 0, sizeof( hints ) );
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
|
||||
hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
|
||||
|
||||
if( getaddrinfo( host, port, &hints, &addr_list ) != 0 )
|
||||
return( MBEDTLS_ERR_NET_UNKNOWN_HOST );
|
||||
|
||||
/* Try the sockaddrs until a connection succeeds */
|
||||
ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
|
||||
for( cur = addr_list; cur != NULL; cur = cur->ai_next )
|
||||
{
|
||||
ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype,
|
||||
cur->ai_protocol );
|
||||
if( ctx->fd < 0 )
|
||||
{
|
||||
ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( connect( ctx->fd, cur->ai_addr, cur->ai_addrlen ) == 0 )
|
||||
{
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
close( ctx->fd );
|
||||
ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
freeaddrinfo( addr_list );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a listening socket on bind_ip:port
|
||||
*/
|
||||
int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto )
|
||||
{
|
||||
int n, ret;
|
||||
struct addrinfo hints, *addr_list, *cur;
|
||||
|
||||
if( ( ret = net_prepare() ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/* Bind to IPv6 and/or IPv4, but only in the desired protocol */
|
||||
memset( &hints, 0, sizeof( hints ) );
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
|
||||
hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
|
||||
|
||||
if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 )
|
||||
return( MBEDTLS_ERR_NET_UNKNOWN_HOST );
|
||||
|
||||
/* Try the sockaddrs until a binding succeeds */
|
||||
ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
|
||||
for( cur = addr_list; cur != NULL; cur = cur->ai_next )
|
||||
{
|
||||
ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype,
|
||||
cur->ai_protocol );
|
||||
if( ctx->fd < 0 )
|
||||
{
|
||||
ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
n = 1;
|
||||
if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *) &n, sizeof( n ) ) != 0 )
|
||||
{
|
||||
close( ctx->fd );
|
||||
ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( bind( ctx->fd, cur->ai_addr, cur->ai_addrlen ) != 0 )
|
||||
{
|
||||
close( ctx->fd );
|
||||
ret = MBEDTLS_ERR_NET_BIND_FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Listen only makes sense for TCP */
|
||||
if( proto == MBEDTLS_NET_PROTO_TCP )
|
||||
{
|
||||
if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 )
|
||||
{
|
||||
close( ctx->fd );
|
||||
ret = MBEDTLS_ERR_NET_LISTEN_FAILED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* I we ever get there, it's a success */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo( addr_list );
|
||||
|
||||
return( ret );
|
||||
|
||||
}
|
||||
|
||||
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
|
||||
!defined(EFI32)
|
||||
/*
|
||||
* Check if the requested operation would be blocking on a non-blocking socket
|
||||
* and thus 'failed' with a negative return value.
|
||||
*/
|
||||
static int net_would_block( const mbedtls_net_context *ctx )
|
||||
{
|
||||
((void) ctx);
|
||||
return( WSAGetLastError() == WSAEWOULDBLOCK );
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Check if the requested operation would be blocking on a non-blocking socket
|
||||
* and thus 'failed' with a negative return value.
|
||||
*
|
||||
* Note: on a blocking socket this function always returns 0!
|
||||
*/
|
||||
static int net_would_block( const mbedtls_net_context *ctx )
|
||||
{
|
||||
/*
|
||||
* Never return 'WOULD BLOCK' on a non-blocking socket
|
||||
*/
|
||||
if( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK )
|
||||
return( 0 );
|
||||
|
||||
switch( errno )
|
||||
{
|
||||
#if defined EAGAIN
|
||||
case EAGAIN:
|
||||
#endif
|
||||
#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
return( 1 );
|
||||
}
|
||||
return( 0 );
|
||||
}
|
||||
#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
|
||||
|
||||
/*
|
||||
* Accept a connection from a remote client
|
||||
*/
|
||||
int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
|
||||
mbedtls_net_context *client_ctx,
|
||||
void *client_ip, size_t buf_size, size_t *ip_len )
|
||||
{
|
||||
int ret;
|
||||
int type;
|
||||
|
||||
struct sockaddr_in client_addr;
|
||||
|
||||
socklen_t n = (socklen_t) sizeof( client_addr );
|
||||
socklen_t type_len = (socklen_t) sizeof( type );
|
||||
|
||||
/* Is this a TCP or UDP socket? */
|
||||
if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE,
|
||||
(void *) &type, (socklen_t *) &type_len ) != 0 ||
|
||||
( type != SOCK_STREAM && type != SOCK_DGRAM ) )
|
||||
{
|
||||
return( MBEDTLS_ERR_NET_ACCEPT_FAILED );
|
||||
}
|
||||
|
||||
if( type == SOCK_STREAM )
|
||||
{
|
||||
/* TCP: actual accept() */
|
||||
ret = client_ctx->fd = (int) accept( bind_ctx->fd,
|
||||
(struct sockaddr *) &client_addr, &n );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* UDP: wait for a message, but keep it in the queue */
|
||||
char buf[1] = { 0 };
|
||||
|
||||
ret = recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK,
|
||||
(struct sockaddr *) &client_addr, &n );
|
||||
|
||||
#if defined(_WIN32)
|
||||
if( ret == SOCKET_ERROR &&
|
||||
WSAGetLastError() == WSAEMSGSIZE )
|
||||
{
|
||||
/* We know buf is too small, thanks, just peeking here */
|
||||
ret = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( ret < 0 )
|
||||
{
|
||||
if( net_would_block( bind_ctx ) != 0 )
|
||||
return( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
|
||||
return( MBEDTLS_ERR_NET_ACCEPT_FAILED );
|
||||
}
|
||||
|
||||
/* UDP: hijack the listening socket to communicate with the client,
|
||||
* then bind a new socket to accept new connections */
|
||||
if( type != SOCK_STREAM )
|
||||
{
|
||||
struct sockaddr_in local_addr;
|
||||
int one = 1;
|
||||
|
||||
if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 )
|
||||
return( MBEDTLS_ERR_NET_ACCEPT_FAILED );
|
||||
|
||||
client_ctx->fd = bind_ctx->fd;
|
||||
bind_ctx->fd = -1; /* In case we exit early */
|
||||
|
||||
n = sizeof( struct sockaddr_in );
|
||||
if( getsockname( client_ctx->fd,
|
||||
(struct sockaddr *) &local_addr, &n ) != 0 ||
|
||||
( bind_ctx->fd = (int) socket( AF_INET,
|
||||
SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ||
|
||||
setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *) &one, sizeof( one ) ) != 0 )
|
||||
{
|
||||
return( MBEDTLS_ERR_NET_SOCKET_FAILED );
|
||||
}
|
||||
|
||||
if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 )
|
||||
{
|
||||
return( MBEDTLS_ERR_NET_BIND_FAILED );
|
||||
}
|
||||
}
|
||||
|
||||
if( client_ip != NULL )
|
||||
{
|
||||
struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;
|
||||
*ip_len = sizeof( addr4->sin_addr.s_addr );
|
||||
|
||||
if( buf_size < *ip_len )
|
||||
return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL );
|
||||
|
||||
memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the socket blocking or non-blocking
|
||||
*/
|
||||
int mbedtls_net_set_block( mbedtls_net_context *ctx )
|
||||
{
|
||||
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
|
||||
!defined(EFI32)
|
||||
u_long n = 0;
|
||||
return( ioctlsocket( ctx->fd, FIONBIO, &n ) );
|
||||
#else
|
||||
return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) & ~O_NONBLOCK ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
int mbedtls_net_set_nonblock( mbedtls_net_context *ctx )
|
||||
{
|
||||
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
|
||||
!defined(EFI32)
|
||||
u_long n = 1;
|
||||
return( ioctlsocket( ctx->fd, FIONBIO, &n ) );
|
||||
#else
|
||||
return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) | O_NONBLOCK ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Portable usleep helper
|
||||
*/
|
||||
void mbedtls_net_usleep( unsigned long usec )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
Sleep( ( usec + 999 ) / 1000 );
|
||||
#else
|
||||
struct timeval tv;
|
||||
tv.tv_sec = usec / 1000000;
|
||||
#if defined(__unix__) || defined(__unix) || \
|
||||
( defined(__APPLE__) && defined(__MACH__) )
|
||||
tv.tv_usec = (suseconds_t) usec % 1000000;
|
||||
#else
|
||||
tv.tv_usec = usec % 1000000;
|
||||
#endif
|
||||
select( 0, NULL, NULL, NULL, &tv );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Read at most 'len' characters
|
||||
*/
|
||||
int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
|
||||
{
|
||||
int ret;
|
||||
int fd = ((mbedtls_net_context *) ctx)->fd;
|
||||
|
||||
if( fd < 0 )
|
||||
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
|
||||
|
||||
ret = (int) read( fd, buf, len );
|
||||
|
||||
if( ret < 0 )
|
||||
{
|
||||
if( net_would_block( ctx ) != 0 )
|
||||
return( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
|
||||
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
|
||||
!defined(EFI32)
|
||||
if( WSAGetLastError() == WSAECONNRESET )
|
||||
return( MBEDTLS_ERR_NET_CONN_RESET );
|
||||
#else
|
||||
if( errno == EPIPE || errno == ECONNRESET )
|
||||
return( MBEDTLS_ERR_NET_CONN_RESET );
|
||||
|
||||
if( errno == EINTR )
|
||||
return( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
#endif
|
||||
|
||||
return( MBEDTLS_ERR_NET_RECV_FAILED );
|
||||
}
|
||||
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/*
|
||||
* Read at most 'len' characters, blocking for at most 'timeout' ms
|
||||
*/
|
||||
int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
|
||||
uint32_t timeout )
|
||||
{
|
||||
int ret;
|
||||
struct timeval tv;
|
||||
fd_set read_fds;
|
||||
int fd = ((mbedtls_net_context *) ctx)->fd;
|
||||
|
||||
if( fd < 0 )
|
||||
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
|
||||
|
||||
FD_ZERO( &read_fds );
|
||||
FD_SET( fd, &read_fds );
|
||||
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = ( timeout % 1000 ) * 1000;
|
||||
|
||||
ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv );
|
||||
|
||||
/* Zero fds ready means we timed out */
|
||||
if( ret == 0 )
|
||||
return( MBEDTLS_ERR_SSL_TIMEOUT );
|
||||
|
||||
if( ret < 0 )
|
||||
{
|
||||
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
|
||||
!defined(EFI32)
|
||||
if( WSAGetLastError() == WSAEINTR )
|
||||
return( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
#else
|
||||
if( errno == EINTR )
|
||||
return( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
#endif
|
||||
|
||||
return( MBEDTLS_ERR_NET_RECV_FAILED );
|
||||
}
|
||||
|
||||
/* This call will not block */
|
||||
return( mbedtls_net_recv( ctx, buf, len ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Write at most 'len' characters
|
||||
*/
|
||||
int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
|
||||
{
|
||||
int ret;
|
||||
int fd = ((mbedtls_net_context *) ctx)->fd;
|
||||
|
||||
if( fd < 0 )
|
||||
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
|
||||
|
||||
ret = (int) write( fd, buf, len );
|
||||
|
||||
if( ret < 0 )
|
||||
{
|
||||
if( net_would_block( ctx ) != 0 )
|
||||
return( MBEDTLS_ERR_SSL_WANT_WRITE );
|
||||
|
||||
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
|
||||
!defined(EFI32)
|
||||
if( WSAGetLastError() == WSAECONNRESET )
|
||||
return( MBEDTLS_ERR_NET_CONN_RESET );
|
||||
#else
|
||||
if( errno == EPIPE || errno == ECONNRESET )
|
||||
return( MBEDTLS_ERR_NET_CONN_RESET );
|
||||
|
||||
if( errno == EINTR )
|
||||
return( MBEDTLS_ERR_SSL_WANT_WRITE );
|
||||
#endif
|
||||
|
||||
return( MBEDTLS_ERR_NET_SEND_FAILED );
|
||||
}
|
||||
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/*
|
||||
* Gracefully close the connection
|
||||
*/
|
||||
void mbedtls_net_free( mbedtls_net_context *ctx )
|
||||
{
|
||||
if( ctx->fd == -1 )
|
||||
return;
|
||||
|
||||
shutdown( ctx->fd, 2 );
|
||||
close( ctx->fd );
|
||||
|
||||
ctx->fd = -1;
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_NET_C */
|
|
@ -32,7 +32,7 @@ ets_printf = printf;
|
|||
*/
|
||||
#ifndef OTA
|
||||
|
||||
#define IROM0_START 0x40240000
|
||||
#define IROM0_START 0x40220000
|
||||
|
||||
/* Non-OTA sizes */
|
||||
#if FLASH_SIZE == 2 /* 256kB */
|
||||
|
@ -136,6 +136,68 @@ SECTIONS
|
|||
_dport0_data_end = ABSOLUTE(.);
|
||||
} >dport0_0_seg :dport0_0_phdr
|
||||
|
||||
.text : ALIGN(4) /* IRAM */
|
||||
{
|
||||
_stext = .;
|
||||
_text_start = ABSOLUTE(.);
|
||||
. = ALIGN (16);
|
||||
*(.vecbase.text)
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
/* esp-open-rtos compiled source files use the .iram1.* section names for IRAM
|
||||
functions, etc. */
|
||||
*(.iram1.*)
|
||||
/* SDK libraries expect their .text sections to link to iram, not irom */
|
||||
*sdklib*:*(.literal .text .literal.* .text.*)
|
||||
/* libgcc integer functions also need to be in .text, as some are called before
|
||||
flash is mapped (also performance)
|
||||
*/
|
||||
*libgcc.a:*i3.o(.literal .text .literal.* .text.*)
|
||||
|
||||
/* libc also in IRAM */
|
||||
*libc.a:*malloc.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*mallocr.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*freer.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*memcpy.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*memset.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*memcmp.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*memmove.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*rand.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*bzero.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*lock.o(.literal .text .literal.* .text.*)
|
||||
|
||||
*libc.a:*printf.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*findfp.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*fputwc.o(.literal .text .literal.* .text.*)
|
||||
|
||||
/* xthal_set_intset() called from PendSV in NMI context */
|
||||
*libhal.a:*set_intset.o(.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
|
||||
|
||||
.irom0.text : ALIGN(4)
|
||||
{
|
||||
_irom0_text_start = ABSOLUTE(.);
|
||||
/* esp-open-rtos compiled code goes into IROM by default
|
||||
(except for libgcc which is matched above.)
|
||||
*/
|
||||
*(.literal .text .literal.* .text.*)
|
||||
/* mbedtls rodata */
|
||||
*mbedtls.a:*.o(.rodata.* .rodata)
|
||||
/* actual certificate in example (TEMPORARY HACK) */
|
||||
*:cert.o(.rodata.* .rodata)
|
||||
/* Anything explicitly marked as "irom" or "irom0" should go here */
|
||||
*(.irom.* .irom.*.* .irom0.*)
|
||||
_irom0_text_end = ABSOLUTE(.);
|
||||
} >irom0_0_seg :irom0_0_phdr
|
||||
|
||||
.data : ALIGN(4)
|
||||
{
|
||||
_data_start = ABSOLUTE(.);
|
||||
|
@ -218,62 +280,6 @@ SECTIONS
|
|||
} >dram0_0_seg :dram0_0_bss_phdr
|
||||
/* __stack = 0x3ffc8000; */
|
||||
|
||||
.text : ALIGN(4) /* IRAM */
|
||||
{
|
||||
_stext = .;
|
||||
_text_start = ABSOLUTE(.);
|
||||
. = ALIGN (16);
|
||||
*(.vecbase.text)
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
/* esp-open-rtos compiled source files use the .iram1.* section names for IRAM
|
||||
functions, etc. */
|
||||
*(.iram1.*)
|
||||
/* SDK libraries expect their .text sections to link to iram, not irom */
|
||||
*sdklib*:*(.literal .text .literal.* .text.*)
|
||||
/* libgcc integer functions also need to be in .text, as some are called before
|
||||
flash is mapped (also performance)
|
||||
*/
|
||||
*libgcc.a:*i3.o(.literal .text .literal.* .text.*)
|
||||
|
||||
/* libc also in IRAM */
|
||||
*libc.a:*malloc.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*mallocr.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*freer.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*memcpy.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*memset.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*memcmp.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*rand.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*bzero.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*lock.o(.literal .text .literal.* .text.*)
|
||||
|
||||
*libc.a:*printf.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*findfp.o(.literal .text .literal.* .text.*)
|
||||
*libc.a:*fputwc.o(.literal .text .literal.* .text.*)
|
||||
|
||||
/* xthal_set_intset() called from PendSV in NMI context */
|
||||
*libhal.a:*set_intset.o(.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
|
||||
|
||||
.irom0.text : ALIGN(4)
|
||||
{
|
||||
_irom0_text_start = ABSOLUTE(.);
|
||||
/* esp-open-rtos compiled code goes into IROM by default
|
||||
(except for libgcc which is matched above.)
|
||||
*/
|
||||
*(.literal .text .literal.* .text.*)
|
||||
/* Anything explicitly marked as "irom" or "irom0" should go here */
|
||||
*(.irom.* .irom.*.* .irom0.*)
|
||||
_irom0_text_end = ABSOLUTE(.);
|
||||
} >irom0_0_seg :irom0_0_phdr
|
||||
|
||||
.lit4 : ALIGN(4)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Component makefile for LWIP
|
||||
|
||||
LWIP_DIR = $(lwip_ROOT)lwip/src/
|
||||
INC_DIRS += $(LWIP_DIR)include $(ROOT)lwip/include $(lwip_ROOT)include $(LWIP_DIR)include/ipv4 $(LWIP_DIR)include/ipv4/lwip $(LWIP_DIR)include/lwip
|
||||
INC_DIRS += $(LWIP_DIR)include $(ROOT)lwip/include $(lwip_ROOT)include $(LWIP_DIR)include/posix $(LWIP_DIR)include/ipv4 $(LWIP_DIR)include/ipv4/lwip $(LWIP_DIR)include/lwip
|
||||
|
||||
# args for passing into compile rule generation
|
||||
lwip_INC_DIR = # all in INC_DIRS, needed for normal operation
|
||||
|
|
Loading…
Reference in a new issue