Skip to content

Commit

Permalink
Merge pull request #946 from UncleGrumpy/stm32_heap_fix
Browse files Browse the repository at this point in the history
Fix STM32 hard fault when using malloc

Fixes a bug that causes a hard fault when suplimental sram chips are accessed on
devices that have more than one bank of ram. This redefinition of `_sbrk_r` is
the recommended solution on the
[libopencm3 wiki](https://github.com/libopencm3/libopencm3/wiki/Using-malloc-with-libopencm3).

Closes #932

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
  • Loading branch information
bettio committed Nov 17, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 150e376 + d73922d commit 2eeb24f
Showing 3 changed files with 50 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed a bug that would make the VM to loop and failing to process selected fds on Linux
- Fixed classes of exceptions in estdlib.
- Fixed STM32 code that was hard coded to the default target device, now configured based on the `cmake -DDEVICE=` parameter
- Fixed hard fault on STM32 durung malloc on boards with more than one bank of sram

### Changed

3 changes: 3 additions & 0 deletions src/platforms/stm32/src/lib/stm_sys.h
Original file line number Diff line number Diff line change
@@ -162,5 +162,8 @@ void nif_collection_destroy_all(GlobalContext *global);

void sys_init_icache(void);
void sys_enable_flash_cache(void);
void *_sbrk_r(struct _reent *, ptrdiff_t);
// This function may be defined to relocate the heap.
void local_heap_setup(uint8_t **start, uint8_t **end);

#endif /* _STM_SYS_H_ */
46 changes: 46 additions & 0 deletions src/platforms/stm32/src/lib/sys.c
Original file line number Diff line number Diff line change
@@ -17,6 +17,9 @@
*
* SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
*/
#include <errno.h>
#include <malloc.h>
#include <stdint.h>
#include <time.h>

#include <avmpack.h>
@@ -36,10 +39,53 @@
#include "stm_sys.h"

#define TAG "sys"
#define RESERVE_STACK_SIZE 4096U

struct PortDriverDefListItem *port_driver_list;
struct NifCollectionDefListItem *nif_collection_list;

/* These functions are needed to fix a hard fault when using malloc in devices with sram spanning
* multiple chips
*/
#pragma weak local_heap_setup = __local_ram

/* these are defined by the linker script */
extern uint8_t _ebss, _stack;

static uint8_t *_cur_brk = NULL;
static uint8_t *_heap_end = NULL;

/*
* If not overridden, this puts the heap into the left
* over ram between the BSS section and the stack while
* preserving RESERVE_STACK_SIZE bytes for the stack itself.
* This may be overridden by defining the function
* `local_heap_setup` (exported in `stm_sys.h`).
*/
static void
__local_ram(uint8_t **start, uint8_t **end)
{
*start = &_ebss;
*end = (uint8_t *) (&_stack - RESERVE_STACK_SIZE);
}

void *_sbrk_r(struct _reent *reent, ptrdiff_t diff)
{
uint8_t *_old_brk;

if (_heap_end == NULL) {
local_heap_setup(&_cur_brk, &_heap_end);
}

_old_brk = _cur_brk;
if (_cur_brk + diff > _heap_end) {
reent->_errno = ENOMEM;
return (void *) -1;
}
_cur_brk += diff;
return _old_brk;
}

// Monotonically increasing number of milliseconds from reset
static volatile uint64_t system_millis;

0 comments on commit 2eeb24f

Please sign in to comment.