Skip to content

Commit 944aa81

Browse files
laurenmurphyx64fabiobaltieri
authored andcommitted
llext: run on harvard arch with static heaps
Splits LLEXT static heap into an instruction heap placed in instruction memory and a data heap placed in data memory. Signed-off-by: Lauren Murphy <[email protected]>
1 parent 92db7bc commit 944aa81

File tree

10 files changed

+108
-28
lines changed

10 files changed

+108
-28
lines changed

doc/services/llext/config.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,26 @@ The following option controls this allocation, when allocating a static heap.
1515

1616
Size of the LLEXT heap in kilobytes.
1717

18+
For boards using the Harvard architecture, the LLEXT heap is split into two:
19+
one heap in instruction memory and another in data memory. The following options
20+
control these allocations.
21+
22+
:kconfig:option:`CONFIG_LLEXT_INSTR_HEAP_SIZE`
23+
24+
Size of the LLEXT heap in instruction memory in kilobytes.
25+
26+
:kconfig:option:`CONFIG_LLEXT_DATA_HEAP_SIZE`
27+
28+
Size of the LLEXT heap in data memory in kilobytes.
29+
30+
.. note::
31+
The LLEXT instruction heap is grouped with Zephyr .rodata, which the linker
32+
typically places after .text in instruction memory.
33+
34+
.. warning::
35+
LLEXT will be unable to link and execute extensions if instruction memory
36+
(i.e., memory the processor can fetch instructions from) is not writable.
37+
1838
Alternatively the application can configure a dynamic heap using the following
1939
option.
2040

doc/services/llext/index.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,4 @@ and introspected to some degree, as well as unloaded when no longer needed.
2222
.. note::
2323

2424
The LLEXT subsystem requires architecture-specific support. It is currently
25-
available only on RISC-V, ARM, ARM64, ARC (experimental) and Xtensa cores.
26-
Harvard architecture cores that separate code and data paths and have no
27-
common memory are not supported.
25+
available only on RISC-V, ARM, ARM64, ARC, x86, and Xtensa cores.

include/zephyr/llext/llext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ int llext_relink_dependency(struct llext *ext, unsigned int n_ext);
447447
* During suspend the user has saved all the extension and loader descriptors
448448
* and related objects and called @ref llext_relink_dependency() to prepare
449449
* dependency pointers.
450-
* When resuming llext_alloc() has to be used to re-allocate all the objects,
450+
* When resuming llext_alloc_data() has to be used to re-allocate all the objects,
451451
* therefore the user needs support from LLEXT core to accomplish that.
452452
* This function takes arrays of pointers to saved copies of extensions and
453453
* loaders as arguments and re-allocates all the objects, while also adding them

subsys/llext/Kconfig

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,27 @@ config LLEXT_HEAP_DYNAMIC
5757

5858
config LLEXT_HEAP_SIZE
5959
int "llext heap memory size in kilobytes"
60-
depends on !LLEXT_HEAP_DYNAMIC
60+
depends on !LLEXT_HEAP_DYNAMIC && !HARVARD
6161
default 8
6262
help
6363
Heap size in kilobytes available to llext for dynamic allocation
6464

65+
config LLEXT_INSTR_HEAP_SIZE
66+
int "llext ICCM heap memory size in kilobytes"
67+
depends on !LLEXT_HEAP_DYNAMIC && HARVARD
68+
default 4
69+
help
70+
ICCM heap size in kilobytes available to llext for dynamic allocation.
71+
Only executable sections will be placed in this heap.
72+
73+
config LLEXT_DATA_HEAP_SIZE
74+
int "llext DCCM heap memory size in kilobytes"
75+
depends on !LLEXT_HEAP_DYNAMIC && HARVARD
76+
default 8
77+
help
78+
DCCM heap size in kilobytes available to llext for dynamic allocation.
79+
Extension data and metadata will be placed in this heap.
80+
6581
config LLEXT_BUILD_PIC
6682
bool "Use -fPIC when building LLEXT"
6783
depends on XTENSA

subsys/llext/llext.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext,
179179
goto out;
180180
}
181181

182-
*ext = llext_alloc(sizeof(struct llext));
182+
*ext = llext_alloc_data(sizeof(struct llext));
183183
if (*ext == NULL) {
184184
LOG_ERR("Not enough memory for extension metadata");
185185
ret = -ENOMEM;

subsys/llext/llext_experimental.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ int llext_relink_dependency(struct llext *ext, unsigned int n_ext)
5151

5252
int llext_restore(struct llext **ext, struct llext_loader **ldr, unsigned int n_ext)
5353
{
54-
struct llext_elf_sect_map **map = llext_alloc(sizeof(*map) * n_ext);
54+
struct llext_elf_sect_map **map = llext_alloc_data(sizeof(*map) * n_ext);
5555
struct llext *next, *tmp, *first = ext[0], *last = ext[n_ext - 1];
5656
unsigned int i, j, n_map, n_exp_tab;
5757
int ret;
@@ -69,7 +69,7 @@ int llext_restore(struct llext **ext, struct llext_loader **ldr, unsigned int n_
6969
*/
7070
for (n_map = 0, n_exp_tab = 0; n_map < n_ext; n_map++) {
7171
/* Need to allocate individually, because that's how they're freed */
72-
map[n_map] = llext_alloc(sizeof(**map) * ext[n_map]->sect_cnt);
72+
map[n_map] = llext_alloc_data(sizeof(**map) * ext[n_map]->sect_cnt);
7373
if (!map[n_map]) {
7474
LOG_ERR("cannot allocate section map of %zu",
7575
sizeof(**map) * ext[n_map]->sect_cnt);
@@ -84,7 +84,7 @@ int llext_restore(struct llext **ext, struct llext_loader **ldr, unsigned int n_
8484
}
8585

8686
/* Array of pointers to exported symbol tables. Can be NULL if n_exp_tab == 0 */
87-
struct llext_symbol **exp_tab = llext_alloc(sizeof(*exp_tab) * n_exp_tab);
87+
struct llext_symbol **exp_tab = llext_alloc_data(sizeof(*exp_tab) * n_exp_tab);
8888

8989
if (n_exp_tab) {
9090
if (!exp_tab) {
@@ -99,7 +99,7 @@ int llext_restore(struct llext **ext, struct llext_loader **ldr, unsigned int n_
9999
if (ext[i]->exp_tab.sym_cnt) {
100100
size_t size = sizeof(**exp_tab) * ext[i]->exp_tab.sym_cnt;
101101

102-
exp_tab[j] = llext_alloc(size);
102+
exp_tab[j] = llext_alloc_data(size);
103103
if (!exp_tab[j]) {
104104
LOG_ERR("cannot allocate exported symbol table of %zu",
105105
size);
@@ -115,7 +115,7 @@ int llext_restore(struct llext **ext, struct llext_loader **ldr, unsigned int n_
115115

116116
/* Allocate extensions and add them to the global list */
117117
for (i = 0, j = 0; i < n_ext; i++) {
118-
next = llext_alloc(sizeof(*next));
118+
next = llext_alloc_data(sizeof(*next));
119119
if (!next) {
120120
LOG_ERR("cannot allocate LLEXT of %zu", sizeof(*next));
121121
ret = -ENOMEM;

subsys/llext/llext_load.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ static int llext_load_elf_data(struct llext_loader *ldr, struct llext *ext)
107107

108108
size_t sect_map_sz = ext->sect_cnt * sizeof(ldr->sect_map[0]);
109109

110-
ldr->sect_map = llext_alloc(sect_map_sz);
110+
ldr->sect_map = llext_alloc_data(sect_map_sz);
111111
if (!ldr->sect_map) {
112112
LOG_ERR("Failed to allocate section map, size %zu", sect_map_sz);
113113
return -ENOMEM;
@@ -125,7 +125,7 @@ static int llext_load_elf_data(struct llext_loader *ldr, struct llext *ext)
125125
size_t sect_hdrs_sz = ext->sect_cnt * sizeof(ext->sect_hdrs[0]);
126126

127127
ext->sect_hdrs_on_heap = true;
128-
ext->sect_hdrs = llext_alloc(sect_hdrs_sz);
128+
ext->sect_hdrs = llext_alloc_data(sect_hdrs_sz);
129129
if (!ext->sect_hdrs) {
130130
LOG_ERR("Failed to allocate section headers, size %zu", sect_hdrs_sz);
131131
return -ENOMEM;
@@ -571,7 +571,7 @@ static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext)
571571
struct llext_symtable *sym_tab = &ext->sym_tab;
572572
size_t syms_size = sym_tab->sym_cnt * sizeof(struct llext_symbol);
573573

574-
sym_tab->syms = llext_alloc(syms_size);
574+
sym_tab->syms = llext_alloc_data(syms_size);
575575
if (!sym_tab->syms) {
576576
return -ENOMEM;
577577
}
@@ -604,7 +604,7 @@ static int llext_export_symbols(struct llext_loader *ldr, struct llext *ext,
604604
return 0;
605605
}
606606

607-
exp_tab->syms = llext_alloc(exp_tab->sym_cnt * sizeof(struct llext_symbol));
607+
exp_tab->syms = llext_alloc_data(exp_tab->sym_cnt * sizeof(struct llext_symbol));
608608
if (!exp_tab->syms) {
609609
return -ENOMEM;
610610
}

subsys/llext/llext_mem.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@ LOG_MODULE_DECLARE(llext, CONFIG_LLEXT_LOG_LEVEL);
3131
struct k_heap llext_heap;
3232
bool llext_heap_inited;
3333
#else
34-
K_HEAP_DEFINE(llext_heap, CONFIG_LLEXT_HEAP_SIZE * 1024);
34+
#ifdef CONFIG_HARVARD
35+
Z_HEAP_DEFINE_IN_SECT(llext_instr_heap, (CONFIG_LLEXT_INSTR_HEAP_SIZE * KB(1)),
36+
__attribute__((section(".rodata.llext_instr_heap"))));
37+
Z_HEAP_DEFINE_IN_SECT(llext_data_heap, (CONFIG_LLEXT_DATA_HEAP_SIZE * KB(1)),
38+
__attribute__((section(".data.llext_data_heap"))));
39+
#else
40+
K_HEAP_DEFINE(llext_heap, CONFIG_LLEXT_HEAP_SIZE * KB(1));
41+
#endif
3542
#endif
3643

3744
/*
@@ -149,7 +156,12 @@ static int llext_copy_region(struct llext_loader *ldr, struct llext *ext,
149156
}
150157

151158
/* Allocate a suitably aligned area for the region. */
152-
ext->mem[mem_idx] = llext_aligned_alloc(region_align, region_alloc);
159+
if (region->sh_flags & SHF_EXECINSTR) {
160+
ext->mem[mem_idx] = llext_aligned_alloc_instr(region_align, region_alloc);
161+
} else {
162+
ext->mem[mem_idx] = llext_aligned_alloc_data(region_align, region_alloc);
163+
}
164+
153165
if (!ext->mem[mem_idx]) {
154166
LOG_ERR("Failed allocating %zd bytes %zd-aligned for region %d",
155167
(size_t)region_alloc, (size_t)region_align, mem_idx);
@@ -296,7 +308,13 @@ void llext_free_regions(struct llext *ext)
296308
#endif
297309
if (ext->mem_on_heap[i]) {
298310
LOG_DBG("freeing memory region %d", i);
299-
llext_free(ext->mem[i]);
311+
312+
if (i == LLEXT_MEM_TEXT) {
313+
llext_free_instr(ext->mem[i]);
314+
} else {
315+
llext_free(ext->mem[i]);
316+
}
317+
300318
ext->mem[i] = NULL;
301319
}
302320
}

subsys/llext/llext_priv.h

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ int llext_copy_regions(struct llext_loader *ldr, struct llext *ext,
3030
void llext_free_regions(struct llext *ext);
3131
void llext_adjust_mmu_permissions(struct llext *ext);
3232

33+
#ifdef CONFIG_HARVARD
34+
extern struct k_heap llext_instr_heap;
35+
extern struct k_heap llext_data_heap;
36+
#else
37+
extern struct k_heap llext_heap;
38+
#define llext_instr_heap llext_heap
39+
#define llext_data_heap llext_heap
40+
#endif
41+
3342
static inline bool llext_heap_is_inited(void)
3443
{
3544
#ifdef CONFIG_LLEXT_HEAP_DYNAMIC
@@ -41,34 +50,51 @@ static inline bool llext_heap_is_inited(void)
4150
#endif
4251
}
4352

44-
static inline void *llext_alloc(size_t bytes)
53+
static inline void *llext_alloc_data(size_t bytes)
4554
{
46-
extern struct k_heap llext_heap;
47-
4855
if (!llext_heap_is_inited()) {
4956
return NULL;
5057
}
51-
return k_heap_alloc(&llext_heap, bytes, K_NO_WAIT);
58+
59+
/* Used for LLEXT metadata */
60+
return k_heap_alloc(&llext_data_heap, bytes, K_NO_WAIT);
5261
}
5362

54-
static inline void *llext_aligned_alloc(size_t align, size_t bytes)
63+
static inline void *llext_aligned_alloc_data(size_t align, size_t bytes)
5564
{
56-
extern struct k_heap llext_heap;
57-
5865
if (!llext_heap_is_inited()) {
5966
return NULL;
6067
}
61-
return k_heap_aligned_alloc(&llext_heap, align, bytes, K_NO_WAIT);
68+
69+
/* Used for LLEXT metadata OR non-executable section */
70+
return k_heap_aligned_alloc(&llext_data_heap, align, bytes, K_NO_WAIT);
6271
}
6372

6473
static inline void llext_free(void *ptr)
6574
{
66-
extern struct k_heap llext_heap;
75+
if (!llext_heap_is_inited()) {
76+
return;
77+
}
6778

79+
k_heap_free(&llext_data_heap, ptr);
80+
}
81+
82+
static inline void *llext_aligned_alloc_instr(size_t align, size_t bytes)
83+
{
84+
if (!llext_heap_is_inited()) {
85+
return NULL;
86+
}
87+
88+
return k_heap_aligned_alloc(&llext_instr_heap, align, bytes, K_NO_WAIT);
89+
}
90+
91+
static inline void llext_free_instr(void *ptr)
92+
{
6893
if (!llext_heap_is_inited()) {
6994
return;
7095
}
71-
k_heap_free(&llext_heap, ptr);
96+
97+
k_heap_free(&llext_instr_heap, ptr);
7298
}
7399

74100
/*
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CONFIG_LLEXT_INSTR_HEAP_SIZE=16
2+
CONFIG_LLEXT_DATA_HEAP_SIZE=48

0 commit comments

Comments
 (0)