Skip to content

per-memory domain copies of libc globals #25891

@andrewboie

Description

@andrewboie

Is your enhancement proposal related to a problem? Please describe.
tl;dr: Library globals only have one instance even if the project has multiple logical applications sharing the same micro-controller. In addition we currently require 1 memory partition per library which scales horribly.

With CONFIG_USERSPACE, memory domains control user thread access to memory that isn't the thread's stack or areas marked at boot time for universal access, like program text.

If a Zephyr application uses a library, that library is statically linked into the combined application+kernel. If a Zephyr project contains multiple logical applications, all of these end up in a single statically linked binary.

It's possible to instantiate k_mem_partition to allow discrete access to library globals, but this still shares those globals with all users of the library, even if they would be otherwise completely isolated. Plus, having discrete memory partitions for every different library does not scale, because MPU regions are limited; having as few as 8 total is very common.

Describe the solution you'd like
At a fundamental level: library data/bss has unique instances per memory domain with a single MPU region to cover it.

Have a mechanism for allocating a properly sized and aligned block of contiguous memory for the data/bss of all shared libraries threads a memory domain will use. It should be possible to program an MPU region at its boundaries.

This memory could be reserved at build time, or we allocate it when memory domains are initialized. Initialization will also involve a data copy for the data section and bss zeroed. We'll call this the Memory domain library region (MDLR).

On context switch, the incoming thread will have access via a dedicated MPU region or the page tables to the MDLR for its memory domain.

When a thread references non-const library globals, some indirection is in place such that the data/bss for the library is in the current MDLR, analogous to how shared libraries work in Linux with the GOT for each process address space. The compiler/linker plays a role here and we should try to leverage something that exists. We don't want to write our own compiler or linker. Dirty post-processing hacks to the generated kernel ELF or intermediate .a files are on the table however as long as they are portable.

Unlike Linux, there is a requirement that the text and rodata for the library be contiguous with the kernel/application text/rodata, so we will not require extra MPU regions to grant access to it; it all must be covered by the boot regions for text and rodata (some platforms have a single read-only+executable region for both).

Only the data/bss must be position-independent.

Not every library needs this treatment; if only one memory domain uses a particular library, instead we would just want its data/bss merged into some memory partition that also has the rest of the doamin's globals (including any other library data/bss only used by that domain)

Additional context
This will really force us to distinguish between library code and subsystem code; only the latter needs to be a singleton entity in the kernel's space. I suspect a few items may switch places.

Metadata

Metadata

Assignees

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions