forked from nuttx/nuttx-update
modlib:Move addrenv logic to modlib
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
parent
52126aede1
commit
dfc5e4dd55
8 changed files with 494 additions and 6 deletions
|
@ -32,6 +32,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include <nuttx/addrenv.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
@ -227,6 +229,17 @@ struct mod_loadinfo_s
|
|||
uint16_t buflen; /* size of iobuffer[] */
|
||||
int filfd; /* Descriptor for the file being loaded */
|
||||
int nexports; /* ET_DYN - Number of symbols exported */
|
||||
|
||||
/* Address environment.
|
||||
*
|
||||
* addrenv - This is the handle created by addrenv_allocate() that can be
|
||||
* used to manage the tasks address space.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
FAR addrenv_t *addrenv; /* Address environment */
|
||||
FAR addrenv_t *oldenv; /* Saved address environment */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -318,6 +331,25 @@ void modlib_setsymtab(FAR const struct symtab_s *symtab, int nsymbols);
|
|||
|
||||
int modlib_load(FAR struct mod_loadinfo_s *loadinfo);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_load_with_addrenv
|
||||
*
|
||||
* Description:
|
||||
* Loads the binary into memory, use the address environment to load the
|
||||
* binary.
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 (OK) is returned on success and a negated errno is returned on
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
int modlib_load_with_addrenv(FAR struct mod_loadinfo_s *loadinfo);
|
||||
#else
|
||||
# define modlib_load_with_addrenv(l) modlib_load(l)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_bind
|
||||
*
|
||||
|
|
|
@ -25,6 +25,7 @@ if(CONFIG_LIBC_MODLIB)
|
|||
list(
|
||||
APPEND
|
||||
SRCS
|
||||
modlib_addrenv.c
|
||||
modlib_bind.c
|
||||
modlib_depend.c
|
||||
modlib_init.c
|
||||
|
|
|
@ -24,8 +24,8 @@ ifeq ($(CONFIG_LIBC_MODLIB),y)
|
|||
|
||||
# Add the nuttx/lib/modlib.h files to the build
|
||||
|
||||
CSRCS += modlib_bind.c modlib_depend.c modlib_init.c modlib_iobuffer.c
|
||||
CSRCS += modlib_load.c modlib_loadhdrs.c modlib_verify.c
|
||||
CSRCS += modlib_addrenv.c modlib_bind.c modlib_depend.c modlib_init.c
|
||||
CSRCS += modlib_iobuffer.c modlib_load.c modlib_loadhdrs.c modlib_verify.c
|
||||
CSRCS += modlib_read.c modlib_registry.c modlib_sections.c
|
||||
CSRCS += modlib_symbols.c modlib_symtab.c modlib_uninit.c modlib_unload.c
|
||||
CSRCS += modlib_gethandle.c modlib_getsymbol.c modlib_insert.c
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/addrenv.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -237,4 +238,87 @@ int modlib_reallocbuffer(FAR struct mod_loadinfo_s *loadinfo,
|
|||
|
||||
int modlib_freebuffers(FAR struct mod_loadinfo_s *loadinfo);
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate memory for the ELF image (textalloc and datastart). If
|
||||
* CONFIG_ARCH_ADDRENV=n, textalloc will be allocated using kmm_zalloc()
|
||||
* and datastart will be a offset from textalloc. If
|
||||
* CONFIG_ARCH_ADDRENV=y, then textalloc and datastart will be allocated
|
||||
* using up_addrenv_create(). In either case, there will be a unique
|
||||
* instance of textalloc and datastart (and stack) for each instance of a
|
||||
* process.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
* textsize - The size (in bytes) of the .text address environment needed
|
||||
* for the ELF image (read/execute).
|
||||
* datasize - The size (in bytes) of the .bss/.data address environment
|
||||
* needed for the ELF image (read/write).
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int modlib_addrenv_alloc(FAR struct mod_loadinfo_s *loadinfo,
|
||||
size_t textsize, size_t datasize);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_select
|
||||
*
|
||||
* Description:
|
||||
* Temporarily select the task's address environment.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int modlib_addrenv_select(FAR struct mod_loadinfo_s *loadinfo);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_restore
|
||||
*
|
||||
* Description:
|
||||
* Restore the address environment before modlib_addrenv_select() was
|
||||
* called.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int modlib_addrenv_restore(FAR struct mod_loadinfo_s *loadinfo);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_free
|
||||
*
|
||||
* Description:
|
||||
* Release the address environment previously created by
|
||||
* modlib_addrenv_alloc(). This function is called only under certain
|
||||
* error conditions after the module has been loaded but not yet started.
|
||||
* After the module has been started, the address environment will
|
||||
* automatically be freed when the module exits.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void modlib_addrenv_free(FAR struct mod_loadinfo_s *loadinfo);
|
||||
|
||||
#endif /* CONFIG_ARCH_ADDRENV */
|
||||
#endif /* __LIBS_LIBC_MODLIB_MODLIB_H */
|
||||
|
|
251
libs/libc/modlib/modlib_addrenv.c
Normal file
251
libs/libc/modlib/modlib_addrenv.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/****************************************************************************
|
||||
* libs/libc/modlib/modlib_addrenv.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "modlib.h"
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define ELF_TEXT_WRE (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
#define ELF_TEXT_RE (PROT_READ | PROT_EXEC)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Constant Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate memory for the ELF image (textalloc and datastart). If
|
||||
* CONFIG_ARCH_ADDRENV=n, textalloc will be allocated using kmm_zalloc()
|
||||
* and datastart will be a offset from textalloc. If
|
||||
* CONFIG_ARCH_ADDRENV=y, then textalloc and datastart will be allocated
|
||||
* using up_addrenv_create(). In either case, there will be a unique
|
||||
* instance of textalloc and datastart (and stack) for each instance of a
|
||||
* process.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
* textsize - The size (in bytes) of the .text address environment needed
|
||||
* for the ELF image (read/execute).
|
||||
* datasize - The size (in bytes) of the .bss/.data address environment
|
||||
* needed for the ELF image (read/write).
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int modlib_addrenv_alloc(FAR struct mod_loadinfo_s *loadinfo,
|
||||
size_t textsize, size_t datasize)
|
||||
{
|
||||
#if defined(CONFIG_ARCH_STACK_DYNAMIC)
|
||||
size_t heapsize = ARCH_HEAP_SIZE;
|
||||
#else
|
||||
size_t heapsize = MAX(ARCH_HEAP_SIZE, CONFIG_ELF_STACKSIZE);
|
||||
#endif
|
||||
FAR struct arch_addrenv_s *addrenv;
|
||||
FAR void *vtext;
|
||||
FAR void *vdata;
|
||||
int ret;
|
||||
|
||||
/* Create an address environment for the new ELF task */
|
||||
|
||||
loadinfo->addrenv = addrenv_allocate();
|
||||
if (!loadinfo->addrenv)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Start creating the address environment sections */
|
||||
|
||||
addrenv = &loadinfo->addrenv->addrenv;
|
||||
|
||||
ret = up_addrenv_create(textsize, datasize, heapsize, addrenv);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: up_addrenv_create failed: %d\n", ret);
|
||||
goto errout_with_addrenv;
|
||||
}
|
||||
|
||||
/* Get the virtual address associated with the start of the address
|
||||
* environment. This is the base address that we will need to use to
|
||||
* access the ELF image (but only if the address environment has been
|
||||
* selected.
|
||||
*/
|
||||
|
||||
ret = up_addrenv_vtext(addrenv, &vtext);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: up_addrenv_vtext failed: %d\n", ret);
|
||||
goto errout_with_addrenv;
|
||||
}
|
||||
|
||||
ret = up_addrenv_vdata(addrenv, textsize, &vdata);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: up_addrenv_vdata failed: %d\n", ret);
|
||||
goto errout_with_addrenv;
|
||||
}
|
||||
|
||||
loadinfo->textalloc = (uintptr_t)vtext;
|
||||
loadinfo->datastart = (uintptr_t)vdata;
|
||||
|
||||
return OK;
|
||||
|
||||
errout_with_addrenv:
|
||||
addrenv_drop(loadinfo->addrenv, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_select
|
||||
*
|
||||
* Description:
|
||||
* Temporarily select the task's address environment.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int modlib_addrenv_select(FAR struct mod_loadinfo_s *loadinfo)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Instantiate the new address environment */
|
||||
|
||||
ret = addrenv_select(loadinfo->addrenv, &loadinfo->oldenv);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: addrenv_select failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allow write access to .text */
|
||||
|
||||
ret = up_addrenv_mprot(&loadinfo->addrenv->addrenv, loadinfo->textalloc,
|
||||
loadinfo->textsize, ELF_TEXT_WRE);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: up_addrenv_text_enable_write failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_restore
|
||||
*
|
||||
* Description:
|
||||
* Restore the address environment before modlib_addrenv_select() was
|
||||
* called.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int modlib_addrenv_restore(FAR struct mod_loadinfo_s *loadinfo)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Remove write access to .text */
|
||||
|
||||
ret = up_addrenv_mprot(&loadinfo->addrenv->addrenv, loadinfo->textalloc,
|
||||
loadinfo->textsize, ELF_TEXT_RE);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: up_addrenv_text_disable_write failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Restore the old address environment */
|
||||
|
||||
ret = addrenv_restore(loadinfo->oldenv);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: addrenv_restore failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_addrenv_free
|
||||
*
|
||||
* Description:
|
||||
* Release the address environment previously created by
|
||||
* modlib_addrenv_alloc(). This function is called only under certain
|
||||
* error conditions after the module has been loaded but not yet started.
|
||||
* After the module has been started, the address environment will
|
||||
* automatically be freed when the module exits.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void modlib_addrenv_free(FAR struct mod_loadinfo_s *loadinfo)
|
||||
{
|
||||
/* Free the address environment */
|
||||
|
||||
addrenv_drop(loadinfo->addrenv, false);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -851,6 +851,23 @@ int modlib_bind(FAR struct module_s *modp,
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* If CONFIG_ARCH_ADDRENV=y, then the loaded ELF lies in a virtual address
|
||||
* space that may not be in place now. modlib_addrenv_select() will
|
||||
* temporarily instantiate that address space.
|
||||
*/
|
||||
|
||||
if (loadinfo->addrenv != NULL)
|
||||
{
|
||||
ret = modlib_addrenv_select(loadinfo);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: modlib_addrenv_select() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Find the symbol and string tables */
|
||||
|
||||
ret = modlib_findsymtab(loadinfo);
|
||||
|
@ -1007,5 +1024,20 @@ int modlib_bind(FAR struct module_s *modp,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
if (loadinfo->addrenv != NULL)
|
||||
{
|
||||
int status = modlib_addrenv_restore(loadinfo);
|
||||
if (status < 0)
|
||||
{
|
||||
berr("ERROR: modlib_addrenv_restore() failed: %d\n", status);
|
||||
if (ret == OK)
|
||||
{
|
||||
ret = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo,
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo)
|
||||
static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo, bool alloc)
|
||||
{
|
||||
size_t textsize = 0;
|
||||
size_t datasize = 0;
|
||||
|
@ -187,7 +187,7 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo)
|
|||
)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION
|
||||
if (modlib_section_alloc(loadinfo, shdr, i) >= 0)
|
||||
if (alloc && modlib_section_alloc(loadinfo, shdr, i) >= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo)
|
|||
else
|
||||
{
|
||||
#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION
|
||||
if (modlib_section_alloc(loadinfo, shdr, i) >= 0)
|
||||
if (alloc && modlib_section_alloc(loadinfo, shdr, i) >= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -456,7 +456,7 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
|
|||
|
||||
/* Determine total size to allocate */
|
||||
|
||||
modlib_elfsize(loadinfo);
|
||||
modlib_elfsize(loadinfo, true);
|
||||
|
||||
/* Allocate (and zero) memory for the ELF file. */
|
||||
|
||||
|
@ -545,3 +545,84 @@ errout_with_buffers:
|
|||
modlib_unload(loadinfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_load_with_addrenv
|
||||
*
|
||||
* Description:
|
||||
* Loads the binary into memory, use the address environment to load the
|
||||
* binary.
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 (OK) is returned on success and a negated errno is returned on
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
int modlib_load_with_addrenv(FAR struct mod_loadinfo_s *loadinfo)
|
||||
{
|
||||
int ret;
|
||||
|
||||
binfo("loadinfo: %p\n", loadinfo);
|
||||
DEBUGASSERT(loadinfo && loadinfo->filfd >= 0);
|
||||
|
||||
/* Load section and program headers into memory */
|
||||
|
||||
ret = modlib_loadhdrs(loadinfo);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: modlib_loadhdrs failed: %d\n", ret);
|
||||
goto errout_with_buffers;
|
||||
}
|
||||
|
||||
/* Determine total size to allocate */
|
||||
|
||||
modlib_elfsize(loadinfo, false);
|
||||
|
||||
ret = modlib_addrenv_alloc(loadinfo, loadinfo->textsize,
|
||||
loadinfo->datasize);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: Failed to create address environment: %d\n", ret);
|
||||
goto errout_with_buffers;
|
||||
}
|
||||
|
||||
/* If CONFIG_ARCH_ADDRENV=y, then the loaded ELF lies in a virtual address
|
||||
* space that may not be in place now. elf_addrenv_select() will
|
||||
* temporarily instantiate that address space.
|
||||
*/
|
||||
|
||||
ret = modlib_addrenv_select(loadinfo);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: elf_addrenv_select() failed: %d\n", ret);
|
||||
goto errout_with_buffers;
|
||||
}
|
||||
|
||||
ret = modlib_loadfile(loadinfo);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: modlib_loadfile failed: %d\n", ret);
|
||||
goto errout_with_addrenv;
|
||||
}
|
||||
|
||||
/* Restore the original address environment */
|
||||
|
||||
ret = modlib_addrenv_restore(loadinfo);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: modlib_addrenv_restore() failed: %d\n", ret);
|
||||
goto errout_with_buffers;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
errout_with_addrenv:
|
||||
modlib_addrenv_restore(loadinfo);
|
||||
|
||||
errout_with_buffers:
|
||||
modlib_unload(loadinfo);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -58,6 +58,13 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo)
|
|||
|
||||
modlib_freebuffers(loadinfo);
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
if (loadinfo->addrenv != NULL)
|
||||
{
|
||||
modlib_addrenv_free(loadinfo);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* Release memory holding the relocated ELF image */
|
||||
|
||||
/* ET_DYN has a single allocation so we only free textalloc */
|
||||
|
|
Loading…
Reference in a new issue