1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * Development of the code in this file was sponsored by Microbric Pty Ltd
5  *
6  * The MIT License (MIT)
7  *
8  * Copyright (c) 2016 Damien P. George
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdarg.h>
32 
33 #include "freertos/FreeRTOS.h"
34 #include "freertos/task.h"
35 #include "esp_system.h"
36 #include "nvs_flash.h"
37 #include "esp_task.h"
38 #include "soc/cpu.h"
39 #include "esp_log.h"
40 
41 #if CONFIG_IDF_TARGET_ESP32
42 #include "esp32/spiram.h"
43 #elif CONFIG_IDF_TARGET_ESP32S2
44 #include "esp32s2/spiram.h"
45 #elif CONFIG_IDF_TARGET_ESP32S3
46 #include "esp32s3/spiram.h"
47 #endif
48 
49 #include "py/stackctrl.h"
50 #include "py/nlr.h"
51 #include "py/compile.h"
52 #include "py/runtime.h"
53 #include "py/persistentcode.h"
54 #include "py/repl.h"
55 #include "py/gc.h"
56 #include "py/mphal.h"
57 #include "shared/readline/readline.h"
58 #include "shared/runtime/pyexec.h"
59 #include "uart.h"
60 #include "usb.h"
61 #include "usb_serial_jtag.h"
62 #include "modmachine.h"
63 #include "modnetwork.h"
64 #include "mpthreadport.h"
65 
66 #if MICROPY_BLUETOOTH_NIMBLE
67 #include "extmod/modbluetooth.h"
68 #endif
69 
70 // MicroPython runs as a task under FreeRTOS
71 #define MP_TASK_PRIORITY        (ESP_TASK_PRIO_MIN + 1)
72 #define MP_TASK_STACK_SIZE      (16 * 1024)
73 
74 // Set the margin for detecting stack overflow, depending on the CPU architecture.
75 #if CONFIG_IDF_TARGET_ESP32C3
76 #define MP_TASK_STACK_LIMIT_MARGIN (2048)
77 #else
78 #define MP_TASK_STACK_LIMIT_MARGIN (1024)
79 #endif
80 
vprintf_null(const char * format,va_list ap)81 int vprintf_null(const char *format, va_list ap) {
82     // do nothing: this is used as a log target during raw repl mode
83     return 0;
84 }
85 
mp_task(void * pvParameter)86 void mp_task(void *pvParameter) {
87     volatile uint32_t sp = (uint32_t)get_sp();
88     #if MICROPY_PY_THREAD
89     mp_thread_init(pxTaskGetStackStart(NULL), MP_TASK_STACK_SIZE / sizeof(uintptr_t));
90     #endif
91     #if CONFIG_USB_ENABLED
92     usb_init();
93     #elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
94     usb_serial_jtag_init();
95     #else
96     uart_init();
97     #endif
98     machine_init();
99 
100     // TODO: CONFIG_SPIRAM_SUPPORT is for 3.3 compatibility, remove after move to 4.0.
101     #if CONFIG_ESP32_SPIRAM_SUPPORT || CONFIG_SPIRAM_SUPPORT
102     // Try to use the entire external SPIRAM directly for the heap
103     size_t mp_task_heap_size;
104     void *mp_task_heap = (void *)0x3f800000;
105     switch (esp_spiram_get_chip_size()) {
106         case ESP_SPIRAM_SIZE_16MBITS:
107             mp_task_heap_size = 2 * 1024 * 1024;
108             break;
109         case ESP_SPIRAM_SIZE_32MBITS:
110         case ESP_SPIRAM_SIZE_64MBITS:
111             mp_task_heap_size = 4 * 1024 * 1024;
112             break;
113         default:
114             // No SPIRAM, fallback to normal allocation
115             mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
116             mp_task_heap = malloc(mp_task_heap_size);
117             break;
118     }
119     #elif CONFIG_ESP32S2_SPIRAM_SUPPORT || CONFIG_ESP32S3_SPIRAM_SUPPORT
120     // Try to use the entire external SPIRAM directly for the heap
121     size_t mp_task_heap_size;
122     size_t esp_spiram_size = esp_spiram_get_size();
123     void *mp_task_heap = (void *)0x3ff80000 - esp_spiram_size;
124     if (esp_spiram_size > 0) {
125         mp_task_heap_size = esp_spiram_size;
126     } else {
127         // No SPIRAM, fallback to normal allocation
128         mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
129         mp_task_heap = malloc(mp_task_heap_size);
130     }
131     #else
132     // Allocate the uPy heap using malloc and get the largest available region
133     size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
134     void *mp_task_heap = malloc(mp_task_heap_size);
135     #endif
136 
137 soft_reset:
138     // initialise the stack pointer for the main thread
139     mp_stack_set_top((void *)sp);
140     mp_stack_set_limit(MP_TASK_STACK_SIZE - MP_TASK_STACK_LIMIT_MARGIN);
141     gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
142     mp_init();
143     mp_obj_list_init(mp_sys_path, 0);
144     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
145     mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
146     mp_obj_list_init(mp_sys_argv, 0);
147     readline_init0();
148 
149     // initialise peripherals
150     machine_pins_init();
151     #if MICROPY_PY_MACHINE_I2S
152     machine_i2s_init0();
153     #endif
154 
155     // run boot-up scripts
156     pyexec_frozen_module("_boot.py");
157     pyexec_file_if_exists("boot.py");
158     if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
159         int ret = pyexec_file_if_exists("main.py");
160         if (ret & PYEXEC_FORCED_EXIT) {
161             goto soft_reset_exit;
162         }
163     }
164 
165     for (;;) {
166         if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
167             vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null);
168             if (pyexec_raw_repl() != 0) {
169                 break;
170             }
171             esp_log_set_vprintf(vprintf_log);
172         } else {
173             if (pyexec_friendly_repl() != 0) {
174                 break;
175             }
176         }
177     }
178 
179 soft_reset_exit:
180 
181     #if MICROPY_BLUETOOTH_NIMBLE
182     mp_bluetooth_deinit();
183     #endif
184 
185     machine_timer_deinit_all();
186 
187     #if MICROPY_PY_THREAD
188     mp_thread_deinit();
189     #endif
190 
191     gc_sweep_all();
192 
193     mp_hal_stdout_tx_str("MPY: soft reboot\r\n");
194 
195     // deinitialise peripherals
196     machine_pins_deinit();
197     machine_deinit();
198     usocket_events_deinit();
199 
200     mp_deinit();
201     fflush(stdout);
202     goto soft_reset;
203 }
204 
app_main(void)205 void app_main(void) {
206     esp_err_t ret = nvs_flash_init();
207     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
208         nvs_flash_erase();
209         nvs_flash_init();
210     }
211     xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID);
212 }
213 
nlr_jump_fail(void * val)214 void nlr_jump_fail(void *val) {
215     printf("NLR jump failed, val=%p\n", val);
216     esp_restart();
217 }
218 
219 // modussl_mbedtls uses this function but it's not enabled in ESP IDF
mbedtls_debug_set_threshold(int threshold)220 void mbedtls_debug_set_threshold(int threshold) {
221     (void)threshold;
222 }
223 
esp_native_code_commit(void * buf,size_t len,void * reloc)224 void *esp_native_code_commit(void *buf, size_t len, void *reloc) {
225     len = (len + 3) & ~3;
226     uint32_t *p = heap_caps_malloc(len, MALLOC_CAP_EXEC);
227     if (p == NULL) {
228         m_malloc_fail(len);
229     }
230     if (reloc) {
231         mp_native_relocate(reloc, buf, (uintptr_t)p);
232     }
233     memcpy(p, buf, len);
234     return p;
235 }
236