Skip to content

Add movable supervisor allocations #3695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 1, 2020
13 changes: 5 additions & 8 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ void start_mp(supervisor_allocation* heap) {
// to recover from limit hit. (Limit is measured in bytes.)
mp_stack_ctrl_init();

if (stack_alloc != NULL) {
mp_stack_set_limit(stack_alloc->length - 1024);
if (stack_get_bottom() != NULL) {
mp_stack_set_limit(stack_get_length() - 1024);
}


#if MICROPY_MAX_STACK_USAGE
// _ezero (same as _ebss) is an int, so start 4 bytes above it.
if (stack_alloc != NULL) {
mp_stack_set_bottom(stack_alloc->ptr);
if (stack_get_bottom() != NULL) {
mp_stack_set_bottom(stack_get_bottom());
mp_stack_fill_with_sentinel();
}
#endif
Expand All @@ -148,7 +148,7 @@ void start_mp(supervisor_allocation* heap) {
#endif

#if MICROPY_ENABLE_GC
gc_init(heap->ptr, heap->ptr + heap->length / 4);
gc_init(heap->ptr, heap->ptr + get_allocation_length(heap) / 4);
#endif
mp_init();
mp_obj_list_init(mp_sys_path, 0);
Expand Down Expand Up @@ -451,9 +451,6 @@ int __attribute__((used)) main(void) {
// initialise the cpu and peripherals
safe_mode_t safe_mode = port_init();

// Init memory after the port in case the port needs to set aside memory.
memory_init();

// Turn on LEDs
init_status_leds();
rgb_led_status_init();
Expand Down
4 changes: 2 additions & 2 deletions ports/atmel-samd/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,8 @@ void reset_cpu(void) {
reset();
}

supervisor_allocation* port_fixed_stack(void) {
return NULL;
bool port_has_fixed_stack(void) {
return false;
}

uint32_t *port_stack_get_limit(void) {
Expand Down
8 changes: 2 additions & 6 deletions ports/cxd56/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,8 @@ void reset_to_bootloader(void) {
}
}

supervisor_allocation _fixed_stack;

supervisor_allocation* port_fixed_stack(void) {
_fixed_stack.ptr = port_stack_get_limit();
_fixed_stack.length = (port_stack_get_top() - port_stack_get_limit()) * sizeof(uint32_t);
return &_fixed_stack;
bool port_has_fixed_stack(void) {
return true;
}

uint32_t *port_stack_get_limit(void) {
Expand Down
8 changes: 2 additions & 6 deletions ports/esp32s2/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,8 @@ uint32_t *port_stack_get_top(void) {
return port_stack_get_limit() + ESP_TASK_MAIN_STACK / (sizeof(uint32_t) / sizeof(StackType_t));
}

supervisor_allocation _fixed_stack;

supervisor_allocation* port_fixed_stack(void) {
_fixed_stack.ptr = port_stack_get_limit();
_fixed_stack.length = (port_stack_get_top() - port_stack_get_limit()) * sizeof(uint32_t);
return &_fixed_stack;
bool port_has_fixed_stack(void) {
return true;
}

// Place the word to save just after our BSS section that gets blanked.
Expand Down
4 changes: 2 additions & 2 deletions ports/litex/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ void reset_cpu(void) {
for(;;) {}
}

supervisor_allocation* port_fixed_stack(void) {
return NULL;
bool port_has_fixed_stack(void) {
return false;
}

uint32_t *port_heap_get_bottom(void) {
Expand Down
7 changes: 2 additions & 5 deletions ports/mimxrt10xx/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,8 @@ uint32_t *port_stack_get_top(void) {
return &_ld_stack_top;
}

supervisor_allocation _fixed_stack;
supervisor_allocation* port_fixed_stack(void) {
_fixed_stack.ptr = port_stack_get_limit();
_fixed_stack.length = (port_stack_get_top() - port_stack_get_limit()) * sizeof(uint32_t);
return &_fixed_stack;
bool port_has_fixed_stack(void) {
return true;
}

uint32_t *port_heap_get_bottom(void) {
Expand Down
4 changes: 2 additions & 2 deletions ports/nrf/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ uint32_t *port_heap_get_top(void) {
return port_stack_get_top();
}

supervisor_allocation* port_fixed_stack(void) {
return NULL;
bool port_has_fixed_stack(void) {
return false;
}

uint32_t *port_stack_get_limit(void) {
Expand Down
4 changes: 2 additions & 2 deletions ports/stm/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ uint32_t *port_heap_get_top(void) {
return &_ld_heap_end;
}

supervisor_allocation* port_fixed_stack(void) {
return NULL;
bool port_has_fixed_stack(void) {
return false;
}

uint32_t *port_stack_get_limit(void) {
Expand Down
5 changes: 4 additions & 1 deletion py/circuitpy_mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,17 +858,20 @@ extern const struct _mp_obj_module_t wifi_module;

#include "supervisor/flash_root_pointers.h"

// From supervisor/memory.c
struct _supervisor_allocation_node;

#define CIRCUITPY_COMMON_ROOT_POINTERS \
const char *readline_hist[8]; \
vstr_t *repl_line; \
mp_obj_t rtc_time_source; \
GAMEPAD_ROOT_POINTERS \
mp_obj_t pew_singleton; \
mp_obj_t terminal_tilegrid_tiles; \
BOARD_UART_ROOT_POINTER \
FLASH_ROOT_POINTERS \
MEMORYMONITOR_ROOT_POINTERS \
NETWORK_ROOT_POINTERS \
struct _supervisor_allocation_node* first_embedded_allocation; \

void supervisor_run_background_tasks_if_tick(void);
#define RUN_BACKGROUND_TASKS (supervisor_run_background_tasks_if_tick())
Expand Down
25 changes: 7 additions & 18 deletions shared-module/rgbmatrix/RGBMatrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self,
// verify that the matrix is big enough
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize-1), false);
} else {
_PM_free(self->bufinfo.buf);
_PM_free(self->protomatter.rgbPins);
_PM_free(self->protomatter.addr);
_PM_free(self->protomatter.screenData);
common_hal_rgbmatrix_free_impl(self->bufinfo.buf);
common_hal_rgbmatrix_free_impl(self->protomatter.rgbPins);
common_hal_rgbmatrix_free_impl(self->protomatter.addr);
common_hal_rgbmatrix_free_impl(self->protomatter.screenData);

self->framebuffer = NULL;
self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize);
Expand Down Expand Up @@ -180,9 +180,6 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) {

void rgbmatrix_rgbmatrix_collect_ptrs(rgbmatrix_rgbmatrix_obj_t* self) {
gc_collect_ptr(self->framebuffer);
gc_collect_ptr(self->protomatter.rgbPins);
gc_collect_ptr(self->protomatter.addr);
gc_collect_ptr(self->protomatter.screenData);
}

void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t* self, bool paused) {
Expand Down Expand Up @@ -217,18 +214,10 @@ int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t* self) {
}

void *common_hal_rgbmatrix_allocator_impl(size_t sz) {
if (gc_alloc_possible()) {
return m_malloc_maybe(sz + sizeof(void*), true);
} else {
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false);
return allocation ? allocation->ptr : NULL;
}
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true);
return allocation ? allocation->ptr : NULL;
}

void common_hal_rgbmatrix_free_impl(void *ptr_in) {
supervisor_allocation *allocation = allocation_from_ptr(ptr_in);

if (allocation) {
free_memory(allocation);
}
free_memory(allocation_from_ptr(ptr_in));
}
57 changes: 14 additions & 43 deletions shared-module/sharpdisplay/SharpMemoryFramebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,10 @@
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"

#include "supervisor/memory.h"
#include "supervisor/shared/safe_mode.h"

#define SHARPMEM_BIT_WRITECMD_LSB (0x80)
#define SHARPMEM_BIT_VCOM_LSB (0x40)

static void *hybrid_alloc(size_t sz) {
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false);
if (allocation) {
memset(allocation->ptr, 0, sz);
return allocation->ptr;
}
if (gc_alloc_possible()) {
return m_malloc(sz, true);
}
reset_into_safe_mode(MEM_MANAGE);
return NULL; // unreached
}

static inline void hybrid_free(void *ptr_in) {
supervisor_allocation *allocation = allocation_from_ptr(ptr_in);

if (allocation) {
free_memory(allocation);
}
}

STATIC uint8_t bitrev(uint8_t n) {
uint8_t r = 0;
for(int i=0;i<8;i++) r |= ((n>>i) & 1)<<(7-i);
Expand Down Expand Up @@ -102,17 +80,22 @@ void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *s
}

void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) {
if (!allocation_from_ptr(self->bufinfo.buf)) {
self->bufinfo.buf = NULL;
}
// Look up the allocation by the old pointer and get the new pointer from it.
supervisor_allocation* alloc = allocation_from_ptr(self->bufinfo.buf);
self->bufinfo.buf = alloc ? alloc->ptr : NULL;
}

void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) {
if (!self->bufinfo.buf) {
int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self);
int height = common_hal_sharpdisplay_framebuffer_get_height(self);
self->bufinfo.len = row_stride * height + 2;
self->bufinfo.buf = hybrid_alloc(self->bufinfo.len);
supervisor_allocation* alloc = allocate_memory(align32_size(self->bufinfo.len), false, true);
if (alloc == NULL) {
m_malloc_fail(self->bufinfo.len);
}
self->bufinfo.buf = alloc->ptr;
memset(alloc->ptr, 0, self->bufinfo.len);

uint8_t *data = self->bufinfo.buf;
*data++ = SHARPMEM_BIT_WRITECMD_LSB;
Expand All @@ -123,7 +106,9 @@ void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_ob
}
self->full_refresh = true;
}
*bufinfo = self->bufinfo;
if (bufinfo) {
*bufinfo = self->bufinfo;
}
}

void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self) {
Expand All @@ -137,7 +122,7 @@ void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *

common_hal_reset_pin(self->chip_select.pin);

hybrid_free(self->bufinfo.buf);
free_memory(allocation_from_ptr(self->bufinfo.buf));

memset(self, 0, sizeof(*self));
}
Expand All @@ -154,19 +139,7 @@ void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_
self->height = height;
self->baudrate = baudrate;

int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self);
self->bufinfo.len = row_stride * height + 2;
// re-use a supervisor allocation if possible
self->bufinfo.buf = hybrid_alloc(self->bufinfo.len);

uint8_t *data = self->bufinfo.buf;
*data++ = SHARPMEM_BIT_WRITECMD_LSB;

for(int y=0; y<self->height; y++) {
*data = bitrev(y+1);
data += row_stride;
}
self->full_refresh = true;
common_hal_sharpdisplay_framebuffer_get_bufinfo(self, NULL);
}

void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask) {
Expand Down Expand Up @@ -271,7 +244,5 @@ const framebuffer_p_t sharpdisplay_framebuffer_proto = {
};

void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t *self) {
gc_collect_ptr(self->framebuffer);
gc_collect_ptr(self->bus);
gc_collect_ptr(self->bufinfo.buf);
}
1 change: 0 additions & 1 deletion shared-module/sharpdisplay/SharpMemoryFramebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

typedef struct {
mp_obj_base_t base;
mp_obj_t framebuffer;
busio_spi_obj_t* bus;
busio_spi_obj_t inline_bus;
digitalio_digitalinout_obj_t chip_select;
Expand Down
8 changes: 4 additions & 4 deletions shared-module/usb_midi/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ supervisor_allocation* usb_midi_allocation;

void usb_midi_init(void) {
// TODO(tannewt): Make this dynamic.
uint16_t tuple_size = align32_size(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t*) * 2);
uint16_t portin_size = align32_size(sizeof(usb_midi_portin_obj_t));
uint16_t portout_size = align32_size(sizeof(usb_midi_portout_obj_t));
size_t tuple_size = align32_size(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t*) * 2);
size_t portin_size = align32_size(sizeof(usb_midi_portin_obj_t));
size_t portout_size = align32_size(sizeof(usb_midi_portout_obj_t));

// For each embedded MIDI Jack in the descriptor we create a Port
usb_midi_allocation = allocate_memory(tuple_size + portin_size + portout_size, false);
usb_midi_allocation = allocate_memory(tuple_size + portin_size + portout_size, false, false);

mp_obj_tuple_t *ports = (mp_obj_tuple_t *) usb_midi_allocation->ptr;
ports->base.type = &mp_type_tuple;
Expand Down
33 changes: 23 additions & 10 deletions supervisor/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,45 @@

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

typedef struct {
uint32_t* ptr;
uint32_t length; // in bytes
} supervisor_allocation;



void memory_init(void);
void free_memory(supervisor_allocation* allocation);

// Find the allocation with the given ptr, NULL if not found. When called from the context of a
// supervisor_move_memory() callback, finds the allocation that had that ptr *before* the move, but
// the returned allocation already contains the ptr after the move.
// When called with NULL, may return either NULL or an unused allocation whose ptr is NULL (this is
// a feature used internally in allocate_memory to save code size). Passing the return value to
// free_memory() is a permissible no-op in either case.
supervisor_allocation* allocation_from_ptr(void *ptr);

supervisor_allocation* allocate_remaining_memory(void);

// Allocate a piece of a given length in bytes. If high_address is true then it should be allocated
// at a lower address from the top of the stack. Otherwise, addresses will increase starting after
// statically allocated memory.
supervisor_allocation* allocate_memory(uint32_t length, bool high_address);
// statically allocated memory. If movable is false, memory will be taken from outside the GC heap
// and will stay stationary until freed. While the VM is running, this will fail unless a previous
// allocation of exactly matching length has recently been freed. If movable is true, memory will be
// taken from either outside or inside the GC heap, and when the VM exits, will be moved outside.
// The ptr of the returned supervisor_allocation will change at that point. If you need to be
// notified of that, add your own callback function at the designated place near the end of
// supervisor_move_memory().
supervisor_allocation* allocate_memory(uint32_t length, bool high_address, bool movable);

static inline uint16_t align32_size(uint16_t size) {
if (size % 4 != 0) {
return (size & 0xfffc) + 0x4;
}
return size;
static inline size_t align32_size(size_t size) {
return (size + 3) & ~3;
}

// Called after the heap is freed in case the supervisor wants to save some values.
size_t get_allocation_length(supervisor_allocation* allocation);

// Called after the GC heap is freed, transfers movable allocations from the GC heap to the
// supervisor heap and compacts the supervisor heap.
void supervisor_move_memory(void);

#endif // MICROPY_INCLUDED_SUPERVISOR_MEMORY_H
Loading