Skip to content

Commit 12cf5e5

Browse files
committed
Allow for resizing the stack area.
1 parent 777542c commit 12cf5e5

File tree

10 files changed

+288
-24
lines changed

10 files changed

+288
-24
lines changed

main.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "supervisor/messages/en-US.h"
5353
#include "supervisor/shared/autoreload.h"
5454
#include "supervisor/shared/rgb_led_status.h"
55+
#include "supervisor/shared/stack.h"
5556
#include "supervisor/serial.h"
5657

5758
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
@@ -81,11 +82,11 @@ void start_mp(supervisor_allocation* heap) {
8182
// Stack limit should be less than real stack size, so we have a chance
8283
// to recover from limit hit. (Limit is measured in bytes.)
8384
mp_stack_ctrl_init();
84-
mp_stack_set_limit((char*)&_estack - (char*)&_ebss - 1024);
85+
mp_stack_set_limit(stack_alloc->length - 1024);
8586

8687
#if MICROPY_MAX_STACK_USAGE
8788
// _ezero (same as _ebss) is an int, so start 4 bytes above it.
88-
mp_stack_set_bottom(&_ezero + 1);
89+
mp_stack_set_bottom(stack_alloc->ptr);
8990
mp_stack_fill_with_sentinel();
9091
#endif
9192

@@ -97,7 +98,7 @@ void start_mp(supervisor_allocation* heap) {
9798
readline_init0();
9899

99100
#if MICROPY_ENABLE_GC
100-
gc_init(heap->ptr, heap->ptr + heap->length);
101+
gc_init(heap->ptr, heap->ptr + heap->length / 4);
101102
#endif
102103
mp_init();
103104
mp_obj_list_init(mp_sys_path, 0);
@@ -171,6 +172,8 @@ bool run_code_py(safe_mode_t safe_mode) {
171172
const char *double_extension_filenames[] = STRING_LIST("code.txt.py", "code.py.txt", "code.txt.txt","code.py.py",
172173
"main.txt.py", "main.py.txt", "main.txt.txt","main.py.py");
173174

175+
stack_resize();
176+
filesystem_flush();
174177
supervisor_allocation* heap = allocate_remaining_memory();
175178
start_mp(heap);
176179
found_main = maybe_run_list(supported_filenames, &result);
@@ -310,6 +313,12 @@ void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
310313
}
311314
#endif
312315

316+
stack_init();
317+
// TODO(tannewt): Allocate temporary space to hold custom usb descriptors.
318+
filesystem_flush();
319+
supervisor_allocation* heap = allocate_remaining_memory();
320+
start_mp(heap);
321+
313322
// TODO(tannewt): Re-add support for flashing boot error output.
314323
bool found_boot = maybe_run_list(boot_py_filenames, NULL);
315324
(void) found_boot;
@@ -325,11 +334,16 @@ void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
325334
// Reset to remove any state that boot.py setup. It should only be used to
326335
// change internal state that's not in the heap.
327336
reset_port();
337+
reset_board();
338+
stop_mp();
339+
free_memory(heap);
328340
}
329341
}
330342

331343
int run_repl(void) {
332344
int exit_code = PYEXEC_FORCED_EXIT;
345+
stack_resize();
346+
filesystem_flush();
333347
supervisor_allocation* heap = allocate_remaining_memory();
334348
start_mp(heap);
335349
autoreload_suspend();
@@ -349,7 +363,7 @@ int run_repl(void) {
349363

350364
int __attribute__((used)) main(void) {
351365
memory_init();
352-
366+
353367
// initialise the cpu and peripherals
354368
safe_mode_t safe_mode = port_init();
355369

ports/atmel-samd/mpconfigport.h

100644100755
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,4 +338,8 @@ void run_background_tasks(void);
338338
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
339339
#define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt"
340340

341+
// TODO(tannewt): Make this 6k+ for any non-express M4 boards because they cache sectors on the
342+
// stack.
343+
#define CIRCUITPY_DEFAULT_STACK_SIZE 2048
344+
341345
#endif // __INCLUDED_MPCONFIGPORT_H

ports/atmel-samd/supervisor/filesystem.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ void filesystem_init(bool create_allowed, bool force_create) {
5151

5252
// try to mount the flash
5353
FRESULT res = f_mount(&vfs_fat->fatfs);
54-
force_create = true;
5554

5655
if ((res == FR_NO_FILESYSTEM && create_allowed) || force_create) {
5756
// No filesystem so create a fresh one, or reformat has been requested.

ports/atmel-samd/supervisor/memory.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ extern uint32_t _estack;
4040
void memory_init(void) {
4141
low_address = &_ebss;
4242
high_address = &_estack;
43-
44-
// snag 3k for stack
45-
allocate_memory(1024*4, true);
4643
}
4744

4845
void free_memory(supervisor_allocation* allocation) {
@@ -56,8 +53,23 @@ void free_memory(supervisor_allocation* allocation) {
5653
}
5754
if (allocation->ptr == high_address) {
5855
high_address += allocation->length / 4;
56+
for (index++; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) {
57+
if (allocations[index].ptr != NULL) {
58+
break;
59+
}
60+
high_address += allocations[index].length / 4;
61+
}
5962
} else if (allocation->ptr + allocation->length / 4 == low_address) {
6063
low_address = allocation->ptr;
64+
for (index--; index >= 0; index--) {
65+
if (allocations[index].ptr != NULL) {
66+
break;
67+
}
68+
low_address -= allocations[index].length / 4;
69+
}
70+
} else {
71+
// Freed memory isn't in the middle so skip updating bounds. The memory will be added to the
72+
// middle when the memory to the inside is freed.
6173
}
6274
allocation->ptr = NULL;
6375
}

ports/nrf/mpconfigport.h

100644100755
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,5 +233,6 @@ void run_background_tasks(void);
233233
#define MICROPY_VM_HOOK_RETURN run_background_tasks();
234234

235235
//#define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt"
236+
#define CIRCUITPY_DEFAULT_STACK_SIZE 2048
236237

237238
#endif

ports/nrf/supervisor/memory.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "supervisor/memory.h"
28+
29+
#include <stddef.h>
30+
31+
#define CIRCUITPY_SUPERVISOR_ALLOC_COUNT 8
32+
33+
static supervisor_allocation allocations[CIRCUITPY_SUPERVISOR_ALLOC_COUNT];
34+
// We use uint32_t* to ensure word (4 byte) alignment.
35+
uint32_t* low_address;
36+
uint32_t* high_address;
37+
extern uint32_t _ebss;
38+
extern uint32_t _estack;
39+
40+
void memory_init(void) {
41+
low_address = &_ebss;
42+
high_address = &_estack;
43+
}
44+
45+
void free_memory(supervisor_allocation* allocation) {
46+
uint8_t index = 0;
47+
bool found = false;
48+
for (index = 0; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) {
49+
found = allocation == &allocations[index];
50+
if (found) {
51+
break;
52+
}
53+
}
54+
if (allocation->ptr == high_address) {
55+
high_address += allocation->length / 4;
56+
for (index++; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) {
57+
if (allocations[index].ptr != NULL) {
58+
break;
59+
}
60+
high_address += allocations[index].length / 4;
61+
}
62+
} else if (allocation->ptr + allocation->length / 4 == low_address) {
63+
low_address = allocation->ptr;
64+
for (index--; index >= 0; index--) {
65+
if (allocations[index].ptr != NULL) {
66+
break;
67+
}
68+
low_address -= allocations[index].length / 4;
69+
}
70+
} else {
71+
// Freed memory isn't in the middle so skip updating bounds. The memory will be added to the
72+
// middle when the memory to the inside is freed.
73+
}
74+
allocation->ptr = NULL;
75+
}
76+
77+
supervisor_allocation* allocate_remaining_memory(void) {
78+
if (low_address == high_address) {
79+
return NULL;
80+
}
81+
return allocate_memory((high_address - low_address) * 4, false);
82+
}
83+
84+
supervisor_allocation* allocate_memory(uint32_t length, bool high) {
85+
if ((high_address - low_address) * 4 < (int32_t) length) {
86+
return NULL;
87+
}
88+
uint8_t index = 0;
89+
int8_t direction = 1;
90+
if (high) {
91+
index = CIRCUITPY_SUPERVISOR_ALLOC_COUNT - 1;
92+
direction = -1;
93+
}
94+
for (; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index += direction) {
95+
if (allocations[index].ptr == NULL) {
96+
break;
97+
}
98+
}
99+
if (index >= CIRCUITPY_SUPERVISOR_ALLOC_COUNT) {
100+
return NULL;
101+
}
102+
supervisor_allocation* alloc = &allocations[index];
103+
if (high) {
104+
high_address -= length / 4;
105+
alloc->ptr = high_address;
106+
} else {
107+
alloc->ptr = low_address;
108+
low_address += length / 4;
109+
}
110+
alloc->length = length;
111+
return alloc;
112+
}

shared-bindings/supervisor/__init__.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@
2323
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2424
* THE SOFTWARE.
2525
*/
26-
#include "py/obj.h"
27-
#include "py/runtime.h"
28-
#include "py/reload.h"
26+
#include "py/obj.h"
27+
#include "py/runtime.h"
28+
#include "py/reload.h"
2929

30-
#include "lib/utils/interrupt_char.h"
31-
#include "supervisor/shared/autoreload.h"
30+
#include "lib/utils/interrupt_char.h"
31+
#include "supervisor/shared/autoreload.h"
32+
#include "supervisor/shared/rgb_led_status.h"
33+
#include "supervisor/shared/stack.h"
3234

33-
#include "supervisor/shared/rgb_led_status.h"
34-
35-
#include "shared-bindings/supervisor/__init__.h"
36-
#include "shared-bindings/supervisor/Runtime.h"
35+
#include "shared-bindings/supervisor/__init__.h"
36+
#include "shared-bindings/supervisor/Runtime.h"
3737

3838
//| :mod:`supervisor` --- Supervisor settings
3939
//| =================================================
@@ -107,15 +107,21 @@ STATIC mp_obj_t supervisor_reload(void) {
107107
}
108108
MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload);
109109

110-
//| .. method:: set_main_file(filename)
110+
//| .. method:: set_next_stack_limit(size)
111111
//|
112-
//| Set which file to run after a reload.
112+
//| Set the size of the stack for the next vm run. If its too large, the default will be used.
113113
//|
114-
STATIC mp_obj_t supervisor_set_main_file(void) {
115-
114+
STATIC mp_obj_t supervisor_set_next_stack_limit(mp_obj_t size_obj) {
115+
mp_int_t size = mp_obj_get_int(size_obj);
116+
117+
if (size < 256) {
118+
mp_raise_ValueError("Stack size must be at least 256");
119+
}
120+
set_next_stack_size(size);
121+
116122
return mp_const_none;
117123
}
118-
MP_DEFINE_CONST_FUN_OBJ_0(supervisor_set_main_file_obj, supervisor_set_main_file);
124+
MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_next_stack_limit_obj, supervisor_set_next_stack_limit);
119125

120126
STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
121127
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) },
@@ -124,7 +130,7 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
124130
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_rgb_status_brightness), MP_ROM_PTR(&supervisor_set_rgb_status_brightness_obj) },
125131
{ MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) },
126132
{ MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&supervisor_reload_obj) },
127-
{ MP_ROM_QSTR(MP_QSTR_set_main_file), MP_ROM_PTR(&supervisor_set_main_file_obj) },
133+
{ MP_ROM_QSTR(MP_QSTR_set_next_stack_limit), MP_ROM_PTR(&supervisor_set_next_stack_limit_obj) },
128134

129135
};
130136

supervisor/shared/stack.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "stack.h"
28+
29+
#include "py/mpconfig.h"
30+
#include "supervisor/cpu.h"
31+
32+
extern uint32_t _estack;
33+
34+
static uint32_t next_stack_size = CIRCUITPY_DEFAULT_STACK_SIZE;
35+
static uint32_t current_stack_size = 0;
36+
supervisor_allocation* stack_alloc = NULL;
37+
38+
#define EXCEPTION_STACK_SIZE 1024
39+
40+
void allocate_stack(void) {
41+
mp_uint_t regs[10];
42+
mp_uint_t sp = cpu_get_regs_and_sp(regs);
43+
44+
mp_uint_t c_size = (uint32_t) &_estack - sp;
45+
46+
stack_alloc = allocate_memory(c_size + next_stack_size + EXCEPTION_STACK_SIZE, true);
47+
if (stack_alloc == NULL) {
48+
stack_alloc = allocate_memory(c_size + CIRCUITPY_DEFAULT_STACK_SIZE + EXCEPTION_STACK_SIZE, true);
49+
current_stack_size = CIRCUITPY_DEFAULT_STACK_SIZE;
50+
} else {
51+
current_stack_size = next_stack_size;
52+
}
53+
}
54+
55+
inline void stack_init(void) {
56+
allocate_stack();
57+
}
58+
59+
inline void stack_resize(void) {
60+
if (next_stack_size == current_stack_size) {
61+
return;
62+
}
63+
free_memory(stack_alloc);
64+
stack_alloc = NULL;
65+
allocate_stack();
66+
}
67+
68+
void set_next_stack_size(uint32_t size) {
69+
next_stack_size = size;
70+
}
71+
72+
uint32_t get_current_stack_size(void) {
73+
return current_stack_size;
74+
}

0 commit comments

Comments
 (0)