diff options
Diffstat (limited to 'sys/arm')
-rw-r--r-- | sys/arm/arm/genassym.c | 5 | ||||
-rw-r--r-- | sys/arm/arm/generic_timer.c | 2 | ||||
-rw-r--r-- | sys/arm/arm/swtch-v6.S | 12 | ||||
-rw-r--r-- | sys/arm/arm/sys_machdep.c | 4 | ||||
-rw-r--r-- | sys/arm/arm/vm_machdep.c | 21 | ||||
-rw-r--r-- | sys/arm/cloudabi32/cloudabi32_sysvec.c | 193 | ||||
-rw-r--r-- | sys/arm/include/frame.h | 4 | ||||
-rw-r--r-- | sys/arm/include/pcpu.h | 13 | ||||
-rw-r--r-- | sys/arm/include/proc.h | 2 |
9 files changed, 237 insertions, 19 deletions
diff --git a/sys/arm/arm/genassym.c b/sys/arm/arm/genassym.c index 34df028..bdcb9cb 100644 --- a/sys/arm/arm/genassym.c +++ b/sys/arm/arm/genassym.c @@ -81,6 +81,9 @@ ASSYM(PCB_R12, offsetof(struct pcb, pcb_regs.sf_r12)); ASSYM(PCB_SP, offsetof(struct pcb, pcb_regs.sf_sp)); ASSYM(PCB_LR, offsetof(struct pcb, pcb_regs.sf_lr)); ASSYM(PCB_PC, offsetof(struct pcb, pcb_regs.sf_pc)); +#if __ARM_ARCH >= 6 +ASSYM(PCB_TPIDRURW, offsetof(struct pcb, pcb_regs.sf_tpidrurw)); +#endif ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb)); ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread)); @@ -100,8 +103,8 @@ ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); ASSYM(TD_PROC, offsetof(struct thread, td_proc)); ASSYM(TD_MD, offsetof(struct thread, td_md)); ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); -ASSYM(MD_TP, offsetof(struct mdthread, md_tp)); #if __ARM_ARCH < 6 +ASSYM(MD_TP, offsetof(struct mdthread, md_tp)); ASSYM(MD_RAS_START, offsetof(struct mdthread, md_ras_start)); ASSYM(MD_RAS_END, offsetof(struct mdthread, md_ras_end)); #endif diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c index 47fe459..d91eee1 100644 --- a/sys/arm/arm/generic_timer.c +++ b/sys/arm/arm/generic_timer.c @@ -259,7 +259,7 @@ arm_tmr_stop(struct eventtimer *et) sc = (struct arm_tmr_softc *)et->et_priv; ctrl = get_ctrl(sc->physical); - ctrl &= GT_CTRL_ENABLE; + ctrl &= ~GT_CTRL_ENABLE; set_ctrl(ctrl, sc->physical); return (0); diff --git a/sys/arm/arm/swtch-v6.S b/sys/arm/arm/swtch-v6.S index d63661a..8bbaac9 100644 --- a/sys/arm/arm/swtch-v6.S +++ b/sys/arm/arm/swtch-v6.S @@ -291,6 +291,8 @@ ENTRY(cpu_switch) ldr r3, [r0, #(TD_PCB)] add r3, #(PCB_R4) stmia r3, {r4-r12, sp, lr, pc} + mrc CP15_TPIDRURW(r4) + str r4, [r3, #(PCB_TPIDRURW - PCB_R4)] #ifdef INVARIANTS cmp r1, #0 /* new thread? */ @@ -437,9 +439,6 @@ sw1: cmp r3, r6 beq 1b #endif - /* Set the new tls */ - ldr r0, [r11, #(TD_MD + MD_TP)] - mcr CP15_TPIDRURO(r0) /* write tls thread reg 2 */ /* We have a new curthread now so make a note it */ str r11, [r8, #PC_CURTHREAD] @@ -452,7 +451,14 @@ sw1: * Restore all saved registers and return. Note that some saved * registers can be changed when either cpu_fork(), cpu_copy_thread(), * cpu_fork_kthread_handler(), or makectx() was called. + * + * The value of TPIDRURW is also written into TPIDRURO, as + * userspace still uses TPIDRURO, modifying it through + * sysarch(ARM_SET_TP, addr). */ + ldr r3, [r7, #PCB_TPIDRURW] + mcr CP15_TPIDRURW(r3) /* write tls thread reg 2 */ + mcr CP15_TPIDRURO(r3) /* write tls thread reg 3 */ add r3, r7, #PCB_R4 ldmia r3, {r4-r12, sp, pc} diff --git a/sys/arm/arm/sys_machdep.c b/sys/arm/arm/sys_machdep.c index 6781572..087afbd 100644 --- a/sys/arm/arm/sys_machdep.c +++ b/sys/arm/arm/sys_machdep.c @@ -166,10 +166,10 @@ static int arm32_set_tp(struct thread *td, void *args) { - td->td_md.md_tp = (register_t)args; #if __ARM_ARCH >= 6 set_tls(args); #else + td->td_md.md_tp = (register_t)args; *(register_t *)ARM_TP_ADDRESS = (register_t)args; #endif return (0); @@ -180,7 +180,7 @@ arm32_get_tp(struct thread *td, void *args) { #if __ARM_ARCH >= 6 - td->td_retval[0] = td->td_md.md_tp; + td->td_retval[0] = (register_t)get_tls(); #else td->td_retval[0] = *(register_t *)ARM_TP_ADDRESS; #endif diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c index e0b7892..ac52543 100644 --- a/sys/arm/arm/vm_machdep.c +++ b/sys/arm/arm/vm_machdep.c @@ -82,8 +82,8 @@ __FBSDID("$FreeBSD$"); * struct switchframe and trapframe must both be a multiple of 8 * for correct stack alignment. */ -CTASSERT(sizeof(struct switchframe) == 48); -CTASSERT(sizeof(struct trapframe) == 80); +_Static_assert((sizeof(struct switchframe) % 8) == 0, "Bad alignment"); +_Static_assert((sizeof(struct trapframe) % 8) == 0, "Bad alignment"); uint32_t initial_fpscr = VFPSCR_DN | VFPSCR_FZ; @@ -134,6 +134,9 @@ cpu_fork(register struct thread *td1, register struct proc *p2, pcb2->pcb_regs.sf_r5 = (register_t)td2; pcb2->pcb_regs.sf_lr = (register_t)fork_trampoline; pcb2->pcb_regs.sf_sp = STACKALIGN(td2->td_frame); +#if __ARM_ARCH >= 6 + pcb2->pcb_regs.sf_tpidrurw = (register_t)get_tls(); +#endif pcb2->pcb_vfpcpu = -1; pcb2->pcb_vfpstate.fpscr = initial_fpscr; @@ -147,9 +150,7 @@ cpu_fork(register struct thread *td1, register struct proc *p2, /* Setup to release spin count in fork_exit(). */ td2->td_md.md_spinlock_count = 1; td2->td_md.md_saved_cspr = PSR_SVC32_MODE; -#if __ARM_ARCH >= 6 - td2->td_md.md_tp = td1->td_md.md_tp; -#else +#if __ARM_ARCH < 6 td2->td_md.md_tp = *(register_t *)ARM_TP_ADDRESS; #endif } @@ -272,16 +273,18 @@ int cpu_set_user_tls(struct thread *td, void *tls_base) { - td->td_md.md_tp = (register_t)tls_base; - if (td == curthread) { - critical_enter(); #if __ARM_ARCH >= 6 + td->td_pcb->pcb_regs.sf_tpidrurw = (register_t)tls_base; + if (td == curthread) set_tls(tls_base); #else + td->td_md.md_tp = (register_t)tls_base; + if (td == curthread) { + critical_enter(); *(register_t *)ARM_TP_ADDRESS = (register_t)tls_base; -#endif critical_exit(); } +#endif return (0); } diff --git a/sys/arm/cloudabi32/cloudabi32_sysvec.c b/sys/arm/cloudabi32/cloudabi32_sysvec.c new file mode 100644 index 0000000..040dcc3 --- /dev/null +++ b/sys/arm/cloudabi32/cloudabi32_sysvec.c @@ -0,0 +1,193 @@ +/*- + * Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/imgact.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/sysent.h> + +#include <vm/vm.h> +#include <vm/pmap.h> + +#include <machine/frame.h> +#include <machine/pcb.h> +#include <machine/vmparam.h> + +#include <compat/cloudabi/cloudabi_util.h> + +#include <compat/cloudabi32/cloudabi32_syscall.h> +#include <compat/cloudabi32/cloudabi32_util.h> + +extern const char *cloudabi32_syscallnames[]; +extern struct sysent cloudabi32_sysent[]; + +static void +cloudabi32_proc_setregs(struct thread *td, struct image_params *imgp, + unsigned long stack) +{ + struct trapframe *regs; + + exec_setregs(td, imgp, stack); + + /* + * The stack now contains a pointer to the TCB and the auxiliary + * vector. Let r0 point to the auxiliary vector, and set + * tpidrurw to the TCB. + */ + regs = td->td_frame; + regs->tf_r0 = td->td_retval[0] = + stack + roundup(sizeof(cloudabi32_tcb_t), sizeof(register_t)); + (void)cpu_set_user_tls(td, (void *)stack); +} + +static int +cloudabi32_fetch_syscall_args(struct thread *td, struct syscall_args *sa) +{ + struct trapframe *frame = td->td_frame; + int error; + + /* Obtain system call number. */ + sa->code = frame->tf_r12; + if (sa->code >= CLOUDABI32_SYS_MAXSYSCALL) + return (ENOSYS); + sa->callp = &cloudabi32_sysent[sa->code]; + sa->narg = sa->callp->sy_narg; + + /* Fetch system call arguments from registers and the stack. */ + sa->args[0] = frame->tf_r0; + sa->args[1] = frame->tf_r1; + sa->args[2] = frame->tf_r2; + sa->args[3] = frame->tf_r3; + if (sa->narg > 4) { + error = copyin((void *)td->td_frame->tf_usr_sp, &sa->args[4], + (sa->narg - 4) * sizeof(register_t)); + if (error != 0) + return (error); + } + + /* Default system call return values. */ + td->td_retval[0] = 0; + td->td_retval[1] = frame->tf_r1; + return (0); +} + +static void +cloudabi32_set_syscall_retval(struct thread *td, int error) +{ + struct trapframe *frame = td->td_frame; + + switch (error) { + case 0: + /* System call succeeded. */ + frame->tf_r0 = td->td_retval[0]; + frame->tf_r1 = td->td_retval[1]; + frame->tf_spsr &= ~PSR_C; + break; + case ERESTART: + /* Restart system call. */ + frame->tf_pc -= 4; + break; + case EJUSTRETURN: + break; + default: + /* System call returned an error. */ + frame->tf_r0 = cloudabi_convert_errno(error); + frame->tf_spsr |= PSR_C; + break; + } +} + +static void +cloudabi32_schedtail(struct thread *td) +{ + struct trapframe *frame = td->td_frame; + + /* + * Initial register values for processes returning from fork. + * Make sure that we only set these values when forking, not + * when creating a new thread. + */ + if ((td->td_pflags & TDP_FORKING) != 0) { + frame->tf_r0 = CLOUDABI_PROCESS_CHILD; + frame->tf_r1 = td->td_tid; + } +} + +int +cloudabi32_thread_setregs(struct thread *td, + const cloudabi32_threadattr_t *attr, uint32_t tcb) +{ + struct trapframe *frame; + stack_t stack; + + /* Perform standard register initialization. */ + stack.ss_sp = TO_PTR(attr->stack); + stack.ss_size = attr->stack_size; + cpu_set_upcall(td, TO_PTR(attr->entry_point), NULL, &stack); + + /* + * Pass in the thread ID of the new thread and the argument + * pointer provided by the parent thread in as arguments to the + * entry point. + */ + frame = td->td_frame; + frame->tf_r0 = td->td_tid; + frame->tf_r1 = attr->argument; + + /* Set up TLS. */ + return (cpu_set_user_tls(td, (void *)tcb)); +} + +static struct sysentvec cloudabi32_elf_sysvec = { + .sv_size = CLOUDABI32_SYS_MAXSYSCALL, + .sv_table = cloudabi32_sysent, + .sv_fixup = cloudabi32_fixup, + .sv_name = "CloudABI ELF32", + .sv_coredump = elf32_coredump, + .sv_pagesize = PAGE_SIZE, + .sv_minuser = VM_MIN_ADDRESS, + .sv_maxuser = VM_MAXUSER_ADDRESS, + .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, + .sv_copyout_strings = cloudabi32_copyout_strings, + .sv_setregs = cloudabi32_proc_setregs, + .sv_flags = SV_ABI_CLOUDABI | SV_CAPSICUM | SV_ILP32, + .sv_set_syscall_retval = cloudabi32_set_syscall_retval, + .sv_fetch_syscall_args = cloudabi32_fetch_syscall_args, + .sv_syscallnames = cloudabi32_syscallnames, + .sv_schedtail = cloudabi32_schedtail, +}; + +INIT_SYSENTVEC(elf_sysvec, &cloudabi32_elf_sysvec); + +Elf32_Brandinfo cloudabi32_brand = { + .brand = ELFOSABI_CLOUDABI, + .machine = EM_ARM, + .sysvec = &cloudabi32_elf_sysvec, + .compat_3_brand = "CloudABI", +}; diff --git a/sys/arm/include/frame.h b/sys/arm/include/frame.h index 7655d89..929bc96 100644 --- a/sys/arm/include/frame.h +++ b/sys/arm/include/frame.h @@ -117,6 +117,10 @@ struct switchframe register_t sf_sp; register_t sf_lr; register_t sf_pc; +#if __ARM_ARCH >= 6 + register_t sf_tpidrurw; + register_t sf_spare0; +#endif }; diff --git a/sys/arm/include/pcpu.h b/sys/arm/include/pcpu.h index 19cb666..c9ebd5e 100644 --- a/sys/arm/include/pcpu.h +++ b/sys/arm/include/pcpu.h @@ -103,7 +103,8 @@ get_tls(void) { void *tls; - __asm __volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tls)); + /* TPIDRURW contains the authoritative value. */ + __asm __volatile("mrc p15, 0, %0, c13, c0, 2" : "=r" (tls)); return (tls); } @@ -111,7 +112,15 @@ static inline void set_tls(void *tls) { - __asm __volatile("mcr p15, 0, %0, c13, c0, 3" : : "r" (tls)); + /* + * Update both TPIDRURW and TPIDRURO. TPIDRURW needs to be written + * first to ensure that a context switch between the two writes will + * still give the desired result of updating both. + */ + __asm __volatile( + "mcr p15, 0, %0, c13, c0, 2\n" + "mcr p15, 0, %0, c13, c0, 3\n" + : : "r" (tls)); } #define curthread get_curthread() diff --git a/sys/arm/include/proc.h b/sys/arm/include/proc.h index 5d42d07..fc4b31e 100644 --- a/sys/arm/include/proc.h +++ b/sys/arm/include/proc.h @@ -53,8 +53,8 @@ struct mdthread { int md_ptrace_addr; int md_ptrace_instr_alt; int md_ptrace_addr_alt; - register_t md_tp; #if __ARM_ARCH < 6 + register_t md_tp; void *md_ras_start; void *md_ras_end; #endif |