1e5acd89cSAndrew Turner /*- 2e5acd89cSAndrew Turner * Copyright (c) 2014 Andrew Turner 3e5acd89cSAndrew Turner * All rights reserved. 4e5acd89cSAndrew Turner * 5e5acd89cSAndrew Turner * Redistribution and use in source and binary forms, with or without 6e5acd89cSAndrew Turner * modification, are permitted provided that the following conditions 7e5acd89cSAndrew Turner * are met: 8e5acd89cSAndrew Turner * 1. Redistributions of source code must retain the above copyright 9e5acd89cSAndrew Turner * notice, this list of conditions and the following disclaimer. 10e5acd89cSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 11e5acd89cSAndrew Turner * notice, this list of conditions and the following disclaimer in the 12e5acd89cSAndrew Turner * documentation and/or other materials provided with the distribution. 13e5acd89cSAndrew Turner * 14e5acd89cSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15e5acd89cSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16e5acd89cSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17e5acd89cSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18e5acd89cSAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19e5acd89cSAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20e5acd89cSAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21e5acd89cSAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22e5acd89cSAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23e5acd89cSAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24e5acd89cSAndrew Turner * SUCH DAMAGE. 25e5acd89cSAndrew Turner * 26e5acd89cSAndrew Turner */ 27e5acd89cSAndrew Turner 28574a7c6cSAndrew Turner #include "opt_platform.h" 29574a7c6cSAndrew Turner 30e5acd89cSAndrew Turner #include <sys/cdefs.h> 31e5acd89cSAndrew Turner __FBSDID("$FreeBSD$"); 32e5acd89cSAndrew Turner 33e5acd89cSAndrew Turner #include <sys/param.h> 34e5acd89cSAndrew Turner #include <sys/systm.h> 35e5acd89cSAndrew Turner #include <sys/limits.h> 36e5acd89cSAndrew Turner #include <sys/proc.h> 37e5acd89cSAndrew Turner #include <sys/sf_buf.h> 38e5acd89cSAndrew Turner #include <sys/signal.h> 398e5d76e6SAndrew Turner #include <sys/sysent.h> 40e5acd89cSAndrew Turner #include <sys/unistd.h> 41e5acd89cSAndrew Turner 42e5acd89cSAndrew Turner #include <vm/vm.h> 43e5acd89cSAndrew Turner #include <vm/vm_page.h> 44e5acd89cSAndrew Turner #include <vm/vm_map.h> 45e5acd89cSAndrew Turner #include <vm/uma.h> 46e5acd89cSAndrew Turner #include <vm/uma_int.h> 47e5acd89cSAndrew Turner 48e5acd89cSAndrew Turner #include <machine/armreg.h> 49e5acd89cSAndrew Turner #include <machine/cpu.h> 509615213bSAndrew Turner #include <machine/md_var.h> 51e5acd89cSAndrew Turner #include <machine/pcb.h> 52e5acd89cSAndrew Turner #include <machine/frame.h> 53e5acd89cSAndrew Turner 542db317caSAndrew Turner #ifdef VFP 552db317caSAndrew Turner #include <machine/vfp.h> 562db317caSAndrew Turner #endif 572db317caSAndrew Turner 58574a7c6cSAndrew Turner #include <dev/psci/psci.h> 59574a7c6cSAndrew Turner 60e5acd89cSAndrew Turner /* 61e5acd89cSAndrew Turner * Finish a fork operation, with process p2 nearly set up. 62e5acd89cSAndrew Turner * Copy and update the pcb, set up the stack so that the child 63e5acd89cSAndrew Turner * ready to run and return to user mode. 64e5acd89cSAndrew Turner */ 65e5acd89cSAndrew Turner void 66e5acd89cSAndrew Turner cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) 67e5acd89cSAndrew Turner { 68e5acd89cSAndrew Turner struct pcb *pcb2; 69e5acd89cSAndrew Turner struct trapframe *tf; 70e5acd89cSAndrew Turner 71e5acd89cSAndrew Turner if ((flags & RFPROC) == 0) 72e5acd89cSAndrew Turner return; 73e5acd89cSAndrew Turner 742db317caSAndrew Turner if (td1 == curthread) { 752db317caSAndrew Turner /* 762db317caSAndrew Turner * Save the tpidr_el0 and the vfp state, these normally happen 772db317caSAndrew Turner * in cpu_switch, but if userland changes these then forks 782db317caSAndrew Turner * this may not have happened. 792db317caSAndrew Turner */ 802db317caSAndrew Turner td1->td_pcb->pcb_tpidr_el0 = READ_SPECIALREG(tpidr_el0); 812db317caSAndrew Turner #ifdef VFP 822db317caSAndrew Turner if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0) 83f692e325SAndrew Turner vfp_save_state(td1, td1->td_pcb); 842db317caSAndrew Turner #endif 852db317caSAndrew Turner } 862db317caSAndrew Turner 87e5acd89cSAndrew Turner pcb2 = (struct pcb *)(td2->td_kstack + 88e5acd89cSAndrew Turner td2->td_kstack_pages * PAGE_SIZE) - 1; 89e5acd89cSAndrew Turner 90e5acd89cSAndrew Turner td2->td_pcb = pcb2; 91e5acd89cSAndrew Turner bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); 92e5acd89cSAndrew Turner 936683b30cSAndrew Turner td2->td_proc->p_md.md_l0addr = 94f2f21fafSAndrew Turner vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l0); 95e5acd89cSAndrew Turner 96e5acd89cSAndrew Turner tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1); 97e5acd89cSAndrew Turner bcopy(td1->td_frame, tf, sizeof(*tf)); 98e5acd89cSAndrew Turner tf->tf_x[0] = 0; 99e5acd89cSAndrew Turner tf->tf_x[1] = 0; 100e5acd89cSAndrew Turner tf->tf_spsr = 0; 101e5acd89cSAndrew Turner 102e5acd89cSAndrew Turner td2->td_frame = tf; 103e5acd89cSAndrew Turner 104e5acd89cSAndrew Turner /* Set the return value registers for fork() */ 105e5acd89cSAndrew Turner td2->td_pcb->pcb_x[8] = (uintptr_t)fork_return; 106e5acd89cSAndrew Turner td2->td_pcb->pcb_x[9] = (uintptr_t)td2; 107e5acd89cSAndrew Turner td2->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; 108e5acd89cSAndrew Turner td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame; 1098ff00301SAndrew Turner td2->td_pcb->pcb_fpusaved = &td2->td_pcb->pcb_fpustate; 110e5acd89cSAndrew Turner td2->td_pcb->pcb_vfpcpu = UINT_MAX; 111e5acd89cSAndrew Turner 112e5acd89cSAndrew Turner /* Setup to release spin count in fork_exit(). */ 113e5acd89cSAndrew Turner td2->td_md.md_spinlock_count = 1; 11471374d5dSAndrew Turner td2->td_md.md_saved_daif = td1->td_md.md_saved_daif & ~DAIF_I_MASKED; 115e5acd89cSAndrew Turner } 116e5acd89cSAndrew Turner 117e5acd89cSAndrew Turner void 118e5acd89cSAndrew Turner cpu_reset(void) 119e5acd89cSAndrew Turner { 120e5acd89cSAndrew Turner 121574a7c6cSAndrew Turner psci_reset(); 122574a7c6cSAndrew Turner 123574a7c6cSAndrew Turner printf("cpu_reset failed"); 124e5acd89cSAndrew Turner while(1) 125e5acd89cSAndrew Turner __asm volatile("wfi" ::: "memory"); 126e5acd89cSAndrew Turner } 127e5acd89cSAndrew Turner 128e5acd89cSAndrew Turner void 129e5acd89cSAndrew Turner cpu_thread_swapin(struct thread *td) 130e5acd89cSAndrew Turner { 131e5acd89cSAndrew Turner } 132e5acd89cSAndrew Turner 133e5acd89cSAndrew Turner void 134e5acd89cSAndrew Turner cpu_thread_swapout(struct thread *td) 135e5acd89cSAndrew Turner { 136e5acd89cSAndrew Turner } 137e5acd89cSAndrew Turner 138e5acd89cSAndrew Turner void 139e5acd89cSAndrew Turner cpu_set_syscall_retval(struct thread *td, int error) 140e5acd89cSAndrew Turner { 141e5acd89cSAndrew Turner struct trapframe *frame; 142e5acd89cSAndrew Turner 143e5acd89cSAndrew Turner frame = td->td_frame; 144e5acd89cSAndrew Turner 145e5acd89cSAndrew Turner switch (error) { 146e5acd89cSAndrew Turner case 0: 147e5acd89cSAndrew Turner frame->tf_x[0] = td->td_retval[0]; 148e5acd89cSAndrew Turner frame->tf_x[1] = td->td_retval[1]; 149e5acd89cSAndrew Turner frame->tf_spsr &= ~PSR_C; /* carry bit */ 150e5acd89cSAndrew Turner break; 151e5acd89cSAndrew Turner case ERESTART: 152e5acd89cSAndrew Turner frame->tf_elr -= 4; 153e5acd89cSAndrew Turner break; 154e5acd89cSAndrew Turner case EJUSTRETURN: 155e5acd89cSAndrew Turner break; 156e5acd89cSAndrew Turner default: 157e5acd89cSAndrew Turner frame->tf_spsr |= PSR_C; /* carry bit */ 1588e5d76e6SAndrew Turner frame->tf_x[0] = SV_ABI_ERRNO(td->td_proc, error); 159e5acd89cSAndrew Turner break; 160e5acd89cSAndrew Turner } 161e5acd89cSAndrew Turner } 162e5acd89cSAndrew Turner 163e5acd89cSAndrew Turner /* 1645c2cf818SKonstantin Belousov * Initialize machine state, mostly pcb and trap frame for a new 1655c2cf818SKonstantin Belousov * thread, about to return to userspace. Put enough state in the new 1665c2cf818SKonstantin Belousov * thread's PCB to get it to go back to the fork_return(), which 1675c2cf818SKonstantin Belousov * finalizes the thread state and handles peculiarities of the first 1685c2cf818SKonstantin Belousov * return to userspace for the new thread. 169e5acd89cSAndrew Turner */ 170e5acd89cSAndrew Turner void 1715c2cf818SKonstantin Belousov cpu_copy_thread(struct thread *td, struct thread *td0) 172e5acd89cSAndrew Turner { 173e5acd89cSAndrew Turner bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); 174e5acd89cSAndrew Turner bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb)); 175e5acd89cSAndrew Turner 176e5acd89cSAndrew Turner td->td_pcb->pcb_x[8] = (uintptr_t)fork_return; 177e5acd89cSAndrew Turner td->td_pcb->pcb_x[9] = (uintptr_t)td; 178e5acd89cSAndrew Turner td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; 179e5acd89cSAndrew Turner td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; 1808ff00301SAndrew Turner td->td_pcb->pcb_fpusaved = &td->td_pcb->pcb_fpustate; 181e5acd89cSAndrew Turner td->td_pcb->pcb_vfpcpu = UINT_MAX; 182e5acd89cSAndrew Turner 183e5acd89cSAndrew Turner /* Setup to release spin count in fork_exit(). */ 184e5acd89cSAndrew Turner td->td_md.md_spinlock_count = 1; 18571374d5dSAndrew Turner td->td_md.md_saved_daif = td0->td_md.md_saved_daif & ~DAIF_I_MASKED; 186e5acd89cSAndrew Turner } 187e5acd89cSAndrew Turner 188e5acd89cSAndrew Turner /* 1895c2cf818SKonstantin Belousov * Set that machine state for performing an upcall that starts 1905c2cf818SKonstantin Belousov * the entry function with the given argument. 191e5acd89cSAndrew Turner */ 192e5acd89cSAndrew Turner void 1935c2cf818SKonstantin Belousov cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, 194e5acd89cSAndrew Turner stack_t *stack) 195e5acd89cSAndrew Turner { 1965f858389SAndrew Turner struct trapframe *tf = td->td_frame; 197e5acd89cSAndrew Turner 198aa949be5SJohn Baldwin tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size); 1995f858389SAndrew Turner tf->tf_elr = (register_t)entry; 2005f858389SAndrew Turner tf->tf_x[0] = (register_t)arg; 201e5acd89cSAndrew Turner } 202e5acd89cSAndrew Turner 203e5acd89cSAndrew Turner int 204e5acd89cSAndrew Turner cpu_set_user_tls(struct thread *td, void *tls_base) 205e5acd89cSAndrew Turner { 2065f858389SAndrew Turner struct pcb *pcb; 207e5acd89cSAndrew Turner 2085f858389SAndrew Turner if ((uintptr_t)tls_base >= VM_MAXUSER_ADDRESS) 2095f858389SAndrew Turner return (EINVAL); 2105f858389SAndrew Turner 2115f858389SAndrew Turner pcb = td->td_pcb; 2125f858389SAndrew Turner pcb->pcb_tpidr_el0 = (register_t)tls_base; 21366bd4c2eSEd Schouten if (td == curthread) 21466bd4c2eSEd Schouten WRITE_SPECIALREG(tpidr_el0, tls_base); 2155f858389SAndrew Turner 2165f858389SAndrew Turner return (0); 217e5acd89cSAndrew Turner } 218e5acd89cSAndrew Turner 219e5acd89cSAndrew Turner void 220e5acd89cSAndrew Turner cpu_thread_exit(struct thread *td) 221e5acd89cSAndrew Turner { 222e5acd89cSAndrew Turner } 223e5acd89cSAndrew Turner 224e5acd89cSAndrew Turner void 225e5acd89cSAndrew Turner cpu_thread_alloc(struct thread *td) 226e5acd89cSAndrew Turner { 227e5acd89cSAndrew Turner 228e5acd89cSAndrew Turner td->td_pcb = (struct pcb *)(td->td_kstack + 229e5acd89cSAndrew Turner td->td_kstack_pages * PAGE_SIZE) - 1; 230e5acd89cSAndrew Turner td->td_frame = (struct trapframe *)STACKALIGN( 23180e21aabSAndrew Turner (struct trapframe *)td->td_pcb - 1); 232e5acd89cSAndrew Turner } 233e5acd89cSAndrew Turner 234e5acd89cSAndrew Turner void 235e5acd89cSAndrew Turner cpu_thread_free(struct thread *td) 236e5acd89cSAndrew Turner { 237e5acd89cSAndrew Turner } 238e5acd89cSAndrew Turner 239e5acd89cSAndrew Turner void 240e5acd89cSAndrew Turner cpu_thread_clean(struct thread *td) 241e5acd89cSAndrew Turner { 242e5acd89cSAndrew Turner } 243e5acd89cSAndrew Turner 244e5acd89cSAndrew Turner /* 245e5acd89cSAndrew Turner * Intercept the return address from a freshly forked process that has NOT 246e5acd89cSAndrew Turner * been scheduled yet. 247e5acd89cSAndrew Turner * 248e5acd89cSAndrew Turner * This is needed to make kernel threads stay in kernel mode. 249e5acd89cSAndrew Turner */ 250e5acd89cSAndrew Turner void 2515c2cf818SKonstantin Belousov cpu_fork_kthread_handler(struct thread *td, void (*func)(void *), void *arg) 252e5acd89cSAndrew Turner { 253e5acd89cSAndrew Turner 254e5acd89cSAndrew Turner td->td_pcb->pcb_x[8] = (uintptr_t)func; 255e5acd89cSAndrew Turner td->td_pcb->pcb_x[9] = (uintptr_t)arg; 256e5acd89cSAndrew Turner td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; 257e5acd89cSAndrew Turner td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; 2588ff00301SAndrew Turner td->td_pcb->pcb_fpusaved = &td->td_pcb->pcb_fpustate; 259e5acd89cSAndrew Turner td->td_pcb->pcb_vfpcpu = UINT_MAX; 260e5acd89cSAndrew Turner } 261e5acd89cSAndrew Turner 262e5acd89cSAndrew Turner void 263e5acd89cSAndrew Turner cpu_exit(struct thread *td) 264e5acd89cSAndrew Turner { 265e5acd89cSAndrew Turner } 266e5acd89cSAndrew Turner 267e5acd89cSAndrew Turner void 268e5acd89cSAndrew Turner swi_vm(void *v) 269e5acd89cSAndrew Turner { 270e5acd89cSAndrew Turner 2719615213bSAndrew Turner if (busdma_swi_pending != 0) 2729615213bSAndrew Turner busdma_swi(); 273e5acd89cSAndrew Turner } 274