xref: /freebsd/sys/riscv/riscv/vm_machdep.c (revision 7804dd52)
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