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 28e5acd89cSAndrew Turner #include <sys/cdefs.h> 29e5acd89cSAndrew Turner __FBSDID("$FreeBSD$"); 30e5acd89cSAndrew Turner 31e5acd89cSAndrew Turner #include <sys/param.h> 32e5acd89cSAndrew Turner #include <sys/systm.h> 33e5acd89cSAndrew Turner #include <sys/limits.h> 34e5acd89cSAndrew Turner #include <sys/proc.h> 35e5acd89cSAndrew Turner #include <sys/sf_buf.h> 36e5acd89cSAndrew Turner #include <sys/signal.h> 37e5acd89cSAndrew Turner #include <sys/unistd.h> 38e5acd89cSAndrew Turner 39e5acd89cSAndrew Turner #include <vm/vm.h> 40e5acd89cSAndrew Turner #include <vm/vm_page.h> 41e5acd89cSAndrew Turner #include <vm/vm_map.h> 42e5acd89cSAndrew Turner #include <vm/uma.h> 43e5acd89cSAndrew Turner #include <vm/uma_int.h> 44e5acd89cSAndrew Turner 45e5acd89cSAndrew Turner #include <machine/armreg.h> 46e5acd89cSAndrew Turner #include <machine/cpu.h> 47e5acd89cSAndrew Turner #include <machine/pcb.h> 48e5acd89cSAndrew Turner #include <machine/frame.h> 49e5acd89cSAndrew Turner 502db317caSAndrew Turner #ifdef VFP 512db317caSAndrew Turner #include <machine/vfp.h> 522db317caSAndrew Turner #endif 532db317caSAndrew Turner 54e5acd89cSAndrew Turner /* 55e5acd89cSAndrew Turner * Finish a fork operation, with process p2 nearly set up. 56e5acd89cSAndrew Turner * Copy and update the pcb, set up the stack so that the child 57e5acd89cSAndrew Turner * ready to run and return to user mode. 58e5acd89cSAndrew Turner */ 59e5acd89cSAndrew Turner void 60e5acd89cSAndrew Turner cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) 61e5acd89cSAndrew Turner { 62e5acd89cSAndrew Turner struct pcb *pcb2; 63e5acd89cSAndrew Turner struct trapframe *tf; 64e5acd89cSAndrew Turner 65e5acd89cSAndrew Turner if ((flags & RFPROC) == 0) 66e5acd89cSAndrew Turner return; 67e5acd89cSAndrew Turner 682db317caSAndrew Turner if (td1 == curthread) { 692db317caSAndrew Turner /* 702db317caSAndrew Turner * Save the tpidr_el0 and the vfp state, these normally happen 712db317caSAndrew Turner * in cpu_switch, but if userland changes these then forks 722db317caSAndrew Turner * this may not have happened. 732db317caSAndrew Turner */ 742db317caSAndrew Turner td1->td_pcb->pcb_tpidr_el0 = READ_SPECIALREG(tpidr_el0); 752db317caSAndrew Turner #ifdef VFP 762db317caSAndrew Turner if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0) 772db317caSAndrew Turner vfp_save_state(td1); 782db317caSAndrew Turner #endif 792db317caSAndrew Turner } 802db317caSAndrew Turner 81e5acd89cSAndrew Turner pcb2 = (struct pcb *)(td2->td_kstack + 82e5acd89cSAndrew Turner td2->td_kstack_pages * PAGE_SIZE) - 1; 83e5acd89cSAndrew Turner 84e5acd89cSAndrew Turner td2->td_pcb = pcb2; 85e5acd89cSAndrew Turner bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); 86e5acd89cSAndrew Turner 87e5acd89cSAndrew Turner td2->td_pcb->pcb_l1addr = 88e5acd89cSAndrew Turner vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l1); 89e5acd89cSAndrew Turner 90e5acd89cSAndrew Turner tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1); 91e5acd89cSAndrew Turner bcopy(td1->td_frame, tf, sizeof(*tf)); 92e5acd89cSAndrew Turner tf->tf_x[0] = 0; 93e5acd89cSAndrew Turner tf->tf_x[1] = 0; 94e5acd89cSAndrew Turner tf->tf_spsr = 0; 95e5acd89cSAndrew Turner 96e5acd89cSAndrew Turner td2->td_frame = tf; 97e5acd89cSAndrew Turner 98e5acd89cSAndrew Turner /* Set the return value registers for fork() */ 99e5acd89cSAndrew Turner td2->td_pcb->pcb_x[8] = (uintptr_t)fork_return; 100e5acd89cSAndrew Turner td2->td_pcb->pcb_x[9] = (uintptr_t)td2; 101e5acd89cSAndrew Turner td2->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; 102e5acd89cSAndrew Turner td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame; 103e5acd89cSAndrew Turner td2->td_pcb->pcb_vfpcpu = UINT_MAX; 104e5acd89cSAndrew Turner 105e5acd89cSAndrew Turner /* Setup to release spin count in fork_exit(). */ 106e5acd89cSAndrew Turner td2->td_md.md_spinlock_count = 1; 107e5acd89cSAndrew Turner td2->td_md.md_saved_daif = 0; 108e5acd89cSAndrew Turner } 109e5acd89cSAndrew Turner 110e5acd89cSAndrew Turner void 111e5acd89cSAndrew Turner cpu_reset(void) 112e5acd89cSAndrew Turner { 113e5acd89cSAndrew Turner 114e5acd89cSAndrew Turner printf("cpu_reset"); 115e5acd89cSAndrew Turner while(1) 116e5acd89cSAndrew Turner __asm volatile("wfi" ::: "memory"); 117e5acd89cSAndrew Turner } 118e5acd89cSAndrew Turner 119e5acd89cSAndrew Turner void 120e5acd89cSAndrew Turner cpu_thread_swapin(struct thread *td) 121e5acd89cSAndrew Turner { 122e5acd89cSAndrew Turner } 123e5acd89cSAndrew Turner 124e5acd89cSAndrew Turner void 125e5acd89cSAndrew Turner cpu_thread_swapout(struct thread *td) 126e5acd89cSAndrew Turner { 127e5acd89cSAndrew Turner } 128e5acd89cSAndrew Turner 129e5acd89cSAndrew Turner void 130e5acd89cSAndrew Turner cpu_set_syscall_retval(struct thread *td, int error) 131e5acd89cSAndrew Turner { 132e5acd89cSAndrew Turner struct trapframe *frame; 133e5acd89cSAndrew Turner 134e5acd89cSAndrew Turner frame = td->td_frame; 135e5acd89cSAndrew Turner 136e5acd89cSAndrew Turner switch (error) { 137e5acd89cSAndrew Turner case 0: 138e5acd89cSAndrew Turner frame->tf_x[0] = td->td_retval[0]; 139e5acd89cSAndrew Turner frame->tf_x[1] = td->td_retval[1]; 140e5acd89cSAndrew Turner frame->tf_spsr &= ~PSR_C; /* carry bit */ 141e5acd89cSAndrew Turner break; 142e5acd89cSAndrew Turner case ERESTART: 143e5acd89cSAndrew Turner frame->tf_elr -= 4; 144e5acd89cSAndrew Turner break; 145e5acd89cSAndrew Turner case EJUSTRETURN: 146e5acd89cSAndrew Turner break; 147e5acd89cSAndrew Turner default: 148e5acd89cSAndrew Turner frame->tf_spsr |= PSR_C; /* carry bit */ 149e5acd89cSAndrew Turner frame->tf_x[0] = error; 150e5acd89cSAndrew Turner break; 151e5acd89cSAndrew Turner } 152e5acd89cSAndrew Turner } 153e5acd89cSAndrew Turner 154e5acd89cSAndrew Turner /* 155e5acd89cSAndrew Turner * Initialize machine state (pcb and trap frame) for a new thread about to 156e5acd89cSAndrew Turner * upcall. Put enough state in the new thread's PCB to get it to go back 157e5acd89cSAndrew Turner * userret(), where we can intercept it again to set the return (upcall) 158e5acd89cSAndrew Turner * Address and stack, along with those from upcals that are from other sources 159e5acd89cSAndrew Turner * such as those generated in thread_userret() itself. 160e5acd89cSAndrew Turner */ 161e5acd89cSAndrew Turner void 162e5acd89cSAndrew Turner cpu_set_upcall(struct thread *td, struct thread *td0) 163e5acd89cSAndrew Turner { 164e5acd89cSAndrew Turner bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); 165e5acd89cSAndrew Turner bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb)); 166e5acd89cSAndrew Turner 167e5acd89cSAndrew Turner td->td_pcb->pcb_x[8] = (uintptr_t)fork_return; 168e5acd89cSAndrew Turner td->td_pcb->pcb_x[9] = (uintptr_t)td; 169e5acd89cSAndrew Turner td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; 170e5acd89cSAndrew Turner td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; 171e5acd89cSAndrew Turner td->td_pcb->pcb_vfpcpu = UINT_MAX; 172e5acd89cSAndrew Turner 173e5acd89cSAndrew Turner /* Setup to release spin count in fork_exit(). */ 174e5acd89cSAndrew Turner td->td_md.md_spinlock_count = 1; 175e5acd89cSAndrew Turner td->td_md.md_saved_daif = 0; 176e5acd89cSAndrew Turner } 177e5acd89cSAndrew Turner 178e5acd89cSAndrew Turner /* 179e5acd89cSAndrew Turner * Set that machine state for performing an upcall that has to 180e5acd89cSAndrew Turner * be done in thread_userret() so that those upcalls generated 181e5acd89cSAndrew Turner * in thread_userret() itself can be done as well. 182e5acd89cSAndrew Turner */ 183e5acd89cSAndrew Turner void 184e5acd89cSAndrew Turner cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg, 185e5acd89cSAndrew Turner stack_t *stack) 186e5acd89cSAndrew Turner { 187e5acd89cSAndrew Turner 188e5acd89cSAndrew Turner panic("cpu_set_upcall_kse"); 189e5acd89cSAndrew Turner } 190e5acd89cSAndrew Turner 191e5acd89cSAndrew Turner int 192e5acd89cSAndrew Turner cpu_set_user_tls(struct thread *td, void *tls_base) 193e5acd89cSAndrew Turner { 194e5acd89cSAndrew Turner 195e5acd89cSAndrew Turner panic("cpu_set_user_tls"); 196e5acd89cSAndrew Turner } 197e5acd89cSAndrew Turner 198e5acd89cSAndrew Turner void 199e5acd89cSAndrew Turner cpu_thread_exit(struct thread *td) 200e5acd89cSAndrew Turner { 201e5acd89cSAndrew Turner } 202e5acd89cSAndrew Turner 203e5acd89cSAndrew Turner void 204e5acd89cSAndrew Turner cpu_thread_alloc(struct thread *td) 205e5acd89cSAndrew Turner { 206e5acd89cSAndrew Turner 207e5acd89cSAndrew Turner td->td_pcb = (struct pcb *)(td->td_kstack + 208e5acd89cSAndrew Turner td->td_kstack_pages * PAGE_SIZE) - 1; 209e5acd89cSAndrew Turner td->td_frame = (struct trapframe *)STACKALIGN( 210e5acd89cSAndrew Turner td->td_pcb - 1); 211e5acd89cSAndrew Turner } 212e5acd89cSAndrew Turner 213e5acd89cSAndrew Turner void 214e5acd89cSAndrew Turner cpu_thread_free(struct thread *td) 215e5acd89cSAndrew Turner { 216e5acd89cSAndrew Turner } 217e5acd89cSAndrew Turner 218e5acd89cSAndrew Turner void 219e5acd89cSAndrew Turner cpu_thread_clean(struct thread *td) 220e5acd89cSAndrew Turner { 221e5acd89cSAndrew Turner } 222e5acd89cSAndrew Turner 223e5acd89cSAndrew Turner /* 224e5acd89cSAndrew Turner * Intercept the return address from a freshly forked process that has NOT 225e5acd89cSAndrew Turner * been scheduled yet. 226e5acd89cSAndrew Turner * 227e5acd89cSAndrew Turner * This is needed to make kernel threads stay in kernel mode. 228e5acd89cSAndrew Turner */ 229e5acd89cSAndrew Turner void 230e5acd89cSAndrew Turner cpu_set_fork_handler(struct thread *td, void (*func)(void *), void *arg) 231e5acd89cSAndrew Turner { 232e5acd89cSAndrew Turner 233e5acd89cSAndrew Turner td->td_pcb->pcb_x[8] = (uintptr_t)func; 234e5acd89cSAndrew Turner td->td_pcb->pcb_x[9] = (uintptr_t)arg; 235e5acd89cSAndrew Turner td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; 236e5acd89cSAndrew Turner td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; 237e5acd89cSAndrew Turner td->td_pcb->pcb_vfpcpu = UINT_MAX; 238e5acd89cSAndrew Turner } 239e5acd89cSAndrew Turner 240e5acd89cSAndrew Turner void 241e5acd89cSAndrew Turner cpu_exit(struct thread *td) 242e5acd89cSAndrew Turner { 243e5acd89cSAndrew Turner } 244e5acd89cSAndrew Turner 245e5acd89cSAndrew Turner void 246e5acd89cSAndrew Turner swi_vm(void *v) 247e5acd89cSAndrew Turner { 248e5acd89cSAndrew Turner 249e5acd89cSAndrew Turner /* Nothing to do here - busdma bounce buffers are not implemented. */ 250e5acd89cSAndrew Turner } 251e5acd89cSAndrew Turner 252e5acd89cSAndrew Turner void * 253e5acd89cSAndrew Turner uma_small_alloc(uma_zone_t zone, vm_size_t bytes, u_int8_t *flags, int wait) 254e5acd89cSAndrew Turner { 255e5acd89cSAndrew Turner 256e5acd89cSAndrew Turner panic("uma_small_alloc"); 257e5acd89cSAndrew Turner } 258e5acd89cSAndrew Turner 259e5acd89cSAndrew Turner void 260e5acd89cSAndrew Turner uma_small_free(void *mem, vm_size_t size, u_int8_t flags) 261e5acd89cSAndrew Turner { 262e5acd89cSAndrew Turner 263e5acd89cSAndrew Turner panic("uma_small_free"); 264e5acd89cSAndrew Turner } 265e5acd89cSAndrew Turner 266