Topics

Memory protection and picolibc global state


Keith Packard
 

I'm continuing to develop picolibc (https://github.com/picolibc) support
for Zephyr under this PR:

https://github.com/zephyrproject-rtos/zephyr/pull/26545

I'm running the sanity checks under qemu on mps2_an521 which uses the
ARM MPU. On this board, the default memory protection configuration
seems to place all libc globals in a region which is protected against
application access. That includes globals used in managing the malloc
heap, and so application calls to malloc end up generating a MPU fault.

I can fix this in at least a couple of possible ways:

1) Create per-thread malloc heaps and track malloc per-thread.

2) Figure out how to change protection for libc globals

3) Replace the picolibc malloc implementation with a Zephyr custom
implementation.

--
-keith


David Brown
 

On Sat, Sep 19, 2020 at 02:06:02PM -0700, Keith Packard via lists.zephyrproject.org wrote:

I'm continuing to develop picolibc (https://github.com/picolibc) support
for Zephyr under this PR:

https://github.com/zephyrproject-rtos/zephyr/pull/26545

I'm running the sanity checks under qemu on mps2_an521 which uses the
ARM MPU. On this board, the default memory protection configuration
seems to place all libc globals in a region which is protected against
application access. That includes globals used in managing the malloc
heap, and so application calls to malloc end up generating a MPU fault.

I can fix this in at least a couple of possible ways:

1) Create per-thread malloc heaps and track malloc per-thread.

2) Figure out how to change protection for libc globals

3) Replace the picolibc malloc implementation with a Zephyr custom
implementation.
I wonder how this works with the newlib implementation. We have
several variants a malloc-like code that can end up in Zephyr,
unfortunately, sometimes at the same time. There is a simplistic
allocator that is part of the Zephyr kernel. It is given a fixed
region of memory to use as a heap. There is also an allocate that
comes in when newlib is enabled (which comes from the SDK). This will
use the space between the end of the image's SRAM usage and the end of
SRAM (which doesn't show up in the image size reports).

I believe these both work with the MPU enabled, although the kernel
heap may only be used from kernel side. What might be worth
investigating why malloc from newlib works. Perhaps there is
something special about how newlib's libc is linked in.

I think it looks like picolib and newlib share code for the allocator,
so hopefully this is just a configuration issue. I supposed it would
also be a good idea just to make sure that using newlib's malloc
actually does work if the MPU is enabled.

David


Boie, Andrew P
 

Hi Keith,

Sorry, just saw this. There are some k_mem_partitions defined which can help with this, z_malloc_partition and z_libc_partition.

z_malloc_partition is for the malloc() arena, which is global.
z_libc_partition is for any other globals associated with the libc.

These are defined in include/sys/libc-hooks.h along with the further comments.

This situation is not ideal. We would eventually like separate libc library globals and malloc arenas on a per memory domain basis (not per thread). This is, to put it mildly, tricky to do when all you have is an MPU. There's a issue here about it: https://github.com/zephyrproject-rtos/zephyr/issues/25891 the last comment has my current thinking on this problem.

HTH,
Andrew

-----Original Message-----
From: devel@... <devel@...> On
Behalf Of Keith Packard via lists.zephyrproject.org
Sent: Saturday, September 19, 2020 2:06 PM
To: devel@...
Subject: [Zephyr-devel] Memory protection and picolibc global state


I'm continuing to develop picolibc (https://github.com/picolibc) support for
Zephyr under this PR:

https://github.com/zephyrproject-rtos/zephyr/pull/26545

I'm running the sanity checks under qemu on mps2_an521 which uses the
ARM MPU. On this board, the default memory protection configuration
seems to place all libc globals in a region which is protected against
application access. That includes globals used in managing the malloc heap,
and so application calls to malloc end up generating a MPU fault.

I can fix this in at least a couple of possible ways:

1) Create per-thread malloc heaps and track malloc per-thread.

2) Figure out how to change protection for libc globals

3) Replace the picolibc malloc implementation with a Zephyr custom
implementation.

--
-keith