Message ID | 20211102225248.52999-15-imp@bsdimp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | bsd-user: arm (32-bit) support | expand |
On 11/2/21 6:52 PM, Warner Losh wrote: > + /* > + * Thumb mode is encoded by the low bit in the entry point (since ARM can't > + * execute at odd addresses). When it's set, set the Thumb bit (T) in the > + * CPSR. > + */ > + if (entry & 0x1) { > + cpsr_write(env, cpsr_read(env) | CPSR_T, CPSR_T, CPSRWriteByInstr); > + } This should be cpsr_write(env, (entry & 1) * CPSR_T, CPSR_T, CPSRWriteByInstr); because you need to clear T for arm mode as well. > + /* FIXME - what to for failure of get_user()? */ > + get_user_ual(regs->ARM_r2, stack + 8); /* envp */ > + get_user_ual(regs->ARM_r1, stack + 4); /* envp */ Surely these values are present in image_info anyway? r~
[[ Adding Olivier Houchard to confirm my reading of the ARM init twisty maze of code ]] On Tue, Nov 2, 2021 at 9:31 PM Richard Henderson < richard.henderson@linaro.org> wrote: > On 11/2/21 6:52 PM, Warner Losh wrote: > > + /* > > + * Thumb mode is encoded by the low bit in the entry point (since > ARM can't > > + * execute at odd addresses). When it's set, set the Thumb bit (T) > in the > > + * CPSR. > > + */ > > + if (entry & 0x1) { > > + cpsr_write(env, cpsr_read(env) | CPSR_T, CPSR_T, > CPSRWriteByInstr); > > + } > > This should be > > cpsr_write(env, (entry & 1) * CPSR_T, CPSR_T, CPSRWriteByInstr); > > because you need to clear T for arm mode as well. > Ah. Right. I'd intended to fix this, but it slipped my mind (along with the other T bit thing you told me about). > > + /* FIXME - what to for failure of get_user()? */ > > + get_user_ual(regs->ARM_r2, stack + 8); /* envp */ > > + get_user_ual(regs->ARM_r1, stack + 4); /* envp */ > > Surely these values are present in image_info anyway? > The host versions are in image_info, but the target versions are not. Linux-user does a similar thing without the #define sugar form ARM_rX. I didn't see where the current bsd-user squirrels this information away (it's computed and stored in local variables), nor did my much more brief look at linux-user. Looking at the FreeBSD kernel, though, we don't set r1 or r2. r0 and r1 are set to 0 explicitly, and r2 is set to 0 because the first user registers are all cleared. In the static case, they are ignored (since r0 = ps_strings, r1 = obj_main (unused) and r2 = cleanup (also unused in the static case). If we're entering via the dynamic loader, it saves r0 and generates r1 (though it's ultimately unused) and r2 (which rtld sets to its cleanup routine). r0 is the ps strings that ps displays, so isn't relevant to emulation. tl;dr: I'll add a comment to that effect and make it simpler (assuming my analysis survives) Warner
diff --git a/bsd-user/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h new file mode 100644 index 0000000000..ae5b0d6c38 --- /dev/null +++ b/bsd-user/arm/target_arch_thread.h @@ -0,0 +1,80 @@ +/* + * arm thread support + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#ifndef _TARGET_ARCH_THREAD_H_ +#define _TARGET_ARCH_THREAD_H_ + +/* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */ +static inline void target_thread_set_upcall(CPUARMState *env, abi_ulong entry, + abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size) +{ + abi_ulong sp; + + /* + * Make sure the stack is properly aligned. + * arm/include/param.h (STACKLIGN() macro) + */ + sp = (u_int)(stack_base + stack_size) & ~0x7; + + /* sp = stack base */ + env->regs[13] = sp; + /* pc = start function entry */ + env->regs[15] = entry & 0xfffffffe; + /* r0 = arg */ + env->regs[0] = arg; + env->spsr = ARM_CPU_MODE_USR; + /* + * Thumb mode is encoded by the low bit in the entry point (since ARM can't + * execute at odd addresses). When it's set, set the Thumb bit (T) in the + * CPSR. + */ + if (entry & 0x1) { + cpsr_write(env, cpsr_read(env) | CPSR_T, CPSR_T, CPSRWriteByInstr); + } +} + +static inline void target_thread_init(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + regs->ARM_cpsr = 0x10; + /* + * Thumb mode is encoded by the low bit in the entry point (since ARM can't + * execute at odd addresses). When it's set, set the Thumb bit (T) in the + * CPSR. + */ + if (infop->entry & 1) { + regs->ARM_cpsr |= CPSR_T; + } + regs->ARM_pc = infop->entry & 0xfffffffe; + regs->ARM_sp = infop->start_stack; + if (bsd_type == target_freebsd) { + regs->ARM_lr = infop->entry & 0xfffffffe; + } + /* FIXME - what to for failure of get_user()? */ + get_user_ual(regs->ARM_r2, stack + 8); /* envp */ + get_user_ual(regs->ARM_r1, stack + 4); /* envp */ + /* XXX: it seems that r0 is zeroed after ! */ + regs->ARM_r0 = 0; + /* For uClinux PIC binaries. */ + /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ + regs->ARM_r10 = infop->start_data; +} + +#endif /* !_TARGET_ARCH_THREAD_H_ */