128029b68SRuslan Bukin /*- 298f50c44SRuslan Bukin * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> 328029b68SRuslan Bukin * All rights reserved. 428029b68SRuslan Bukin * 528029b68SRuslan Bukin * Portions of this software were developed by SRI International and the 628029b68SRuslan Bukin * University of Cambridge Computer Laboratory under DARPA/AFRL contract 728029b68SRuslan Bukin * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 828029b68SRuslan Bukin * 928029b68SRuslan Bukin * Portions of this software were developed by the University of Cambridge 1028029b68SRuslan Bukin * Computer Laboratory as part of the CTSRD Project, with support from the 1128029b68SRuslan Bukin * UK Higher Education Innovation Fund (HEIF). 1228029b68SRuslan Bukin * 1328029b68SRuslan Bukin * Redistribution and use in source and binary forms, with or without 1428029b68SRuslan Bukin * modification, are permitted provided that the following conditions 1528029b68SRuslan Bukin * are met: 1628029b68SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 1728029b68SRuslan Bukin * notice, this list of conditions and the following disclaimer. 1828029b68SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 1928029b68SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 2028029b68SRuslan Bukin * documentation and/or other materials provided with the distribution. 2128029b68SRuslan Bukin * 2228029b68SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2328029b68SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2428029b68SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2528029b68SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2628029b68SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2728029b68SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2828029b68SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2928029b68SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3028029b68SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3128029b68SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3228029b68SRuslan Bukin * SUCH DAMAGE. 3328029b68SRuslan Bukin */ 3428029b68SRuslan Bukin 3528029b68SRuslan Bukin #include <sys/cdefs.h> 3628029b68SRuslan Bukin __FBSDID("$FreeBSD$"); 3728029b68SRuslan Bukin 3828029b68SRuslan Bukin #include <sys/param.h> 3928029b68SRuslan Bukin #include <sys/systm.h> 4028029b68SRuslan Bukin #include <sys/limits.h> 4128029b68SRuslan Bukin #include <sys/proc.h> 4228029b68SRuslan Bukin #include <sys/sf_buf.h> 4328029b68SRuslan Bukin #include <sys/signal.h> 4428029b68SRuslan Bukin #include <sys/unistd.h> 4528029b68SRuslan Bukin 4628029b68SRuslan Bukin #include <vm/vm.h> 4728029b68SRuslan Bukin #include <vm/vm_page.h> 4828029b68SRuslan Bukin #include <vm/vm_map.h> 4928029b68SRuslan Bukin #include <vm/uma.h> 5028029b68SRuslan Bukin #include <vm/uma_int.h> 5128029b68SRuslan Bukin 5228029b68SRuslan Bukin #include <machine/riscvreg.h> 5328029b68SRuslan Bukin #include <machine/cpu.h> 5428029b68SRuslan Bukin #include <machine/pcb.h> 5528029b68SRuslan Bukin #include <machine/frame.h> 565f8228b2SRuslan Bukin #include <machine/sbi.h> 5728029b68SRuslan Bukin 5828029b68SRuslan Bukin /* 5928029b68SRuslan Bukin * Finish a fork operation, with process p2 nearly set up. 6028029b68SRuslan Bukin * Copy and update the pcb, set up the stack so that the child 6128029b68SRuslan Bukin * ready to run and return to user mode. 6228029b68SRuslan Bukin */ 6328029b68SRuslan Bukin void 6428029b68SRuslan Bukin cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) 6528029b68SRuslan Bukin { 6628029b68SRuslan Bukin struct pcb *pcb2; 6728029b68SRuslan Bukin struct trapframe *tf; 6828029b68SRuslan Bukin 6928029b68SRuslan Bukin if ((flags & RFPROC) == 0) 7028029b68SRuslan Bukin return; 7128029b68SRuslan Bukin 7228029b68SRuslan Bukin pcb2 = (struct pcb *)(td2->td_kstack + 7328029b68SRuslan Bukin td2->td_kstack_pages * PAGE_SIZE) - 1; 7428029b68SRuslan Bukin 7528029b68SRuslan Bukin td2->td_pcb = pcb2; 7628029b68SRuslan Bukin bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); 7728029b68SRuslan Bukin 7828029b68SRuslan Bukin td2->td_pcb->pcb_l1addr = 7928029b68SRuslan Bukin vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l1); 8028029b68SRuslan Bukin 8128029b68SRuslan Bukin tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1); 8228029b68SRuslan Bukin bcopy(td1->td_frame, tf, sizeof(*tf)); 8328029b68SRuslan Bukin 8428029b68SRuslan Bukin /* Clear syscall error flag */ 8528029b68SRuslan Bukin tf->tf_t[0] = 0; 8628029b68SRuslan Bukin 8728029b68SRuslan Bukin /* Arguments for child */ 8828029b68SRuslan Bukin tf->tf_a[0] = 0; 8928029b68SRuslan Bukin tf->tf_a[1] = 0; 907804dd52SRuslan Bukin tf->tf_sstatus |= (SSTATUS_SPIE); /* Enable interrupts. */ 917804dd52SRuslan Bukin tf->tf_sstatus &= ~(SSTATUS_SPP); /* User mode. */ 9228029b68SRuslan Bukin 9328029b68SRuslan Bukin td2->td_frame = tf; 9428029b68SRuslan Bukin 9528029b68SRuslan Bukin /* Set the return value registers for fork() */ 96486ff498SRuslan Bukin td2->td_pcb->pcb_s[0] = (uintptr_t)fork_return; 97486ff498SRuslan Bukin td2->td_pcb->pcb_s[1] = (uintptr_t)td2; 9828029b68SRuslan Bukin td2->td_pcb->pcb_ra = (uintptr_t)fork_trampoline; 9928029b68SRuslan Bukin td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame; 10028029b68SRuslan Bukin 10128029b68SRuslan Bukin /* Setup to release spin count in fork_exit(). */ 10228029b68SRuslan Bukin td2->td_md.md_spinlock_count = 1; 10398f50c44SRuslan Bukin td2->td_md.md_saved_sstatus_ie = (SSTATUS_SIE); 10428029b68SRuslan Bukin } 10528029b68SRuslan Bukin 10628029b68SRuslan Bukin void 10728029b68SRuslan Bukin cpu_reset(void) 10828029b68SRuslan Bukin { 10928029b68SRuslan Bukin 1105f8228b2SRuslan Bukin sbi_shutdown(); 1115f8228b2SRuslan Bukin 1125f8228b2SRuslan Bukin while(1); 11328029b68SRuslan Bukin } 11428029b68SRuslan Bukin 11528029b68SRuslan Bukin void 11628029b68SRuslan Bukin cpu_thread_swapin(struct thread *td) 11728029b68SRuslan Bukin { 11828029b68SRuslan Bukin } 11928029b68SRuslan Bukin 12028029b68SRuslan Bukin void 12128029b68SRuslan Bukin cpu_thread_swapout(struct thread *td) 12228029b68SRuslan Bukin { 12328029b68SRuslan Bukin } 12428029b68SRuslan Bukin 12528029b68SRuslan Bukin void 12628029b68SRuslan Bukin cpu_set_syscall_retval(struct thread *td, int error) 12728029b68SRuslan Bukin { 12828029b68SRuslan Bukin struct trapframe *frame; 12928029b68SRuslan Bukin 13028029b68SRuslan Bukin frame = td->td_frame; 13128029b68SRuslan Bukin 13228029b68SRuslan Bukin switch (error) { 13328029b68SRuslan Bukin case 0: 13428029b68SRuslan Bukin frame->tf_a[0] = td->td_retval[0]; 13528029b68SRuslan Bukin frame->tf_a[1] = td->td_retval[1]; 13628029b68SRuslan Bukin frame->tf_t[0] = 0; /* syscall succeeded */ 13728029b68SRuslan Bukin break; 13828029b68SRuslan Bukin case ERESTART: 13928029b68SRuslan Bukin frame->tf_sepc -= 4; /* prev instruction */ 14028029b68SRuslan Bukin break; 14128029b68SRuslan Bukin case EJUSTRETURN: 14228029b68SRuslan Bukin break; 14328029b68SRuslan Bukin default: 14428029b68SRuslan Bukin frame->tf_a[0] = error; 14528029b68SRuslan Bukin frame->tf_t[0] = 1; /* syscall error */ 14628029b68SRuslan Bukin break; 14728029b68SRuslan Bukin } 14828029b68SRuslan Bukin } 14928029b68SRuslan Bukin 15028029b68SRuslan Bukin /* 1515c2cf818SKonstantin Belousov * Initialize machine state, mostly pcb and trap frame for a new 1525c2cf818SKonstantin Belousov * thread, about to return to userspace. Put enough state in the new 1535c2cf818SKonstantin Belousov * thread's PCB to get it to go back to the fork_return(), which 1545c2cf818SKonstantin Belousov * finalizes the thread state and handles peculiarities of the first 1555c2cf818SKonstantin Belousov * return to userspace for the new thread. 15628029b68SRuslan Bukin */ 15728029b68SRuslan Bukin void 1585c2cf818SKonstantin Belousov cpu_copy_thread(struct thread *td, struct thread *td0) 15928029b68SRuslan Bukin { 16028029b68SRuslan Bukin 16128029b68SRuslan Bukin bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); 16228029b68SRuslan Bukin bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb)); 16328029b68SRuslan Bukin 164486ff498SRuslan Bukin td->td_pcb->pcb_s[0] = (uintptr_t)fork_return; 165486ff498SRuslan Bukin td->td_pcb->pcb_s[1] = (uintptr_t)td; 16628029b68SRuslan Bukin td->td_pcb->pcb_ra = (uintptr_t)fork_trampoline; 16728029b68SRuslan Bukin td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; 16828029b68SRuslan Bukin 16928029b68SRuslan Bukin /* Setup to release spin count in fork_exit(). */ 17028029b68SRuslan Bukin td->td_md.md_spinlock_count = 1; 17198f50c44SRuslan Bukin td->td_md.md_saved_sstatus_ie = (SSTATUS_SIE); 17228029b68SRuslan Bukin } 17328029b68SRuslan Bukin 17428029b68SRuslan Bukin /* 1755c2cf818SKonstantin Belousov * Set that machine state for performing an upcall that starts 1765c2cf818SKonstantin Belousov * the entry function with the given argument. 17728029b68SRuslan Bukin */ 17828029b68SRuslan Bukin void 1795c2cf818SKonstantin Belousov cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, 18028029b68SRuslan Bukin stack_t *stack) 18128029b68SRuslan Bukin { 18228029b68SRuslan Bukin struct trapframe *tf = td->td_frame; 18328029b68SRuslan Bukin 18428029b68SRuslan Bukin tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size); 18528029b68SRuslan Bukin tf->tf_sepc = (register_t)entry; 18628029b68SRuslan Bukin tf->tf_a[0] = (register_t)arg; 18728029b68SRuslan Bukin } 18828029b68SRuslan Bukin 18928029b68SRuslan Bukin int 19028029b68SRuslan Bukin cpu_set_user_tls(struct thread *td, void *tls_base) 19128029b68SRuslan Bukin { 19228029b68SRuslan Bukin struct pcb *pcb; 19328029b68SRuslan Bukin 19428029b68SRuslan Bukin if ((uintptr_t)tls_base >= VM_MAXUSER_ADDRESS) 19528029b68SRuslan Bukin return (EINVAL); 19628029b68SRuslan Bukin 19728029b68SRuslan Bukin pcb = td->td_pcb; 19828029b68SRuslan Bukin pcb->pcb_tp = (register_t)tls_base; 19928029b68SRuslan Bukin 20028029b68SRuslan Bukin return (0); 20128029b68SRuslan Bukin } 20228029b68SRuslan Bukin 20328029b68SRuslan Bukin void 20428029b68SRuslan Bukin cpu_thread_exit(struct thread *td) 20528029b68SRuslan Bukin { 20628029b68SRuslan Bukin } 20728029b68SRuslan Bukin 20828029b68SRuslan Bukin void 20928029b68SRuslan Bukin cpu_thread_alloc(struct thread *td) 21028029b68SRuslan Bukin { 21128029b68SRuslan Bukin 21228029b68SRuslan Bukin td->td_pcb = (struct pcb *)(td->td_kstack + 21328029b68SRuslan Bukin td->td_kstack_pages * PAGE_SIZE) - 1; 21428029b68SRuslan Bukin td->td_frame = (struct trapframe *)STACKALIGN( 2154d50647dSRuslan Bukin (caddr_t)td->td_pcb - 8 - sizeof(struct trapframe)); 21628029b68SRuslan Bukin } 21728029b68SRuslan Bukin 21828029b68SRuslan Bukin void 21928029b68SRuslan Bukin cpu_thread_free(struct thread *td) 22028029b68SRuslan Bukin { 22128029b68SRuslan Bukin } 22228029b68SRuslan Bukin 22328029b68SRuslan Bukin void 22428029b68SRuslan Bukin cpu_thread_clean(struct thread *td) 22528029b68SRuslan Bukin { 22628029b68SRuslan Bukin } 22728029b68SRuslan Bukin 22828029b68SRuslan Bukin /* 22928029b68SRuslan Bukin * Intercept the return address from a freshly forked process that has NOT 23028029b68SRuslan Bukin * been scheduled yet. 23128029b68SRuslan Bukin * 23228029b68SRuslan Bukin * This is needed to make kernel threads stay in kernel mode. 23328029b68SRuslan Bukin */ 23428029b68SRuslan Bukin void 2355c2cf818SKonstantin Belousov cpu_fork_kthread_handler(struct thread *td, void (*func)(void *), void *arg) 23628029b68SRuslan Bukin { 23728029b68SRuslan Bukin 238486ff498SRuslan Bukin td->td_pcb->pcb_s[0] = (uintptr_t)func; 239486ff498SRuslan Bukin td->td_pcb->pcb_s[1] = (uintptr_t)arg; 24028029b68SRuslan Bukin td->td_pcb->pcb_ra = (uintptr_t)fork_trampoline; 24128029b68SRuslan Bukin td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; 24228029b68SRuslan Bukin } 24328029b68SRuslan Bukin 24428029b68SRuslan Bukin void 24528029b68SRuslan Bukin cpu_exit(struct thread *td) 24628029b68SRuslan Bukin { 24728029b68SRuslan Bukin } 24828029b68SRuslan Bukin 24928029b68SRuslan Bukin void 25028029b68SRuslan Bukin swi_vm(void *v) 25128029b68SRuslan Bukin { 25228029b68SRuslan Bukin 25328029b68SRuslan Bukin /* Nothing to do here - busdma bounce buffers are not implemented. */ 25428029b68SRuslan Bukin } 255