Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
20a3b4c0cd
101 changed files with 8203 additions and 1133 deletions
510
core/app_main.c
Normal file
510
core/app_main.c
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
/* Implementation of libmain/app_main.o from the Espressif SDK.
|
||||
*
|
||||
* This contains most of the startup code for the SDK/OS, some event handlers,
|
||||
* etc.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <lwip/tcpip.h>
|
||||
|
||||
#include "common_macros.h"
|
||||
#include "xtensa_ops.h"
|
||||
#include "esp/rom.h"
|
||||
#include "esp/iomux_regs.h"
|
||||
#include "esp/uart_regs.h"
|
||||
#include "esp/spi_regs.h"
|
||||
#include "esp/dport_regs.h"
|
||||
#include "esp/wdev_regs.h"
|
||||
#include "os_version.h"
|
||||
|
||||
#include "espressif/esp_common.h"
|
||||
#include "sdk_internal.h"
|
||||
|
||||
/* This is not declared in any header file (but arguably should be) */
|
||||
|
||||
void user_init(void);
|
||||
|
||||
#define UART_DIVISOR 1068 // 74906 bps (yeah, I don't understand it either)
|
||||
#define BOOT_INFO_SIZE 28
|
||||
//TODO: phy_info should probably be a struct (no idea about its organization, though)
|
||||
#define PHY_INFO_SIZE 128
|
||||
|
||||
// These are the offsets of these values within the RTCMEM regions. It appears
|
||||
// that the ROM saves them to RTCMEM before calling us, and we pull them out of
|
||||
// there to display them in startup messages (not sure why it works that way).
|
||||
#define RTCMEM_BACKUP_PHY_VER 31
|
||||
#define RTCMEM_SYSTEM_PP_VER 62
|
||||
|
||||
#define halt() while (1) {}
|
||||
|
||||
extern uint32_t _bss_start;
|
||||
extern uint32_t _bss_end;
|
||||
|
||||
// .Ldata003 -- .irom.text+0x0
|
||||
static const uint8_t IROM default_phy_info[PHY_INFO_SIZE] = {
|
||||
0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02,
|
||||
0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05,
|
||||
0x04, 0xfe, 0xfd, 0xff, 0xf0, 0xf0, 0xf0, 0xe0,
|
||||
0xe0, 0xe0, 0xe1, 0x0a, 0xff, 0xff, 0xf8, 0x00,
|
||||
0xf8, 0xf8, 0x52, 0x4e, 0x4a, 0x44, 0x40, 0x38,
|
||||
0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xe1, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// user_init_flag -- .bss+0x0
|
||||
uint8_t sdk_user_init_flag;
|
||||
|
||||
// info -- .bss+0x4
|
||||
struct sdk_info_st sdk_info;
|
||||
|
||||
// xUserTaskHandle -- .bss+0x28
|
||||
xTaskHandle sdk_xUserTaskHandle;
|
||||
|
||||
// xWatchDogTaskHandle -- .bss+0x2c
|
||||
xTaskHandle sdk_xWatchDogTaskHandle;
|
||||
|
||||
/* Static function prototypes */
|
||||
|
||||
static void IRAM get_otp_mac_address(uint8_t *buf);
|
||||
static void IRAM set_spi0_divisor(uint32_t divisor);
|
||||
static int IRAM default_putc(char c);
|
||||
static void IRAM default_putc1(char c);
|
||||
static void zero_bss(void);
|
||||
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr);
|
||||
static void init_g_ic(void);
|
||||
static void dump_excinfo(void);
|
||||
static void user_start_phase2(void);
|
||||
static void dump_flash_sector(uint32_t start_sector, uint32_t length);
|
||||
static void dump_flash_config_sectors(uint32_t start_sector);
|
||||
|
||||
// .Lfunc001 -- .text+0x14
|
||||
static void IRAM get_otp_mac_address(uint8_t *buf) {
|
||||
uint32_t otp_flags;
|
||||
uint32_t otp_id0, otp_id1;
|
||||
uint32_t otp_vendor_id;
|
||||
|
||||
otp_flags = DPORT.OTP_CHIPID;
|
||||
otp_id1 = DPORT.OTP_MAC1;
|
||||
otp_id0 = DPORT.OTP_MAC0;
|
||||
if (!(otp_flags & 0x8000)) {
|
||||
//FIXME: do we really need this check?
|
||||
printf("Firmware ONLY supports ESP8266!!!\n");
|
||||
halt();
|
||||
}
|
||||
if (otp_id0 == 0 && otp_id1 == 0) {
|
||||
printf("empty otp\n");
|
||||
halt();
|
||||
}
|
||||
if (otp_flags & 0x1000) {
|
||||
// If bit 12 is set, it indicates that the vendor portion of the MAC
|
||||
// address is stored in DPORT.OTP_MAC2.
|
||||
otp_vendor_id = DPORT.OTP_MAC2;
|
||||
buf[0] = otp_vendor_id >> 16;
|
||||
buf[1] = otp_vendor_id >> 8;
|
||||
buf[2] = otp_vendor_id;
|
||||
} else {
|
||||
// If bit 12 is clear, there's no MAC vendor in DPORT.OTP_MAC2, so
|
||||
// default to the Espressif MAC vendor prefix instead.
|
||||
buf[1] = 0xfe;
|
||||
buf[0] = 0x18;
|
||||
buf[2] = 0x34;
|
||||
}
|
||||
buf[3] = otp_id1 >> 8;
|
||||
buf[4] = otp_id1;
|
||||
buf[5] = otp_id0 >> 24;
|
||||
}
|
||||
|
||||
// .Lfunc002 -- .text+0xa0
|
||||
static void IRAM set_spi0_divisor(uint32_t divisor) {
|
||||
int cycle_len, half_cycle_len, clkdiv;
|
||||
|
||||
if (divisor < 2) {
|
||||
clkdiv = 0;
|
||||
SPI(0).CTRL0 |= SPI_CTRL0_CLOCK_EQU_SYS_CLOCK;
|
||||
IOMUX.CONF |= IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
|
||||
} else {
|
||||
cycle_len = divisor - 1;
|
||||
half_cycle_len = (divisor / 2) - 1;
|
||||
clkdiv = VAL2FIELD(SPI_CTRL0_CLOCK_NUM, cycle_len)
|
||||
| VAL2FIELD(SPI_CTRL0_CLOCK_HIGH, half_cycle_len)
|
||||
| VAL2FIELD(SPI_CTRL0_CLOCK_LOW, cycle_len);
|
||||
SPI(0).CTRL0 &= ~SPI_CTRL0_CLOCK_EQU_SYS_CLOCK;
|
||||
IOMUX.CONF &= ~IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
|
||||
}
|
||||
SPI(0).CTRL0 = SET_FIELD(SPI(0).CTRL0, SPI_CTRL0_CLOCK, clkdiv);
|
||||
}
|
||||
|
||||
// .text+0x148
|
||||
void IRAM sdk_user_fatal_exception_handler(void) {
|
||||
if (!sdk_NMIIrqIsOn) {
|
||||
vPortEnterCritical();
|
||||
do {
|
||||
DPORT.DPORT0 &= 0xffffffe0;
|
||||
} while (DPORT.DPORT0 & 0x00000001);
|
||||
}
|
||||
Cache_Read_Disable();
|
||||
Cache_Read_Enable(0, 0, 1);
|
||||
dump_excinfo();
|
||||
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(0).STATUS)) {}
|
||||
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(1).STATUS)) {}
|
||||
sdk_system_restart_in_nmi();
|
||||
halt();
|
||||
}
|
||||
|
||||
// .Lfunc003 -- .text+0x1d0
|
||||
static int IRAM default_putc(char c) {
|
||||
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(0).STATUS) > 125) {}
|
||||
UART(0).FIFO = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// .Lfunc004 -- .text+0x1f4
|
||||
static void IRAM default_putc1(char c) {
|
||||
if (c == '\n') {
|
||||
default_putc('\r');
|
||||
} else if (c == '\r') {
|
||||
return;
|
||||
}
|
||||
default_putc(c);
|
||||
}
|
||||
|
||||
// .text+0x258
|
||||
void IRAM sdk_user_start(void) {
|
||||
uint32_t buf32[sizeof(struct sdk_g_ic_saved_st) / 4];
|
||||
uint8_t *buf8 = (uint8_t *)buf32;
|
||||
uint32_t flash_speed_divisor;
|
||||
uint32_t flash_sectors;
|
||||
uint32_t flash_size;
|
||||
int boot_slot;
|
||||
uint32_t cksum_magic;
|
||||
uint32_t cksum_len;
|
||||
uint32_t cksum_value;
|
||||
uint32_t ic_flash_addr;
|
||||
|
||||
SPI(0).USER0 |= SPI_USER0_CS_SETUP;
|
||||
sdk_SPIRead(0, buf32, 4);
|
||||
|
||||
switch (buf8[3] & 0x0f) {
|
||||
case 0xf: // 80 MHz
|
||||
flash_speed_divisor = 1;
|
||||
break;
|
||||
case 0x0: // 40 MHz
|
||||
flash_speed_divisor = 2;
|
||||
break;
|
||||
case 0x1: // 26 MHz
|
||||
flash_speed_divisor = 3;
|
||||
break;
|
||||
case 0x2: // 20 MHz
|
||||
flash_speed_divisor = 4;
|
||||
break;
|
||||
default: // Invalid -- Assume 40 MHz
|
||||
flash_speed_divisor = 2;
|
||||
}
|
||||
switch (buf8[3] >> 4) {
|
||||
case 0x0: // 4 Mbit (512 KByte)
|
||||
flash_sectors = 128;
|
||||
break;
|
||||
case 0x1: // 2 Mbit (256 Kbyte)
|
||||
flash_sectors = 64;
|
||||
break;
|
||||
case 0x2: // 8 Mbit (1 Mbyte)
|
||||
flash_sectors = 256;
|
||||
break;
|
||||
case 0x3: // 16 Mbit (2 Mbyte)
|
||||
flash_sectors = 512;
|
||||
break;
|
||||
case 0x4: // 32 Mbit (4 Mbyte)
|
||||
flash_sectors = 1024;
|
||||
break;
|
||||
default: // Invalid -- Assume 4 Mbit (512 KByte)
|
||||
flash_sectors = 128;
|
||||
}
|
||||
//FIXME: we should probably calculate flash_sectors by starting with flash_size and dividing by sdk_flashchip.sector_size instead of vice-versa.
|
||||
flash_size = flash_sectors * 4096;
|
||||
sdk_flashchip.chip_size = flash_size;
|
||||
set_spi0_divisor(flash_speed_divisor);
|
||||
sdk_SPIRead(flash_size - 4096, buf32, BOOT_INFO_SIZE);
|
||||
boot_slot = buf8[0] ? 1 : 0;
|
||||
cksum_magic = buf32[1];
|
||||
cksum_len = buf32[3 + boot_slot];
|
||||
cksum_value = buf32[5 + boot_slot];
|
||||
ic_flash_addr = (flash_sectors - 3 + boot_slot) * sdk_flashchip.sector_size;
|
||||
sdk_SPIRead(ic_flash_addr, buf32, sizeof(struct sdk_g_ic_saved_st));
|
||||
Cache_Read_Enable(0, 0, 1);
|
||||
zero_bss();
|
||||
sdk_os_install_putc1(default_putc1);
|
||||
if (cksum_magic == 0xffffffff) {
|
||||
// No checksum required
|
||||
} else if ((cksum_magic == 0x55aa55aa) &&
|
||||
(sdk_system_get_checksum(buf8, cksum_len) == cksum_value)) {
|
||||
// Checksum OK
|
||||
} else {
|
||||
// Bad checksum or bad cksum_magic value
|
||||
dump_flash_config_sectors(flash_sectors - 4);
|
||||
//FIXME: should we halt here? (original SDK code doesn't)
|
||||
}
|
||||
memcpy(&sdk_g_ic.s, buf32, sizeof(struct sdk_g_ic_saved_st));
|
||||
|
||||
user_start_phase2();
|
||||
}
|
||||
|
||||
// .text+0x3a8
|
||||
void IRAM vApplicationStackOverflowHook(xTaskHandle task, char *task_name) {
|
||||
printf("\"%s\"(stack_size = %lu) overflow the heap_size.\n", task_name, uxTaskGetStackHighWaterMark(task));
|
||||
}
|
||||
|
||||
// .text+0x3d8
|
||||
void IRAM vApplicationIdleHook(void) {
|
||||
printf("idle %u\n", WDEV.SYS_TIME);
|
||||
}
|
||||
|
||||
// .text+0x404
|
||||
void IRAM vApplicationTickHook(void) {
|
||||
printf("tick %u\n", WDEV.SYS_TIME);
|
||||
}
|
||||
|
||||
// .Lfunc005 -- .irom0.text+0x8
|
||||
static void zero_bss(void) {
|
||||
uint32_t *addr;
|
||||
|
||||
for (addr = &_bss_start; addr < &_bss_end; addr++) {
|
||||
*addr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// .Lfunc006 -- .irom0.text+0x70
|
||||
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr) {
|
||||
if (sdk_register_chipv6_phy(phy_info)) {
|
||||
printf("FATAL: sdk_register_chipv6_phy failed");
|
||||
halt();
|
||||
}
|
||||
sdk_uart_div_modify(0, UART_DIVISOR);
|
||||
sdk_uart_div_modify(1, UART_DIVISOR);
|
||||
sdk_phy_disable_agc();
|
||||
sdk_ieee80211_phy_init(sdk_g_ic.s.phy_mode);
|
||||
sdk_lmacInit();
|
||||
sdk_wDev_Initialize();
|
||||
sdk_pp_attach();
|
||||
sdk_ieee80211_ifattach(&sdk_g_ic, mac_addr);
|
||||
_xt_isr_mask(1);
|
||||
DPORT.DPORT0 = SET_FIELD(DPORT.DPORT0, DPORT_DPORT0_FIELD0, 1);
|
||||
sdk_pm_attach();
|
||||
sdk_phy_enable_agc();
|
||||
sdk_cnx_attach(&sdk_g_ic);
|
||||
sdk_wDevEnableRx();
|
||||
}
|
||||
|
||||
// .Lfunc007 -- .irom0.text+0x148
|
||||
static void init_g_ic(void) {
|
||||
if (sdk_g_ic.s.wifi_mode == 0xff) {
|
||||
sdk_g_ic.s.wifi_mode = 2;
|
||||
}
|
||||
sdk_wifi_softap_set_default_ssid();
|
||||
if (sdk_g_ic.s._unknown30d < 1 || sdk_g_ic.s._unknown30d > 14) {
|
||||
sdk_g_ic.s._unknown30d = 1;
|
||||
}
|
||||
if (sdk_g_ic.s._unknown544 < 100 || sdk_g_ic.s._unknown544 > 60000) {
|
||||
sdk_g_ic.s._unknown544 = 100;
|
||||
}
|
||||
if (sdk_g_ic.s._unknown30e == 1 || sdk_g_ic.s._unknown30e > 4) {
|
||||
sdk_g_ic.s._unknown30e = 0;
|
||||
}
|
||||
bzero(sdk_g_ic.s._unknown2ac, sizeof(sdk_g_ic.s._unknown2ac));
|
||||
if (sdk_g_ic.s._unknown30f > 1) {
|
||||
sdk_g_ic.s._unknown30f = 0;
|
||||
}
|
||||
if (sdk_g_ic.s._unknown310 > 4) {
|
||||
sdk_g_ic.s._unknown310 = 4;
|
||||
}
|
||||
if (sdk_g_ic.s._unknown1e4._unknown1e4 == 0xffffffff) {
|
||||
bzero(&sdk_g_ic.s._unknown1e4, sizeof(sdk_g_ic.s._unknown1e4));
|
||||
bzero(&sdk_g_ic.s._unknown20f, sizeof(sdk_g_ic.s._unknown20f));
|
||||
}
|
||||
sdk_g_ic.s.wifi_led_enable = 0;
|
||||
if (sdk_g_ic.s._unknown281 > 1) {
|
||||
sdk_g_ic.s._unknown281 = 0;
|
||||
}
|
||||
if (sdk_g_ic.s.ap_number > 5) {
|
||||
sdk_g_ic.s.ap_number = 1;
|
||||
}
|
||||
if (sdk_g_ic.s.phy_mode < 1 || sdk_g_ic.s.phy_mode > 3) {
|
||||
sdk_g_ic.s.phy_mode = PHY_MODE_11N;
|
||||
}
|
||||
}
|
||||
|
||||
// .Lfunc008 -- .irom0.text+0x2a0
|
||||
static void dump_excinfo(void) {
|
||||
uint32_t exccause, epc1, epc2, epc3, excvaddr, depc, excsave1;
|
||||
uint32_t excinfo[8];
|
||||
|
||||
RSR(exccause, exccause);
|
||||
printf("Fatal exception (%d): \n", (int)exccause);
|
||||
RSR(epc1, epc1);
|
||||
RSR(epc2, epc2);
|
||||
RSR(epc3, epc3);
|
||||
RSR(excvaddr, excvaddr);
|
||||
RSR(depc, depc);
|
||||
RSR(excsave1, excsave1);
|
||||
printf("%s=0x%08x\n", "epc1", epc1);
|
||||
printf("%s=0x%08x\n", "epc2", epc2);
|
||||
printf("%s=0x%08x\n", "epc3", epc3);
|
||||
printf("%s=0x%08x\n", "excvaddr", excvaddr);
|
||||
printf("%s=0x%08x\n", "depc", depc);
|
||||
printf("%s=0x%08x\n", "excsave1", excsave1);
|
||||
sdk_system_rtc_mem_read(0, excinfo, 32); // Why?
|
||||
excinfo[0] = 2;
|
||||
excinfo[1] = exccause;
|
||||
excinfo[2] = epc1;
|
||||
excinfo[3] = epc2;
|
||||
excinfo[4] = epc3;
|
||||
excinfo[5] = excvaddr;
|
||||
excinfo[6] = depc;
|
||||
excinfo[7] = excsave1;
|
||||
sdk_system_rtc_mem_write(0, excinfo, 32);
|
||||
}
|
||||
|
||||
// .irom0.text+0x368
|
||||
int sdk_uart_rx_one_char(char *buf) {
|
||||
if (FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(0).STATUS)) {
|
||||
*buf = UART(0).FIFO;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// .irom0.text+0x398
|
||||
void sdk_wdt_init(void) {
|
||||
WDT.CTRL &= ~WDT_CTRL_ENABLE;
|
||||
DPORT.INT_ENABLE |= DPORT_INT_ENABLE_WDT;
|
||||
WDT.REG1 = 0x0000000b;
|
||||
WDT.REG2 = 0x0000000c;
|
||||
WDT.CTRL |= WDT_CTRL_FLAG3 | WDT_CTRL_FLAG4 | WDT_CTRL_FLAG5;
|
||||
WDT.CTRL = SET_FIELD(WDT.CTRL, WDT_CTRL_FIELD0, 0);
|
||||
WDT.CTRL |= WDT_CTRL_ENABLE;
|
||||
sdk_pp_soft_wdt_init();
|
||||
}
|
||||
|
||||
// .irom0.text+0x474
|
||||
void sdk_user_init_task(void *params) {
|
||||
int phy_ver, pp_ver;
|
||||
|
||||
sdk_ets_timer_init();
|
||||
printf("\nESP-Open-SDK ver: %s compiled @ %s %s\n", OS_VERSION_STR, __DATE__, __TIME__);
|
||||
phy_ver = RTCMEM_BACKUP[RTCMEM_BACKUP_PHY_VER] >> 16;
|
||||
printf("phy ver: %d, ", phy_ver);
|
||||
pp_ver = RTCMEM_SYSTEM[RTCMEM_SYSTEM_PP_VER];
|
||||
printf("pp ver: %d.%d\n\n", (pp_ver >> 8) & 0xff, pp_ver & 0xff);
|
||||
user_init();
|
||||
sdk_user_init_flag = 1;
|
||||
sdk_wifi_mode_set(sdk_g_ic.s.wifi_mode);
|
||||
if (sdk_g_ic.s.wifi_mode == 1) {
|
||||
sdk_wifi_station_start();
|
||||
netif_set_default(sdk_g_ic.v.station_netif_info->netif);
|
||||
}
|
||||
if (sdk_g_ic.s.wifi_mode == 2) {
|
||||
sdk_wifi_softap_start();
|
||||
netif_set_default(sdk_g_ic.v.softap_netif_info->netif);
|
||||
}
|
||||
if (sdk_g_ic.s.wifi_mode == 3) {
|
||||
sdk_wifi_station_start();
|
||||
sdk_wifi_softap_start();
|
||||
netif_set_default(sdk_g_ic.v.softap_netif_info->netif);
|
||||
}
|
||||
if (sdk_wifi_station_get_auto_connect()) {
|
||||
sdk_wifi_station_connect();
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// .Lfunc009 -- .irom0.text+0x5b4
|
||||
static void user_start_phase2(void) {
|
||||
uint8_t *buf;
|
||||
uint8_t *phy_info;
|
||||
|
||||
sdk_system_rtc_mem_read(0, &sdk_rst_if, sizeof(sdk_rst_if));
|
||||
if (sdk_rst_if.version > 3) {
|
||||
// Bad version number. Probably garbage.
|
||||
bzero(&sdk_rst_if, sizeof(sdk_rst_if));
|
||||
}
|
||||
buf = malloc(sizeof(sdk_rst_if));
|
||||
bzero(buf, sizeof(sdk_rst_if));
|
||||
sdk_system_rtc_mem_write(0, buf, sizeof(sdk_rst_if));
|
||||
free(buf);
|
||||
sdk_sleep_reset_analog_rtcreg_8266();
|
||||
get_otp_mac_address(sdk_info.sta_mac_addr);
|
||||
sdk_wifi_softap_cacl_mac(sdk_info.softap_mac_addr, sdk_info.sta_mac_addr);
|
||||
sdk_info._unknown0 = 0x0104a8c0;
|
||||
sdk_info._unknown1 = 0x00ffffff;
|
||||
sdk_info._unknown2 = 0x0104a8c0;
|
||||
init_g_ic();
|
||||
phy_info = malloc(PHY_INFO_SIZE);
|
||||
sdk_spi_flash_read(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)phy_info, PHY_INFO_SIZE);
|
||||
|
||||
// Wait for UARTs to finish sending anything in their queues.
|
||||
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(0).STATUS) > 0) {}
|
||||
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(1).STATUS) > 0) {}
|
||||
|
||||
if (phy_info[0] != 5) {
|
||||
// Bad version byte. Discard what we read and use default values
|
||||
// instead.
|
||||
memcpy(phy_info, default_phy_info, PHY_INFO_SIZE);
|
||||
}
|
||||
init_networking(phy_info, sdk_info.sta_mac_addr);
|
||||
free(phy_info);
|
||||
tcpip_init(NULL, NULL);
|
||||
sdk_wdt_init();
|
||||
xTaskCreate(sdk_user_init_task, (signed char *)"uiT", 1024, 0, 14, &sdk_xUserTaskHandle);
|
||||
vTaskStartScheduler();
|
||||
}
|
||||
|
||||
// .Lfunc010 -- .irom0.text+0x710
|
||||
static void dump_flash_sector(uint32_t start_sector, uint32_t length) {
|
||||
uint8_t *buf;
|
||||
int bufsize, i;
|
||||
|
||||
bufsize = (length + 3) & 0xfffc;
|
||||
buf = malloc(bufsize);
|
||||
sdk_spi_flash_read(start_sector * sdk_flashchip.sector_size, (uint32_t *)buf
|
||||
, bufsize);
|
||||
for (i = 0; i < length; i++) {
|
||||
if ((i & 0xf) == 0) {
|
||||
if (i) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("%04x:", i);
|
||||
}
|
||||
printf(" %02x", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
free(buf);
|
||||
}
|
||||
|
||||
// .Lfunc011 -- .irom0.text+0x790
|
||||
static void dump_flash_config_sectors(uint32_t start_sector) {
|
||||
printf("system param error\n");
|
||||
// Note: original SDK code didn't dump PHY info
|
||||
printf("phy_info:\n");
|
||||
dump_flash_sector(start_sector, PHY_INFO_SIZE);
|
||||
printf("\ng_ic saved 0:\n");
|
||||
dump_flash_sector(start_sector + 1, sizeof(struct sdk_g_ic_saved_st));
|
||||
printf("\ng_ic saved 1:\n");
|
||||
dump_flash_sector(start_sector + 2, sizeof(struct sdk_g_ic_saved_st));
|
||||
printf("\nboot info:\n");
|
||||
dump_flash_sector(start_sector + 3, BOOT_INFO_SIZE);
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
INC_DIRS += $(core_ROOT)include
|
||||
|
||||
# args for passing into compile rule generation
|
||||
core_ROOT = $(ROOT)core/
|
||||
core_SRC_DIR = $(core_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,core))
|
||||
|
|
|
|||
25
core/cplusplus_operators.cpp
Normal file
25
core/cplusplus_operators.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* Part of esp-open-rtos
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
27
core/esp_hwrand.c
Normal file
27
core/esp_hwrand.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* Hardware Random Number Generator Functions
|
||||
*
|
||||
* For documentation, see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Angus Gratton
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <esp/hwrand.h>
|
||||
#include <esp/wdev_regs.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Return a random 32-bit number */
|
||||
uint32_t hwrand(void)
|
||||
{
|
||||
return WDEV.HWRNG;
|
||||
}
|
||||
|
||||
/* Fill a variable size buffer with data from the Hardware RNG */
|
||||
void hwrand_fill(uint8_t *buf, size_t len)
|
||||
{
|
||||
for(size_t i = 0; i < len; i+=4) {
|
||||
uint32_t random = WDEV.HWRNG;
|
||||
/* using memcpy here in case 'buf' is unaligned */
|
||||
memcpy(buf + i, &random, (i+4 <= len) ? 4 : (len % 4));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,256 +1,541 @@
|
|||
/* 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,
|
||||
which gets picked up specially in the linker script and placed
|
||||
at beginning of IRAM.
|
||||
#include "led_debug.s"
|
||||
|
||||
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.
|
||||
/* Some UserException causes, see table Table 4–64 in ISA reference */
|
||||
|
||||
Part of esp-open-rtos
|
||||
Original vector contents Copyright (C) 2014-2015 Espressif Systems
|
||||
Additions Copyright (C) Superhouse Automation Pty Ltd
|
||||
BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
.text
|
||||
.section .vecbase.text, "x"
|
||||
.align 256
|
||||
.global VecBase
|
||||
.type VecBase, @function /* it's not really a function, but treat it like one */
|
||||
#define CAUSE_SYSCALL 1
|
||||
#define CAUSE_LOADSTORE 3
|
||||
#define CAUSE_LVL1INT 4
|
||||
|
||||
.section .bss
|
||||
|
||||
NMIHandlerStack: # stack space for NMI handler
|
||||
.skip 4*0x100
|
||||
.LNMIHandlerStackTop:
|
||||
NMIRegisterSaved: # register space for saving NMI registers
|
||||
.skip 4*(16 + 6)
|
||||
|
||||
LoadStoreErrorHandlerStack:
|
||||
.word 0 # a0
|
||||
.word 0 # (unused)
|
||||
.word 0 # a2
|
||||
.word 0 # a3
|
||||
.word 0 # a4
|
||||
|
||||
/***************************** Exception Vectors *****************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Note: Exception vectors must be aligned on a 256-byte (0x100) boundary or
|
||||
* they will not function properly. (This is taken care of in the linker
|
||||
* script by ensuring .vecbase.text is aligned properly, and putting VecBase
|
||||
* right at the beginning of .vecbase.text) */
|
||||
.org 0
|
||||
VecBase:
|
||||
/* IMPORTANT: exception vector literals will go here, but we
|
||||
can't have more than 4 otherwise we push DebugExceptionVector past
|
||||
offset 0x10 relative to VecBase. There should be ways to avoid this,
|
||||
and also keep the VecBase offsets easy to read, but this works for now.
|
||||
*/
|
||||
.literal_position
|
||||
.align 16
|
||||
.global VecBase
|
||||
/* IMPORTANT: exception vector literals will go here, but we
|
||||
* can't have more than 4 otherwise we push DebugExceptionVector past
|
||||
* offset 0x10 relative to VecBase. There should be ways to avoid this,
|
||||
* and also keep the VecBase offsets easy to read, but this works for
|
||||
* now. */
|
||||
.literal_position
|
||||
|
||||
.org VecBase + 0x10
|
||||
DebugExceptionVector:
|
||||
wsr.excsave2 a0
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
rfi 2
|
||||
.align 16
|
||||
.type DebugExceptionVector, @function
|
||||
|
||||
wsr a0, excsave2
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
rfi 2
|
||||
|
||||
.org VecBase + 0x20
|
||||
NMIExceptionVector:
|
||||
wsr.excsave3 a0
|
||||
call0 CallNMIExceptionHandler
|
||||
rfi 3 /* CallNMIExceptionHandler should call rfi itself */
|
||||
.align 16
|
||||
.type NMIExceptionVector, @function
|
||||
|
||||
wsr a0, excsave3
|
||||
call0 CallNMIExceptionHandler
|
||||
rfi 3 # Should never be reached
|
||||
|
||||
.org VecBase + 0x30
|
||||
KernelExceptionVector:
|
||||
break 1, 0
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
rfe
|
||||
.align 16
|
||||
.L_EmptyVectorEntry:
|
||||
nop
|
||||
.align 16
|
||||
.type KernelExceptionVector, @function
|
||||
|
||||
break 1, 0
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
rfe
|
||||
|
||||
.org VecBase + 0x50
|
||||
UserExceptionVector:
|
||||
wsr.excsave1 a0
|
||||
call0 CallUserExceptionHandler
|
||||
rfe /* CallUserExceptionHandler should call rfe itself */
|
||||
.align 16
|
||||
.L_EmptyVectorEntry2:
|
||||
nop
|
||||
.align 16
|
||||
.type UserExceptionVector, @function
|
||||
|
||||
wsr a1, excsave1
|
||||
rsr a1, exccause
|
||||
beqi a1, CAUSE_LOADSTORE, LoadStoreErrorHandler
|
||||
j UserExceptionHandler
|
||||
|
||||
.org VecBase + 0x70
|
||||
DoubleExceptionVector:
|
||||
break 1, 4
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
.align 16
|
||||
.L_UnusedResetVector:
|
||||
/* reset vector slot doesn't get used, as vecbase goes back to mask ROM on reset */
|
||||
nop
|
||||
.type DoubleExceptionVector, @function
|
||||
|
||||
.section .bss
|
||||
NMIHandlerStack: /* stack space for NMI handler */
|
||||
.skip 4*0x100
|
||||
NMIRegisterSaved: /* register space for saving NMI registers */
|
||||
.skip 4*(0x16 + 6)
|
||||
break 1, 4
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
|
||||
/* this symbol is _Pri_3_HandlerAddress in the RTOS SDK, appears totally
|
||||
unused (stays zero at all times) */
|
||||
.global NMIHandlerAddress
|
||||
NMIHandlerAddress:
|
||||
.long 0
|
||||
/* Reset vector at offset 0x80 is unused, as vecbase gets reset to mask ROM
|
||||
* vectors on chip reset. */
|
||||
|
||||
/*************************** LoadStoreError Handler **************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Xtensa "Load/Store Exception" handler:
|
||||
* Completes L8/L16 load instructions from Instruction address space, for which
|
||||
* the architecture only supports 32-bit reads.
|
||||
*
|
||||
* Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause
|
||||
*
|
||||
* (Fast path (no branches) is for L8UI)
|
||||
*/
|
||||
.literal_position
|
||||
|
||||
.balign 4
|
||||
LoadStoreErrorHandler:
|
||||
.type LoadStoreErrorHandler, @function
|
||||
|
||||
/* Registers are saved in the address corresponding to their register
|
||||
* number times 4. This allows a quick and easy mapping later on when
|
||||
* needing to store the value to a particular register number. */
|
||||
movi sp, LoadStoreErrorHandlerStack
|
||||
s32i a0, sp, 0
|
||||
s32i a2, sp, 0x08
|
||||
s32i a3, sp, 0x0c
|
||||
s32i a4, sp, 0x10
|
||||
rsr a0, sar # Save SAR in a0 to restore later
|
||||
|
||||
/* Examine the opcode which generated the exception */
|
||||
/* Note: Instructions are in this order to avoid pipeline stalls. */
|
||||
rsr a2, epc1
|
||||
movi a3, ~3
|
||||
ssa8l a2 # sar is now correct shift for aligned read
|
||||
and a2, a2, a3 # a2 now 4-byte aligned address of instruction
|
||||
l32i a4, a2, 0
|
||||
l32i a2, a2, 4
|
||||
movi a3, 0x00700F # opcode mask for l8ui/l16si/l16ui
|
||||
src a2, a2, a4 # a2 now instruction that failed
|
||||
and a3, a2, a3 # a3 is masked instruction
|
||||
bnei a3, 0x000002, .LSE_check_l16
|
||||
|
||||
/* Note: At this point, opcode could technically be one of two things:
|
||||
* xx0xx2 (L8UI)
|
||||
* xx8xx2 (Reserved (invalid) opcode)
|
||||
* It is assumed that we'll never get to this point from an illegal
|
||||
* opcode, so we don't bother to check for that case and presume this
|
||||
* is always an L8UI. */
|
||||
|
||||
movi a4, ~3
|
||||
rsr a3, excvaddr # read faulting address
|
||||
and a4, a3, a4 # a4 now word aligned read address
|
||||
|
||||
l32i a4, a4, 0 # perform the actual read
|
||||
ssa8l a3 # sar is now shift to extract a3's byte
|
||||
srl a3, a4 # shift right correct distance
|
||||
extui a4, a3, 0, 8 # mask off bits we need for an l8
|
||||
|
||||
.LSE_post_fetch:
|
||||
/* We jump back here after either the L8UI or the L16*I routines do the
|
||||
* necessary work to read the value from memory.
|
||||
* At this point, a2 holds the faulting instruction and a4 holds the
|
||||
* correctly read value.
|
||||
|
||||
* Restore original SAR value (saved in a0) and update EPC so we'll
|
||||
* return back to the instruction following the one we just emulated */
|
||||
|
||||
/* Note: Instructions are in this order to avoid pipeline stalls */
|
||||
rsr a3, epc1
|
||||
wsr a0, sar
|
||||
addi a3, a3, 0x3
|
||||
wsr a3, epc1
|
||||
|
||||
/* Stupid opcode tricks: The jumptable we use later on needs 16 bytes
|
||||
* per entry (so we can avoid a second jump by just doing a RFE inside
|
||||
* each entry). Unfortunately, however, Xtensa doesn't have an addx16
|
||||
* operation to make that easy for us. Luckily, all of the faulting
|
||||
* opcodes we're processing are guaranteed to have bit 3 be zero, which
|
||||
* means if we just shift the register bits of the opcode down by 3
|
||||
* instead of 4, we will get the register number multiplied by 2. This
|
||||
* combined with an addx8 will give us an effective addx16 without
|
||||
* needing any extra shift operations. */
|
||||
extui a2, a2, 3, 5 # a2 is now destination register 0-15 times 2
|
||||
|
||||
bgei a2, 10, .LSE_assign_reg # a5..a15 use jumptable
|
||||
beqi a2, 2, .LSE_assign_a1 # a1 uses a special routine
|
||||
|
||||
/* We're storing into a0 or a2..a4, which are all saved in our "stack"
|
||||
* area. Calculate the correct address and stick the value in there,
|
||||
* then just do our normal restore and RFE (no jumps required, which
|
||||
* actually makes a0..a4 substantially faster). */
|
||||
addx2 a2, a2, sp
|
||||
s32i a4, a2, 0
|
||||
|
||||
/* Restore all regs and return */
|
||||
l32i a0, sp, 0
|
||||
l32i a2, sp, 0x08
|
||||
l32i a3, sp, 0x0c
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1 # restore a1 saved by UserExceptionVector
|
||||
rfe
|
||||
|
||||
.LSE_assign_reg:
|
||||
/* At this point, a2 contains the register number times 2, a4 is the
|
||||
* read value. */
|
||||
|
||||
/* Calculate the jumptable address, and restore all regs except a2 and
|
||||
* a4 so we have less to do after jumping. */
|
||||
/* Note: Instructions are in this order to avoid pipeline stalls. */
|
||||
movi a3, .LSE_jumptable_base
|
||||
l32i a0, sp, 0
|
||||
addx8 a2, a2, a3 # a2 is now the address to jump to
|
||||
l32i a3, sp, 0x0c
|
||||
|
||||
jx a2
|
||||
|
||||
.balign 4
|
||||
.LSE_check_l16:
|
||||
/* At this point, a2 contains the opcode, a3 is masked opcode */
|
||||
movi a4, 0x001002 # l16si or l16ui opcode after masking
|
||||
bne a3, a4, .LSE_wrong_opcode
|
||||
|
||||
/* Note: At this point, the opcode could be one of two things:
|
||||
* xx1xx2 (L16UI)
|
||||
* xx9xx2 (L16SI)
|
||||
* Both of these we can handle. */
|
||||
|
||||
movi a4, ~3
|
||||
rsr a3, excvaddr # read faulting address
|
||||
and a4, a3, a4 # a4 now word aligned read address
|
||||
|
||||
l32i a4, a4, 0 # perform the actual read
|
||||
ssa8l a3 # sar is now shift to extract a3's bytes
|
||||
srl a3, a4 # shift right correct distance
|
||||
extui a4, a3, 0, 16 # mask off bits we need for an l16
|
||||
|
||||
bbci a2, 15, .LSE_post_fetch # Not a signed op
|
||||
bbci a4, 15, .LSE_post_fetch # Value does not need sign-extension
|
||||
|
||||
movi a3, 0xFFFF0000
|
||||
or a4, a3, a4 # set 32-bit sign bits
|
||||
j .LSE_post_fetch
|
||||
|
||||
.LSE_wrong_opcode:
|
||||
/* If we got here it's not an opcode we can try to fix, so bomb out.
|
||||
* Restore registers so any dump the fatal exception routine produces
|
||||
* will have correct values */
|
||||
wsr a0, sar
|
||||
l32i a0, sp, 0
|
||||
l32i a2, sp, 0x08
|
||||
l32i a3, sp, 0x0c
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
|
||||
.balign 4
|
||||
.LSE_assign_a1:
|
||||
/* a1 is saved in excsave1, so just update that with the value, */
|
||||
wsr a4, excsave1
|
||||
/* Then restore all regs and return */
|
||||
l32i a0, sp, 0
|
||||
l32i a2, sp, 0x08
|
||||
l32i a3, sp, 0x0c
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.balign 4
|
||||
.LSE_jumptable:
|
||||
/* The first 5 entries (80 bytes) of this table are unused (registers
|
||||
* a0..a4 are handled separately above). Rather than have a whole bunch
|
||||
* of wasted space, we just pretend that the table starts 80 bytes
|
||||
* earlier in memory. */
|
||||
.set .LSE_jumptable_base, .LSE_jumptable - (16 * 5)
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 5)
|
||||
mov a5, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 6)
|
||||
mov a6, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 7)
|
||||
mov a7, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 8)
|
||||
mov a8, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 9)
|
||||
mov a9, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 10)
|
||||
mov a10, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 11)
|
||||
mov a11, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 12)
|
||||
mov a12, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 13)
|
||||
mov a13, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 14)
|
||||
mov a14, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
.org .LSE_jumptable_base + (16 * 15)
|
||||
mov a15, a4
|
||||
l32i a2, sp, 0x08
|
||||
l32i a4, sp, 0x10
|
||||
rsr a1, excsave1
|
||||
rfe
|
||||
|
||||
/****************************** call_user_start ******************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* This is the first entrypoint called from the ROM after loading the image
|
||||
* into IRAM. It just sets up the VECBASE register to point at our own
|
||||
* exception vectors and then calls sdk_user_start() */
|
||||
|
||||
.literal_position
|
||||
|
||||
.balign 4
|
||||
call_user_start:
|
||||
.global call_user_start
|
||||
.type call_user_start, @function
|
||||
|
||||
movi a2, VecBase
|
||||
wsr a2, vecbase
|
||||
call0 sdk_user_start
|
||||
|
||||
/*************************** NMI Exception Handler ***************************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Save register relative to a0 */
|
||||
.macro SAVE_REG register, regnum
|
||||
s32i \register, a0, (0x20 + 4 * \regnum)
|
||||
s32i \register, a0, (4 * (\regnum + 6))
|
||||
.endm
|
||||
|
||||
/* Load register relative to sp */
|
||||
.macro LOAD_REG register, regnum
|
||||
l32i \register, sp, (0x20 + 4 * \regnum)
|
||||
l32i \register, sp, (4 * (\regnum + 6))
|
||||
.endm
|
||||
|
||||
.text
|
||||
.section .vecbase.text
|
||||
.literal_position
|
||||
.align 4
|
||||
.global call_user_start
|
||||
.type call_user_start, @function
|
||||
call_user_start:
|
||||
movi a2, VecBase
|
||||
wsr.vecbase a2
|
||||
call0 sdk_user_start
|
||||
.literal_position
|
||||
|
||||
.literal_position
|
||||
.align 16
|
||||
.type CallNMIExceptionHandler, @function
|
||||
.balign 16
|
||||
CallNMIExceptionHandler:
|
||||
movi a0, NMIRegisterSaved
|
||||
SAVE_REG a2, 2
|
||||
movi a2, NMIHandlerAddress
|
||||
l32i a2, a2, 0
|
||||
SAVE_REG sp, 1
|
||||
SAVE_REG a3, 3
|
||||
xsr.excsave3 a2 /* excsave3 is now NMIHandlerAddress, a2 is former a0 */
|
||||
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
|
||||
.type CallNMIExceptionHandler, @function
|
||||
|
||||
/* Some UserException causes, see table Table 4–64 in ISA reference */
|
||||
#define CAUSE_SYSCALL 1
|
||||
#define CAUSE_LVL1INT 4
|
||||
movi a0, NMIRegisterSaved
|
||||
SAVE_REG a2, 2
|
||||
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
|
||||
CallUserExceptionHandler:
|
||||
rsr.exccause a0
|
||||
beqi a0, CAUSE_SYSCALL, UserSyscallHandler
|
||||
mov a0, sp
|
||||
addi sp, sp, -0x50
|
||||
s32i a0, sp, 0x10
|
||||
rsr.ps a0
|
||||
s32i a0, sp, 0x08
|
||||
rsr.epc1 a0
|
||||
s32i a0, sp, 0x04
|
||||
rsr.excsave1 a0 /* a0 was saved in UserExceptionVector */
|
||||
s32i a0, sp, 0x0c
|
||||
movi a0, _xt_user_exit
|
||||
s32i a0, sp, 0x0
|
||||
call0 sdk__xt_int_enter
|
||||
movi a0, 0x23
|
||||
wsr.ps a0
|
||||
rsync
|
||||
rsr.exccause a2
|
||||
beqi a2, CAUSE_LVL1INT, UserHandleInterrupt
|
||||
/* Any UserException cause other than level 1 interrupt triggers a panic */
|
||||
/*********************** General UserException Handler ***********************/
|
||||
|
||||
.section .vecbase.text, "x"
|
||||
|
||||
/* Called by UserExceptionVector if EXCCAUSE is anything other than
|
||||
* LoadStoreCause. */
|
||||
|
||||
.literal_position
|
||||
|
||||
.balign 4
|
||||
UserExceptionHandler:
|
||||
.type UserExceptionHandler, @function
|
||||
xsr a0, excsave1 # a0 now contains sp
|
||||
mov sp, a0
|
||||
addi sp, sp, -0x50
|
||||
s32i a0, sp, 0x10
|
||||
rsr a0, ps
|
||||
s32i a0, sp, 0x08
|
||||
rsr a0, epc1
|
||||
s32i a0, sp, 0x04
|
||||
rsr a0, excsave1
|
||||
s32i a0, sp, 0x0c
|
||||
movi a0, _xt_user_exit
|
||||
s32i a0, sp, 0x0
|
||||
call0 sdk__xt_int_enter
|
||||
movi a0, 0x23
|
||||
wsr a0, ps
|
||||
rsync
|
||||
rsr a2, exccause
|
||||
beqi a2, CAUSE_LVL1INT, UserHandleInterrupt
|
||||
/* Any UserException cause other than level 1 interrupt should panic */
|
||||
UserFailOtherExceptionCause:
|
||||
break 1, 1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
break 1, 1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
UserHandleInterrupt:
|
||||
rsil a0, 1
|
||||
rsr.intenable a2
|
||||
rsr.interrupt a3
|
||||
movi a4, 0x3fff
|
||||
and a2, a2, a3
|
||||
and a2, a2, a4 /* a2 = 0x3FFF & INTENABLE & INTERRUPT */
|
||||
rsil a0, 1
|
||||
rsr a2, intenable
|
||||
rsr a3, interrupt
|
||||
movi a4, 0x3fff
|
||||
and a2, a2, a3
|
||||
and a2, a2, a4 # a2 = 0x3FFF & INTENABLE & INTERRUPT
|
||||
UserHandleTimer:
|
||||
movi a3, 0xffbf
|
||||
and a3, a2, a3 /* a3 = a2 & 0xFFBF, ie remove 0x40 from a2 if set */
|
||||
bnez a3, UserTimerDone /* bits other than 0x40 are set */
|
||||
movi a3, 0x40
|
||||
sub a12, a2, a3 /* a12 - a2 - 0x40 - I think a12 _must_ be zero here? */
|
||||
call0 sdk__xt_timer_int /* tick timer interrupt */
|
||||
mov a2, a12 /* restore a2 from a12, ie zero */
|
||||
beqz a2, UserIntDone
|
||||
movi a3, 0xffbf
|
||||
and a3, a2, a3 # a3 = a2 with bit 6 cleared
|
||||
bnez a3, UserTimerDone # If any non-timer interrupt bits set
|
||||
movi a3, 0x40
|
||||
sub a12, a2, a3 # a12 = a2 - 0x40 -- Will be zero if bit 6 set
|
||||
call0 sdk__xt_timer_int # tick timer interrupt
|
||||
mov a2, a12 # restore a2 from a12, ie zero
|
||||
beqz a2, UserIntDone
|
||||
UserTimerDone:
|
||||
call0 _xt_isr_handler
|
||||
bnez a2, UserHandleTimer
|
||||
call0 _xt_isr_handler
|
||||
bnez a2, UserHandleTimer
|
||||
UserIntDone:
|
||||
beqz a2, UserIntExit
|
||||
break 1, 1 /* non-zero remnant in a2 means fail */
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
beqz a2, UserIntExit
|
||||
/* FIXME: this code will never be reached */
|
||||
break 1, 1
|
||||
call0 sdk_user_fatal_exception_handler
|
||||
UserIntExit:
|
||||
call0 sdk__xt_int_exit /* calls rfi */
|
||||
call0 sdk__xt_int_exit # jumps to _xt_user_exit. Never returns here
|
||||
|
||||
/* As far as I can tell, the syscall handler is basically a no-op */
|
||||
UserSyscallHandler:
|
||||
addi sp, sp, -0x10
|
||||
s32i a2, sp, 0x08
|
||||
s32i a2, sp, 0x0c
|
||||
rsr.epc1 a2
|
||||
addi a3, a2, 0x3
|
||||
wsr.epc1 a3
|
||||
l32i a2, sp, 0x8
|
||||
l32i a3, sp, 0xc
|
||||
addi sp, sp, 0x10
|
||||
movi a0, 0x7f
|
||||
movnez a2, a0, a2
|
||||
rsr.excsave1 a0
|
||||
rfe
|
||||
.section .text
|
||||
|
||||
.global _xt_user_exit
|
||||
.type _xt_user_exit, @function
|
||||
/* _xt_user_exit is used to exit interrupt context. */
|
||||
/* TODO: Find a better place for this to live. */
|
||||
_xt_user_exit:
|
||||
l32i a0, sp, 0x8
|
||||
wsr.ps a0
|
||||
l32i a0, sp, 0x4
|
||||
wsr.epc1 a0
|
||||
l32i a0, sp, 0xc
|
||||
l32i sp, sp, 0x10
|
||||
rsync
|
||||
rfe
|
||||
.global _xt_user_exit
|
||||
.type _xt_user_exit, @function
|
||||
|
||||
l32i a0, sp, 0x8
|
||||
wsr a0, ps
|
||||
l32i a0, sp, 0x4
|
||||
wsr a0, epc1
|
||||
l32i a0, sp, 0xc
|
||||
l32i sp, sp, 0x10
|
||||
rsync
|
||||
rfe
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#ifndef _COMMON_MACROS_H
|
||||
#define _COMMON_MACROS_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#define UNUSED __attributed((unused))
|
||||
|
||||
#ifndef BIT
|
||||
|
|
@ -20,12 +22,21 @@
|
|||
* and shift) constants. Used primarily with ESP8266 register access.
|
||||
*/
|
||||
|
||||
#define VAL2FIELD(fieldname, value) (((value) & fieldname##_M) << fieldname##_S)
|
||||
#define VAL2FIELD(fieldname, value) ((value) << fieldname##_S)
|
||||
#define FIELD2VAL(fieldname, regbits) (((regbits) >> fieldname##_S) & fieldname##_M)
|
||||
|
||||
#define FIELD_MASK(fieldname) (fieldname##_M << fieldname##_S)
|
||||
#define SET_FIELD(regbits, fieldname, value) (((regbits) & ~FIELD_MASK(fieldname)) | VAL2FIELD(fieldname, value))
|
||||
|
||||
/* VAL2FIELD/SET_FIELD do not normally check to make sure that the passed value
|
||||
* will fit in the specified field (without clobbering other bits). This makes
|
||||
* them faster and is usually fine. If you do need to make sure that the value
|
||||
* will not overflow the field, use VAL2FIELD_M or SET_FIELD_M (which will
|
||||
* first mask the supplied value to only the allowed number of bits) instead.
|
||||
*/
|
||||
#define VAL2FIELD_M(fieldname, value) (((value) & fieldname##_M) << fieldname##_S)
|
||||
#define SET_FIELD_M(regbits, fieldname, value) (((regbits) & ~FIELD_MASK(fieldname)) | VAL2FIELD_M(fieldname, value))
|
||||
|
||||
/* Use this macro to store constant values in IROM flash instead
|
||||
of having them loaded into rodata (which resides in DRAM)
|
||||
|
||||
|
|
@ -36,7 +47,11 @@
|
|||
Important to note: IROM flash can only be accessed via 32-bit word
|
||||
aligned reads. It's up to the user of this attribute to ensure this.
|
||||
*/
|
||||
#define IROM __attribute__((section(".irom0.literal"))) const
|
||||
#ifdef __cplusplus
|
||||
#define IROM __attribute__((section(".irom0.literal")))
|
||||
#else
|
||||
#define IROM __attribute__((section(".irom0.literal"))) const
|
||||
#endif
|
||||
|
||||
#define INLINED inline static __attribute__((always_inline)) __attribute__((unused))
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ struct DPORT_REGS {
|
|||
uint32_t volatile OTP_MAC1; // 0x54
|
||||
uint32_t volatile OTP_CHIPID; // 0x58
|
||||
uint32_t volatile OTP_MAC2; // 0x5c
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct DPORT_REGS) == 0x60, "DPORT_REGS is the wrong size");
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ _Static_assert(sizeof(struct DPORT_REGS) == 0x60, "DPORT_REGS is the wrong size"
|
|||
|
||||
/* Currently very little known about this register. The following is based on analysis of the startup code in the Espressif SDK: */
|
||||
|
||||
#define DPORT_DPORT0_FIELD0_M 0x0000007f
|
||||
#define DPORT_DPORT0_FIELD0_M 0x0000001f
|
||||
#define DPORT_DPORT0_FIELD0_S 0
|
||||
|
||||
/* Details for INT_ENABLE register */
|
||||
|
|
|
|||
|
|
@ -27,28 +27,26 @@ typedef enum {
|
|||
INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction)
|
||||
{
|
||||
uint32_t iomux_flags;
|
||||
uint32_t ctrl_val;
|
||||
|
||||
switch(direction) {
|
||||
case GPIO_INPUT:
|
||||
iomux_flags = 0;
|
||||
ctrl_val = 0;
|
||||
break;
|
||||
case GPIO_OUTPUT:
|
||||
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
|
||||
ctrl_val = GPIO_CONF_PUSH_PULL;
|
||||
break;
|
||||
case GPIO_OUT_OPEN_DRAIN:
|
||||
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
|
||||
ctrl_val = 0;
|
||||
break;
|
||||
case GPIO_INPUT_PULLUP:
|
||||
iomux_flags = IOMUX_PIN_PULLUP;
|
||||
ctrl_val = 0;
|
||||
break;
|
||||
}
|
||||
iomux_set_gpio_function(gpio_num, iomux_flags);
|
||||
GPIO.CONF[gpio_num] = (GPIO.CONF[gpio_num] & FIELD_MASK(GPIO_CONF_INTTYPE)) | ctrl_val;
|
||||
if(direction == GPIO_OUT_OPEN_DRAIN)
|
||||
GPIO.CONF[gpio_num] |= GPIO_CONF_OPEN_DRAIN;
|
||||
else
|
||||
GPIO.CONF[gpio_num] &= ~GPIO_CONF_OPEN_DRAIN;
|
||||
if (iomux_flags & IOMUX_PIN_OUTPUT_ENABLE)
|
||||
GPIO.ENABLE_OUT_SET = BIT(gpio_num);
|
||||
else
|
||||
|
|
@ -124,7 +122,7 @@ INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int
|
|||
/* Return the interrupt type set for a pin */
|
||||
INLINED gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
|
||||
{
|
||||
return FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
|
||||
return (gpio_inttype_t)FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ struct GPIO_REGS {
|
|||
uint32_t volatile PWM; // 0x68
|
||||
uint32_t volatile RTC_CALIB; // 0x6c
|
||||
uint32_t volatile RTC_CALIB_RESULT; // 0x70
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size");
|
||||
|
||||
|
|
@ -76,10 +76,15 @@ _Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size");
|
|||
* Under what conditions this GPIO input should generate an interrupt.
|
||||
* (see gpio_inttype_t enum below for values)
|
||||
*
|
||||
* GPIO_CONF_PUSH_PULL (boolean)
|
||||
* When set, a high output state will pull the pin up to +Vcc (3.3V). When
|
||||
* cleared, output functions in "open drain" mode (low state will pull down
|
||||
* to ground, but high state allows output to "float").
|
||||
* GPIO_CONF_OPEN_DRAIN (boolean)
|
||||
* If this bit is set, the pin is in "open drain" mode - a high output state
|
||||
* will leave the pin floating but not source any current. If bit is cleared,
|
||||
* the pin is in push/pull mode so a high output state will drive the pin up
|
||||
* to +Vcc (3.3V). In either case, a low output state will pull the pin down
|
||||
* to ground.
|
||||
*
|
||||
* GPIO_CONF_OPEN_DRAIN does not appear to work on all pins.
|
||||
*
|
||||
*
|
||||
* GPIO_CONF_SOURCE_PWM (boolean)
|
||||
* When set, GPIO pin output will be connected to the sigma-delta PWM
|
||||
|
|
@ -93,7 +98,7 @@ _Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size");
|
|||
#define GPIO_CONF_WAKEUP_ENABLE BIT(10)
|
||||
#define GPIO_CONF_INTTYPE_M 0x00000007
|
||||
#define GPIO_CONF_INTTYPE_S 7
|
||||
#define GPIO_CONF_PUSH_PULL BIT(2)
|
||||
#define GPIO_CONF_OPEN_DRAIN BIT(2)
|
||||
#define GPIO_CONF_SOURCE_PWM BIT(0)
|
||||
|
||||
/* Valid values for the GPIO_CONF_INTTYPE field */
|
||||
|
|
|
|||
30
core/include/esp/hwrand.h
Normal file
30
core/include/esp/hwrand.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/** 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>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -11,6 +11,10 @@
|
|||
#include "esp/types.h"
|
||||
#include "esp/iomux_regs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Convert a GPIO pin number to an iomux register index.
|
||||
*
|
||||
|
|
@ -64,4 +68,8 @@ inline static void iomux_set_gpio_function(const uint8_t gpio_number, const uint
|
|||
declared above */
|
||||
#include "esp/iomux_private.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
struct IOMUX_REGS {
|
||||
uint32_t volatile CONF; // 0x00
|
||||
uint32_t volatile PIN[16]; // 0x04 - 0x40
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size");
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ _Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size"
|
|||
#define IOMUX_PIN_FUNC_MASK 0x00001030
|
||||
|
||||
/* WARNING: Macro evaluates argument twice */
|
||||
#define IOMUX_FUNC(val) (VAL2FIELD(IOMUX_PIN_FUNC_LOW, val) | VAL2FIELD(IOMUX_PIN_FUNC_HIGH, val))
|
||||
#define IOMUX_FUNC(val) (VAL2FIELD_M(IOMUX_PIN_FUNC_LOW, val) | VAL2FIELD_M(IOMUX_PIN_FUNC_HIGH, val))
|
||||
|
||||
/* WARNING: Macro evaluates argument twice */
|
||||
#define IOMUX_FUNC_VALUE(regbits) (FIELD2VAL(IOMUX_PIN_FUNC_LOW, regbits) | FIELD2VAL(IOMUX_PIN_FUNC_HIGH, regbits))
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@
|
|||
*/
|
||||
#ifndef _ESP_ROM_H
|
||||
#define _ESP_ROM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void Cache_Read_Disable(void);
|
||||
|
||||
/* http://esp8266-re.foogod.com/wiki/Cache_Read_Enable
|
||||
|
|
@ -18,4 +21,8 @@ void Cache_Read_Disable(void);
|
|||
*/
|
||||
void Cache_Read_Enable(uint32_t odd_even, uint32_t mb_count, uint32_t no_idea);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ struct SPI_REGS {
|
|||
uint32_t volatile EXT1; // 0xf4
|
||||
uint32_t volatile EXT2; // 0xf8
|
||||
uint32_t volatile EXT3; // 0xfc
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
#include "esp/timer_regs.h"
|
||||
#include "esp/cpu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
FRC1 = 0,
|
||||
FRC2 = 1,
|
||||
|
|
@ -129,4 +133,8 @@ INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us);
|
|||
|
||||
#include "timer_private.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
#ifndef _ESP_TIMER_PRIVATE_H
|
||||
#define _ESP_TIMER_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -193,7 +197,7 @@ INLINED bool _timer_set_frequency_impl(const timer_frc_t frc, uint32_t freq)
|
|||
counts = timer_freq_to_count(frc, freq, div);
|
||||
if(counts == 0)
|
||||
{
|
||||
printf("ABORT: No counter for timer %u frequency %lu\r\n", frc, freq);
|
||||
printf("ABORT: No counter for timer %u frequency %u\r\n", frc, freq);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
|
@ -255,6 +259,8 @@ INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us)
|
|||
return _timer_set_timeout_runtime(frc, us);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct TIMER_REGS { // FRC1 FRC2
|
|||
uint32_t volatile CTRL; // 0x08 0x28
|
||||
uint32_t volatile STATUS; // 0x0c 0x2c
|
||||
uint32_t volatile ALARM; // 0x30
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct TIMER_REGS) == 0x14, "TIMER_REGS is the wrong size");
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
*/
|
||||
|
||||
#define UART_BASE 0x60000000
|
||||
#define UART(i) (*(struct UART_REGS *)(0x60000200 - (i)*0xf00))
|
||||
#define UART(i) (*(struct UART_REGS *)(UART_BASE + (i)*0xf00))
|
||||
|
||||
#define UART0_BASE UART_BASE
|
||||
#define UART1_BASE (UART_BASE + 0xf00)
|
||||
|
|
@ -46,7 +46,7 @@ struct UART_REGS {
|
|||
uint32_t volatile _unused[17]; // 0x34 - 0x74
|
||||
uint32_t volatile DATE; // 0x78
|
||||
uint32_t volatile ID; // 0x7c
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct UART_REGS) == 0x80, "UART_REGS is the wrong size");
|
||||
|
||||
|
|
|
|||
42
core/include/esp/wdev_regs.h
Normal file
42
core/include/esp/wdev_regs.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* esp/wdev_regs.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _ESP_WDEV_REGS_H
|
||||
#define _ESP_WDEV_REGS_H
|
||||
|
||||
#include "esp/types.h"
|
||||
#include "common_macros.h"
|
||||
|
||||
#define WDEV_BASE 0x3FF20000
|
||||
#define WDEV (*(struct WDEV_REGS *)(WDEV_BASE))
|
||||
|
||||
/* Note: This memory region is not currently well understood. Pretty much all
|
||||
* of the definitions here are from reverse-engineering the Espressif SDK code,
|
||||
* many are just educated guesses, and almost certainly some are misleading or
|
||||
* wrong. If you can improve on any of this, please contribute!
|
||||
*/
|
||||
|
||||
struct WDEV_REGS {
|
||||
uint32_t volatile _unknown0[768]; // 0x0000 - 0x0bfc
|
||||
uint32_t volatile SYS_TIME; // 0x0c00
|
||||
uint32_t volatile _unknown1[144]; // 0x0c04 - 0x0e40
|
||||
uint32_t volatile HWRNG; // 0xe44 HW RNG, see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
_Static_assert(sizeof(struct WDEV_REGS) == 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 */
|
||||
|
||||
|
|
@ -27,10 +27,21 @@ struct WDT_REGS {
|
|||
uint32_t volatile REG2; // 0x08
|
||||
uint32_t volatile _unused[2]; // 0x0c - 0x10
|
||||
uint32_t volatile FEED; // 0x14
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct WDT_REGS) == 0x18, "WDT_REGS is the wrong size");
|
||||
|
||||
/* Details for CTRL register */
|
||||
|
||||
/* Note: these are currently just guesses based on interpretation of the startup code */
|
||||
|
||||
#define WDT_CTRL_ENABLE BIT(0)
|
||||
#define WDT_CTRL_FIELD0_M 0x00000003
|
||||
#define WDT_CTRL_FIELD0_S 1
|
||||
#define WDT_CTRL_FLAG3 BIT(3)
|
||||
#define WDT_CTRL_FLAG4 BIT(4)
|
||||
#define WDT_CTRL_FLAG5 BIT(5)
|
||||
|
||||
/* Writing WDT_FEED_MAGIC to WDT.FEED register "feeds the dog" and holds off
|
||||
* triggering for another cycle (unconfirmed) */
|
||||
#define WDT_FEED_MAGIC 0x73
|
||||
|
|
|
|||
6
core/include/os_version.h
Normal file
6
core/include/os_version.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _VERSION_H
|
||||
#define _VERSION_H
|
||||
|
||||
#define OS_VERSION_STR "0.0.1"
|
||||
|
||||
#endif /* _VERSION_H */
|
||||
232
core/include/sdk_internal.h
Normal file
232
core/include/sdk_internal.h
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
#ifndef _INTERNAL_SDK_STRUCTURES_H
|
||||
#define _INTERNAL_SDK_STRUCTURES_H
|
||||
|
||||
#include "espressif/esp_wifi.h"
|
||||
#include "espressif/spi_flash.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Internal structures and data objects //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 'info' is declared in app_main.o at .bss+0x4
|
||||
|
||||
struct sdk_info_st {
|
||||
uint32_t _unknown0;
|
||||
uint32_t _unknown1;
|
||||
uint32_t _unknown2;
|
||||
uint8_t _unknown3[12];
|
||||
uint8_t softap_mac_addr[6];
|
||||
uint8_t sta_mac_addr[6];
|
||||
};
|
||||
|
||||
extern struct sdk_info_st sdk_info;
|
||||
|
||||
// 'rst_if' is declared in user_interface.o at .bss+0xfc
|
||||
|
||||
struct sdk_rst_if_st {
|
||||
uint32_t version;
|
||||
uint8_t _unknown[28];
|
||||
};
|
||||
|
||||
extern struct sdk_rst_if_st sdk_rst_if;
|
||||
|
||||
// 'g_ic' is declared in libnet80211/ieee80211.o at .bss+0x0
|
||||
// See also: http://esp8266-re.foogod.com/wiki/G_ic_(IoT_RTOS_SDK_0.9.9)
|
||||
|
||||
struct sdk_g_ic_netif_info {
|
||||
struct netif *netif;
|
||||
//TODO: rest of this structure is unknown.
|
||||
};
|
||||
|
||||
// This is the portion of g_ic which is not loaded/saved to the flash ROM, and
|
||||
// starts out zeroed on every boot.
|
||||
struct sdk_g_ic_volatile_st {
|
||||
void *_unknown0;
|
||||
void *_unknown4;
|
||||
|
||||
uint8_t _unknown8[8];
|
||||
|
||||
struct sdk_g_ic_netif_info *station_netif_info;
|
||||
struct sdk_g_ic_netif_info *softap_netif_info;
|
||||
uint8_t _unknown18;
|
||||
uint32_t _unknown1c;
|
||||
uint32_t _unknown20;
|
||||
|
||||
uint8_t _unknown24[8];
|
||||
|
||||
uint8_t _unknown2c;
|
||||
|
||||
uint8_t _unknown30[76];
|
||||
|
||||
uint8_t _unknown7c;
|
||||
uint8_t _unknown7d;
|
||||
uint8_t _unknown7e;
|
||||
uint8_t _unknown7f;
|
||||
|
||||
uint8_t _unknown80[204];
|
||||
|
||||
void *_unknown14c;
|
||||
|
||||
uint8_t _unknown150[20];
|
||||
|
||||
uint32_t _unknown164;
|
||||
void *_unknown168;
|
||||
void *_unknown16c;
|
||||
void *_unknown170;
|
||||
void *_unknown174;
|
||||
void *_unknown178;
|
||||
|
||||
uint8_t _unknown17c[4];
|
||||
|
||||
void *_unknown180;
|
||||
void *_unknown184;
|
||||
struct station_info *station_info_head;
|
||||
struct station_info *station_info_tail;
|
||||
uint32_t _unknown190;
|
||||
uint32_t _unknown194;
|
||||
|
||||
uint8_t _unknown198[40];
|
||||
|
||||
void *_unknown1c0;
|
||||
void *_unknown1c4;
|
||||
uint32_t _unknown1c8;
|
||||
|
||||
uint8_t _unknown1cc[4];
|
||||
|
||||
uint16_t _unknown1d0;
|
||||
|
||||
uint8_t _unknown1d2[2];
|
||||
|
||||
uint8_t _unknown1d4;
|
||||
|
||||
uint8_t _unknown1d5[3];
|
||||
};
|
||||
|
||||
struct sdk_g_ic_unk0_st {
|
||||
uint32_t _unknown1e4;
|
||||
uint8_t _unknown1e8[32];
|
||||
};
|
||||
|
||||
// This is the portion of g_ic which is loaded/saved to the flash ROM, and thus
|
||||
// is preserved across reboots.
|
||||
struct sdk_g_ic_saved_st {
|
||||
uint8_t _unknown1d8;
|
||||
uint8_t boot_info;
|
||||
uint8_t user0_addr[3];
|
||||
uint8_t user1_addr[3];
|
||||
uint8_t wifi_mode;
|
||||
uint8_t wifi_led_enable;
|
||||
uint8_t wifi_led_gpio;
|
||||
uint8_t _unknown1e3;
|
||||
|
||||
struct sdk_g_ic_unk0_st _unknown1e4;
|
||||
|
||||
uint8_t _unknown208;
|
||||
uint8_t _unknown209;
|
||||
uint8_t _unknown20a;
|
||||
uint8_t _unknown20b;
|
||||
uint8_t _unknown20c;
|
||||
uint8_t _unknown20d;
|
||||
uint8_t _unknown20e;
|
||||
uint8_t _unknown20f[64];
|
||||
uint8_t _unknown24f;
|
||||
|
||||
uint8_t _unknown250[49];
|
||||
|
||||
uint8_t _unknown281;
|
||||
|
||||
uint8_t _unknown282[6];
|
||||
|
||||
uint32_t _unknown288;
|
||||
uint8_t _unknown28c;
|
||||
|
||||
uint8_t _unknown28d[31];
|
||||
|
||||
uint8_t _unknown2ac[64];
|
||||
uint8_t _unknonwn2ec;
|
||||
|
||||
uint8_t _unknown2ed[32];
|
||||
|
||||
uint8_t _unknown30d;
|
||||
uint8_t _unknown30e;
|
||||
uint8_t _unknown30f;
|
||||
uint8_t _unknown310;
|
||||
|
||||
uint8_t _unknown311[3];
|
||||
|
||||
uint8_t ap_number;
|
||||
uint8_t current_ap_id;
|
||||
|
||||
uint8_t _unknown316[502];
|
||||
|
||||
uint32_t _unknown50c;
|
||||
uint16_t _unknown510;
|
||||
uint16_t _unknown512;
|
||||
uint16_t _unknown514;
|
||||
|
||||
uint8_t _unknown516[2];
|
||||
|
||||
uint8_t auto_connect;
|
||||
|
||||
uint8_t _unknown519[3];
|
||||
|
||||
enum sdk_phy_mode phy_mode;
|
||||
|
||||
uint8_t _unknown520[36];
|
||||
|
||||
uint16_t _unknown544;
|
||||
|
||||
uint8_t _unknown546[2];
|
||||
};
|
||||
|
||||
struct sdk_g_ic_st {
|
||||
struct sdk_g_ic_volatile_st v; // 0x0 - 0x1d8
|
||||
struct sdk_g_ic_saved_st s; // 0x1d8 - 0x548
|
||||
};
|
||||
|
||||
extern struct sdk_g_ic_st sdk_g_ic;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The above structures all refer to data regions outside our control, and a
|
||||
// simple mistake/misunderstanding editing things here can completely screw up
|
||||
// how we access them, so do some basic sanity checks to make sure that they
|
||||
// appear to match up correctly with the actual data structures other parts of
|
||||
// the SDK are expecting.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_Static_assert(sizeof(struct sdk_info_st) == 0x24, "info_st is the wrong size!");
|
||||
_Static_assert(sizeof(struct sdk_rst_if_st) == 0x20, "sdk_rst_if_st is the wrong size!");
|
||||
_Static_assert(sizeof(struct sdk_g_ic_volatile_st) == 0x1d8, "sdk_g_ic_volatile_st is the wrong size!");
|
||||
_Static_assert(sizeof(struct sdk_g_ic_saved_st) == 0x370, "sdk_g_ic_saved_st is the wrong size!");
|
||||
_Static_assert(sizeof(struct sdk_g_ic_st) == 0x548, "sdk_g_ic_st is the wrong size!");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Function Prototypes //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sdk_SpiFlashOpResult sdk_SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size);
|
||||
sdk_SpiFlashOpResult sdk_SPIWrite(uint32_t des_addr, uint32_t *src_addr, uint32_t size);
|
||||
void sdk_cnx_attach(struct sdk_g_ic_st *);
|
||||
void sdk_ets_timer_init(void);
|
||||
void sdk_ieee80211_ifattach(struct sdk_g_ic_st *, uint8_t *);
|
||||
void sdk_ieee80211_phy_init(enum sdk_phy_mode);
|
||||
void sdk_lmacInit(void);
|
||||
void sdk_phy_disable_agc(void);
|
||||
void sdk_phy_enable_agc(void);
|
||||
void sdk_pm_attach(void);
|
||||
void sdk_pp_attach(void);
|
||||
void sdk_pp_soft_wdt_init(void);
|
||||
int sdk_register_chipv6_phy(uint8_t *);
|
||||
void sdk_sleep_reset_analog_rtcreg_8266(void);
|
||||
uint32_t sdk_system_get_checksum(uint8_t *, uint32_t);
|
||||
void sdk_system_restart_in_nmi(void);
|
||||
void sdk_wDevEnableRx(void);
|
||||
void sdk_wDev_Initialize(void);
|
||||
void sdk_wifi_mode_set(uint8_t);
|
||||
void sdk_wifi_softap_cacl_mac(uint8_t *, uint8_t *);
|
||||
void sdk_wifi_softap_set_default_ssid(void);
|
||||
void sdk_wifi_softap_start(void);
|
||||
void sdk_wifi_station_start(void);
|
||||
|
||||
#endif /* _INTERNAL_SDK_STRUCTURES_H */
|
||||
21
core/include/xtensa_ops.h
Normal file
21
core/include/xtensa_ops.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/** xtensa_ops.h
|
||||
*
|
||||
* Special macros/etc which deal with Xtensa-specific architecture/CPU
|
||||
* considerations.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
#ifndef _XTENSA_OPS_H
|
||||
#define _XTENSA_OPS_H
|
||||
|
||||
// GCC macros for reading, writing, and exchanging Xtensa processor special
|
||||
// registers:
|
||||
|
||||
#define RSR(var, reg) asm volatile ("rsr %0, " #reg : "=r" (var));
|
||||
#define WSR(var, reg) asm volatile ("wsr %0, " #reg : : "r" (var));
|
||||
#define XSR(var, reg) asm volatile ("xsr %0, " #reg : "+r" (var));
|
||||
|
||||
#endif /* _XTENSA_OPS_H */
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
*
|
||||
* To have this work from initial reset, without needing an iomux call
|
||||
* first, choose a pin where iomux defaults to GPIO (ie 0,2,4,5)
|
||||
*
|
||||
* Current sets on=LOW, as the GPIO2 pin is active low
|
||||
*/
|
||||
LED_GPIO=2
|
||||
GPIO_DIR_SET = 0x6000030c
|
||||
|
|
@ -19,11 +21,11 @@ GPIO_OUT_CLEAR = 0x60000308
|
|||
.endm
|
||||
|
||||
// Turn LED on. rega, regb will be clobbered
|
||||
.macro led_on rega, regb
|
||||
.macro led_off rega, regb
|
||||
led_op \rega, \regb, GPIO_OUT_SET
|
||||
.endm
|
||||
|
||||
// Turn LED off. rega, regb will be clobbered
|
||||
.macro led_off rega, regb
|
||||
// Turn LED on. rega, regb will be clobbered
|
||||
.macro led_on rega, regb
|
||||
led_op \rega, \regb, GPIO_OUT_CLEAR
|
||||
.endm
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
#include <sys/reent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/errno.h>
|
||||
#include <espressif/sdk_private.h>
|
||||
#include <common_macros.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -37,6 +38,10 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr)
|
|||
*/
|
||||
long _write_r(struct _reent *r, int fd, const char *ptr, int len )
|
||||
{
|
||||
if(fd != r->_stdout->_file) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
for(int i = 0; i < len; i++)
|
||||
sdk_os_putc(ptr[i]);
|
||||
return len;
|
||||
|
|
@ -49,29 +54,31 @@ long _write_r(struct _reent *r, int fd, const char *ptr, int len )
|
|||
*/
|
||||
long __attribute__((weak)) _read_r( struct _reent *r, int fd, char *ptr, int len )
|
||||
{
|
||||
for(int i = 0; i < len; i++) {
|
||||
char ch;
|
||||
while (sdk_uart_rx_one_char(&ch)) ;
|
||||
ptr[i] = ch;
|
||||
|
||||
}
|
||||
return len;
|
||||
if(fd != r->_stdin->_file) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
for(int i = 0; i < len; i++) {
|
||||
char ch;
|
||||
while (sdk_uart_rx_one_char(&ch)) ;
|
||||
ptr[i] = ch;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* These are stub implementations for the reentrant syscalls that
|
||||
* newlib is configured to expect */
|
||||
int _fstat_r(struct _reent *r, int fd, void *buf)
|
||||
/* Stub syscall implementations follow, to allow compiling newlib functions that
|
||||
pull these in via various codepaths
|
||||
*/
|
||||
__attribute__((alias("syscall_returns_enosys"))) int _open_r(struct _reent *r, const char *pathname, int flags, int mode);
|
||||
__attribute__((alias("syscall_returns_enosys"))) int _fstat_r(struct _reent *r, int fd, void *buf);
|
||||
__attribute__((alias("syscall_returns_enosys"))) int _close_r(struct _reent *r, int fd);
|
||||
__attribute__((alias("syscall_returns_enosys"))) off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence);
|
||||
|
||||
/* Generic stub for any newlib syscall that fails with errno ENOSYS
|
||||
("Function not implemented") and a return value equivalent to
|
||||
(int)-1. */
|
||||
static int syscall_returns_enosys(struct _reent *r)
|
||||
{
|
||||
r->_errno=ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _close_r(struct _reent *r, int fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence)
|
||||
{
|
||||
return (off_t)-1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,3 +14,18 @@ void IRAM *zalloc(size_t nbytes)
|
|||
{
|
||||
return calloc(1, nbytes);
|
||||
}
|
||||
|
||||
extern void (*__init_array_start)(void);
|
||||
extern void (*__init_array_end)(void);
|
||||
|
||||
/* Do things which should be done as part of the startup code, but aren't.
|
||||
|
||||
Can be replaced with _start() once we have open source startup code.
|
||||
*/
|
||||
void sdk_compat_initialise()
|
||||
{
|
||||
/* Call C++ constructors or C functions marked with __attribute__((constructor)) */
|
||||
void (**p)(void);
|
||||
for ( p = &__init_array_start; p != &__init_array_end; ++p)
|
||||
(*p)();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue