1 /*- 2 * Copyright (C) 2002 Benno Rice 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 /*- 26 * Copyright (C) 1993 Wolfgang Solfrank. 27 * Copyright (C) 1993 TooLs GmbH. 28 * All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. All advertising materials mentioning features or use of this software 39 * must display the following acknowledgement: 40 * This product includes software developed by TooLs GmbH. 41 * 4. The name of TooLs GmbH may not be used to endorse or promote products 42 * derived from this software without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 49 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 50 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 51 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 52 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 53 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 */ 55 56 #include <sys/cdefs.h> 57 __FBSDID("$FreeBSD$"); 58 59 #include <sys/param.h> 60 #include <sys/systm.h> 61 #include <sys/proc.h> 62 63 #include <vm/vm.h> 64 #include <vm/pmap.h> 65 #include <vm/vm_map.h> 66 67 #include <machine/pcb.h> 68 #include <machine/sr.h> 69 70 int setfault(faultbuf); /* defined in locore.S */ 71 72 /* 73 * Makes sure that the right segment of userspace is mapped in. 74 */ 75 static __inline void 76 set_user_sr(register_t vsid) 77 { 78 79 isync(); 80 __asm __volatile ("mtsr %0,%1" :: "n"(USER_SR), "r"(vsid)); 81 isync(); 82 } 83 84 int 85 copyout(const void *kaddr, void *udaddr, size_t len) 86 { 87 struct thread *td; 88 pmap_t pm; 89 faultbuf env; 90 const char *kp; 91 char *up, *p; 92 size_t l; 93 94 td = PCPU_GET(curthread); 95 pm = &td->td_proc->p_vmspace->vm_pmap; 96 97 if (setfault(env)) { 98 td->td_pcb->pcb_onfault = NULL; 99 return (EFAULT); 100 } 101 102 kp = kaddr; 103 up = udaddr; 104 105 while (len > 0) { 106 p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK); 107 108 l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p; 109 if (l > len) 110 l = len; 111 112 set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]); 113 114 bcopy(kp, p, l); 115 116 up += l; 117 kp += l; 118 len -= l; 119 } 120 121 td->td_pcb->pcb_onfault = NULL; 122 return (0); 123 } 124 125 int 126 copyin(const void *udaddr, void *kaddr, size_t len) 127 { 128 struct thread *td; 129 pmap_t pm; 130 faultbuf env; 131 const char *up; 132 char *kp, *p; 133 size_t l; 134 135 td = PCPU_GET(curthread); 136 pm = &td->td_proc->p_vmspace->vm_pmap; 137 138 if (setfault(env)) { 139 td->td_pcb->pcb_onfault = NULL; 140 return (EFAULT); 141 } 142 143 kp = kaddr; 144 up = udaddr; 145 146 while (len > 0) { 147 p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK); 148 149 l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p; 150 if (l > len) 151 l = len; 152 153 set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]); 154 155 bcopy(p, kp, l); 156 157 up += l; 158 kp += l; 159 len -= l; 160 } 161 162 td->td_pcb->pcb_onfault = NULL; 163 return (0); 164 } 165 166 int 167 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) 168 { 169 struct thread *td; 170 pmap_t pm; 171 faultbuf env; 172 const char *up; 173 char *kp; 174 size_t l; 175 int rv, c; 176 177 td = PCPU_GET(curthread); 178 pm = &td->td_proc->p_vmspace->vm_pmap; 179 180 if (setfault(env)) { 181 td->td_pcb->pcb_onfault = NULL; 182 return (EFAULT); 183 } 184 185 kp = kaddr; 186 up = udaddr; 187 188 rv = ENAMETOOLONG; 189 190 for (l = 0; len-- > 0; l++) { 191 if ((c = fubyte(up++)) < 0) { 192 rv = EFAULT; 193 break; 194 } 195 196 if (!(*kp++ = c)) { 197 l++; 198 rv = 0; 199 break; 200 } 201 } 202 203 if (done != NULL) { 204 *done = l; 205 } 206 207 td->td_pcb->pcb_onfault = NULL; 208 return (rv); 209 } 210 211 int 212 subyte(void *addr, int byte) 213 { 214 struct thread *td; 215 pmap_t pm; 216 faultbuf env; 217 char *p; 218 219 td = PCPU_GET(curthread); 220 pm = &td->td_proc->p_vmspace->vm_pmap; 221 p = (char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK)); 222 223 if (setfault(env)) { 224 td->td_pcb->pcb_onfault = NULL; 225 return (-1); 226 } 227 228 set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]); 229 230 *p = (char)byte; 231 232 td->td_pcb->pcb_onfault = NULL; 233 return (0); 234 } 235 236 int 237 suword(void *addr, long word) 238 { 239 struct thread *td; 240 pmap_t pm; 241 faultbuf env; 242 long *p; 243 244 td = PCPU_GET(curthread); 245 pm = &td->td_proc->p_vmspace->vm_pmap; 246 p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK)); 247 248 if (setfault(env)) { 249 td->td_pcb->pcb_onfault = NULL; 250 return (-1); 251 } 252 253 set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]); 254 255 *p = word; 256 257 td->td_pcb->pcb_onfault = NULL; 258 return (0); 259 } 260 261 int 262 suword32(void *addr, int32_t word) 263 { 264 return (suword(addr, (long)word)); 265 } 266 267 268 int 269 fubyte(const void *addr) 270 { 271 struct thread *td; 272 pmap_t pm; 273 faultbuf env; 274 u_char *p; 275 int val; 276 277 td = PCPU_GET(curthread); 278 pm = &td->td_proc->p_vmspace->vm_pmap; 279 p = (u_char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK)); 280 281 if (setfault(env)) { 282 td->td_pcb->pcb_onfault = NULL; 283 return (-1); 284 } 285 286 set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]); 287 288 val = *p; 289 290 td->td_pcb->pcb_onfault = NULL; 291 return (val); 292 } 293 294 long 295 fuword(const void *addr) 296 { 297 struct thread *td; 298 pmap_t pm; 299 faultbuf env; 300 long *p, val; 301 302 td = PCPU_GET(curthread); 303 pm = &td->td_proc->p_vmspace->vm_pmap; 304 p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK)); 305 306 if (setfault(env)) { 307 td->td_pcb->pcb_onfault = NULL; 308 return (-1); 309 } 310 311 set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]); 312 313 val = *p; 314 315 td->td_pcb->pcb_onfault = NULL; 316 return (val); 317 } 318 319 int32_t 320 fuword32(const void *addr) 321 { 322 return ((int32_t)fuword(addr)); 323 } 324 325 uint32_t 326 casuword32(volatile uint32_t *base, uint32_t oldval, uint32_t newval) 327 { 328 return (casuword((volatile u_long *)base, oldval, newval)); 329 } 330 331 u_long 332 casuword(volatile u_long *addr, u_long old, u_long new) 333 { 334 struct thread *td; 335 pmap_t pm; 336 faultbuf env; 337 u_long *p, val; 338 339 td = PCPU_GET(curthread); 340 pm = &td->td_proc->p_vmspace->vm_pmap; 341 p = (u_long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK)); 342 343 set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]); 344 345 if (setfault(env)) { 346 td->td_pcb->pcb_onfault = NULL; 347 return (-1); 348 } 349 350 val = *p; 351 (void) atomic_cmpset_32((volatile uint32_t *)p, old, new); 352 353 td->td_pcb->pcb_onfault = NULL; 354 355 return (val); 356 } 357