| @@ -1,340 +1,338 @@ | | | @@ -1,340 +1,338 @@ |
1 | /* $NetBSD: vm_machdep.c,v 1.98 2009/05/16 17:01:15 cegger Exp $ */ | | 1 | /* $NetBSD: vm_machdep.c,v 1.99 2009/05/27 04:08:06 mrg Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1996 | | 4 | * Copyright (c) 1996 |
5 | * The President and Fellows of Harvard College. All rights reserved. | | 5 | * The President and Fellows of Harvard College. All rights reserved. |
6 | * Copyright (c) 1992, 1993 | | 6 | * Copyright (c) 1992, 1993 |
7 | * The Regents of the University of California. All rights reserved. | | 7 | * The Regents of the University of California. All rights reserved. |
8 | * | | 8 | * |
9 | * This software was developed by the Computer Systems Engineering group | | 9 | * This software was developed by the Computer Systems Engineering group |
10 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | | 10 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and |
11 | * contributed to Berkeley. | | 11 | * contributed to Berkeley. |
12 | * | | 12 | * |
13 | * All advertising materials mentioning features or use of this software | | 13 | * All advertising materials mentioning features or use of this software |
14 | * must display the following acknowledgement: | | 14 | * must display the following acknowledgement: |
15 | * This product includes software developed by the University of | | 15 | * This product includes software developed by the University of |
16 | * California, Lawrence Berkeley Laboratory. | | 16 | * California, Lawrence Berkeley Laboratory. |
17 | * This product includes software developed by Harvard University. | | 17 | * This product includes software developed by Harvard University. |
18 | * | | 18 | * |
19 | * Redistribution and use in source and binary forms, with or without | | 19 | * Redistribution and use in source and binary forms, with or without |
20 | * modification, are permitted provided that the following conditions | | 20 | * modification, are permitted provided that the following conditions |
21 | * are met: | | 21 | * are met: |
22 | * 1. Redistributions of source code must retain the above copyright | | 22 | * 1. Redistributions of source code must retain the above copyright |
23 | * notice, this list of conditions and the following disclaimer. | | 23 | * notice, this list of conditions and the following disclaimer. |
24 | * 2. Redistributions in binary form must reproduce the above copyright | | 24 | * 2. Redistributions in binary form must reproduce the above copyright |
25 | * notice, this list of conditions and the following disclaimer in the | | 25 | * notice, this list of conditions and the following disclaimer in the |
26 | * documentation and/or other materials provided with the distribution. | | 26 | * documentation and/or other materials provided with the distribution. |
27 | * 3. All advertising materials mentioning features or use of this software | | 27 | * 3. All advertising materials mentioning features or use of this software |
28 | * must display the following acknowledgement: | | 28 | * must display the following acknowledgement: |
29 | * This product includes software developed by Harvard University. | | 29 | * This product includes software developed by Harvard University. |
30 | * This product includes software developed by the University of | | 30 | * This product includes software developed by the University of |
31 | * California, Berkeley and its contributors. | | 31 | * California, Berkeley and its contributors. |
32 | * 4. Neither the name of the University nor the names of its contributors | | 32 | * 4. Neither the name of the University nor the names of its contributors |
33 | * may be used to endorse or promote products derived from this software | | 33 | * may be used to endorse or promote products derived from this software |
34 | * without specific prior written permission. | | 34 | * without specific prior written permission. |
35 | * | | 35 | * |
36 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 36 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
37 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 37 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
38 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 38 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
39 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 39 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
40 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 40 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
41 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 41 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
42 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 42 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
44 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 44 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
45 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 45 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
46 | * SUCH DAMAGE. | | 46 | * SUCH DAMAGE. |
47 | * | | 47 | * |
48 | * @(#)vm_machdep.c 8.2 (Berkeley) 9/23/93 | | 48 | * @(#)vm_machdep.c 8.2 (Berkeley) 9/23/93 |
49 | */ | | 49 | */ |
50 | | | 50 | |
51 | #include <sys/cdefs.h> | | 51 | #include <sys/cdefs.h> |
52 | __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.98 2009/05/16 17:01:15 cegger Exp $"); | | 52 | __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.99 2009/05/27 04:08:06 mrg Exp $"); |
53 | | | 53 | |
54 | #include "opt_multiprocessor.h" | | 54 | #include "opt_multiprocessor.h" |
55 | | | 55 | |
56 | #include <sys/param.h> | | 56 | #include <sys/param.h> |
57 | #include <sys/systm.h> | | 57 | #include <sys/systm.h> |
58 | #include <sys/proc.h> | | 58 | #include <sys/proc.h> |
59 | #include <sys/user.h> | | 59 | #include <sys/user.h> |
60 | #include <sys/core.h> | | 60 | #include <sys/core.h> |
61 | #include <sys/malloc.h> | | 61 | #include <sys/malloc.h> |
62 | #include <sys/buf.h> | | 62 | #include <sys/buf.h> |
63 | #include <sys/exec.h> | | 63 | #include <sys/exec.h> |
64 | #include <sys/vnode.h> | | 64 | #include <sys/vnode.h> |
65 | #include <sys/simplelock.h> | | 65 | #include <sys/simplelock.h> |
66 | | | 66 | |
67 | #include <uvm/uvm_extern.h> | | 67 | #include <uvm/uvm_extern.h> |
68 | | | 68 | |
69 | #include <machine/cpu.h> | | 69 | #include <machine/cpu.h> |
70 | #include <machine/frame.h> | | 70 | #include <machine/frame.h> |
71 | #include <machine/trap.h> | | 71 | #include <machine/trap.h> |
72 | | | 72 | |
73 | #include <sparc/sparc/cpuvar.h> | | 73 | #include <sparc/sparc/cpuvar.h> |
74 | | | 74 | |
75 | /* | | 75 | /* |
76 | * Map a user I/O request into kernel virtual address space. | | 76 | * Map a user I/O request into kernel virtual address space. |
77 | * Note: the pages are already locked by uvm_vslock(), so we | | 77 | * Note: the pages are already locked by uvm_vslock(), so we |
78 | * do not need to pass an access_type to pmap_enter(). | | 78 | * do not need to pass an access_type to pmap_enter(). |
79 | */ | | 79 | */ |
80 | void | | 80 | void |
81 | vmapbuf(struct buf *bp, vsize_t len) | | 81 | vmapbuf(struct buf *bp, vsize_t len) |
82 | { | | 82 | { |
83 | struct pmap *upmap, *kpmap; | | 83 | struct pmap *upmap, *kpmap; |
84 | vaddr_t uva; /* User VA (map from) */ | | 84 | vaddr_t uva; /* User VA (map from) */ |
85 | vaddr_t kva; /* Kernel VA (new to) */ | | 85 | vaddr_t kva; /* Kernel VA (new to) */ |
86 | paddr_t pa; /* physical address */ | | 86 | paddr_t pa; /* physical address */ |
87 | vsize_t off; | | 87 | vsize_t off; |
88 | | | 88 | |
89 | if ((bp->b_flags & B_PHYS) == 0) | | 89 | if ((bp->b_flags & B_PHYS) == 0) |
90 | panic("vmapbuf"); | | 90 | panic("vmapbuf"); |
91 | | | 91 | |
92 | /* | | 92 | /* |
93 | * XXX: It might be better to round/trunc to a | | 93 | * XXX: It might be better to round/trunc to a |
94 | * segment boundary to avoid VAC problems! | | 94 | * segment boundary to avoid VAC problems! |
95 | */ | | 95 | */ |
96 | bp->b_saveaddr = bp->b_data; | | 96 | bp->b_saveaddr = bp->b_data; |
97 | uva = trunc_page((vaddr_t)bp->b_data); | | 97 | uva = trunc_page((vaddr_t)bp->b_data); |
98 | off = (vaddr_t)bp->b_data - uva; | | 98 | off = (vaddr_t)bp->b_data - uva; |
99 | len = round_page(off + len); | | 99 | len = round_page(off + len); |
100 | kva = uvm_km_alloc(kernel_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); | | 100 | kva = uvm_km_alloc(kernel_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); |
101 | bp->b_data = (void *)(kva + off); | | 101 | bp->b_data = (void *)(kva + off); |
102 | | | 102 | |
103 | /* | | 103 | /* |
104 | * We have to flush any write-back cache on the | | 104 | * We have to flush any write-back cache on the |
105 | * user-space mappings so our new mappings will | | 105 | * user-space mappings so our new mappings will |
106 | * have the correct contents. | | 106 | * have the correct contents. |
107 | */ | | 107 | */ |
108 | if (CACHEINFO.c_vactype != VAC_NONE) | | 108 | if (CACHEINFO.c_vactype != VAC_NONE) |
109 | cache_flush((void *)uva, len); | | 109 | cache_flush((void *)uva, len); |
110 | | | 110 | |
111 | upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map); | | 111 | upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map); |
112 | kpmap = vm_map_pmap(kernel_map); | | 112 | kpmap = vm_map_pmap(kernel_map); |
113 | do { | | 113 | do { |
114 | if (pmap_extract(upmap, uva, &pa) == false) | | 114 | if (pmap_extract(upmap, uva, &pa) == false) |
115 | panic("vmapbuf: null page frame"); | | 115 | panic("vmapbuf: null page frame"); |
116 | /* Now map the page into kernel space. */ | | 116 | /* Now map the page into kernel space. */ |
117 | pmap_enter(kpmap, kva, pa, | | 117 | pmap_enter(kpmap, kva, pa, |
118 | VM_PROT_READ|VM_PROT_WRITE, PMAP_WIRED); | | 118 | VM_PROT_READ|VM_PROT_WRITE, PMAP_WIRED); |
119 | uva += PAGE_SIZE; | | 119 | uva += PAGE_SIZE; |
120 | kva += PAGE_SIZE; | | 120 | kva += PAGE_SIZE; |
121 | len -= PAGE_SIZE; | | 121 | len -= PAGE_SIZE; |
122 | } while (len); | | 122 | } while (len); |
123 | pmap_update(kpmap); | | 123 | pmap_update(kpmap); |
124 | } | | 124 | } |
125 | | | 125 | |
126 | /* | | 126 | /* |
127 | * Unmap a previously-mapped user I/O request. | | 127 | * Unmap a previously-mapped user I/O request. |
128 | */ | | 128 | */ |
129 | void | | 129 | void |
130 | vunmapbuf(struct buf *bp, vsize_t len) | | 130 | vunmapbuf(struct buf *bp, vsize_t len) |
131 | { | | 131 | { |
132 | vaddr_t kva; | | 132 | vaddr_t kva; |
133 | vsize_t off; | | 133 | vsize_t off; |
134 | | | 134 | |
135 | if ((bp->b_flags & B_PHYS) == 0) | | 135 | if ((bp->b_flags & B_PHYS) == 0) |
136 | panic("vunmapbuf"); | | 136 | panic("vunmapbuf"); |
137 | | | 137 | |
138 | kva = trunc_page((vaddr_t)bp->b_data); | | 138 | kva = trunc_page((vaddr_t)bp->b_data); |
139 | off = (vaddr_t)bp->b_data - kva; | | 139 | off = (vaddr_t)bp->b_data - kva; |
140 | len = round_page(off + len); | | 140 | len = round_page(off + len); |
141 | pmap_remove(vm_map_pmap(kernel_map), kva, kva + len); | | 141 | pmap_remove(vm_map_pmap(kernel_map), kva, kva + len); |
142 | pmap_update(vm_map_pmap(kernel_map)); | | 142 | pmap_update(vm_map_pmap(kernel_map)); |
143 | uvm_km_free(kernel_map, kva, len, UVM_KMF_VAONLY); | | 143 | uvm_km_free(kernel_map, kva, len, UVM_KMF_VAONLY); |
144 | bp->b_data = bp->b_saveaddr; | | 144 | bp->b_data = bp->b_saveaddr; |
145 | bp->b_saveaddr = NULL; | | 145 | bp->b_saveaddr = NULL; |
146 | | | 146 | |
147 | #if 0 /* XXX: The flush above is sufficient, right? */ | | 147 | #if 0 /* XXX: The flush above is sufficient, right? */ |
148 | if (CACHEINFO.c_vactype != VAC_NONE) | | 148 | if (CACHEINFO.c_vactype != VAC_NONE) |
149 | cpuinfo.cache_flush(bp->b_data, len); | | 149 | cpuinfo.cache_flush(bp->b_data, len); |
150 | #endif | | 150 | #endif |
151 | } | | 151 | } |
152 | | | 152 | |
153 | | | 153 | |
154 | void | | 154 | void |
155 | cpu_proc_fork(struct proc *p1, struct proc *p2) | | 155 | cpu_proc_fork(struct proc *p1, struct proc *p2) |
156 | { | | 156 | { |
157 | | | 157 | |
158 | p2->p_md.md_flags = p1->p_md.md_flags; | | 158 | p2->p_md.md_flags = p1->p_md.md_flags; |
159 | } | | 159 | } |
160 | | | 160 | |
161 | | | 161 | |
162 | /* | | 162 | /* |
163 | * The offset of the topmost frame in the kernel stack. | | 163 | * The offset of the topmost frame in the kernel stack. |
164 | */ | | 164 | */ |
165 | #define TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-sizeof(struct frame)) | | 165 | #define TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-sizeof(struct frame)) |
166 | | | 166 | |
167 | /* | | 167 | /* |
168 | * Finish a fork operation, with process l2 nearly set up. | | 168 | * Finish a fork operation, with process l2 nearly set up. |
169 | * Copy and update the pcb and trap frame, making the child ready to run. | | 169 | * Copy and update the pcb and trap frame, making the child ready to run. |
170 | * | | 170 | * |
171 | * Rig the child's kernel stack so that it will start out in | | 171 | * Rig the child's kernel stack so that it will start out in |
172 | * lwp_trampoline() and call child_return() with l2 as an | | 172 | * lwp_trampoline() and call child_return() with l2 as an |
173 | * argument. This causes the newly-created child process to go | | 173 | * argument. This causes the newly-created child process to go |
174 | * directly to user level with an apparent return value of 0 from | | 174 | * directly to user level with an apparent return value of 0 from |
175 | * fork(), while the parent process returns normally. | | 175 | * fork(), while the parent process returns normally. |
176 | * | | 176 | * |
177 | * l1 is the process being forked; if l1 == &lwp0, we are creating | | 177 | * l1 is the process being forked; if l1 == &lwp0, we are creating |
178 | * a kernel thread, and the return path and argument are specified with | | 178 | * a kernel thread, and the return path and argument are specified with |
179 | * `func' and `arg'. | | 179 | * `func' and `arg'. |
180 | * | | 180 | * |
181 | * If an alternate user-level stack is requested (with non-zero values | | 181 | * If an alternate user-level stack is requested (with non-zero values |
182 | * in both the stack and stacksize args), set up the user stack pointer | | 182 | * in both the stack and stacksize args), set up the user stack pointer |
183 | * accordingly. | | 183 | * accordingly. |
184 | */ | | 184 | */ |
185 | void | | 185 | void |
186 | cpu_lwp_fork(struct lwp *l1, struct lwp *l2, | | 186 | cpu_lwp_fork(struct lwp *l1, struct lwp *l2, |
187 | void *stack, size_t stacksize, | | 187 | void *stack, size_t stacksize, |
188 | void (*func)(void *), void *arg) | | 188 | void (*func)(void *), void *arg) |
189 | { | | 189 | { |
190 | struct pcb *opcb = &l1->l_addr->u_pcb; | | 190 | struct pcb *opcb = &l1->l_addr->u_pcb; |
191 | struct pcb *npcb = &l2->l_addr->u_pcb; | | 191 | struct pcb *npcb = &l2->l_addr->u_pcb; |
192 | struct trapframe *tf2; | | 192 | struct trapframe *tf2; |
193 | struct rwindow *rp; | | 193 | struct rwindow *rp; |
194 | | | 194 | |
195 | /* | | 195 | /* |
196 | * Save all user registers to l1's stack or, in the case of | | 196 | * Save all user registers to l1's stack or, in the case of |
197 | * user registers and invalid stack pointers, to opcb. | | 197 | * user registers and invalid stack pointers, to opcb. |
198 | * We then copy the whole pcb to l2; when switch() selects l2 | | 198 | * We then copy the whole pcb to l2; when switch() selects l2 |
199 | * to run, it will run at the `lwp_trampoline' stub, rather | | 199 | * to run, it will run at the `lwp_trampoline' stub, rather |
200 | * than returning at the copying code below. | | 200 | * than returning at the copying code below. |
201 | * | | 201 | * |
202 | * If process l1 has an FPU state, we must copy it. If it is | | 202 | * If process l1 has an FPU state, we must copy it. If it is |
203 | * the FPU user, we must save the FPU state first. | | 203 | * the FPU user, we must save the FPU state first. |
204 | */ | | 204 | */ |
205 | | | 205 | |
206 | if (l1 == curlwp) { | | 206 | if (l1 == curlwp) { |
207 | write_user_windows(); | | 207 | write_user_windows(); |
208 | opcb->pcb_psr = getpsr(); | | 208 | opcb->pcb_psr = getpsr(); |
209 | } | | 209 | } |
| | | 210 | #ifdef DIAGNOSTIC |
| | | 211 | else if (l1 != &lwp0) /* XXX is this valid? */ |
| | | 212 | panic("cpu_lwp_fork: curlwp"); |
| | | 213 | #endif |
210 | | | 214 | |
211 | memcpy((void *)npcb, (void *)opcb, sizeof(struct pcb)); | | 215 | memcpy((void *)npcb, (void *)opcb, sizeof(struct pcb)); |
212 | if (l1->l_md.md_fpstate != NULL) { | | 216 | if (l1->l_md.md_fpstate != NULL) { |
213 | struct cpu_info *cpi; | | 217 | struct cpu_info *cpi; |
214 | int s; | | 218 | int s; |
215 | | | 219 | |
216 | l2->l_md.md_fpstate = malloc(sizeof(struct fpstate), | | 220 | l2->l_md.md_fpstate = malloc(sizeof(struct fpstate), |
217 | M_SUBPROC, M_WAITOK); | | 221 | M_SUBPROC, M_WAITOK); |
218 | | | 222 | |
219 | FPU_LOCK(s); | | 223 | FPU_LOCK(s); |
220 | if ((cpi = l1->l_md.md_fpu) != NULL) { | | 224 | if ((cpi = l1->l_md.md_fpu) != NULL) { |
221 | if (cpi->fplwp != l1) | | 225 | if (cpi->fplwp != l1) |
222 | panic("FPU(%d): fplwp %p", | | 226 | panic("FPU(%d): fplwp %p", |
223 | cpi->ci_cpuid, cpi->fplwp); | | 227 | cpi->ci_cpuid, cpi->fplwp); |
224 | if (l1 == cpuinfo.fplwp) | | 228 | if (l1 == cpuinfo.fplwp) |
225 | savefpstate(l1->l_md.md_fpstate); | | 229 | savefpstate(l1->l_md.md_fpstate); |
226 | #if defined(MULTIPROCESSOR) | | 230 | #if defined(MULTIPROCESSOR) |
227 | else | | 231 | else |
228 | XCALL1(savefpstate, l1->l_md.md_fpstate, | | 232 | XCALL1(savefpstate, l1->l_md.md_fpstate, |
229 | 1 << cpi->ci_cpuid); | | 233 | 1 << cpi->ci_cpuid); |
230 | #endif | | 234 | #endif |
231 | } | | 235 | } |
232 | memcpy(l2->l_md.md_fpstate, l1->l_md.md_fpstate, | | 236 | memcpy(l2->l_md.md_fpstate, l1->l_md.md_fpstate, |
233 | sizeof(struct fpstate)); | | 237 | sizeof(struct fpstate)); |
234 | FPU_UNLOCK(s); | | 238 | FPU_UNLOCK(s); |
235 | } else | | 239 | } else |
236 | l2->l_md.md_fpstate = NULL; | | 240 | l2->l_md.md_fpstate = NULL; |
237 | | | 241 | |
238 | l2->l_md.md_fpu = NULL; | | 242 | l2->l_md.md_fpu = NULL; |
239 | | | 243 | |
240 | /* | | 244 | /* |
241 | * Setup (kernel) stack frame that will by-pass the child | | 245 | * Setup (kernel) stack frame that will by-pass the child |
242 | * out of the kernel. (The trap frame invariably resides at | | 246 | * out of the kernel. (The trap frame invariably resides at |
243 | * the tippity-top of the u. area.) | | 247 | * the tippity-top of the u. area.) |
244 | */ | | 248 | */ |
245 | tf2 = l2->l_md.md_tf = (struct trapframe *) | | 249 | tf2 = l2->l_md.md_tf = (struct trapframe *) |
246 | ((int)npcb + USPACE - sizeof(*tf2)); | | 250 | ((int)npcb + USPACE - sizeof(*tf2)); |
247 | | | 251 | |
248 | /* Copy parent's trapframe */ | | 252 | /* Copy parent's trapframe */ |
249 | *tf2 = *(struct trapframe *)((int)opcb + USPACE - sizeof(*tf2)); | | 253 | *tf2 = *(struct trapframe *)((int)opcb + USPACE - sizeof(*tf2)); |
250 | | | 254 | |
251 | /* | | 255 | /* |
252 | * If specified, give the child a different stack. | | 256 | * If specified, give the child a different stack. |
253 | */ | | 257 | */ |
254 | if (stack != NULL) | | 258 | if (stack != NULL) |
255 | tf2->tf_out[6] = (u_int)stack + stacksize; | | 259 | tf2->tf_out[6] = (u_int)stack + stacksize; |
256 | | | 260 | |
257 | /* | | 261 | /* |
258 | * The fork system call always uses the old system call | | 262 | * The fork system call always uses the old system call |
259 | * convention; clear carry and skip trap instruction as | | 263 | * convention; clear carry and skip trap instruction as |
260 | * in syscall(). | | 264 | * in syscall(). |
261 | * note: lwp_trampoline() sets a fresh psr when returning | | 265 | * note: lwp_trampoline() sets a fresh psr when returning |
262 | * to user mode. | | 266 | * to user mode. |
263 | */ | | 267 | */ |
264 | /*tf2->tf_psr &= ~PSR_C; -* success */ | | 268 | /*tf2->tf_psr &= ~PSR_C; -* success */ |
265 | tf2->tf_pc = tf2->tf_npc; | | 269 | tf2->tf_pc = tf2->tf_npc; |
266 | tf2->tf_npc = tf2->tf_pc + 4; | | 270 | tf2->tf_npc = tf2->tf_pc + 4; |
267 | | | 271 | |
268 | /* Set return values in child mode */ | | 272 | /* Set return values in child mode */ |
269 | tf2->tf_out[0] = 0; | | 273 | tf2->tf_out[0] = 0; |
270 | tf2->tf_out[1] = 1; | | 274 | tf2->tf_out[1] = 1; |
271 | | | 275 | |
272 | /* Construct kernel frame to return to in cpu_switch() */ | | 276 | /* Construct kernel frame to return to in cpu_switch() */ |
273 | rp = (struct rwindow *)((u_int)npcb + TOPFRAMEOFF); | | 277 | rp = (struct rwindow *)((u_int)npcb + TOPFRAMEOFF); |
274 | rp->rw_local[0] = (int)func; /* Function to call */ | | | |
275 | rp->rw_local[1] = (int)arg; /* and its argument */ | | | |
276 | rp->rw_local[2] = (int)l2; /* the new LWP */ | | | |
277 | | | 278 | |
278 | npcb->pcb_pc = (int)lwp_trampoline - 8; | | 279 | cpu_setfunc(l2, func, arg); |
279 | npcb->pcb_sp = (int)rp; | | | |
280 | npcb->pcb_psr &= ~PSR_CWP; /* Run in window #0 */ | | | |
281 | npcb->pcb_wim = 1; /* Fence at window #1 */ | | | |
282 | } | | 280 | } |
283 | | | 281 | |
284 | /* | | 282 | /* |
285 | * Cleanup FPU state. | | 283 | * Cleanup FPU state. |
286 | */ | | 284 | */ |
287 | void | | 285 | void |
288 | cpu_lwp_free(struct lwp *l, int proc) | | 286 | cpu_lwp_free(struct lwp *l, int proc) |
289 | { | | 287 | { |
290 | struct fpstate *fs; | | 288 | struct fpstate *fs; |
291 | | | 289 | |
292 | if ((fs = l->l_md.md_fpstate) != NULL) { | | 290 | if ((fs = l->l_md.md_fpstate) != NULL) { |
293 | struct cpu_info *cpi; | | 291 | struct cpu_info *cpi; |
294 | int s; | | 292 | int s; |
295 | | | 293 | |
296 | FPU_LOCK(s); | | 294 | FPU_LOCK(s); |
297 | if ((cpi = l->l_md.md_fpu) != NULL) { | | 295 | if ((cpi = l->l_md.md_fpu) != NULL) { |
298 | if (cpi->fplwp != l) | | 296 | if (cpi->fplwp != l) |
299 | panic("FPU(%d): fplwp %p", | | 297 | panic("FPU(%d): fplwp %p", |
300 | cpi->ci_cpuid, cpi->fplwp); | | 298 | cpi->ci_cpuid, cpi->fplwp); |
301 | if (l == cpuinfo.fplwp) | | 299 | if (l == cpuinfo.fplwp) |
302 | savefpstate(fs); | | 300 | savefpstate(fs); |
303 | #if defined(MULTIPROCESSOR) | | 301 | #if defined(MULTIPROCESSOR) |
304 | else | | 302 | else |
305 | XCALL1(savefpstate, fs, 1 << cpi->ci_cpuid); | | 303 | XCALL1(savefpstate, fs, 1 << cpi->ci_cpuid); |
306 | #endif | | 304 | #endif |
307 | cpi->fplwp = NULL; | | 305 | cpi->fplwp = NULL; |
308 | } | | 306 | } |
309 | l->l_md.md_fpu = NULL; | | 307 | l->l_md.md_fpu = NULL; |
310 | FPU_UNLOCK(s); | | 308 | FPU_UNLOCK(s); |
311 | } | | 309 | } |
312 | } | | 310 | } |
313 | | | 311 | |
314 | void | | 312 | void |
315 | cpu_lwp_free2(struct lwp *l) | | 313 | cpu_lwp_free2(struct lwp *l) |
316 | { | | 314 | { |
317 | struct fpstate *fs; | | 315 | struct fpstate *fs; |
318 | | | 316 | |
319 | if ((fs = l->l_md.md_fpstate) != NULL) | | 317 | if ((fs = l->l_md.md_fpstate) != NULL) |
320 | free((void *)fs, M_SUBPROC); | | 318 | free((void *)fs, M_SUBPROC); |
321 | } | | 319 | } |
322 | | | 320 | |
323 | void | | 321 | void |
324 | cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg) | | 322 | cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg) |
325 | { | | 323 | { |
326 | struct pcb *pcb = &l->l_addr->u_pcb; | | 324 | struct pcb *pcb = &l->l_addr->u_pcb; |
327 | /*struct trapframe *tf = l->l_md.md_tf;*/ | | 325 | /*struct trapframe *tf = l->l_md.md_tf;*/ |
328 | struct rwindow *rp; | | 326 | struct rwindow *rp; |
329 | | | 327 | |
330 | /* Construct kernel frame to return to in cpu_switch() */ | | 328 | /* Construct kernel frame to return to in cpu_switch() */ |
331 | rp = (struct rwindow *)((u_int)pcb + TOPFRAMEOFF); | | 329 | rp = (struct rwindow *)((u_int)pcb + TOPFRAMEOFF); |
332 | rp->rw_local[0] = (int)func; /* Function to call */ | | 330 | rp->rw_local[0] = (int)func; /* Function to call */ |
333 | rp->rw_local[1] = (int)arg; /* and its argument */ | | 331 | rp->rw_local[1] = (int)arg; /* and its argument */ |
334 | rp->rw_local[2] = (int)l; /* new lwp */ | | 332 | rp->rw_local[2] = (int)l; /* new lwp */ |
335 | | | 333 | |
336 | pcb->pcb_pc = (int)lwp_trampoline - 8; | | 334 | pcb->pcb_pc = (int)lwp_trampoline - 8; |
337 | pcb->pcb_sp = (int)rp; | | 335 | pcb->pcb_sp = (int)rp; |
338 | pcb->pcb_psr &= ~PSR_CWP; /* Run in window #0 */ | | 336 | pcb->pcb_psr &= ~PSR_CWP; /* Run in window #0 */ |
339 | pcb->pcb_wim = 1; /* Fence at window #1 */ | | 337 | pcb->pcb_wim = 1; /* Fence at window #1 */ |
340 | } | | 338 | } |