[PATCH 24/89] linux-user/arm: Create init_main_thread

Richard Henderson posted 89 patches 3 months, 2 weeks ago
Maintainers: Riku Voipio <riku.voipio@iki.fi>, Laurent Vivier <laurent@vivier.eu>, Brian Cain <brian.cain@oss.qualcomm.com>, Paolo Bonzini <pbonzini@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>
There is a newer version of this series
[PATCH 24/89] linux-user/arm: Create init_main_thread
Posted by Richard Henderson 3 months, 2 weeks ago
Merge init_thread and target_cpu_copy_regs.
There's no point going through a target_pt_regs intermediate.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/arm/cpu_loop.c | 53 ++++++++++++++++++++++++++++++++-------
 linux-user/elfload.c      | 41 +-----------------------------
 2 files changed, 45 insertions(+), 49 deletions(-)

diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index 1f3bb96484..8974b35e8d 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -480,19 +480,54 @@ void cpu_loop(CPUARMState *env)
     }
 }
 
-void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
+void init_main_thread(CPUState *cs, struct image_info *info)
 {
-    cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
-               CPSRWriteByInstr);
-    for (int i = 0; i < 16; i++) {
-        env->regs[i] = regs->uregs[i];
+    CPUARMState *env = cpu_env(cs);
+    abi_ptr stack = info->start_stack;
+    abi_ptr entry = info->entry;
+
+    cpsr_write(env, ARM_CPU_MODE_USR | (entry & 1 ? CPSR_T : 0),
+               CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
+
+    env->regs[15] = entry & 0xfffffffe;
+    env->regs[13] = stack;
+
+    /* FIXME - what to for failure of get_user()? */
+    /* FIXME - a modern kernel does not do this? */
+    get_user_ual(env->regs[2], stack + 8); /* envp */
+    get_user_ual(env->regs[1], stack + 4); /* envp */
+
+    /*
+     * Per the SVR4 ABI, r0 contains a pointer to a function to be
+     * registered with atexit.  A value of 0 means we have no such handler.
+     */
+    env->regs[0] = 0;
+
+    /* For uClinux PIC binaries.  */
+    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
+    env->regs[10] = info->start_data;
+
+    /* Support ARM FDPIC.  */
+    if (info_is_fdpic(info)) {
+        /*
+         * As described in the ABI document, r7 points to the loadmap info
+         * prepared by the kernel. If an interpreter is needed, r8 points
+         * to the interpreter loadmap and r9 points to the interpreter
+         * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
+         * r9 points to the main program PT_DYNAMIC info.
+         */
+        env->regs[7] = info->loadmap_addr;
+        if (info->interpreter_loadmap_addr) {
+            /* Executable is dynamically loaded.  */
+            env->regs[8] = info->interpreter_loadmap_addr;
+            env->regs[9] = info->interpreter_pt_dynamic_addr;
+        } else {
+            env->regs[8] = 0;
+            env->regs[9] = info->pt_dynamic_addr;
+        }
     }
 
     if (TARGET_BIG_ENDIAN) {
-        CPUState *cpu = env_cpu(env);
-        TaskState *ts = get_task_state(cpu);
-        struct image_info *info = ts->info;
-
         /* Enable BE8.  */
         if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
             && (info->elf_flags & EF_ARM_BE8)) {
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 553d632d46..a9a1d7222a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -299,46 +299,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en
 #define ELF_CLASS       ELFCLASS32
 #define EXSTACK_DEFAULT true
 
-static inline void init_thread(struct target_pt_regs *regs,
-                               struct image_info *infop)
-{
-    abi_long stack = infop->start_stack;
-    memset(regs, 0, sizeof(*regs));
-
-    regs->uregs[16] = ARM_CPU_MODE_USR;
-    if (infop->entry & 1) {
-        regs->uregs[16] |= CPSR_T;
-    }
-    regs->uregs[15] = infop->entry & 0xfffffffe;
-    regs->uregs[13] = infop->start_stack;
-    /* FIXME - what to for failure of get_user()? */
-    get_user_ual(regs->uregs[2], stack + 8); /* envp */
-    get_user_ual(regs->uregs[1], stack + 4); /* envp */
-    /* XXX: it seems that r0 is zeroed after ! */
-    regs->uregs[0] = 0;
-    /* For uClinux PIC binaries.  */
-    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
-    regs->uregs[10] = infop->start_data;
-
-    /* Support ARM FDPIC.  */
-    if (info_is_fdpic(infop)) {
-        /* As described in the ABI document, r7 points to the loadmap info
-         * prepared by the kernel. If an interpreter is needed, r8 points
-         * to the interpreter loadmap and r9 points to the interpreter
-         * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
-         * r9 points to the main program PT_DYNAMIC info.
-         */
-        regs->uregs[7] = infop->loadmap_addr;
-        if (infop->interpreter_loadmap_addr) {
-            /* Executable is dynamically loaded.  */
-            regs->uregs[8] = infop->interpreter_loadmap_addr;
-            regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
-        } else {
-            regs->uregs[8] = 0;
-            regs->uregs[9] = infop->pt_dynamic_addr;
-        }
-    }
-}
+#define HAVE_INIT_MAIN_THREAD
 
 #define ELF_NREG    18
 typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
-- 
2.43.0
Re: [PATCH 24/89] linux-user/arm: Create init_main_thread
Posted by Peter Maydell 3 months, 2 weeks ago
On Wed, 30 Jul 2025 at 01:21, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Merge init_thread and target_cpu_copy_regs.
> There's no point going through a target_pt_regs intermediate.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/arm/cpu_loop.c | 53 ++++++++++++++++++++++++++++++++-------
>  linux-user/elfload.c      | 41 +-----------------------------
>  2 files changed, 45 insertions(+), 49 deletions(-)
>
> diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
> index 1f3bb96484..8974b35e8d 100644
> --- a/linux-user/arm/cpu_loop.c
> +++ b/linux-user/arm/cpu_loop.c
> @@ -480,19 +480,54 @@ void cpu_loop(CPUARMState *env)
>      }
>  }
>
> -void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
> +void init_main_thread(CPUState *cs, struct image_info *info)
>  {
> -    cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
> -               CPSRWriteByInstr);
> -    for (int i = 0; i < 16; i++) {
> -        env->regs[i] = regs->uregs[i];
> +    CPUARMState *env = cpu_env(cs);
> +    abi_ptr stack = info->start_stack;
> +    abi_ptr entry = info->entry;
> +
> +    cpsr_write(env, ARM_CPU_MODE_USR | (entry & 1 ? CPSR_T : 0),
> +               CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
> +
> +    env->regs[15] = entry & 0xfffffffe;
> +    env->regs[13] = stack;
> +
> +    /* FIXME - what to for failure of get_user()? */
> +    /* FIXME - a modern kernel does not do this? */
> +    get_user_ual(env->regs[2], stack + 8); /* envp */
> +    get_user_ual(env->regs[1], stack + 4); /* envp */

This seems to have originally been in the kernel as
a half-hearted attempt to support a.out format:
kernel commit acfdd4b1f7590d0 from 2013 removed the
setting up of r1 and r2 along with the rest of that
partial a.out handling. (The commit message explains the
confused kernel handling of r0 which is the origin of our
"/* XXX: it seems that r0 is zeroed after ! */" comment.)

QEMU has never supported a.out binaries, so we should
clean this up too...

Anyway, this patch is just moving code around, so
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM