xref: /freebsd/sys/arm64/arm64/vm_machdep.c (revision 2db317ca)
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