1/* $NetBSD: copy.s,v 1.50 2023/09/26 14:33:55 tsutsui Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2019 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum and by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/*- 33 * Copyright (c) 1990 The Regents of the University of California. 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * the Systems Programming Group of the University of Utah Computer 38 * Science Department. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65/* 66 * This file contains the functions for user-space access: 67 * copyin/copyout, ufetch/ustore, etc. 68 */ 69 70#include <sys/errno.h> 71#include <machine/asm.h> 72 73#include "assym.h" 74 75 .file "copy.s" 76 .text 77 78#ifdef CI_CURPCB 79#define GETCURPCB(r) movl _C_LABEL(cpu_info_store)+CI_CURPCB,r 80#else 81#define GETCURPCB(r) movl _C_LABEL(curpcb),r 82#endif 83 84#ifdef DIAGNOSTIC 85/* 86 * The following routines all use the "moves" instruction to access 87 * memory with "user" privilege while running in supervisor mode. 88 * The "function code" registers actually determine what type of 89 * access "moves" does, and the kernel arranges to leave them set 90 * for "user data" access when these functions are called. 91 * 92 * The diagnostics: CHECK_SFC, CHECK_DFC 93 * will verify that the sfc/dfc register values are correct. 94 */ 95.Lbadfc: 96 PANIC("copy.s: bad sfc or dfc") 97 jra .Lbadfc 98#define CHECK_SFC movec %sfc,%d0; subql #FC_USERD,%d0; bne .Lbadfc 99#define CHECK_DFC movec %dfc,%d0; subql #FC_USERD,%d0; bne .Lbadfc 100#else /* DIAGNOSTIC */ 101#define CHECK_SFC 102#define CHECK_DFC 103#endif /* DIAGNOSTIC */ 104 105/* 106 * copyin(void *from, void *to, size_t len); 107 * Copy len bytes from the user's address space. 108 * 109 * This is probably not the best we can do, but it is still 2-10 times 110 * faster than the C version in the portable gen directory. 111 * 112 * Things that might help: 113 * - unroll the longword copy loop (might not be good for a 68020) 114 * - longword align when possible (only on the 68020) 115 */ 116ENTRY(copyin) 117 CHECK_SFC 118 movl 12(%sp),%d0 | check count 119 jeq .Lciret | == 0, don't do anything 120 movl %d2,-(%sp) | save scratch register 121 GETCURPCB(%a0) | set fault handler 122 movl #.Lcifault,PCB_ONFAULT(%a0) 123 movl 8(%sp),%a0 | src address 124 movl 12(%sp),%a1 | dest address 125 movl %a0,%d1 126 btst #0,%d1 | src address odd? 127 jeq .Lcieven | no, skip alignment 128 movsb (%a0)+,%d2 | yes, copy a byte 129 movb %d2,(%a1)+ 130 subql #1,%d0 | adjust count 131 jeq .Lcidone | count 0, all done 132.Lcieven: 133 movl %a1,%d1 134 btst #0,%d1 | dest address odd? 135 jne .Lcibytes | yes, must copy bytes 136 movl %d0,%d1 | OK, both even. Get count 137 lsrl #2,%d1 | and convert to longwords 138 jeq .Lcibytes | count 0, skip longword loop 139 subql #1,%d1 | predecrement for dbf 140.Lcilloop: 141 movsl (%a0)+,%d2 | copy a longword 142 movl %d2,(%a1)+ 143 dbf %d1,.Lcilloop | decrement low word of count 144 subil #0x10000,%d1 | decrement high word of count 145 jcc .Lcilloop 146 andl #3,%d0 | what remains 147 jeq .Lcidone | nothing, all done 148.Lcibytes: 149 subql #1,%d0 | predecrement for dbf 150.Lcibloop: 151 movsb (%a0)+,%d2 | copy a byte 152 movb %d2,(%a1)+ 153 dbf %d0,.Lcibloop | decrement low word of count 154 subil #0x10000,%d0 | decrement high word of count 155 jcc .Lcibloop 156 clrl %d0 | no error 157.Lcidone: 158 GETCURPCB(%a0) | clear fault handler 159 clrl PCB_ONFAULT(%a0) 160 movl (%sp)+,%d2 | restore scratch register 161.Lciret: 162 rts 163.Lcifault: 164 jra .Lcidone 165 166/* 167 * copyout(void *from, void *to, size_t len); 168 * Copy len bytes into the user's address space. 169 * 170 * This is probably not the best we can do, but it is still 2-10 times 171 * faster than the C version in the portable gen directory. 172 * 173 * Things that might help: 174 * - unroll the longword copy loop (might not be good for a 68020) 175 * - longword align when possible (only on the 68020) 176 */ 177ENTRY(copyout) 178 CHECK_DFC 179 movl 12(%sp),%d0 | check count 180 jeq .Lcoret | == 0, don't do anything 181 movl %d2,-(%sp) | save scratch register 182 GETCURPCB(%a0) | set fault handler 183 movl #.Lcofault,PCB_ONFAULT(%a0) 184 movl 8(%sp),%a0 | src address 185 movl 12(%sp),%a1 | dest address 186 movl %a0,%d1 187 btst #0,%d1 | src address odd? 188 jeq .Lcoeven | no, skip alignment 189 movb (%a0)+,%d2 | yes, copy a byte 190 movsb %d2,(%a1)+ 191 subql #1,%d0 | adjust count 192 jeq .Lcodone | count 0, all done 193.Lcoeven: 194 movl %a1,%d1 195 btst #0,%d1 | dest address odd? 196 jne .Lcobytes | yes, must copy bytes 197 movl %d0,%d1 | OK, both even. Get count 198 lsrl #2,%d1 | and convert to longwords 199 jeq .Lcobytes | count 0, skip longword loop 200 subql #1,%d1 | predecrement for dbf 201.Lcolloop: 202 movl (%a0)+,%d2 | copy a longword 203 movsl %d2,(%a1)+ 204 dbf %d1,.Lcolloop | decrement low word of count 205 subil #0x10000,%d1 | decrement high word of count 206 jcc .Lcolloop 207 andl #3,%d0 | what remains 208 jeq .Lcodone | nothing, all done 209.Lcobytes: 210 subql #1,%d0 | predecrement for dbf 211.Lcobloop: 212 movb (%a0)+,%d2 | copy a byte 213 movsb %d2,(%a1)+ 214 dbf %d0,.Lcobloop | decrement low word of count 215 subil #0x10000,%d0 | decrement high word of count 216 jcc .Lcobloop 217 clrl %d0 | no error 218.Lcodone: 219 GETCURPCB(%a0) | clear fault handler 220 clrl PCB_ONFAULT(%a0) 221 movl (%sp)+,%d2 | restore scratch register 222.Lcoret: 223 rts 224.Lcofault: 225 jra .Lcodone 226 227/* 228 * copyinstr(void *from, void *to, size_t maxlen, size_t *lencopied); 229 * Copy a NUL-terminated string, at most maxlen characters long, from the 230 * user's address space. Return the number of characters copied (including 231 * the NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; 232 * else return 0 or EFAULT. 233 */ 234ENTRY(copyinstr) 235 CHECK_SFC 236 GETCURPCB(%a0) | set fault handler 237 movl #.Lcisfault,PCB_ONFAULT(%a0) 238 movl 4(%sp),%a0 | a0 = fromaddr 239 movl 8(%sp),%a1 | a1 = toaddr 240 clrl %d0 241 movl 12(%sp),%d1 | count 242 jeq .Lcistoolong | nothing to copy 243 subql #1,%d1 | predecrement for dbeq 244.Lcisloop: 245 movsb (%a0)+,%d0 | copy a byte 246 movb %d0,(%a1)+ 247 dbeq %d1,.Lcisloop | decrement low word of count 248 jeq .Lcisdone | copied null, exit 249 subil #0x10000,%d1 | decrement high word of count 250 jcc .Lcisloop | more room, keep going 251.Lcistoolong: 252 moveq #ENAMETOOLONG,%d0 | ran out of space 253.Lcisdone: 254 tstl 16(%sp) | length desired? 255 jeq .Lcisexit 256 subl 4(%sp),%a0 | yes, calculate length copied 257 movl 16(%sp),%a1 | store at return location 258 movl %a0,(%a1) 259.Lcisexit: 260 GETCURPCB(%a0) | clear fault handler 261 clrl PCB_ONFAULT(%a0) 262 rts 263.Lcisfault: 264 jra .Lcisdone 265 266/* 267 * copyoutstr(void *from, void *to, size_t maxlen, size_t *lencopied); 268 * Copy a NUL-terminated string, at most maxlen characters long, into the 269 * user's address space. Return the number of characters copied (including 270 * the NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; 271 * else return 0 or EFAULT. 272 */ 273ENTRY(copyoutstr) 274 CHECK_DFC 275 GETCURPCB(%a0) | set fault handler 276 movl #.Lcosfault,PCB_ONFAULT(%a0) 277 movl 4(%sp),%a0 | a0 = fromaddr 278 movl 8(%sp),%a1 | a1 = toaddr 279 clrl %d0 280 movl 12(%sp),%d1 | count 281 jeq .Lcostoolong | nothing to copy 282 subql #1,%d1 | predecrement for dbeq 283.Lcosloop: 284 movb (%a0)+,%d0 | copy a byte 285 movsb %d0,(%a1)+ 286 dbeq %d1,.Lcosloop | decrement low word of count 287 jeq .Lcosdone | copied null, exit 288 subil #0x10000,%d1 | decrement high word of count 289 jcc .Lcosloop | more room, keep going 290.Lcostoolong: 291 moveq #ENAMETOOLONG,%d0 | ran out of space 292.Lcosdone: 293 tstl 16(%sp) | length desired? 294 jeq .Lcosexit 295 subl 4(%sp),%a0 | yes, calculate length copied 296 movl 16(%sp),%a1 | store at return location 297 movl %a0,(%a1) 298.Lcosexit: 299 GETCURPCB(%a0) | clear fault handler 300 clrl PCB_ONFAULT(%a0) 301 rts 302.Lcosfault: 303 jra .Lcosdone 304 305/* 306 * kcopy(const void *src, void *dst, size_t len); 307 * 308 * Copy len bytes from src to dst, aborting if we encounter a fatal 309 * page fault. 310 * 311 * kcopy() _must_ save and restore the old fault handler since it is 312 * called by uiomove(), which may be in the path of servicing a non-fatal 313 * page fault. 314 */ 315ENTRY(kcopy) 316 link %a6,#-4 317 GETCURPCB(%a0) | set fault handler 318 movl PCB_ONFAULT(%a0),-4(%a6) | save old handler first 319 movl #.Lkcfault,PCB_ONFAULT(%a0) 320 movl 16(%a6),-(%sp) | push len 321 movl 8(%a6),-(%sp) | push src 322 movl 12(%a6),-(%sp) | push dst 323 jbsr _C_LABEL(memcpy) | copy it 324 addl #12,%sp | pop args 325 clrl %d0 | success! 326.Lkcdone: 327 GETCURPCB(%a0) | restore fault handler 328 movl -4(%a6),PCB_ONFAULT(%a0) 329 unlk %a6 330 rts 331.Lkcfault: 332 addl #16,%sp | pop args and return address 333 jra .Lkcdone 334 335#define UFETCH_PROLOGUE \ 336 CHECK_SFC ; \ 337 movl 4(%sp),%a0 /* address to read */ ; \ 338 GETCURPCB(%a1) /* a1 = curpcb */ ; \ 339 movl #.Lufetchstore_fault,PCB_ONFAULT(%a1) 340 341/* LINTSTUB: _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */ 342ENTRY(_ufetch_8) 343 UFETCH_PROLOGUE 344 movsb (%a0),%d0 | do read from user space 345 movl 8(%sp),%a0 | destination address 346 movb %d0,(%a0) 347 jra .Lufetchstore_success 348 349/* LINTSTUB: _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */ 350ENTRY(_ufetch_16) 351 UFETCH_PROLOGUE 352 movsw (%a0),%d0 | do read from user space 353 movl 8(%sp),%a0 | destination address 354 movw %d0,(%a0) 355 jra .Lufetchstore_success 356 357/* LINTSTUB: _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */ 358ENTRY(_ufetch_32) 359 UFETCH_PROLOGUE 360 movsl (%a0),%d0 | do read from user space 361 movl 8(%sp),%a0 | destination address 362 movl %d0,(%a0) 363 jra .Lufetchstore_success 364 365#define USTORE_PROLOGUE \ 366 CHECK_DFC ; \ 367 movl 4(%sp),%a0 /* address to write */ ; \ 368 GETCURPCB(%a1) /* a1 = curpcb */ ; \ 369 movl #.Lufetchstore_fault,PCB_ONFAULT(%a1) 370 371/* LINTSTUB: _ustore_8(uint8_t *uaddr, uint8_t val); */ 372ENTRY(_ustore_8) 373 USTORE_PROLOGUE 374 movb 11(%sp),%d0 | value to store 375 movsb %d0,(%a0) | do write to user space 376 jra .Lufetchstore_success 377 378/* LINTSTUB: _ustore_16(uint16_t *uaddr, uint16_t val); */ 379ENTRY(_ustore_16) 380 USTORE_PROLOGUE 381 movw 10(%sp),%d0 | value to store 382 movsw %d0,(%a0) | do write to user space 383 jra .Lufetchstore_success 384 385/* LINTSTUB: _ustore_32(uint32_t *uaddr, uint32_t val); */ 386ENTRY(_ustore_32) 387 USTORE_PROLOGUE 388 movl 8(%sp),%d0 | value to store 389 movsl %d0,(%a0) | do write to user space 390 jra .Lufetchstore_success 391 392.Lufetchstore_success: 393 clrl %d0 | return 0 394.Lufetchstore_fault: 395 clrl PCB_ONFAULT(%a1) | clear fault handler 396 rts 397