]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/vm_machdep.c
Merge from head
[FreeBSD/FreeBSD.git] / sys / arm / arm / vm_machdep.c
1 /*-
2  * Copyright (c) 1982, 1986 The Regents of the University of California.
3  * Copyright (c) 1989, 1990 William Jolitz
4  * Copyright (c) 1994 John Dyson
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * the Systems Programming Group of the University of Utah Computer
9  * Science Department, and William Jolitz.
10  *
11  * Redistribution and use in source and binary :forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *      from: @(#)vm_machdep.c  7.3 (Berkeley) 5/13/91
40  *      Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
41  */
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mbuf.h>
51 #include <sys/proc.h>
52 #include <sys/socketvar.h>
53 #include <sys/syscall.h>
54 #include <sys/sysctl.h>
55 #include <sys/sysent.h>
56 #include <sys/unistd.h>
57 #include <machine/cpu.h>
58 #include <machine/frame.h>
59 #include <machine/pcb.h>
60 #include <machine/sysarch.h>
61 #include <sys/lock.h>
62 #include <sys/mutex.h>
63
64 #include <vm/vm.h>
65 #include <vm/pmap.h>
66 #include <vm/vm_extern.h>
67 #include <vm/vm_kern.h>
68 #include <vm/vm_page.h>
69 #include <vm/vm_map.h>
70 #include <vm/vm_param.h>
71 #include <vm/vm_pageout.h>
72 #include <vm/uma.h>
73 #include <vm/uma_int.h>
74
75 #include <machine/md_var.h>
76 #include <machine/vfp.h>
77
78 /*
79  * struct switchframe and trapframe must both be a multiple of 8
80  * for correct stack alignment.
81  */
82 CTASSERT(sizeof(struct switchframe) == 24);
83 CTASSERT(sizeof(struct trapframe) == 80);
84
85 /*
86  * Finish a fork operation, with process p2 nearly set up.
87  * Copy and update the pcb, set up the stack so that the child
88  * ready to run and return to user mode.
89  */
90 void
91 cpu_fork(register struct thread *td1, register struct proc *p2,
92     struct thread *td2, int flags)
93 {
94         struct pcb *pcb2;
95         struct trapframe *tf;
96         struct switchframe *sf;
97         struct mdproc *mdp2;
98
99         if ((flags & RFPROC) == 0)
100                 return;
101         pcb2 = (struct pcb *)(td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1;
102 #ifdef __XSCALE__
103 #ifndef CPU_XSCALE_CORE3
104         pmap_use_minicache(td2->td_kstack, td2->td_kstack_pages * PAGE_SIZE);
105 #endif
106 #endif
107         td2->td_pcb = pcb2;
108         bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
109         mdp2 = &p2->p_md;
110         bcopy(&td1->td_proc->p_md, mdp2, sizeof(*mdp2));
111         pcb2->un_32.pcb32_sp = td2->td_kstack +
112             USPACE_SVC_STACK_TOP - sizeof(*pcb2);
113         pcb2->pcb_vfpcpu = -1;
114         pcb2->pcb_vfpstate.fpscr = VFPSCR_DN | VFPSCR_FZ;
115         pmap_activate(td2);
116         td2->td_frame = tf = (struct trapframe *)STACKALIGN(
117             pcb2->un_32.pcb32_sp - sizeof(struct trapframe));
118         *tf = *td1->td_frame;
119         sf = (struct switchframe *)tf - 1;
120         sf->sf_r4 = (u_int)fork_return;
121         sf->sf_r5 = (u_int)td2;
122         sf->sf_pc = (u_int)fork_trampoline;
123         tf->tf_spsr &= ~PSR_C;
124         tf->tf_r0 = 0;
125         tf->tf_r1 = 0;
126         pcb2->un_32.pcb32_sp = (u_int)sf;
127         KASSERT((pcb2->un_32.pcb32_sp & 7) == 0,
128             ("cpu_fork: Incorrect stack alignment"));
129
130         /* Setup to release spin count in fork_exit(). */
131         td2->td_md.md_spinlock_count = 1;
132         td2->td_md.md_saved_cspr = 0;
133 #ifdef ARM_TP_ADDRESS
134         td2->td_md.md_tp = *(register_t *)ARM_TP_ADDRESS;
135 #else
136         td2->td_md.md_tp = (register_t) get_tls();
137 #endif
138 }
139                                 
140 void
141 cpu_thread_swapin(struct thread *td)
142 {
143 }
144
145 void
146 cpu_thread_swapout(struct thread *td)
147 {
148 }
149
150 void
151 cpu_set_syscall_retval(struct thread *td, int error)
152 {
153         struct trapframe *frame;
154         int fixup;
155 #ifdef __ARMEB__
156         u_int call;
157 #endif
158
159         frame = td->td_frame;
160         fixup = 0;
161
162 #ifdef __ARMEB__
163         /*
164          * __syscall returns an off_t while most other syscalls return an
165          * int. As an off_t is 64-bits and an int is 32-bits we need to
166          * place the returned data into r1. As the lseek and frerebsd6_lseek
167          * syscalls also return an off_t they do not need this fixup.
168          */
169 #ifdef __ARM_EABI__
170         call = frame->tf_r7;
171 #else
172         call = *(u_int32_t *)(frame->tf_pc - INSN_SIZE) & 0x000fffff;
173 #endif
174         if (call == SYS___syscall) {
175                 register_t *ap = &frame->tf_r0;
176                 register_t code = ap[_QUAD_LOWWORD];
177                 if (td->td_proc->p_sysent->sv_mask)
178                         code &= td->td_proc->p_sysent->sv_mask;
179                 fixup = (code != SYS_freebsd6_lseek && code != SYS_lseek)
180                     ? 1 : 0;
181         }
182 #endif
183
184         switch (error) {
185         case 0:
186                 if (fixup) {
187                         frame->tf_r0 = 0;
188                         frame->tf_r1 = td->td_retval[0];
189                 } else {
190                         frame->tf_r0 = td->td_retval[0];
191                         frame->tf_r1 = td->td_retval[1];
192                 }
193                 frame->tf_spsr &= ~PSR_C;   /* carry bit */
194                 break;
195         case ERESTART:
196                 /*
197                  * Reconstruct the pc to point at the swi.
198                  */
199                 frame->tf_pc -= INSN_SIZE;
200                 break;
201         case EJUSTRETURN:
202                 /* nothing to do */
203                 break;
204         default:
205                 frame->tf_r0 = error;
206                 frame->tf_spsr |= PSR_C;    /* carry bit */
207                 break;
208         }
209 }
210
211 /*
212  * Initialize machine state (pcb and trap frame) for a new thread about to
213  * upcall. Put enough state in the new thread's PCB to get it to go back
214  * userret(), where we can intercept it again to set the return (upcall)
215  * Address and stack, along with those from upcals that are from other sources
216  * such as those generated in thread_userret() itself.
217  */
218 void
219 cpu_set_upcall(struct thread *td, struct thread *td0)
220 {
221         struct trapframe *tf;
222         struct switchframe *sf;
223
224         bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe));
225         bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb));
226         tf = td->td_frame;
227         sf = (struct switchframe *)tf - 1;
228         sf->sf_r4 = (u_int)fork_return;
229         sf->sf_r5 = (u_int)td;
230         sf->sf_pc = (u_int)fork_trampoline;
231         tf->tf_spsr &= ~PSR_C;
232         tf->tf_r0 = 0;
233         td->td_pcb->un_32.pcb32_sp = (u_int)sf;
234         KASSERT((td->td_pcb->un_32.pcb32_sp & 7) == 0,
235             ("cpu_set_upcall: Incorrect stack alignment"));
236
237         /* Setup to release spin count in fork_exit(). */
238         td->td_md.md_spinlock_count = 1;
239         td->td_md.md_saved_cspr = 0;
240 }
241
242 /*
243  * Set that machine state for performing an upcall that has to
244  * be done in thread_userret() so that those upcalls generated
245  * in thread_userret() itself can be done as well.
246  */
247 void
248 cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
249         stack_t *stack)
250 {
251         struct trapframe *tf = td->td_frame;
252
253         tf->tf_usr_sp = STACKALIGN((int)stack->ss_sp + stack->ss_size
254             - sizeof(struct trapframe));
255         tf->tf_pc = (int)entry;
256         tf->tf_r0 = (int)arg;
257         tf->tf_spsr = PSR_USR32_MODE;
258 }
259
260 int
261 cpu_set_user_tls(struct thread *td, void *tls_base)
262 {
263
264         td->td_md.md_tp = (register_t)tls_base;
265         if (td == curthread) {
266                 critical_enter();
267 #ifdef ARM_TP_ADDRESS
268                 *(register_t *)ARM_TP_ADDRESS = (register_t)tls_base;
269 #else
270                 set_tls((void *)tls_base);
271 #endif
272                 critical_exit();
273         }
274         return (0);
275 }
276
277 void
278 cpu_thread_exit(struct thread *td)
279 {
280 }
281
282 void
283 cpu_thread_alloc(struct thread *td)
284 {
285         td->td_pcb = (struct pcb *)(td->td_kstack + td->td_kstack_pages *
286             PAGE_SIZE) - 1;
287         /*
288          * Ensure td_frame is aligned to an 8 byte boundary as it will be
289          * placed into the stack pointer which must be 8 byte aligned in
290          * the ARM EABI.
291          */
292         td->td_frame = (struct trapframe *)STACKALIGN((u_int)td->td_kstack +
293             USPACE_SVC_STACK_TOP - sizeof(struct pcb) -
294             sizeof(struct trapframe));
295 #ifdef __XSCALE__
296 #ifndef CPU_XSCALE_CORE3
297         pmap_use_minicache(td->td_kstack, td->td_kstack_pages * PAGE_SIZE);
298 #endif
299 #endif
300 }
301
302 void
303 cpu_thread_free(struct thread *td)
304 {
305 }
306
307 void
308 cpu_thread_clean(struct thread *td)
309 {
310 }
311
312 /*
313  * Intercept the return address from a freshly forked process that has NOT
314  * been scheduled yet.
315  *
316  * This is needed to make kernel threads stay in kernel mode.
317  */
318 void
319 cpu_set_fork_handler(struct thread *td, void (*func)(void *), void *arg)
320 {
321         struct switchframe *sf;
322         struct trapframe *tf;
323         
324         tf = td->td_frame;
325         sf = (struct switchframe *)tf - 1;
326         sf->sf_r4 = (u_int)func;
327         sf->sf_r5 = (u_int)arg;
328         td->td_pcb->un_32.pcb32_sp = (u_int)sf;
329         KASSERT((td->td_pcb->un_32.pcb32_sp & 7) == 0,
330             ("cpu_set_fork_handler: Incorrect stack alignment"));
331 }
332
333 /*
334  * Software interrupt handler for queued VM system processing.
335  */
336 void
337 swi_vm(void *dummy)
338 {
339         
340         if (busdma_swi_pending)
341                 busdma_swi();
342 }
343
344 void
345 cpu_exit(struct thread *td)
346 {
347 }
348