1*d71e829bSmaxv/* $NetBSD: copy.S,v 1.32 2020/06/30 16:20:01 maxv Exp $ */ 2443e88c5Syamt 3f42d24b1Smaxv/* 452b171caSad * Copyright (c) 1998, 2000, 2004, 2008 The NetBSD Foundation, Inc. 5443e88c5Syamt * All rights reserved. 6443e88c5Syamt * 7443e88c5Syamt * This code is derived from software contributed to The NetBSD Foundation 8443e88c5Syamt * by Charles M. Hannum. 9443e88c5Syamt * 10443e88c5Syamt * Redistribution and use in source and binary forms, with or without 11443e88c5Syamt * modification, are permitted provided that the following conditions 12443e88c5Syamt * are met: 13443e88c5Syamt * 1. Redistributions of source code must retain the above copyright 14443e88c5Syamt * notice, this list of conditions and the following disclaimer. 15443e88c5Syamt * 2. Redistributions in binary form must reproduce the above copyright 16443e88c5Syamt * notice, this list of conditions and the following disclaimer in the 17443e88c5Syamt * documentation and/or other materials provided with the distribution. 18443e88c5Syamt * 19443e88c5Syamt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20443e88c5Syamt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21443e88c5Syamt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22443e88c5Syamt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23443e88c5Syamt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24443e88c5Syamt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25443e88c5Syamt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26443e88c5Syamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27443e88c5Syamt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28443e88c5Syamt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29443e88c5Syamt * POSSIBILITY OF SUCH DAMAGE. 30443e88c5Syamt */ 31443e88c5Syamt 32f42d24b1Smaxv/* 33443e88c5Syamt * Copyright (c) 1990 The Regents of the University of California. 34443e88c5Syamt * All rights reserved. 35443e88c5Syamt * 36443e88c5Syamt * This code is derived from software contributed to Berkeley by 37443e88c5Syamt * William Jolitz. 38443e88c5Syamt * 39443e88c5Syamt * Redistribution and use in source and binary forms, with or without 40443e88c5Syamt * modification, are permitted provided that the following conditions 41443e88c5Syamt * are met: 42443e88c5Syamt * 1. Redistributions of source code must retain the above copyright 43443e88c5Syamt * notice, this list of conditions and the following disclaimer. 44443e88c5Syamt * 2. Redistributions in binary form must reproduce the above copyright 45443e88c5Syamt * notice, this list of conditions and the following disclaimer in the 46443e88c5Syamt * documentation and/or other materials provided with the distribution. 47443e88c5Syamt * 3. Neither the name of the University nor the names of its contributors 48443e88c5Syamt * may be used to endorse or promote products derived from this software 49443e88c5Syamt * without specific prior written permission. 50443e88c5Syamt * 51443e88c5Syamt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52443e88c5Syamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53443e88c5Syamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54443e88c5Syamt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55443e88c5Syamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56443e88c5Syamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57443e88c5Syamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58443e88c5Syamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59443e88c5Syamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60443e88c5Syamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61443e88c5Syamt * SUCH DAMAGE. 62443e88c5Syamt * 63443e88c5Syamt * @(#)locore.s 7.3 (Berkeley) 5/13/91 64443e88c5Syamt */ 65443e88c5Syamt 66a4914dc7Slukem#include <machine/asm.h> 67*d71e829bSmaxv__KERNEL_RCSID(0, "$NetBSD: copy.S,v 1.32 2020/06/30 16:20:01 maxv Exp $"); 68a4914dc7Slukem 69443e88c5Syamt#include "assym.h" 70443e88c5Syamt 71443e88c5Syamt#include <sys/errno.h> 72443e88c5Syamt 73443e88c5Syamt#include <machine/frameasm.h> 74443e88c5Syamt#include <machine/cputypes.h> 75443e88c5Syamt 76f0301095Syamt#define GET_CURPCB(reg) \ 77f0301095Syamt movl CPUVAR(CURLWP),reg; \ 783f18fe81Srmind movl L_PCB(reg),reg 79443e88c5Syamt 80443e88c5Syamt/* 8164bcc9bdSad * These are arranged so that the abnormal case is a forwards 8264bcc9bdSad * conditional branch - which will be predicted not-taken by 8364bcc9bdSad * both Intel and AMD processors. 8464bcc9bdSad */ 8564bcc9bdSad#define DEFERRED_SWITCH_CHECK \ 8664bcc9bdSad CHECK_DEFERRED_SWITCH ; \ 8764bcc9bdSad jnz 99f ; \ 8864bcc9bdSad98: 8964bcc9bdSad 9064bcc9bdSad#define DEFERRED_SWITCH_CALL \ 9164bcc9bdSad99: ; \ 9264bcc9bdSad call _C_LABEL(do_pmap_load) ; \ 9364bcc9bdSad jmp 98b 9464bcc9bdSad 9564bcc9bdSad/* 9652b171caSad * The following primitives are to copy regions of memory. 97614719fdSrmind * Label must be before all copy functions. 98443e88c5Syamt */ 9964bcc9bdSad .text 100dd80381cSchsLABEL(x86_copyfunc_start) 10164bcc9bdSad 10264bcc9bdSad/* 10364bcc9bdSad * Handle deferred pmap switch. We must re-enable preemption without 10464bcc9bdSad * making a function call, so that the program counter is visible to 10564bcc9bdSad * cpu_kpreempt_exit(). It can then know if it needs to restore the 10664bcc9bdSad * pmap on returning, because a preemption occurred within one of the 10764bcc9bdSad * copy functions. 10864bcc9bdSad */ 1090c52a5deSmaxvENTRY(do_pmap_load) 11064bcc9bdSad pushl %ebp 11164bcc9bdSad movl %esp,%ebp 11264bcc9bdSad pushl %ebx 11364bcc9bdSad movl CPUVAR(CURLWP),%ebx 11464bcc9bdSad1: 11564bcc9bdSad incl L_NOPREEMPT(%ebx) 11664bcc9bdSad call _C_LABEL(pmap_load) 11764bcc9bdSad decl L_NOPREEMPT(%ebx) 11864bcc9bdSad jnz 2f 11964bcc9bdSad cmpl $0,L_DOPREEMPT(%ebx) 12064bcc9bdSad jz 2f 12164bcc9bdSad pushl $0 12264bcc9bdSad call _C_LABEL(kpreempt) 12364bcc9bdSad addl $4,%esp 12464bcc9bdSad2: 12564bcc9bdSad cmpl $0,CPUVAR(WANT_PMAPLOAD) 12664bcc9bdSad jnz 1b 12764bcc9bdSad popl %ebx 12864bcc9bdSad leave 12964bcc9bdSad ret 130f42d24b1SmaxvEND(do_pmap_load) 131443e88c5Syamt 132443e88c5Syamt/* 1333d5b001dSdyoung * void *return_address(unsigned int level); 1343d5b001dSdyoung * 1353d5b001dSdyoung * The return address if level == 0, the return address of the caller 1363d5b001dSdyoung * `level' levels down the stack if level > 0. 1373d5b001dSdyoung */ 1383d5b001dSdyoungENTRY(return_address) 1393d5b001dSdyoung movl %ebp,%eax /* frame pointer -> %eax */ 1403d5b001dSdyoung movl 4(%esp),%ecx /* level -> %ecx */ 1415df4a900Sdyoung movl CPUVAR(CURLWP),%edx 1423f18fe81Srmind movl L_PCB(%edx),%edx 1435df4a900Sdyoung movl $_C_LABEL(return_address_fault),PCB_ONFAULT(%edx) 1443d5b001dSdyoung cmpl $0,%ecx 1453d5b001dSdyoung je 2f 1463d5b001dSdyoung1: 1473d5b001dSdyoung movl (%eax),%eax /* next frame pointer */ 1483d5b001dSdyoung decl %ecx 1493d5b001dSdyoung jnz 1b 1503d5b001dSdyoung2: 1513d5b001dSdyoung movl 0x4(%eax),%eax 1525df4a900Sdyoung movl $0,PCB_ONFAULT(%edx) 1533d5b001dSdyoung ret 154f42d24b1SmaxvEND(return_address) 1553d5b001dSdyoung 1563d5b001dSdyoung/* 157443e88c5Syamt * int kcopy(const void *from, void *to, size_t len); 158f42d24b1Smaxv * Copy len bytes from and to kernel memory, and abort on fault. 159443e88c5Syamt */ 160443e88c5SyamtENTRY(kcopy) 161443e88c5Syamt pushl %esi 162443e88c5Syamt pushl %edi 163d0f12a6aSyamt movl 12(%esp),%esi 164d0f12a6aSyamt movl 16(%esp),%edi 165d0f12a6aSyamt movl 20(%esp),%ecx 16664bcc9bdSad.Lkcopy_start: 167443e88c5Syamt movl %edi,%eax 168443e88c5Syamt subl %esi,%eax 16919a4beadSmaxv cmpl %ecx,%eax /* overlapping? */ 170d0f12a6aSyamt movl %ecx,%edx 171443e88c5Syamt jb 1f 17219a4beadSmaxv /* nope, copy forward */ 17319a4beadSmaxv shrl $2,%ecx /* copy by 32-bit words */ 174443e88c5Syamt rep 175443e88c5Syamt movsl 176d0f12a6aSyamt movl %edx,%ecx 17719a4beadSmaxv andl $3,%ecx /* any bytes left? */ 17833e2fcd0Sad jz 0f 179443e88c5Syamt rep 180443e88c5Syamt movsb 18133e2fcd0Sad0: 182443e88c5Syamt popl %edi 183443e88c5Syamt popl %esi 184443e88c5Syamt xorl %eax,%eax 185443e88c5Syamt ret 186443e88c5Syamt 187443e88c5Syamt ALIGN_TEXT 18819a4beadSmaxv1: addl %ecx,%edi /* copy backward */ 189443e88c5Syamt addl %ecx,%esi 190443e88c5Syamt std 19119a4beadSmaxv andl $3,%ecx /* any fractional bytes? */ 192443e88c5Syamt decl %edi 193443e88c5Syamt decl %esi 194443e88c5Syamt rep 195443e88c5Syamt movsb 19619a4beadSmaxv movl %edx,%ecx /* copy remainder by 32-bit words */ 197443e88c5Syamt shrl $2,%ecx 198443e88c5Syamt subl $3,%esi 199443e88c5Syamt subl $3,%edi 200443e88c5Syamt rep 201443e88c5Syamt movsl 202443e88c5Syamt cld 203443e88c5Syamt 204d0f12a6aSyamt.Lkcopy_end: 205443e88c5Syamt popl %edi 206443e88c5Syamt popl %esi 207443e88c5Syamt xorl %eax,%eax 208443e88c5Syamt ret 209f42d24b1SmaxvEND(kcopy) 210443e88c5Syamt 211443e88c5Syamt/*****************************************************************************/ 212443e88c5Syamt 213443e88c5Syamt/* 214443e88c5Syamt * The following primitives are used to copy data in and out of the user's 215443e88c5Syamt * address space. 216443e88c5Syamt */ 217443e88c5Syamt 218443e88c5Syamt/* 219443e88c5Syamt * int copyout(const void *from, void *to, size_t len); 220443e88c5Syamt * Copy len bytes into the user's address space. 221443e88c5Syamt * see copyout(9) 222443e88c5Syamt */ 223443e88c5SyamtENTRY(copyout) 22464bcc9bdSad DEFERRED_SWITCH_CHECK 225deae4f32Sad pushl %esi 226deae4f32Sad pushl %edi 227f42d24b1Smaxv movl 12(%esp),%esi /* from */ 228f42d24b1Smaxv movl 16(%esp),%edi /* to */ 229f42d24b1Smaxv movl 20(%esp),%eax /* len */ 230f42d24b1Smaxv 231443e88c5Syamt movl %edi,%edx 232443e88c5Syamt addl %eax,%edx 233443e88c5Syamt jc _C_LABEL(copy_efault) 234443e88c5Syamt cmpl $VM_MAXUSER_ADDRESS,%edx 235443e88c5Syamt ja _C_LABEL(copy_efault) 236f42d24b1Smaxv 237ce18565bSmaxv SMAP_DISABLE 238f42d24b1Smaxv.Lcopyout_start: 239443e88c5Syamt movl %eax,%ecx 240443e88c5Syamt shrl $2,%ecx 241443e88c5Syamt rep 242443e88c5Syamt movsl 24333e2fcd0Sad andl $3,%eax 244f42d24b1Smaxv jz .Lcopyout_end 245443e88c5Syamt movl %eax,%ecx 246443e88c5Syamt rep 247443e88c5Syamt movsb 248d0f12a6aSyamt.Lcopyout_end: 249ce18565bSmaxv SMAP_ENABLE 250f42d24b1Smaxv 251443e88c5Syamt popl %edi 252443e88c5Syamt popl %esi 253443e88c5Syamt xorl %eax,%eax 254443e88c5Syamt ret 25564bcc9bdSad DEFERRED_SWITCH_CALL 256f42d24b1SmaxvEND(copyout) 257443e88c5Syamt 258443e88c5Syamt/* 259443e88c5Syamt * int copyin(const void *from, void *to, size_t len); 260443e88c5Syamt * Copy len bytes from the user's address space. 261443e88c5Syamt * see copyin(9) 262443e88c5Syamt */ 263443e88c5SyamtENTRY(copyin) 26464bcc9bdSad DEFERRED_SWITCH_CHECK 265443e88c5Syamt pushl %esi 266443e88c5Syamt pushl %edi 267f42d24b1Smaxv movl 12(%esp),%esi /* from */ 268f42d24b1Smaxv movl 16(%esp),%edi /* to */ 269f42d24b1Smaxv movl 20(%esp),%eax /* len */ 270f42d24b1Smaxv 271443e88c5Syamt movl %esi,%edx 272443e88c5Syamt addl %eax,%edx 273443e88c5Syamt jc _C_LABEL(copy_efault) 274443e88c5Syamt cmpl $VM_MAXUSER_ADDRESS,%edx 275443e88c5Syamt ja _C_LABEL(copy_efault) 276f42d24b1Smaxv 277ce18565bSmaxv SMAP_DISABLE 278f42d24b1Smaxv.Lcopyin_start: 279443e88c5Syamt movl %eax,%ecx 280443e88c5Syamt shrl $2,%ecx 281443e88c5Syamt rep 282443e88c5Syamt movsl 28333e2fcd0Sad andl $3,%eax 284f42d24b1Smaxv jz .Lcopyin_end 285443e88c5Syamt movl %eax,%ecx 286443e88c5Syamt rep 287443e88c5Syamt movsb 288d0f12a6aSyamt.Lcopyin_end: 289ce18565bSmaxv SMAP_ENABLE 290f42d24b1Smaxv 291443e88c5Syamt popl %edi 292443e88c5Syamt popl %esi 293443e88c5Syamt xorl %eax,%eax 294443e88c5Syamt ret 29564bcc9bdSad DEFERRED_SWITCH_CALL 296f42d24b1SmaxvEND(copyin) 297443e88c5Syamt 2980c52a5deSmaxvENTRY(copy_efault) 299443e88c5Syamt movl $EFAULT,%eax 300f42d24b1Smaxv popl %edi 301f42d24b1Smaxv popl %esi 302f42d24b1Smaxv ret 303f42d24b1SmaxvEND(copy_efault) 304443e88c5Syamt 305443e88c5Syamt/* 306443e88c5Syamt * kcopy_fault is used by kcopy and copy_fault is used by copyin/out. 307443e88c5Syamt * 308443e88c5Syamt * they're distinguished for lazy pmap switching. see trap(). 309443e88c5Syamt */ 310f42d24b1Smaxv 3110c52a5deSmaxvENTRY(kcopy_fault) 3128f3bea6eSmaxv cld 313443e88c5Syamt popl %edi 314443e88c5Syamt popl %esi 315443e88c5Syamt ret 316f42d24b1SmaxvEND(kcopy_fault) 317443e88c5Syamt 3180c52a5deSmaxvENTRY(copy_fault) 319ce18565bSmaxv SMAP_ENABLE 320443e88c5Syamt popl %edi 321443e88c5Syamt popl %esi 322443e88c5Syamt ret 323f42d24b1SmaxvEND(copy_fault) 324443e88c5Syamt 3250c52a5deSmaxvENTRY(return_address_fault) 3265df4a900Sdyoung movl $0,PCB_ONFAULT(%edx) 3273d5b001dSdyoung movl $0,%eax 3283d5b001dSdyoung ret 329f42d24b1SmaxvEND(return_address_fault) 3303d5b001dSdyoung 331443e88c5Syamt/* 332443e88c5Syamt * int copyoutstr(const void *from, void *to, size_t maxlen, size_t *lencopied); 333443e88c5Syamt * Copy a NUL-terminated string, at most maxlen characters long, into the 334443e88c5Syamt * user's address space. Return the number of characters copied (including the 335443e88c5Syamt * NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; else 336443e88c5Syamt * return 0 or EFAULT. 337443e88c5Syamt * see copyoutstr(9) 338443e88c5Syamt */ 339443e88c5SyamtENTRY(copyoutstr) 34064bcc9bdSad DEFERRED_SWITCH_CHECK 341443e88c5Syamt pushl %esi 342443e88c5Syamt pushl %edi 34319a4beadSmaxv movl 12(%esp),%esi /* esi = from */ 34419a4beadSmaxv movl 16(%esp),%edi /* edi = to */ 34519a4beadSmaxv movl 20(%esp),%edx /* edx = maxlen */ 346f42d24b1Smaxv 347443e88c5Syamt /* 348443e88c5Syamt * Get min(%edx, VM_MAXUSER_ADDRESS-%edi). 349443e88c5Syamt */ 350443e88c5Syamt movl $VM_MAXUSER_ADDRESS,%eax 351443e88c5Syamt subl %edi,%eax 352443e88c5Syamt jc _C_LABEL(copystr_efault) 353443e88c5Syamt cmpl %edx,%eax 354443e88c5Syamt jae 1f 355443e88c5Syamt movl %eax,%edx 356443e88c5Syamt movl %eax,20(%esp) 357443e88c5Syamt1: incl %edx 358443e88c5Syamt 359ce18565bSmaxv SMAP_DISABLE 360f42d24b1Smaxv.Lcopyoutstr_start: 361443e88c5Syamt1: decl %edx 362443e88c5Syamt jz 2f 363443e88c5Syamt lodsb 364443e88c5Syamt stosb 365443e88c5Syamt testb %al,%al 366443e88c5Syamt jnz 1b 367f42d24b1Smaxv.Lcopyoutstr_end: 368ce18565bSmaxv SMAP_ENABLE 369443e88c5Syamt 370443e88c5Syamt /* Success -- 0 byte reached. */ 371443e88c5Syamt decl %edx 372443e88c5Syamt xorl %eax,%eax 373443e88c5Syamt jmp copystr_return 374443e88c5Syamt 375443e88c5Syamt2: /* edx is zero -- return EFAULT or ENAMETOOLONG. */ 376ce18565bSmaxv SMAP_ENABLE 377443e88c5Syamt cmpl $VM_MAXUSER_ADDRESS,%edi 378443e88c5Syamt jae _C_LABEL(copystr_efault) 379443e88c5Syamt movl $ENAMETOOLONG,%eax 380443e88c5Syamt jmp copystr_return 38164bcc9bdSad DEFERRED_SWITCH_CALL 382f42d24b1SmaxvEND(copyoutstr) 383443e88c5Syamt 384443e88c5Syamt/* 385443e88c5Syamt * int copyinstr(const void *from, void *to, size_t maxlen, size_t *lencopied); 386443e88c5Syamt * Copy a NUL-terminated string, at most maxlen characters long, from the 387443e88c5Syamt * user's address space. Return the number of characters copied (including the 388443e88c5Syamt * NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; else 389443e88c5Syamt * return 0 or EFAULT. 390443e88c5Syamt * see copyinstr(9) 391443e88c5Syamt */ 392443e88c5SyamtENTRY(copyinstr) 39364bcc9bdSad DEFERRED_SWITCH_CHECK 394443e88c5Syamt pushl %esi 395443e88c5Syamt pushl %edi 39619a4beadSmaxv movl 12(%esp),%esi /* %esi = from */ 39719a4beadSmaxv movl 16(%esp),%edi /* %edi = to */ 39819a4beadSmaxv movl 20(%esp),%edx /* %edx = maxlen */ 399443e88c5Syamt 400443e88c5Syamt /* 401443e88c5Syamt * Get min(%edx, VM_MAXUSER_ADDRESS-%esi). 402443e88c5Syamt */ 403443e88c5Syamt movl $VM_MAXUSER_ADDRESS,%eax 404443e88c5Syamt subl %esi,%eax 405443e88c5Syamt jc _C_LABEL(copystr_efault) 406443e88c5Syamt cmpl %edx,%eax 407443e88c5Syamt jae 1f 408443e88c5Syamt movl %eax,%edx 409443e88c5Syamt movl %eax,20(%esp) 410443e88c5Syamt1: incl %edx 411443e88c5Syamt 412ce18565bSmaxv SMAP_DISABLE 413f42d24b1Smaxv.Lcopyinstr_start: 414443e88c5Syamt1: decl %edx 415443e88c5Syamt jz 2f 416443e88c5Syamt lodsb 417443e88c5Syamt stosb 418443e88c5Syamt testb %al,%al 419443e88c5Syamt jnz 1b 420f42d24b1Smaxv.Lcopyinstr_end: 421ce18565bSmaxv SMAP_ENABLE 422443e88c5Syamt 423443e88c5Syamt /* Success -- 0 byte reached. */ 424443e88c5Syamt decl %edx 425443e88c5Syamt xorl %eax,%eax 426443e88c5Syamt jmp copystr_return 427443e88c5Syamt 428443e88c5Syamt2: /* edx is zero -- return EFAULT or ENAMETOOLONG. */ 429ce18565bSmaxv SMAP_ENABLE 430443e88c5Syamt cmpl $VM_MAXUSER_ADDRESS,%esi 431443e88c5Syamt jae _C_LABEL(copystr_efault) 432443e88c5Syamt movl $ENAMETOOLONG,%eax 433443e88c5Syamt jmp copystr_return 43464bcc9bdSad DEFERRED_SWITCH_CALL 435f42d24b1SmaxvEND(copyinstr) 436443e88c5Syamt 4370c52a5deSmaxvENTRY(copystr_efault) 438443e88c5Syamt movl $EFAULT,%eax 439f42d24b1Smaxv jmp copystr_return 440f42d24b1SmaxvEND(copystr_efault) 441443e88c5Syamt 4420c52a5deSmaxvENTRY(copystr_fault) 443ce18565bSmaxv SMAP_ENABLE 444443e88c5Syamtcopystr_return: 445443e88c5Syamt /* Set *lencopied and return %eax. */ 446443e88c5Syamt movl 20(%esp),%ecx 447443e88c5Syamt subl %edx,%ecx 448443e88c5Syamt movl 24(%esp),%edx 449443e88c5Syamt testl %edx,%edx 450443e88c5Syamt jz 8f 451443e88c5Syamt movl %ecx,(%edx) 452443e88c5Syamt 453443e88c5Syamt8: popl %edi 454443e88c5Syamt popl %esi 455443e88c5Syamt ret 456f42d24b1SmaxvEND(copystr_fault) 457443e88c5Syamt 458e3f92458Sthorpej/**************************************************************************/ 459e3f92458Sthorpej 46015ef08dfSthorpej#define UFETCHSTORE_PROLOGUE(x) \ 461e3f92458Sthorpej movl 4(%esp),%edx ; \ 46215ef08dfSthorpej cmpl $VM_MAXUSER_ADDRESS-x,%edx ; \ 463e3f92458Sthorpej ja _C_LABEL(ufetchstore_efault) 464e3f92458Sthorpej 465e3f92458Sthorpej/* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */ 466e3f92458SthorpejENTRY(_ufetch_8) 46764bcc9bdSad DEFERRED_SWITCH_CHECK 46815ef08dfSthorpej UFETCHSTORE_PROLOGUE(1) 469f42d24b1Smaxv 470ce18565bSmaxv SMAP_DISABLE 471e3f92458Sthorpej.L_ufetch_8_start: 472e3f92458Sthorpej movb (%edx),%al 473e3f92458Sthorpej.L_ufetch_8_end: 474ce18565bSmaxv SMAP_ENABLE 475f42d24b1Smaxv 476e3f92458Sthorpej movl 8(%esp),%edx 477e3f92458Sthorpej movb %al,(%edx) 478443e88c5Syamt xorl %eax,%eax 479443e88c5Syamt ret 480e3f92458Sthorpej DEFERRED_SWITCH_CALL 481e3f92458SthorpejEND(_ufetch_8) 482443e88c5Syamt 483e3f92458Sthorpej/* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */ 484e3f92458SthorpejENTRY(_ufetch_16) 48564bcc9bdSad DEFERRED_SWITCH_CHECK 48615ef08dfSthorpej UFETCHSTORE_PROLOGUE(2) 487e3f92458Sthorpej 488e3f92458Sthorpej SMAP_DISABLE 489e3f92458Sthorpej.L_ufetch_16_start: 490e3f92458Sthorpej movw (%edx),%ax 491e3f92458Sthorpej.L_ufetch_16_end: 492e3f92458Sthorpej SMAP_ENABLE 493e3f92458Sthorpej 494e3f92458Sthorpej movl 8(%esp),%edx 495e3f92458Sthorpej movw %ax,(%edx) 496e3f92458Sthorpej xorl %eax,%eax 497e3f92458Sthorpej ret 498e3f92458Sthorpej DEFERRED_SWITCH_CALL 499e3f92458SthorpejEND(_ufetch_16) 500e3f92458Sthorpej 501e3f92458Sthorpej/* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */ 502e3f92458SthorpejENTRY(_ufetch_32) 503e3f92458Sthorpej DEFERRED_SWITCH_CHECK 50415ef08dfSthorpej UFETCHSTORE_PROLOGUE(4) 505e3f92458Sthorpej 506e3f92458Sthorpej SMAP_DISABLE 507e3f92458Sthorpej.L_ufetch_32_start: 508e3f92458Sthorpej movl (%edx),%eax 509e3f92458Sthorpej.L_ufetch_32_end: 510e3f92458Sthorpej SMAP_ENABLE 511e3f92458Sthorpej 512e3f92458Sthorpej movl 8(%esp),%edx 513e3f92458Sthorpej movl %eax,(%edx) 514e3f92458Sthorpej xorl %eax,%eax 515e3f92458Sthorpej ret 516e3f92458Sthorpej DEFERRED_SWITCH_CALL 517e3f92458SthorpejEND(_ufetch_32) 518e3f92458Sthorpej 519e3f92458Sthorpej/* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */ 520e3f92458SthorpejENTRY(_ustore_8) 521e3f92458Sthorpej DEFERRED_SWITCH_CHECK 52215ef08dfSthorpej UFETCHSTORE_PROLOGUE(1) 523443e88c5Syamt movb 8(%esp),%al 524f42d24b1Smaxv 525ce18565bSmaxv SMAP_DISABLE 526e3f92458Sthorpej.L_ustore_8_start: 527443e88c5Syamt movb %al,(%edx) 528e3f92458Sthorpej.L_ustore_8_end: 529ce18565bSmaxv SMAP_ENABLE 530f42d24b1Smaxv 531443e88c5Syamt xorl %eax,%eax 532443e88c5Syamt ret 53364bcc9bdSad DEFERRED_SWITCH_CALL 534e3f92458SthorpejEND(_ustore_8) 535e3f92458Sthorpej 536e3f92458Sthorpej/* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */ 537e3f92458SthorpejENTRY(_ustore_16) 538e3f92458Sthorpej DEFERRED_SWITCH_CHECK 53915ef08dfSthorpej UFETCHSTORE_PROLOGUE(2) 540e3f92458Sthorpej movw 8(%esp),%ax 541e3f92458Sthorpej 542e3f92458Sthorpej SMAP_DISABLE 543e3f92458Sthorpej.L_ustore_16_start: 544e3f92458Sthorpej movw %ax,(%edx) 545e3f92458Sthorpej.L_ustore_16_end: 546e3f92458Sthorpej SMAP_ENABLE 547e3f92458Sthorpej 548e3f92458Sthorpej xorl %eax,%eax 549e3f92458Sthorpej ret 550e3f92458Sthorpej DEFERRED_SWITCH_CALL 551e3f92458SthorpejEND(_ustore_16) 552e3f92458Sthorpej 553e3f92458Sthorpej/* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */ 554e3f92458SthorpejENTRY(_ustore_32) 555e3f92458Sthorpej DEFERRED_SWITCH_CHECK 55615ef08dfSthorpej UFETCHSTORE_PROLOGUE(4) 557e3f92458Sthorpej movl 8(%esp),%eax 558e3f92458Sthorpej 559e3f92458Sthorpej SMAP_DISABLE 560e3f92458Sthorpej.L_ustore_32_start: 561e3f92458Sthorpej movl %eax,(%edx) 562e3f92458Sthorpej.L_ustore_32_end: 563e3f92458Sthorpej SMAP_ENABLE 564e3f92458Sthorpej 565e3f92458Sthorpej xorl %eax,%eax 566e3f92458Sthorpej ret 567e3f92458Sthorpej DEFERRED_SWITCH_CALL 568e3f92458SthorpejEND(_ustore_32) 569e3f92458Sthorpej 570e3f92458SthorpejENTRY(ufetchstore_efault) 571e3f92458Sthorpej movl $EFAULT,%eax 572e3f92458Sthorpej ret 573e3f92458SthorpejEND(ufetchstore_efault) 574e3f92458Sthorpej 575e3f92458SthorpejENTRY(ufetchstore_fault) 576e3f92458Sthorpej SMAP_ENABLE 577e3f92458Sthorpej ret 578e3f92458SthorpejEND(ufetchstore_fault) 579e3f92458Sthorpej 580e3f92458Sthorpej/**************************************************************************/ 58117be89c2Sad 58217be89c2Sad/* 583f7d3fa20Srmind * Compare-and-swap the 32-bit integer in the user-space. 584f7d3fa20Srmind * 585e3f92458Sthorpej * int _ucas_32(volatile uint32_t *uptr, uint32_t old, uint32_t new, 586e3f92458Sthorpej * uint32_t *ret); 587f7d3fa20Srmind */ 588e3f92458SthorpejENTRY(_ucas_32) 589f7d3fa20Srmind DEFERRED_SWITCH_CHECK 590f7d3fa20Srmind movl 4(%esp),%edx 591f7d3fa20Srmind movl 8(%esp),%eax 592f7d3fa20Srmind movl 12(%esp),%ecx 593f7d3fa20Srmind /* Fail if kernel-space */ 594f7d3fa20Srmind cmpl $VM_MAXUSER_ADDRESS-4,%edx 595dd80381cSchs ja _C_LABEL(ucas_efault) 596f42d24b1Smaxv 597ce18565bSmaxv SMAP_DISABLE 598f7d3fa20Srmind.Lucas32_start: 599f7d3fa20Srmind /* Perform the CAS */ 600f7d3fa20Srmind lock 601f7d3fa20Srmind cmpxchgl %ecx,(%edx) 602f7d3fa20Srmind.Lucas32_end: 603ce18565bSmaxv SMAP_ENABLE 604f42d24b1Smaxv 605f7d3fa20Srmind /* 606f7d3fa20Srmind * Note: %eax is "old" value. 607f7d3fa20Srmind * Set the return values. 608f7d3fa20Srmind */ 609f7d3fa20Srmind movl 16(%esp),%edx 610f7d3fa20Srmind movl %eax,(%edx) 611f7d3fa20Srmind xorl %eax,%eax 612f7d3fa20Srmind ret 613f7d3fa20Srmind DEFERRED_SWITCH_CALL 614e3f92458SthorpejEND(_ucas_32) 615f7d3fa20Srmind 6160c52a5deSmaxvENTRY(ucas_efault) 617f42d24b1Smaxv movl $EFAULT,%eax 618f42d24b1Smaxv ret 619f42d24b1SmaxvEND(ucas_efault) 620f42d24b1Smaxv 6210c52a5deSmaxvENTRY(ucas_fault) 622ce18565bSmaxv SMAP_ENABLE 623f7d3fa20Srmind ret 624f42d24b1SmaxvEND(ucas_fault) 625f7d3fa20Srmind 626f7d3fa20Srmind/* 62717be89c2Sad * copyin() optimised for bringing in syscall arguments. 62817be89c2Sad */ 62917be89c2SadENTRY(x86_copyargs) 63064bcc9bdSad DEFERRED_SWITCH_CHECK 63117be89c2Sad pushl %esi 632d0f12a6aSyamt movl 8(%esp),%esi 633d0f12a6aSyamt movl 12(%esp),%edx 634d0f12a6aSyamt movl 16(%esp),%ecx 63517be89c2Sad 63617be89c2Sad /* 637548506e1Smaxv * In this function, we may copy more than the size given in the third 638548506e1Smaxv * argument. In order to make sure the real end of the destination 639548506e1Smaxv * buffer is not past the end of the user's address space, we don't 640548506e1Smaxv * check the third argument but rather the largest possible size, which 641548506e1Smaxv * is: 642548506e1Smaxv * (2 + SYS_MAXSYSARGS) * 4 = 10 * 4 64317be89c2Sad */ 64417be89c2Sad movl %esi,%eax 645548506e1Smaxv addl $(10 * 4),%eax 64617be89c2Sad jc _C_LABEL(x86_copyargs_efault) 64717be89c2Sad cmpl $VM_MAXUSER_ADDRESS,%eax 64817be89c2Sad ja _C_LABEL(x86_copyargs_efault) 649f42d24b1Smaxv 650ce18565bSmaxv SMAP_DISABLE 651f42d24b1Smaxv.Lx86_copyargs_start: 652aa21c280Sdsl /* There are a maximum of 8 args + 2 for syscall indirect */ 653aa21c280Sdsl cmp $16,%ecx 65417be89c2Sad movl (%esi),%eax 655aa21c280Sdsl movl 4(%esi),%ecx 65617be89c2Sad movl %eax,(%edx) 657aa21c280Sdsl movl %ecx,4(%edx) 65817be89c2Sad movl 8(%esi),%eax 659aa21c280Sdsl movl 12(%esi),%ecx 66017be89c2Sad movl %eax,8(%edx) 661aa21c280Sdsl movl %ecx,12(%edx) 662f42d24b1Smaxv 663aa21c280Sdsl ja 2f /* Optimise since most sycalls have <= 4 args */ 664f42d24b1Smaxv jmp .Lx86_copyargs_end 665aa21c280Sdsl2: 666f42d24b1Smaxv 667aa21c280Sdsl movl 16(%esi),%eax 668aa21c280Sdsl movl 20(%esi),%ecx 669aa21c280Sdsl movl %eax,16(%edx) 670aa21c280Sdsl movl %ecx,20(%edx) 671aa21c280Sdsl movl 24(%esi),%eax 672aa21c280Sdsl movl 28(%esi),%ecx 673aa21c280Sdsl movl %eax,24(%edx) 674aa21c280Sdsl movl %ecx,28(%edx) 675aa21c280Sdsl movl 32(%esi),%eax 676aa21c280Sdsl movl 36(%esi),%ecx 677aa21c280Sdsl movl %eax,32(%edx) 678aa21c280Sdsl movl %ecx,36(%edx) 679d0f12a6aSyamt.Lx86_copyargs_end: 680ce18565bSmaxv SMAP_ENABLE 68117be89c2Sad 682f42d24b1Smaxv popl %esi 683f42d24b1Smaxv xorl %eax,%eax 684f42d24b1Smaxv ret 685f42d24b1Smaxv DEFERRED_SWITCH_CALL 686f42d24b1SmaxvEND(x86_copyargs) 687f42d24b1Smaxv 6880c52a5deSmaxvENTRY(x86_copyargs_efault) 68917be89c2Sad movl $EFAULT,%eax 690f42d24b1Smaxv popl %esi 691f42d24b1Smaxv ret 692f42d24b1SmaxvEND(x86_copyargs_efault) 69317be89c2Sad 6940c52a5deSmaxvENTRY(x86_copyargs_fault) 695ce18565bSmaxv SMAP_ENABLE 69617be89c2Sad popl %esi 69717be89c2Sad ret 698f42d24b1SmaxvEND(x86_copyargs_fault) 69964bcc9bdSad 700614719fdSrmind/* 701614719fdSrmind * Label must be after all copy functions. 702614719fdSrmind */ 703dd80381cSchsLABEL(x86_copyfunc_end) 704d0f12a6aSyamt 705614719fdSrmind/* 706614719fdSrmind * Fault table of copy functions for trap(). 707614719fdSrmind */ 708d0f12a6aSyamt .section ".rodata" 709d0f12a6aSyamt .globl _C_LABEL(onfault_table) 710f42d24b1Smaxv 711d0f12a6aSyamt_C_LABEL(onfault_table): 712d0f12a6aSyamt .long .Lcopyin_start 713d0f12a6aSyamt .long .Lcopyin_end 714d0f12a6aSyamt .long _C_LABEL(copy_fault) 715d0f12a6aSyamt 716d0f12a6aSyamt .long .Lcopyout_start 717d0f12a6aSyamt .long .Lcopyout_end 718d0f12a6aSyamt .long _C_LABEL(copy_fault) 719d0f12a6aSyamt 720d0f12a6aSyamt .long .Lkcopy_start 721d0f12a6aSyamt .long .Lkcopy_end 722d0f12a6aSyamt .long _C_LABEL(kcopy_fault) 723d0f12a6aSyamt 724d0f12a6aSyamt .long .Lcopyoutstr_start 725d0f12a6aSyamt .long .Lcopyoutstr_end 726d0f12a6aSyamt .long _C_LABEL(copystr_fault) 727d0f12a6aSyamt 728d0f12a6aSyamt .long .Lcopyinstr_start 729d0f12a6aSyamt .long .Lcopyinstr_end 730d0f12a6aSyamt .long _C_LABEL(copystr_fault) 731d0f12a6aSyamt 732f7d3fa20Srmind .long .Lucas32_start 733f7d3fa20Srmind .long .Lucas32_end 734f7d3fa20Srmind .long _C_LABEL(ucas_fault) 735f7d3fa20Srmind 736e3f92458Sthorpej .long .L_ufetch_8_start 737e3f92458Sthorpej .long .L_ufetch_8_end 738e3f92458Sthorpej .long _C_LABEL(ufetchstore_fault) 739e3f92458Sthorpej 740e3f92458Sthorpej .long .L_ufetch_16_start 741e3f92458Sthorpej .long .L_ufetch_16_end 742e3f92458Sthorpej .long _C_LABEL(ufetchstore_fault) 743e3f92458Sthorpej 744e3f92458Sthorpej .long .L_ufetch_32_start 745e3f92458Sthorpej .long .L_ufetch_32_end 746e3f92458Sthorpej .long _C_LABEL(ufetchstore_fault) 747e3f92458Sthorpej 748e3f92458Sthorpej .long .L_ustore_8_start 749e3f92458Sthorpej .long .L_ustore_8_end 750e3f92458Sthorpej .long _C_LABEL(ufetchstore_fault) 751e3f92458Sthorpej 752e3f92458Sthorpej .long .L_ustore_16_start 753e3f92458Sthorpej .long .L_ustore_16_end 754e3f92458Sthorpej .long _C_LABEL(ufetchstore_fault) 755e3f92458Sthorpej 756e3f92458Sthorpej .long .L_ustore_32_start 757e3f92458Sthorpej .long .L_ustore_32_end 758e3f92458Sthorpej .long _C_LABEL(ufetchstore_fault) 759e3f92458Sthorpej 760d0f12a6aSyamt .long .Lx86_copyargs_start 761d0f12a6aSyamt .long .Lx86_copyargs_end 762d0f12a6aSyamt .long _C_LABEL(x86_copyargs_fault) 763d0f12a6aSyamt 764d0f12a6aSyamt .long 0 /* terminate */ 765d0f12a6aSyamt 766d0f12a6aSyamt .text 767