Merge branch 'feature/mbedtls'

This commit is contained in:
Angus Gratton 2015-09-28 13:29:38 +10:00
commit 65307aed75
33 changed files with 4571 additions and 822 deletions

7
.gitmodules vendored
View file

@ -1,7 +1,6 @@
[submodule "lwip/lwip"] [submodule "lwip/lwip"]
path = lwip/lwip path = lwip/lwip
url = https://github.com/SuperHouse/esp-lwip.git url = https://github.com/SuperHouse/esp-lwip.git
[submodule "axtls/axtls"] [submodule "extras/mbedtls/mbedtls"]
path = axtls/axtls path = extras/mbedtls/mbedtls
url = https://github.com/SuperHouse/axtls.git url = https://github.com/ARMmbed/mbedtls.git

View file

@ -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. * `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. * `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: * `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)) - 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/)) - 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)) - 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. * `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). * `libc` contains the newlib libc. [Libc details here](https://github.com/SuperHouse/esp-open-rtos/wiki/libc-configuration).
## Open Source Components ## Open Source Components
* [FreeRTOS](http://freertos.org) V7.5.2 * [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. * [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. * [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). 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. 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: 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)). * 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 ## 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. * 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. * 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. Components under `extras/` may contain different licenses, please see those directories for details.
## Contributions ## Contributions

@ -1 +0,0 @@
Subproject commit a4860ef68d7f5d98a8731f99787d51cc44c433c9

View file

@ -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) {}
}

View file

@ -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'")

View file

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

View file

@ -1,6 +0,0 @@
#ifndef _OS_INT_H
#define _OS_INT_H
#include <stdint.h>
#endif

View file

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

View file

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

View file

@ -80,7 +80,7 @@ OBJDUMP = $(CROSS)objdump
# Source components to compile and link. Each of these are subdirectories # Source components to compile and link. Each of these are subdirectories
# of the root, with a 'component.mk' file. # 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. # binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking.
SDK_LIBS ?= main net80211 phy pp wpa SDK_LIBS ?= main net80211 phy pp wpa
@ -94,14 +94,25 @@ OWN_LIBC ?= 1
# Note: you will need a recent esp # Note: you will need a recent esp
ENTRY_SYMBOL ?= call_user_start 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++_ # Common flags for both C & C++_
C_CXX_FLAGS = -Wall -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals $(CPPFLAGS) C_CXX_FLAGS = -Wall -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals $(CPPFLAGS)
# Flags for C only # Flags for C only
CFLAGS = $(C_CXX_FLAGS) -std=gnu99 CFLAGS = $(C_CXX_FLAGS) -std=gnu99
# Flags for C++ only # Flags for C++ only
CXXFLAGS = $(C_CXX_FLAGS) -fno-exceptions -fno-rtti 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) 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) ifeq ($(FLAVOR),debug)
C_CXX_FLAGS += -g -O0 C_CXX_FLAGS += -g -O0
LDFLAGS += -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 # for non-OTA, we create two different files for uploading into the flash
# these are the names and options to generate them # these are the names and options to generate them
FW_ADDR_1 = 0x00000 FW_ADDR_1 = 0x00000
FW_ADDR_2 = 0x40000 FW_ADDR_2 = 0x20000
FW_FILE_1 = $(addprefix $(FW_BASE),$(FW_ADDR_1).bin) FW_FILE_1 = $(addprefix $(FW_BASE),$(FW_ADDR_1).bin)
FW_FILE_2 = $(addprefix $(FW_BASE),$(FW_ADDR_2).bin) FW_FILE_2 = $(addprefix $(FW_BASE),$(FW_ADDR_2).bin)
else else
@ -263,6 +274,7 @@ $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.S $$($(1)_MAKEFILE) $(wildcard $(ROOT)*
$(vecho) "AS $$<" $(vecho) "AS $$<"
$(Q) mkdir -p $$(dir $$@) $(Q) mkdir -p $$(dir $$@)
$$($(1)_CC_ARGS) -c $$< -o $$@ $$($(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 # 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 # for missing explicitly named source files

27
core/esp_hwrand.c Normal file
View 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));
}
}

View file

@ -1,256 +1,541 @@
/* Xtensa Exception (ie interrupt) Vectors & low-level handler code /* 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 and Angus Gratton
* BSD Licensed as described in the file LICENSE
*/
Core exception handler code is placed in the .vecbase section, #include "led_debug.s"
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 /* Some UserException causes, see table Table 464 in ISA reference */
(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 #define CAUSE_SYSCALL 1
Original vector contents Copyright (C) 2014-2015 Espressif Systems #define CAUSE_LOADSTORE 3
Additions Copyright (C) Superhouse Automation Pty Ltd #define CAUSE_LVL1INT 4
BSD Licensed as described in the file LICENSE
*/ .section .bss
.text
.section .vecbase.text, "x" NMIHandlerStack: # stack space for NMI handler
.align 256 .skip 4*0x100
.global VecBase .LNMIHandlerStackTop:
.type VecBase, @function /* it's not really a function, but treat it like one */ 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: VecBase:
/* IMPORTANT: exception vector literals will go here, but we .global VecBase
can't have more than 4 otherwise we push DebugExceptionVector past /* IMPORTANT: exception vector literals will go here, but we
offset 0x10 relative to VecBase. There should be ways to avoid this, * can't have more than 4 otherwise we push DebugExceptionVector past
and also keep the VecBase offsets easy to read, but this works for now. * 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
.literal_position * now. */
.align 16 .literal_position
.org VecBase + 0x10
DebugExceptionVector: DebugExceptionVector:
wsr.excsave2 a0 .type DebugExceptionVector, @function
call0 sdk_user_fatal_exception_handler
rfi 2 wsr a0, excsave2
.align 16 call0 sdk_user_fatal_exception_handler
rfi 2
.org VecBase + 0x20
NMIExceptionVector: NMIExceptionVector:
wsr.excsave3 a0 .type NMIExceptionVector, @function
call0 CallNMIExceptionHandler
rfi 3 /* CallNMIExceptionHandler should call rfi itself */ wsr a0, excsave3
.align 16 call0 CallNMIExceptionHandler
rfi 3 # Should never be reached
.org VecBase + 0x30
KernelExceptionVector: KernelExceptionVector:
break 1, 0 .type KernelExceptionVector, @function
call0 sdk_user_fatal_exception_handler
rfe break 1, 0
.align 16 call0 sdk_user_fatal_exception_handler
.L_EmptyVectorEntry: rfe
nop
.align 16 .org VecBase + 0x50
UserExceptionVector: UserExceptionVector:
wsr.excsave1 a0 .type UserExceptionVector, @function
call0 CallUserExceptionHandler
rfe /* CallUserExceptionHandler should call rfe itself */ wsr a1, excsave1
.align 16 rsr a1, exccause
.L_EmptyVectorEntry2: beqi a1, CAUSE_LOADSTORE, LoadStoreErrorHandler
nop j UserExceptionHandler
.align 16
.org VecBase + 0x70
DoubleExceptionVector: DoubleExceptionVector:
break 1, 4 .type DoubleExceptionVector, @function
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 break 1, 4
NMIHandlerStack: /* stack space for NMI handler */ call0 sdk_user_fatal_exception_handler
.skip 4*0x100
NMIRegisterSaved: /* register space for saving NMI registers */
.skip 4*(0x16 + 6)
/* this symbol is _Pri_3_HandlerAddress in the RTOS SDK, appears totally /* Reset vector at offset 0x80 is unused, as vecbase gets reset to mask ROM
unused (stays zero at all times) */ * vectors on chip reset. */
.global NMIHandlerAddress
NMIHandlerAddress: /*************************** LoadStoreError Handler **************************/
.long 0
.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 */ /* Save register relative to a0 */
.macro SAVE_REG register, regnum .macro SAVE_REG register, regnum
s32i \register, a0, (0x20 + 4 * \regnum) s32i \register, a0, (4 * (\regnum + 6))
.endm .endm
/* Load register relative to sp */ /* Load register relative to sp */
.macro LOAD_REG register, regnum .macro LOAD_REG register, regnum
l32i \register, sp, (0x20 + 4 * \regnum) l32i \register, sp, (4 * (\regnum + 6))
.endm .endm
.text .literal_position
.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 .balign 16
.align 16
.type CallNMIExceptionHandler, @function
CallNMIExceptionHandler: CallNMIExceptionHandler:
movi a0, NMIRegisterSaved .type CallNMIExceptionHandler, @function
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 */
SAVE_REG a4, 4
SAVE_REG a2, 0
rsr.epc1 a3
rsr.exccause a4
SAVE_REG a3, -5
SAVE_REG a4, -4
rsr.excvaddr a3
SAVE_REG a3, -3
rsr.excsave1 a3
SAVE_REG a3, -2
SAVE_REG a5, 5
SAVE_REG a6, 6
SAVE_REG a7, 7
SAVE_REG a8, 8
SAVE_REG a9, 9
SAVE_REG a10, 10
SAVE_REG a11, 11
SAVE_REG a12, 12
SAVE_REG a13, 13
SAVE_REG a14, 14
SAVE_REG a15, 15
movi sp, NMIRegisterSaved /* also top of NMIHandlerStack */
movi a0, 0
movi a2, 0x23 /* argument for handler */
wsr.ps a2
rsync
rsr.sar a14
s32i a14, sp, 0 /* this is also NMIRegisterSaved+0 */
call0 sdk_wDev_ProcessFiq
l32i a15, sp, 0
wsr.sar a15
movi a2, 0x33
wsr.ps a2
rsync
LOAD_REG a4, 4
LOAD_REG a5, 5
LOAD_REG a6, 6
LOAD_REG a7, 7
LOAD_REG a8, 8
LOAD_REG a9, 9
LOAD_REG a10, 10
LOAD_REG a11, 11
LOAD_REG a12, 12
LOAD_REG a13, 13
LOAD_REG a14, 14
LOAD_REG a15, 15
LOAD_REG a2, -5
LOAD_REG a3, -4
wsr.epc1 a2
wsr.exccause a3
LOAD_REG a2, -3
LOAD_REG a3, -2
wsr.excvaddr a2
wsr.excsave1 a3
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) */
movi a2, 0x3ff00000
movi a3, 0x1
s32i a3, a2, 0
LOAD_REG a2, 2
LOAD_REG a3, 3
LOAD_REG a1, 1
rfi 0x3
/* Some UserException causes, see table Table 464 in ISA reference */ movi a0, NMIRegisterSaved
#define CAUSE_SYSCALL 1 SAVE_REG a2, 2
#define CAUSE_LVL1INT 4 SAVE_REG sp, 1
SAVE_REG a3, 3
rsr a2, excsave3 # a2 is now former a0
SAVE_REG a4, 4
SAVE_REG a2, 0
rsr a3, epc1
rsr a4, exccause
SAVE_REG a3, -5
SAVE_REG a4, -4
rsr a3, excvaddr
SAVE_REG a3, -3
rsr a3, excsave1
SAVE_REG a3, -2
SAVE_REG a5, 5
SAVE_REG a6, 6
SAVE_REG a7, 7
SAVE_REG a8, 8
SAVE_REG a9, 9
SAVE_REG a10, 10
SAVE_REG a11, 11
SAVE_REG a12, 12
SAVE_REG a13, 13
SAVE_REG a14, 14
SAVE_REG a15, 15
movi sp, .LNMIHandlerStackTop
movi a0, 0
movi a2, 0x23 # argument for handler
wsr a2, ps
rsync
rsr a14, sar
s32i a14, sp, 0 # this is also NMIRegisterSaved+0
call0 sdk_wDev_ProcessFiq
l32i a15, sp, 0
wsr a15, sar
movi a2, 0x33
wsr a2, ps
rsync
LOAD_REG a4, 4
LOAD_REG a5, 5
LOAD_REG a6, 6
LOAD_REG a7, 7
LOAD_REG a8, 8
LOAD_REG a9, 9
LOAD_REG a10, 10
LOAD_REG a11, 11
LOAD_REG a12, 12
LOAD_REG a13, 13
LOAD_REG a14, 14
LOAD_REG a15, 15
LOAD_REG a2, -5
LOAD_REG a3, -4
wsr a2, epc1
wsr a3, exccause
LOAD_REG a2, -3
LOAD_REG a3, -2
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)
*/
movi a2, 0x3ff00000
movi a3, 0x1
s32i a3, a2, 0
LOAD_REG a2, 2
LOAD_REG a3, 3
LOAD_REG a1, 1
rfi 3
.type CallUserExceptionHandler, @function /*********************** General UserException Handler ***********************/
CallUserExceptionHandler:
rsr.exccause a0 .section .vecbase.text, "x"
beqi a0, CAUSE_SYSCALL, UserSyscallHandler
mov a0, sp /* Called by UserExceptionVector if EXCCAUSE is anything other than
addi sp, sp, -0x50 * LoadStoreCause. */
s32i a0, sp, 0x10
rsr.ps a0 .literal_position
s32i a0, sp, 0x08
rsr.epc1 a0 .balign 4
s32i a0, sp, 0x04 UserExceptionHandler:
rsr.excsave1 a0 /* a0 was saved in UserExceptionVector */ .type UserExceptionHandler, @function
s32i a0, sp, 0x0c xsr a0, excsave1 # a0 now contains sp
movi a0, _xt_user_exit mov sp, a0
s32i a0, sp, 0x0 addi sp, sp, -0x50
call0 sdk__xt_int_enter s32i a0, sp, 0x10
movi a0, 0x23 rsr a0, ps
wsr.ps a0 s32i a0, sp, 0x08
rsync rsr a0, epc1
rsr.exccause a2 s32i a0, sp, 0x04
beqi a2, CAUSE_LVL1INT, UserHandleInterrupt rsr a0, excsave1
/* Any UserException cause other than level 1 interrupt triggers a panic */ s32i a0, sp, 0x0c
movi a0, _xt_user_exit
s32i a0, sp, 0x0
call0 sdk__xt_int_enter
movi a0, 0x23
wsr a0, ps
rsync
rsr a2, exccause
beqi a2, CAUSE_LVL1INT, UserHandleInterrupt
/* Any UserException cause other than level 1 interrupt should panic */
UserFailOtherExceptionCause: UserFailOtherExceptionCause:
break 1, 1 break 1, 1
call0 sdk_user_fatal_exception_handler call0 sdk_user_fatal_exception_handler
UserHandleInterrupt: UserHandleInterrupt:
rsil a0, 1 rsil a0, 1
rsr.intenable a2 rsr a2, intenable
rsr.interrupt a3 rsr a3, interrupt
movi a4, 0x3fff movi a4, 0x3fff
and a2, a2, a3 and a2, a2, a3
and a2, a2, a4 /* a2 = 0x3FFF & INTENABLE & INTERRUPT */ and a2, a2, a4 # a2 = 0x3FFF & INTENABLE & INTERRUPT
UserHandleTimer: UserHandleTimer:
movi a3, 0xffbf movi a3, 0xffbf
and a3, a2, a3 /* a3 = a2 & 0xFFBF, ie remove 0x40 from a2 if set */ and a3, a2, a3 # a3 = a2 with bit 6 cleared
bnez a3, UserTimerDone /* bits other than 0x40 are set */ bnez a3, UserTimerDone # If any non-timer interrupt bits set
movi a3, 0x40 movi a3, 0x40
sub a12, a2, a3 /* a12 - a2 - 0x40 - I think a12 _must_ be zero here? */ sub a12, a2, a3 # a12 = a2 - 0x40 -- Will be zero if bit 6 set
call0 sdk__xt_timer_int /* tick timer interrupt */ call0 sdk__xt_timer_int # tick timer interrupt
mov a2, a12 /* restore a2 from a12, ie zero */ mov a2, a12 # restore a2 from a12, ie zero
beqz a2, UserIntDone beqz a2, UserIntDone
UserTimerDone: UserTimerDone:
call0 _xt_isr_handler call0 _xt_isr_handler
bnez a2, UserHandleTimer bnez a2, UserHandleTimer
UserIntDone: UserIntDone:
beqz a2, UserIntExit beqz a2, UserIntExit
break 1, 1 /* non-zero remnant in a2 means fail */ /* FIXME: this code will never be reached */
call0 sdk_user_fatal_exception_handler break 1, 1
call0 sdk_user_fatal_exception_handler
UserIntExit: 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 */ .section .text
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
.global _xt_user_exit /* _xt_user_exit is used to exit interrupt context. */
.type _xt_user_exit, @function /* TODO: Find a better place for this to live. */
_xt_user_exit: _xt_user_exit:
l32i a0, sp, 0x8 .global _xt_user_exit
wsr.ps a0 .type _xt_user_exit, @function
l32i a0, sp, 0x4
wsr.epc1 a0 l32i a0, sp, 0x8
l32i a0, sp, 0xc wsr a0, ps
l32i sp, sp, 0x10 l32i a0, sp, 0x4
rsync wsr a0, epc1
rfe l32i a0, sp, 0xc
l32i sp, sp, 0x10
rsync
rfe

22
core/include/esp/hwrand.h Normal file
View 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

View file

@ -2,6 +2,9 @@
* *
* ESP8266 register definitions for the "wdev" region (0x3FF2xxx) * 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. * Not compatible with ESP SDK register access code.
*/ */
@ -21,10 +24,19 @@
*/ */
struct WDEV_REGS { 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 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 )); } __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 */ #endif /* _ESP_WDEV_REGS_H */

View file

@ -4,6 +4,8 @@
* *
* To have this work from initial reset, without needing an iomux call * 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) * 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 LED_GPIO=2
GPIO_DIR_SET = 0x6000030c GPIO_DIR_SET = 0x6000030c
@ -19,11 +21,11 @@ GPIO_OUT_CLEAR = 0x60000308
.endm .endm
// Turn LED on. rega, regb will be clobbered // 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 led_op \rega, \regb, GPIO_OUT_SET
.endm .endm
// Turn LED off. rega, regb will be clobbered // Turn LED on. rega, regb will be clobbered
.macro led_off rega, regb .macro led_on rega, regb
led_op \rega, \regb, GPIO_OUT_CLEAR led_op \rega, \regb, GPIO_OUT_CLEAR
.endm .endm

View file

@ -103,4 +103,4 @@ extern "C" void user_init(void)
task_1.task_create("tsk1"); task_1.task_create("tsk1");
task_2.task_create("tsk2"); task_2.task_create("tsk2");
} }

View file

@ -0,0 +1,2 @@
PROGRAM=unaligned_load
include ../../../common.mk

View 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");
}

View file

@ -0,0 +1,4 @@
PROGRAM=http_get_mbedtls
COMPONENTS = FreeRTOS lwip core extras/mbedtls
include ../../common.mk

View 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";

View 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);
}

View 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

View file

@ -1,2 +0,0 @@
PROGRAM=http_get_ssl
include ../../common.mk

View file

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

View file

@ -1,2 +1,3 @@
PROGRAM=hmac_test PROGRAM=hmac_test
EXTRA_COMPONENTS=extras/mbedtls
include ../../../common.mk include ../../../common.mk

View file

@ -10,7 +10,7 @@
#include "espressif/esp_common.h" #include "espressif/esp_common.h"
#include "espressif/sdk_private.h" #include "espressif/sdk_private.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "ssl.h" #include "mbedtls/md.h"
#include <string.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,
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 const uint8_t NUM_MD5_VECTORS = 7;
routines don't support keys longer than the block size. */
const uint8_t NUM_MD5_VECTORS = 5;
static const struct test_vector md5_vectors[] = { static const struct test_vector md5_vectors[] = {
{ /* vector 1*/ { /* 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) static void test_md5(void)
{ {
printf("\r\nTesting MD5 vectors...\r\n"); 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++) { for(int i = 0; i < NUM_MD5_VECTORS; i++) {
const struct test_vector *vector = &md5_vectors[i]; const struct test_vector *vector = &md5_vectors[i];
printf("Test case %d: ", i+1); 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; uint8_t first = 0;
for(first = 0; first < 16; first++) { for(first = 0; first < 16; first++) {
if(test_digest[first] != vector->digest[first]) { if(test_digest[first] != vector->digest[first]) {

View 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'")

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

File diff suppressed because it is too large Load diff

@ -0,0 +1 @@
Subproject commit 0a0c22e0efcf2f8f71d7e16712f80b8f77326f72

510
extras/mbedtls/net_lwip.c Normal file
View 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 */

View file

@ -32,7 +32,7 @@ ets_printf = printf;
*/ */
#ifndef OTA #ifndef OTA
#define IROM0_START 0x40240000 #define IROM0_START 0x40220000
/* Non-OTA sizes */ /* Non-OTA sizes */
#if FLASH_SIZE == 2 /* 256kB */ #if FLASH_SIZE == 2 /* 256kB */
@ -136,6 +136,68 @@ SECTIONS
_dport0_data_end = ABSOLUTE(.); _dport0_data_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr } >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 : ALIGN(4)
{ {
_data_start = ABSOLUTE(.); _data_start = ABSOLUTE(.);
@ -218,62 +280,6 @@ SECTIONS
} >dram0_0_seg :dram0_0_bss_phdr } >dram0_0_seg :dram0_0_bss_phdr
/* __stack = 0x3ffc8000; */ /* __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) .lit4 : ALIGN(4)
{ {

View file

@ -1,7 +1,7 @@
# Component makefile for LWIP # Component makefile for LWIP
LWIP_DIR = $(lwip_ROOT)lwip/src/ 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 # args for passing into compile rule generation
lwip_INC_DIR = # all in INC_DIRS, needed for normal operation lwip_INC_DIR = # all in INC_DIRS, needed for normal operation