@@ -50,6 +50,101 @@ extern struct tr_ctx lib_manager_tr;
5050
5151#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE
5252
53+ #include <zephyr/sys/bitarray.h>
54+ #include <zephyr/llext/elf.h>
55+
56+ #define LLEXT_LIB_PAGES (CONFIG_LIBRARY_REGION_SIZE / PAGE_SZ)
57+ SYS_BITARRAY_DEFINE_STATIC (lib_vma_bitarray , LLEXT_LIB_PAGES );
58+
59+ static uintptr_t llext_manager_alloc_vma (size_t size )
60+ {
61+ size_t num_pages = ALIGN_UP (size , PAGE_SZ ) / PAGE_SZ ;
62+ size_t offset ;
63+ int ret ;
64+
65+ ret = sys_bitarray_alloc (& lib_vma_bitarray , num_pages , & offset );
66+ if (ret < 0 ) {
67+ tr_err (& lib_manager_tr , "llext_manager_alloc_vma: failed to allocate %zu pages" , num_pages );
68+ return 0 ;
69+ }
70+
71+ return CONFIG_LIBRARY_BASE_ADDRESS + offset * PAGE_SZ ;
72+ }
73+
74+ void llext_manager_free_vma (uintptr_t vma , size_t size )
75+ {
76+ if (!vma || !size )
77+ return ;
78+
79+ size_t num_pages = ALIGN_UP (size , PAGE_SZ ) / PAGE_SZ ;
80+ size_t offset = (vma - CONFIG_LIBRARY_BASE_ADDRESS ) / PAGE_SZ ;
81+
82+ sys_bitarray_free (& lib_vma_bitarray , num_pages , offset );
83+ }
84+
85+ static enum llext_mem llext_manager_get_sec_mem_idx (const char * name , const elf_shdr_t * shdr )
86+ {
87+ if (strcmp (name , ".exported_sym" ) == 0 )
88+ return LLEXT_MEM_EXPORT ;
89+
90+ switch (shdr -> sh_type ) {
91+ case SHT_NOBITS :
92+ return LLEXT_MEM_BSS ;
93+ case SHT_PROGBITS :
94+ if (shdr -> sh_flags & SHF_EXECINSTR )
95+ return LLEXT_MEM_TEXT ;
96+ else if (shdr -> sh_flags & SHF_WRITE )
97+ return LLEXT_MEM_DATA ;
98+ else
99+ return LLEXT_MEM_RODATA ;
100+ case SHT_PREINIT_ARRAY :
101+ return LLEXT_MEM_PREINIT ;
102+ case SHT_INIT_ARRAY :
103+ return LLEXT_MEM_INIT ;
104+ case SHT_FINI_ARRAY :
105+ return LLEXT_MEM_FINI ;
106+ default :
107+ return LLEXT_MEM_COUNT ;
108+ }
109+ }
110+
111+ static size_t llext_manager_layout_sections (uint8_t * elf_buf , uintptr_t vma_base )
112+ {
113+ elf_ehdr_t * hdr = (elf_ehdr_t * )elf_buf ;
114+ elf_shdr_t * shdrs = (elf_shdr_t * )(elf_buf + hdr -> e_shoff );
115+ elf_shdr_t * shstr_shdr = shdrs + hdr -> e_shstrndx ;
116+ const char * shstrtab = (const char * )(elf_buf + shstr_shdr -> sh_offset );
117+
118+ uintptr_t current_vma = vma_base ;
119+ enum llext_mem last_region = LLEXT_MEM_COUNT ;
120+
121+ for (int i = 0 ; i < hdr -> e_shnum ; i ++ ) {
122+ elf_shdr_t * shdr = shdrs + i ;
123+
124+ if (!(shdr -> sh_flags & SHF_ALLOC ) || shdr -> sh_size == 0 )
125+ continue ;
126+
127+ const char * name = shstrtab + shdr -> sh_name ;
128+ enum llext_mem s_region = llext_manager_get_sec_mem_idx (name , shdr );
129+
130+ if (s_region == LLEXT_MEM_COUNT )
131+ continue ;
132+
133+ if (last_region != LLEXT_MEM_COUNT && last_region != s_region ) {
134+ current_vma = ALIGN_UP (current_vma , PAGE_SZ );
135+ }
136+ last_region = s_region ;
137+
138+ current_vma = ALIGN_UP (current_vma , shdr -> sh_addralign );
139+ if (vma_base ) {
140+ shdr -> sh_addr = current_vma ;
141+ }
142+ current_vma += shdr -> sh_size ;
143+ }
144+
145+ return current_vma - vma_base ;
146+ }
147+
53148static int llext_manager_update_flags (void __sparse_cache * vma , size_t size , uint32_t flags )
54149{
55150 size_t pre_pad_size = (uintptr_t )vma & (PAGE_SZ - 1 );
@@ -383,6 +478,26 @@ static int llext_manager_link(const char *name,
383478 }
384479
385480 if (!* llext || mctx -> mapped ) {
481+ if (!* llext ) {
482+ uint8_t * elf_buf = (uint8_t * )mctx -> ebl -> buf ;
483+ size_t total_size = llext_manager_layout_sections (elf_buf , 0 );
484+ if (total_size == 0 ) {
485+ tr_err (& lib_manager_tr , "llext_manager_link: layout sections failed" );
486+ return - EINVAL ;
487+ }
488+
489+ uintptr_t vma_base = llext_manager_alloc_vma (total_size );
490+ if (!vma_base ) {
491+ tr_err (& lib_manager_tr , "llext_manager_link: VMA allocation failed" );
492+ return - ENOMEM ;
493+ }
494+
495+ mctx -> vma_base = vma_base ;
496+ mctx -> vma_size = total_size ;
497+
498+ llext_manager_layout_sections (elf_buf , vma_base );
499+ }
500+
386501 /*
387502 * Either the very first time loading this module, or the module
388503 * is already mapped, we just call llext_load() to refcount it
@@ -395,8 +510,15 @@ static int llext_manager_link(const char *name,
395510 };
396511
397512 ret = llext_load (ldr , name , llext , & ldr_parm );
398- if (ret )
513+ if (ret ) {
514+ tr_err (& lib_manager_tr , "llext_load failed: ret=%d" , ret );
515+ if (mctx -> vma_base ) {
516+ llext_manager_free_vma (mctx -> vma_base , mctx -> vma_size );
517+ mctx -> vma_base = 0 ;
518+ mctx -> vma_size = 0 ;
519+ }
399520 return ret ;
521+ }
400522 }
401523
402524 /* All code sections */
0 commit comments