support.s revision 21979
1178825Sdfr/*- 2178825Sdfr * Copyright (c) 1993 The Regents of the University of California. 3178825Sdfr * All rights reserved. 4178825Sdfr * 5178825Sdfr * Redistribution and use in source and binary forms, with or without 6178825Sdfr * modification, are permitted provided that the following conditions 7178825Sdfr * are met: 8178825Sdfr * 1. Redistributions of source code must retain the above copyright 9178825Sdfr * notice, this list of conditions and the following disclaimer. 10178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer in the 12178825Sdfr * documentation and/or other materials provided with the distribution. 13178825Sdfr * 3. All advertising materials mentioning features or use of this software 14178825Sdfr * must display the following acknowledgement: 15178825Sdfr * This product includes software developed by the University of 16178825Sdfr * California, Berkeley and its contributors. 17178825Sdfr * 4. Neither the name of the University nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr * 33178825Sdfr * $FreeBSD: head/sys/i386/i386/support.s 21979 1997-01-24 20:37:57Z bde $ 34178825Sdfr */ 35178825Sdfr 36178825Sdfr#include "opt_cpu.h" 37178825Sdfr 38178825Sdfr#include <machine/asmacros.h> 39178825Sdfr#include <machine/cputypes.h> 40178825Sdfr#include <machine/pmap.h> 41178825Sdfr#include <machine/specialreg.h> 42178825Sdfr 43178825Sdfr#include "assym.s" 44178825Sdfr 45178825Sdfr#define KDSEL 0x10 /* kernel data selector */ 46178825Sdfr#define IDXSHIFT 10 47178825Sdfr 48178825Sdfr .data 49178825Sdfr .globl _bcopy_vector 50178825Sdfr_bcopy_vector: 51178825Sdfr .long _generic_bcopy 52178825Sdfr .globl _bzero 53178825Sdfr_bzero: 54178825Sdfr .long _generic_bzero 55178825Sdfr .globl _copyin_vector 56178825Sdfr_copyin_vector: 57178825Sdfr .long _generic_copyin 58178825Sdfr .globl _copyout_vector 59178825Sdfr_copyout_vector: 60178825Sdfr .long _generic_copyout 61178825Sdfr .globl _ovbcopy_vector 62178825Sdfr_ovbcopy_vector: 63178825Sdfr .long _generic_bcopy 64178825Sdfrkernel_fpu_lock: 65178825Sdfr .byte 0xfe 66178825Sdfr .space 3 67178825Sdfr 68178825Sdfr .text 69178825Sdfr 70178825Sdfr/* 71178825Sdfr * bcopy family 72178825Sdfr * void bzero(void *buf, u_int len) 73178825Sdfr */ 74178825Sdfr 75178825SdfrENTRY(generic_bzero) 76178825Sdfr pushl %edi 77178825Sdfr movl 8(%esp),%edi 78178825Sdfr movl 12(%esp),%ecx 79178825Sdfr xorl %eax,%eax 80178825Sdfr shrl $2,%ecx 81178825Sdfr cld 82178825Sdfr rep 83178825Sdfr stosl 84178825Sdfr movl 12(%esp),%ecx 85178825Sdfr andl $3,%ecx 86178825Sdfr rep 87178825Sdfr stosb 88178825Sdfr popl %edi 89178825Sdfr ret 90178825Sdfr 91178825Sdfr#if defined(I486_CPU) 92178825SdfrENTRY(i486_bzero) 93178825Sdfr movl 4(%esp),%edx 94178825Sdfr movl 8(%esp),%ecx 95178825Sdfr xorl %eax,%eax 96178825Sdfr/* 97178825Sdfr * do 64 byte chunks first 98178825Sdfr * 99178825Sdfr * XXX this is probably over-unrolled at least for DX2's 100178825Sdfr */ 101178825Sdfr2: 102178825Sdfr cmpl $64,%ecx 103178825Sdfr jb 3f 104178825Sdfr movl %eax,(%edx) 105178825Sdfr movl %eax,4(%edx) 106178825Sdfr movl %eax,8(%edx) 107178825Sdfr movl %eax,12(%edx) 108178825Sdfr movl %eax,16(%edx) 109178825Sdfr movl %eax,20(%edx) 110178825Sdfr movl %eax,24(%edx) 111178825Sdfr movl %eax,28(%edx) 112178825Sdfr movl %eax,32(%edx) 113178825Sdfr movl %eax,36(%edx) 114178825Sdfr movl %eax,40(%edx) 115178825Sdfr movl %eax,44(%edx) 116178825Sdfr movl %eax,48(%edx) 117178825Sdfr movl %eax,52(%edx) 118178825Sdfr movl %eax,56(%edx) 119178825Sdfr movl %eax,60(%edx) 120178825Sdfr addl $64,%edx 121178825Sdfr subl $64,%ecx 122178825Sdfr jnz 2b 123178825Sdfr ret 124178825Sdfr 125178825Sdfr/* 126178825Sdfr * do 16 byte chunks 127178825Sdfr */ 128178825Sdfr SUPERALIGN_TEXT 129178825Sdfr3: 130178825Sdfr cmpl $16,%ecx 131178825Sdfr jb 4f 132178825Sdfr movl %eax,(%edx) 133178825Sdfr movl %eax,4(%edx) 134178825Sdfr movl %eax,8(%edx) 135178825Sdfr movl %eax,12(%edx) 136178825Sdfr addl $16,%edx 137178825Sdfr subl $16,%ecx 138178825Sdfr jnz 3b 139178825Sdfr ret 140178825Sdfr 141178825Sdfr/* 142178825Sdfr * do 4 byte chunks 143178825Sdfr */ 144178825Sdfr SUPERALIGN_TEXT 145178825Sdfr4: 146178825Sdfr cmpl $4,%ecx 147178825Sdfr jb 5f 148178825Sdfr movl %eax,(%edx) 149178825Sdfr addl $4,%edx 150178825Sdfr subl $4,%ecx 151178825Sdfr jnz 4b 152178825Sdfr ret 153178825Sdfr 154178825Sdfr/* 155178825Sdfr * do 1 byte chunks 156178825Sdfr * a jump table seems to be faster than a loop or more range reductions 157178825Sdfr * 158178825Sdfr * XXX need a const section for non-text 159178825Sdfr */ 160178825Sdfr .data 161178825Sdfrjtab: 162178825Sdfr .long do0 163178825Sdfr .long do1 164178825Sdfr .long do2 165178825Sdfr .long do3 166178825Sdfr 167178825Sdfr .text 168178825Sdfr SUPERALIGN_TEXT 169178825Sdfr5: 170178825Sdfr jmp jtab(,%ecx,4) 171178825Sdfr 172178825Sdfr SUPERALIGN_TEXT 173178825Sdfrdo3: 174178825Sdfr movw %ax,(%edx) 175178825Sdfr movb %al,2(%edx) 176178825Sdfr ret 177178825Sdfr 178178825Sdfr SUPERALIGN_TEXT 179178825Sdfrdo2: 180178825Sdfr movw %ax,(%edx) 181178825Sdfr ret 182178825Sdfr 183178825Sdfr SUPERALIGN_TEXT 184178825Sdfrdo1: 185178825Sdfr movb %al,(%edx) 186178825Sdfr ret 187178825Sdfr 188178825Sdfr SUPERALIGN_TEXT 189178825Sdfrdo0: 190178825Sdfr ret 191178825Sdfr#endif 192178825Sdfr 193178825Sdfr#ifdef I586_CPU 194178825SdfrENTRY(i586_bzero) 195178825Sdfr movl 4(%esp),%edx 196178825Sdfr movl 8(%esp),%ecx 197178825Sdfr 198178825Sdfr /* 199178825Sdfr * The FPU register method is twice as fast as the integer register 200178825Sdfr * method unless the target is in the L1 cache and we pre-allocate a 201178825Sdfr * cache line for it (then the integer register method is 4-5 times 202178825Sdfr * faster). However, we never pre-allocate cache lines, since that 203178825Sdfr * would make the integer method 25% or more slower for the common 204178825Sdfr * case when the target isn't in either the L1 cache or the L2 cache. 205178825Sdfr * Thus we normally use the FPU register method unless the overhead 206178825Sdfr * would be too large. 207178825Sdfr */ 208178825Sdfr cmpl $256,%ecx /* empirical; clts, fninit, smsw cost a lot */ 209178825Sdfr jb intreg_i586_bzero 210178825Sdfr 211178825Sdfr /* 212178825Sdfr * The FPU registers may belong to an application or to fastmove() 213178825Sdfr * or to another invocation of bcopy() or ourself in a higher level 214178825Sdfr * interrupt or trap handler. Preserving the registers is 215178825Sdfr * complicated since we avoid it if possible at all levels. We 216178825Sdfr * want to localize the complications even when that increases them. 217178825Sdfr * Here the extra work involves preserving CR0_TS in TS. 218178825Sdfr * `npxproc != NULL' is supposed to be the condition that all the 219178825Sdfr * FPU resources belong to an application, but npxproc and CR0_TS 220178825Sdfr * aren't set atomically enough for this condition to work in 221178825Sdfr * interrupt handlers. 222178825Sdfr * 223178825Sdfr * Case 1: FPU registers belong to the application: we must preserve 224178825Sdfr * the registers if we use them, so we only use the FPU register 225178825Sdfr * method if the target size is large enough to amortize the extra 226178825Sdfr * overhead for preserving them. CR0_TS must be preserved although 227178825Sdfr * it is very likely to end up as set. 228178825Sdfr * 229178825Sdfr * Case 2: FPU registers belong to fastmove(): fastmove() currently 230178825Sdfr * makes the registers look like they belong to an application so 231178825Sdfr * that cpu_switch() and savectx() don't have to know about it, so 232178825Sdfr * this case reduces to case 1. 233178825Sdfr * 234178825Sdfr * Case 3: FPU registers belong to the kernel: don't use the FPU 235178825Sdfr * register method. This case is unlikely, and supporting it would 236178825Sdfr * be more complicated and might take too much stack. 237178825Sdfr * 238178825Sdfr * Case 4: FPU registers don't belong to anyone: the FPU registers 239178825Sdfr * don't need to be preserved, so we always use the FPU register 240178825Sdfr * method. CR0_TS must be preserved although it is very likely to 241178825Sdfr * always end up as clear. 242178825Sdfr */ 243178825Sdfr cmpl $0,_npxproc 244178825Sdfr je i586_bz1 245233294Sstas cmpl $256+184,%ecx /* empirical; not quite 2*108 more */ 246178825Sdfr jb intreg_i586_bzero 247178825Sdfr sarb $1,kernel_fpu_lock 248178825Sdfr jc intreg_i586_bzero 249178825Sdfr smsw %ax 250178825Sdfr clts 251178825Sdfr subl $108,%esp 252178825Sdfr fnsave 0(%esp) 253178825Sdfr jmp i586_bz2 254178825Sdfr 255178825Sdfri586_bz1: 256178825Sdfr sarb $1,kernel_fpu_lock 257178825Sdfr jc intreg_i586_bzero 258178825Sdfr smsw %ax 259178825Sdfr clts 260178825Sdfr fninit /* XXX should avoid needing this */ 261178825Sdfri586_bz2: 262178825Sdfr fldz 263178825Sdfr 264178825Sdfr /* 265178825Sdfr * Align to an 8 byte boundary (misalignment in the main loop would 266178825Sdfr * cost a factor of >= 2). Avoid jumps (at little cost if it is 267178825Sdfr * already aligned) by always zeroing 8 bytes and using the part up 268178825Sdfr * to the _next_ alignment position. 269178825Sdfr */ 270178825Sdfr fstl 0(%edx) 271178825Sdfr addl %edx,%ecx /* part of %ecx -= new_%edx - %edx */ 272178825Sdfr addl $8,%edx 273178825Sdfr andl $~7,%edx 274178825Sdfr subl %edx,%ecx 275178825Sdfr 276178825Sdfr /* 277178825Sdfr * Similarly align `len' to a multiple of 8. 278178825Sdfr */ 279178825Sdfr fstl -8(%edx,%ecx) 280178825Sdfr decl %ecx 281178825Sdfr andl $~7,%ecx 282178825Sdfr 283178825Sdfr /* 284178825Sdfr * This wouldn't be any faster if it were unrolled, since the loop 285178825Sdfr * control instructions are much faster than the fstl and/or done 286178825Sdfr * in parallel with it so their overhead is insignificant. 287178825Sdfr */ 288178825Sdfrfpureg_i586_bzero_loop: 289178825Sdfr fstl 0(%edx) 290178825Sdfr addl $8,%edx 291178825Sdfr subl $8,%ecx 292178825Sdfr cmpl $8,%ecx 293178825Sdfr jae fpureg_i586_bzero_loop 294178825Sdfr 295178825Sdfr cmpl $0,_npxproc 296178825Sdfr je i586_bz3 297178825Sdfr frstor 0(%esp) 298178825Sdfr addl $108,%esp 299178825Sdfr lmsw %ax 300178825Sdfr movb $0xfe,kernel_fpu_lock 301178825Sdfr ret 302178825Sdfr 303178825Sdfri586_bz3: 304178825Sdfr fstpl %st(0) 305178825Sdfr lmsw %ax 306178825Sdfr movb $0xfe,kernel_fpu_lock 307178825Sdfr ret 308178825Sdfr 309178825Sdfrintreg_i586_bzero: 310178825Sdfr /* 311178825Sdfr * `rep stos' seems to be the best method in practice for small 312178825Sdfr * counts. Fancy methods usually take too long to start up due 313178825Sdfr * to cache and BTB misses. 314178825Sdfr */ 315178825Sdfr pushl %edi 316178825Sdfr movl %edx,%edi 317178825Sdfr xorl %eax,%eax 318178825Sdfr shrl $2,%ecx 319178825Sdfr cld 320178825Sdfr rep 321178825Sdfr stosl 322178825Sdfr movl 12(%esp),%ecx 323178825Sdfr andl $3,%ecx 324178825Sdfr jne 1f 325178825Sdfr popl %edi 326178825Sdfr ret 327178825Sdfr 328178825Sdfr1: 329178825Sdfr rep 330178825Sdfr stosb 331178825Sdfr popl %edi 332178825Sdfr ret 333178825Sdfr#endif /* I586_CPU */ 334178825Sdfr 335178825Sdfr/* fillw(pat, base, cnt) */ 336178825SdfrENTRY(fillw) 337178825Sdfr pushl %edi 338178825Sdfr movl 8(%esp),%eax 339178825Sdfr movl 12(%esp),%edi 340178825Sdfr movl 16(%esp),%ecx 341178825Sdfr cld 342178825Sdfr rep 343178825Sdfr stosw 344178825Sdfr popl %edi 345178825Sdfr ret 346178825Sdfr 347178825SdfrENTRY(bcopyb) 348178825Sdfrbcopyb: 349178825Sdfr pushl %esi 350178825Sdfr pushl %edi 351178825Sdfr movl 12(%esp),%esi 352178825Sdfr movl 16(%esp),%edi 353178825Sdfr movl 20(%esp),%ecx 354178825Sdfr movl %edi,%eax 355178825Sdfr subl %esi,%eax 356178825Sdfr cmpl %ecx,%eax /* overlapping && src < dst? */ 357178825Sdfr jb 1f 358178825Sdfr cld /* nope, copy forwards */ 359178825Sdfr rep 360178825Sdfr movsb 361178825Sdfr popl %edi 362178825Sdfr popl %esi 363178825Sdfr ret 364178825Sdfr 365178825Sdfr ALIGN_TEXT 366178825Sdfr1: 367178825Sdfr addl %ecx,%edi /* copy backwards. */ 368178825Sdfr addl %ecx,%esi 369178825Sdfr decl %edi 370178825Sdfr decl %esi 371178825Sdfr std 372178825Sdfr rep 373178825Sdfr movsb 374178825Sdfr popl %edi 375178825Sdfr popl %esi 376178825Sdfr cld 377178825Sdfr ret 378178825Sdfr 379178825SdfrENTRY(bcopy) 380178825Sdfr MEXITCOUNT 381178825Sdfr jmp *_bcopy_vector 382178825Sdfr 383178825SdfrENTRY(ovbcopy) 384178825Sdfr MEXITCOUNT 385178825Sdfr jmp *_ovbcopy_vector 386178825Sdfr 387178825Sdfr/* 388178825Sdfr * generic_bcopy(src, dst, cnt) 389178825Sdfr * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 390178825Sdfr */ 391178825SdfrENTRY(generic_bcopy) 392178825Sdfr pushl %esi 393178825Sdfr pushl %edi 394178825Sdfr movl 12(%esp),%esi 395178825Sdfr movl 16(%esp),%edi 396178825Sdfr movl 20(%esp),%ecx 397178825Sdfr 398178825Sdfr movl %edi,%eax 399178825Sdfr subl %esi,%eax 400178825Sdfr cmpl %ecx,%eax /* overlapping && src < dst? */ 401178825Sdfr jb 1f 402178825Sdfr 403178825Sdfr shrl $2,%ecx /* copy by 32-bit words */ 404178825Sdfr cld /* nope, copy forwards */ 405178825Sdfr rep 406178825Sdfr movsl 407178825Sdfr movl 20(%esp),%ecx 408178825Sdfr andl $3,%ecx /* any bytes left? */ 409178825Sdfr rep 410178825Sdfr movsb 411178825Sdfr popl %edi 412178825Sdfr popl %esi 413178825Sdfr ret 414178825Sdfr 415178825Sdfr ALIGN_TEXT 416178825Sdfr1: 417178825Sdfr addl %ecx,%edi /* copy backwards */ 418178825Sdfr addl %ecx,%esi 419178825Sdfr decl %edi 420178825Sdfr decl %esi 421178825Sdfr andl $3,%ecx /* any fractional bytes? */ 422178825Sdfr std 423178825Sdfr rep 424178825Sdfr movsb 425178825Sdfr movl 20(%esp),%ecx /* copy remainder by 32-bit words */ 426178825Sdfr shrl $2,%ecx 427178825Sdfr subl $3,%esi 428178825Sdfr subl $3,%edi 429178825Sdfr rep 430178825Sdfr movsl 431178825Sdfr popl %edi 432178825Sdfr popl %esi 433178825Sdfr cld 434178825Sdfr ret 435178825Sdfr 436178825Sdfr#ifdef I586_CPU 437178825SdfrENTRY(i586_bcopy) 438178825Sdfr pushl %esi 439178825Sdfr pushl %edi 440178825Sdfr movl 12(%esp),%esi 441178825Sdfr movl 16(%esp),%edi 442178825Sdfr movl 20(%esp),%ecx 443178825Sdfr 444178825Sdfr movl %edi,%eax 445178825Sdfr subl %esi,%eax 446178825Sdfr cmpl %ecx,%eax /* overlapping && src < dst? */ 447178825Sdfr jb 1f 448178825Sdfr 449178825Sdfr cmpl $1024,%ecx 450178825Sdfr jb small_i586_bcopy 451178825Sdfr 452178825Sdfr sarb $1,kernel_fpu_lock 453178825Sdfr jc small_i586_bcopy 454178825Sdfr cmpl $0,_npxproc 455178825Sdfr je i586_bc1 456178825Sdfr smsw %dx 457178825Sdfr clts 458178825Sdfr subl $108,%esp 459178825Sdfr fnsave 0(%esp) 460178825Sdfr jmp 4f 461178825Sdfr 462178825Sdfri586_bc1: 463178825Sdfr smsw %dx 464178825Sdfr clts 465178825Sdfr fninit /* XXX should avoid needing this */ 466178825Sdfr 467178825Sdfr ALIGN_TEXT 468178825Sdfr4: 469178825Sdfr pushl %ecx 470178825Sdfr#define DCACHE_SIZE 8192 471178825Sdfr cmpl $(DCACHE_SIZE-512)/2,%ecx 472178825Sdfr jbe 2f 473178825Sdfr movl $(DCACHE_SIZE-512)/2,%ecx 474178825Sdfr2: 475178825Sdfr subl %ecx,0(%esp) 476178825Sdfr cmpl $256,%ecx 477178825Sdfr jb 5f /* XXX should prefetch if %ecx >= 32 */ 478178825Sdfr pushl %esi 479178825Sdfr pushl %ecx 480178825Sdfr ALIGN_TEXT 481178825Sdfr3: 482178825Sdfr movl 0(%esi),%eax 483178825Sdfr movl 32(%esi),%eax 484178825Sdfr movl 64(%esi),%eax 485178825Sdfr movl 96(%esi),%eax 486178825Sdfr movl 128(%esi),%eax 487178825Sdfr movl 160(%esi),%eax 488178825Sdfr movl 192(%esi),%eax 489178825Sdfr movl 224(%esi),%eax 490178825Sdfr addl $256,%esi 491178825Sdfr subl $256,%ecx 492178825Sdfr cmpl $256,%ecx 493178825Sdfr jae 3b 494178825Sdfr popl %ecx 495178825Sdfr popl %esi 496178825Sdfr5: 497178825Sdfr ALIGN_TEXT 498178825Sdfrlarge_i586_bcopy_loop: 499178825Sdfr fildq 0(%esi) 500178825Sdfr fildq 8(%esi) 501178825Sdfr fildq 16(%esi) 502178825Sdfr fildq 24(%esi) 503178825Sdfr fildq 32(%esi) 504178825Sdfr fildq 40(%esi) 505178825Sdfr fildq 48(%esi) 506178825Sdfr fildq 56(%esi) 507178825Sdfr fistpq 56(%edi) 508178825Sdfr fistpq 48(%edi) 509178825Sdfr fistpq 40(%edi) 510178825Sdfr fistpq 32(%edi) 511178825Sdfr fistpq 24(%edi) 512178825Sdfr fistpq 16(%edi) 513178825Sdfr fistpq 8(%edi) 514178825Sdfr fistpq 0(%edi) 515178825Sdfr addl $64,%esi 516178825Sdfr addl $64,%edi 517178825Sdfr subl $64,%ecx 518178825Sdfr cmpl $64,%ecx 519178825Sdfr jae large_i586_bcopy_loop 520178825Sdfr popl %eax 521178825Sdfr addl %eax,%ecx 522178825Sdfr cmpl $64,%ecx 523178825Sdfr jae 4b 524178825Sdfr 525178825Sdfr cmpl $0,_npxproc 526178825Sdfr je i586_bc2 527178825Sdfr frstor 0(%esp) 528178825Sdfr addl $108,%esp 529178825Sdfri586_bc2: 530178825Sdfr lmsw %dx 531178825Sdfr movb $0xfe,kernel_fpu_lock 532178825Sdfr 533178825Sdfr/* 534178825Sdfr * This is a duplicate of the main part of generic_bcopy. See the comments 535178825Sdfr * there. Jumping into generic_bcopy would cost a whole 0-1 cycles and 536178825Sdfr * would mess up high resolution profiling. 537178825Sdfr */ 538178825Sdfr ALIGN_TEXT 539178825Sdfrsmall_i586_bcopy: 540178825Sdfr shrl $2,%ecx 541178825Sdfr cld 542178825Sdfr rep 543178825Sdfr movsl 544178825Sdfr movl 20(%esp),%ecx 545178825Sdfr andl $3,%ecx 546178825Sdfr rep 547178825Sdfr movsb 548178825Sdfr popl %edi 549178825Sdfr popl %esi 550178825Sdfr ret 551178825Sdfr 552178825Sdfr ALIGN_TEXT 553178825Sdfr1: 554178825Sdfr addl %ecx,%edi 555178825Sdfr addl %ecx,%esi 556178825Sdfr decl %edi 557178825Sdfr decl %esi 558178825Sdfr andl $3,%ecx 559178825Sdfr std 560178825Sdfr rep 561178825Sdfr movsb 562178825Sdfr movl 20(%esp),%ecx 563178825Sdfr shrl $2,%ecx 564178825Sdfr subl $3,%esi 565178825Sdfr subl $3,%edi 566178825Sdfr rep 567178825Sdfr movsl 568178825Sdfr popl %edi 569178825Sdfr popl %esi 570178825Sdfr cld 571178825Sdfr ret 572178825Sdfr#endif /* I586_CPU */ 573178825Sdfr 574178825Sdfr/* 575178825Sdfr * Note: memcpy does not support overlapping copies 576178825Sdfr */ 577178825SdfrENTRY(memcpy) 578178825Sdfr pushl %edi 579178825Sdfr pushl %esi 580178825Sdfr movl 12(%esp),%edi 581178825Sdfr movl 16(%esp),%esi 582178825Sdfr movl 20(%esp),%ecx 583178825Sdfr movl %edi,%eax 584178825Sdfr shrl $2,%ecx /* copy by 32-bit words */ 585178825Sdfr cld /* nope, copy forwards */ 586178825Sdfr rep 587178825Sdfr movsl 588178825Sdfr movl 20(%esp),%ecx 589178825Sdfr andl $3,%ecx /* any bytes left? */ 590178825Sdfr rep 591178825Sdfr movsb 592178825Sdfr popl %esi 593178825Sdfr popl %edi 594178825Sdfr ret 595178825Sdfr 596178825Sdfr 597178825Sdfr/*****************************************************************************/ 598178825Sdfr/* copyout and fubyte family */ 599178825Sdfr/*****************************************************************************/ 600178825Sdfr/* 601178825Sdfr * Access user memory from inside the kernel. These routines and possibly 602178825Sdfr * the math- and DOS emulators should be the only places that do this. 603178825Sdfr * 604178825Sdfr * We have to access the memory with user's permissions, so use a segment 605178825Sdfr * selector with RPL 3. For writes to user space we have to additionally 606178825Sdfr * check the PTE for write permission, because the 386 does not check 607178825Sdfr * write permissions when we are executing with EPL 0. The 486 does check 608178825Sdfr * this if the WP bit is set in CR0, so we can use a simpler version here. 609178825Sdfr * 610178825Sdfr * These routines set curpcb->onfault for the time they execute. When a 611178825Sdfr * protection violation occurs inside the functions, the trap handler 612178825Sdfr * returns to *curpcb->onfault instead of the function. 613178825Sdfr */ 614178825Sdfr 615178825Sdfr/* copyout(from_kernel, to_user, len) */ 616178825SdfrENTRY(copyout) 617178825Sdfr MEXITCOUNT 618178825Sdfr jmp *_copyout_vector 619178825Sdfr 620178825SdfrENTRY(generic_copyout) 621178825Sdfr movl _curpcb,%eax 622178825Sdfr movl $copyout_fault,PCB_ONFAULT(%eax) 623178825Sdfr pushl %esi 624178825Sdfr pushl %edi 625178825Sdfr pushl %ebx 626178825Sdfr movl 16(%esp),%esi 627178825Sdfr movl 20(%esp),%edi 628178825Sdfr movl 24(%esp),%ebx 629178825Sdfr testl %ebx,%ebx /* anything to do? */ 630178825Sdfr jz done_copyout 631178825Sdfr 632178825Sdfr /* 633178825Sdfr * Check explicitly for non-user addresses. If 486 write protection 634178825Sdfr * is being used, this check is essential because we are in kernel 635178825Sdfr * mode so the h/w does not provide any protection against writing 636178825Sdfr * kernel addresses. 637178825Sdfr */ 638178825Sdfr 639178825Sdfr /* 640178825Sdfr * First, prevent address wrapping. 641178825Sdfr */ 642178825Sdfr movl %edi,%eax 643178825Sdfr addl %ebx,%eax 644178825Sdfr jc copyout_fault 645178825Sdfr/* 646178825Sdfr * XXX STOP USING VM_MAXUSER_ADDRESS. 647178825Sdfr * It is an end address, not a max, so every time it is used correctly it 648178825Sdfr * looks like there is an off by one error, and of course it caused an off 649178825Sdfr * by one error in several places. 650178825Sdfr */ 651178825Sdfr cmpl $VM_MAXUSER_ADDRESS,%eax 652178825Sdfr ja copyout_fault 653178825Sdfr 654178825Sdfr#if defined(I386_CPU) 655178825Sdfr 656178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 657178825Sdfr cmpl $CPUCLASS_386,_cpu_class 658178825Sdfr jne 3f 659178825Sdfr#endif 660178825Sdfr/* 661178825Sdfr * We have to check each PTE for user write permission. 662178825Sdfr * The checking may cause a page fault, so it is important to set 663178825Sdfr * up everything for return via copyout_fault before here. 664178825Sdfr */ 665178825Sdfr /* compute number of pages */ 666178825Sdfr movl %edi,%ecx 667178825Sdfr andl $PAGE_MASK,%ecx 668233294Sstas addl %ebx,%ecx 669233294Sstas decl %ecx 670233294Sstas shrl $IDXSHIFT+2,%ecx 671233294Sstas incl %ecx 672233294Sstas 673233294Sstas /* compute PTE offset for start address */ 674233294Sstas movl %edi,%edx 675233294Sstas shrl $IDXSHIFT,%edx 676233294Sstas andb $0xfc,%dl 677233294Sstas 678178825Sdfr1: 679178825Sdfr /* check PTE for each page */ 680178825Sdfr leal _PTmap(%edx),%eax 681178825Sdfr shrl $IDXSHIFT,%eax 682178825Sdfr andb $0xfc,%al 683178825Sdfr testb $PG_V,_PTmap(%eax) /* PTE page must be valid */ 684178825Sdfr je 4f 685178825Sdfr movb _PTmap(%edx),%al 686178825Sdfr andb $PG_V|PG_RW|PG_U,%al /* page must be valid and user writable */ 687178825Sdfr cmpb $PG_V|PG_RW|PG_U,%al 688178825Sdfr je 2f 689178825Sdfr 690178825Sdfr4: 691178825Sdfr /* simulate a trap */ 692178825Sdfr pushl %edx 693178825Sdfr pushl %ecx 694178825Sdfr shll $IDXSHIFT,%edx 695178825Sdfr pushl %edx 696178825Sdfr call _trapwrite /* trapwrite(addr) */ 697178825Sdfr popl %edx 698178825Sdfr popl %ecx 699178825Sdfr popl %edx 700178825Sdfr 701178825Sdfr testl %eax,%eax /* if not ok, return EFAULT */ 702178825Sdfr jnz copyout_fault 703178825Sdfr 704178825Sdfr2: 705178825Sdfr addl $4,%edx 706178825Sdfr decl %ecx 707178825Sdfr jnz 1b /* check next page */ 708178825Sdfr#endif /* I386_CPU */ 709178825Sdfr 710178825Sdfr /* bcopy(%esi, %edi, %ebx) */ 711178825Sdfr3: 712178825Sdfr movl %ebx,%ecx 713178825Sdfr 714178825Sdfr#ifdef I586_CPU 715178825Sdfr ALIGN_TEXT 716178825Sdfrslow_copyout: 717178825Sdfr#endif 718178825Sdfr shrl $2,%ecx 719178825Sdfr cld 720178825Sdfr rep 721178825Sdfr movsl 722178825Sdfr movb %bl,%cl 723178825Sdfr andb $3,%cl 724178825Sdfr rep 725178825Sdfr movsb 726178825Sdfr 727178825Sdfrdone_copyout: 728178825Sdfr popl %ebx 729178825Sdfr popl %edi 730178825Sdfr popl %esi 731178825Sdfr xorl %eax,%eax 732178825Sdfr movl _curpcb,%edx 733178825Sdfr movl %eax,PCB_ONFAULT(%edx) 734178825Sdfr ret 735178825Sdfr 736178825Sdfr ALIGN_TEXT 737178825Sdfrcopyout_fault: 738178825Sdfr popl %ebx 739178825Sdfr popl %edi 740178825Sdfr popl %esi 741178825Sdfr movl _curpcb,%edx 742178825Sdfr movl $0,PCB_ONFAULT(%edx) 743178825Sdfr movl $EFAULT,%eax 744178825Sdfr ret 745178825Sdfr 746178825Sdfr#ifdef I586_CPU 747178825SdfrENTRY(i586_copyout) 748178825Sdfr /* 749178825Sdfr * Duplicated from generic_copyout. Could be done a bit better. 750178825Sdfr */ 751178825Sdfr movl _curpcb,%eax 752178825Sdfr movl $copyout_fault,PCB_ONFAULT(%eax) 753178825Sdfr pushl %esi 754178825Sdfr pushl %edi 755178825Sdfr pushl %ebx 756178825Sdfr movl 16(%esp),%esi 757178825Sdfr movl 20(%esp),%edi 758178825Sdfr movl 24(%esp),%ebx 759178825Sdfr testl %ebx,%ebx /* anything to do? */ 760178825Sdfr jz done_copyout 761178825Sdfr 762178825Sdfr /* 763178825Sdfr * Check explicitly for non-user addresses. If 486 write protection 764178825Sdfr * is being used, this check is essential because we are in kernel 765178825Sdfr * mode so the h/w does not provide any protection against writing 766178825Sdfr * kernel addresses. 767178825Sdfr */ 768178825Sdfr 769178825Sdfr /* 770178825Sdfr * First, prevent address wrapping. 771178825Sdfr */ 772178825Sdfr movl %edi,%eax 773178825Sdfr addl %ebx,%eax 774178825Sdfr jc copyout_fault 775178825Sdfr/* 776178825Sdfr * XXX STOP USING VM_MAXUSER_ADDRESS. 777178825Sdfr * It is an end address, not a max, so every time it is used correctly it 778178825Sdfr * looks like there is an off by one error, and of course it caused an off 779178825Sdfr * by one error in several places. 780178825Sdfr */ 781178825Sdfr cmpl $VM_MAXUSER_ADDRESS,%eax 782178825Sdfr ja copyout_fault 783178825Sdfr 784178825Sdfr /* bcopy(%esi, %edi, %ebx) */ 785178825Sdfr3: 786178825Sdfr movl %ebx,%ecx 787178825Sdfr /* 788178825Sdfr * End of duplicated code. 789178825Sdfr */ 790178825Sdfr 791178825Sdfr cmpl $1024,%ecx 792178825Sdfr jb slow_copyout 793178825Sdfr 794178825Sdfr pushl %ecx 795178825Sdfr call _fastmove 796178825Sdfr addl $4,%esp 797178825Sdfr jmp done_copyout 798178825Sdfr#endif /* I586_CPU */ 799178825Sdfr 800178825Sdfr/* copyin(from_user, to_kernel, len) */ 801178825SdfrENTRY(copyin) 802178825Sdfr MEXITCOUNT 803178825Sdfr jmp *_copyin_vector 804178825Sdfr 805178825SdfrENTRY(generic_copyin) 806178825Sdfr movl _curpcb,%eax 807178825Sdfr movl $copyin_fault,PCB_ONFAULT(%eax) 808178825Sdfr pushl %esi 809178825Sdfr pushl %edi 810178825Sdfr movl 12(%esp),%esi /* caddr_t from */ 811178825Sdfr movl 16(%esp),%edi /* caddr_t to */ 812178825Sdfr movl 20(%esp),%ecx /* size_t len */ 813178825Sdfr 814178825Sdfr /* 815178825Sdfr * make sure address is valid 816178825Sdfr */ 817178825Sdfr movl %esi,%edx 818178825Sdfr addl %ecx,%edx 819178825Sdfr jc copyin_fault 820178825Sdfr cmpl $VM_MAXUSER_ADDRESS,%edx 821178825Sdfr ja copyin_fault 822178825Sdfr 823178825Sdfr#ifdef I586_CPU 824178825Sdfr ALIGN_TEXT 825178825Sdfrslow_copyin: 826178825Sdfr#endif 827178825Sdfr movb %cl,%al 828178825Sdfr shrl $2,%ecx /* copy longword-wise */ 829178825Sdfr cld 830178825Sdfr rep 831178825Sdfr movsl 832178825Sdfr movb %al,%cl 833178825Sdfr andb $3,%cl /* copy remaining bytes */ 834178825Sdfr rep 835178825Sdfr movsb 836178825Sdfr 837178825Sdfr#if defined(I586_CPU) 838178825Sdfr ALIGN_TEXT 839178825Sdfrdone_copyin: 840178825Sdfr#endif /* I586_CPU */ 841178825Sdfr popl %edi 842178825Sdfr popl %esi 843178825Sdfr xorl %eax,%eax 844178825Sdfr movl _curpcb,%edx 845178825Sdfr movl %eax,PCB_ONFAULT(%edx) 846178825Sdfr ret 847178825Sdfr 848178825Sdfr ALIGN_TEXT 849178825Sdfrcopyin_fault: 850178825Sdfr popl %edi 851178825Sdfr popl %esi 852178825Sdfr movl _curpcb,%edx 853178825Sdfr movl $0,PCB_ONFAULT(%edx) 854178825Sdfr movl $EFAULT,%eax 855178825Sdfr ret 856178825Sdfr 857178825Sdfr#ifdef I586_CPU 858178825SdfrENTRY(i586_copyin) 859178825Sdfr /* 860178825Sdfr * Duplicated from generic_copyin. Could be done a bit better. 861178825Sdfr */ 862178825Sdfr movl _curpcb,%eax 863178825Sdfr movl $copyin_fault,PCB_ONFAULT(%eax) 864178825Sdfr pushl %esi 865178825Sdfr pushl %edi 866178825Sdfr movl 12(%esp),%esi /* caddr_t from */ 867178825Sdfr movl 16(%esp),%edi /* caddr_t to */ 868178825Sdfr movl 20(%esp),%ecx /* size_t len */ 869178825Sdfr 870178825Sdfr /* 871178825Sdfr * make sure address is valid 872178825Sdfr */ 873178825Sdfr movl %esi,%edx 874178825Sdfr addl %ecx,%edx 875178825Sdfr jc copyin_fault 876178825Sdfr cmpl $VM_MAXUSER_ADDRESS,%edx 877178825Sdfr ja copyin_fault 878178825Sdfr /* 879178825Sdfr * End of duplicated code. 880178825Sdfr */ 881178825Sdfr 882178825Sdfr cmpl $1024,%ecx 883178825Sdfr jb slow_copyin 884178825Sdfr 885178825Sdfr pushl %ebx /* XXX prepare for fastmove_fault */ 886178825Sdfr pushl %ecx 887178825Sdfr call _fastmove 888178825Sdfr addl $8,%esp 889178825Sdfr jmp done_copyin 890178825Sdfr#endif /* I586_CPU */ 891178825Sdfr 892178825Sdfr#if defined(I586_CPU) 893178825Sdfr/* fastmove(src, dst, len) 894178825Sdfr src in %esi 895178825Sdfr dst in %edi 896178825Sdfr len in %ecx XXX changed to on stack for profiling 897178825Sdfr uses %eax and %edx for tmp. storage 898178825Sdfr */ 899178825Sdfr/* XXX use ENTRY() to get profiling. fastmove() is actually a non-entry. */ 900178825SdfrENTRY(fastmove) 901178825Sdfr pushl %ebp 902178825Sdfr movl %esp,%ebp 903178825Sdfr subl $PCB_SAVEFPU_SIZE+3*4,%esp 904178825Sdfr 905178825Sdfr movl 8(%ebp),%ecx 906178825Sdfr cmpl $63,%ecx 907178825Sdfr jbe fastmove_tail 908178825Sdfr 909178825Sdfr testl $7,%esi /* check if src addr is multiple of 8 */ 910178825Sdfr jnz fastmove_tail 911178825Sdfr 912178825Sdfr testl $7,%edi /* check if dst addr is multiple of 8 */ 913178825Sdfr jnz fastmove_tail 914178825Sdfr 915178825Sdfr/* if (npxproc != NULL) { */ 916178825Sdfr cmpl $0,_npxproc 917178825Sdfr je 6f 918178825Sdfr/* fnsave(&curpcb->pcb_savefpu); */ 919178825Sdfr movl _curpcb,%eax 920178825Sdfr fnsave PCB_SAVEFPU(%eax) 921178825Sdfr/* npxproc = NULL; */ 922178825Sdfr movl $0,_npxproc 923178825Sdfr/* } */ 924178825Sdfr6: 925178825Sdfr/* now we own the FPU. */ 926178825Sdfr 927178825Sdfr/* 928178825Sdfr * The process' FP state is saved in the pcb, but if we get 929178825Sdfr * switched, the cpu_switch() will store our FP state in the 930178825Sdfr * pcb. It should be possible to avoid all the copying for 931178825Sdfr * this, e.g., by setting a flag to tell cpu_switch() to 932178825Sdfr * save the state somewhere else. 933178825Sdfr */ 934178825Sdfr/* tmp = curpcb->pcb_savefpu; */ 935178825Sdfr movl %ecx,-12(%ebp) 936178825Sdfr movl %esi,-8(%ebp) 937178825Sdfr movl %edi,-4(%ebp) 938178825Sdfr movl %esp,%edi 939178825Sdfr movl _curpcb,%esi 940178825Sdfr addl $PCB_SAVEFPU,%esi 941178825Sdfr cld 942178825Sdfr movl $PCB_SAVEFPU_SIZE>>2,%ecx 943178825Sdfr rep 944178825Sdfr movsl 945178825Sdfr movl -12(%ebp),%ecx 946178825Sdfr movl -8(%ebp),%esi 947178825Sdfr movl -4(%ebp),%edi 948178825Sdfr/* stop_emulating(); */ 949178825Sdfr clts 950178825Sdfr/* npxproc = curproc; */ 951178825Sdfr movl _curproc,%eax 952178825Sdfr movl %eax,_npxproc 953178825Sdfr movl _curpcb,%eax 954178825Sdfr movl $fastmove_fault,PCB_ONFAULT(%eax) 955178825Sdfr4: 956178825Sdfr movl %ecx,-12(%ebp) 957178825Sdfr cmpl $1792,%ecx 958178825Sdfr jbe 2f 959178825Sdfr movl $1792,%ecx 960178825Sdfr2: 961178825Sdfr subl %ecx,-12(%ebp) 962178825Sdfr cmpl $256,%ecx 963178825Sdfr jb 5f 964178825Sdfr movl %ecx,-8(%ebp) 965178825Sdfr movl %esi,-4(%ebp) 966178825Sdfr ALIGN_TEXT 967178825Sdfr3: 968178825Sdfr movl 0(%esi),%eax 969178825Sdfr movl 32(%esi),%eax 970178825Sdfr movl 64(%esi),%eax 971178825Sdfr movl 96(%esi),%eax 972178825Sdfr movl 128(%esi),%eax 973178825Sdfr movl 160(%esi),%eax 974178825Sdfr movl 192(%esi),%eax 975178825Sdfr movl 224(%esi),%eax 976178825Sdfr addl $256,%esi 977178825Sdfr subl $256,%ecx 978178825Sdfr cmpl $256,%ecx 979178825Sdfr jae 3b 980178825Sdfr movl -8(%ebp),%ecx 981178825Sdfr movl -4(%ebp),%esi 982178825Sdfr5: 983178825Sdfr ALIGN_TEXT 984178825Sdfrfastmove_loop: 985178825Sdfr fildq 0(%esi) 986178825Sdfr fildq 8(%esi) 987178825Sdfr fildq 16(%esi) 988178825Sdfr fildq 24(%esi) 989178825Sdfr fildq 32(%esi) 990178825Sdfr fildq 40(%esi) 991178825Sdfr fildq 48(%esi) 992178825Sdfr fildq 56(%esi) 993178825Sdfr fistpq 56(%edi) 994178825Sdfr fistpq 48(%edi) 995178825Sdfr fistpq 40(%edi) 996178825Sdfr fistpq 32(%edi) 997178825Sdfr fistpq 24(%edi) 998178825Sdfr fistpq 16(%edi) 999178825Sdfr fistpq 8(%edi) 1000178825Sdfr fistpq 0(%edi) 1001178825Sdfr addl $-64,%ecx 1002178825Sdfr addl $64,%esi 1003178825Sdfr addl $64,%edi 1004178825Sdfr cmpl $63,%ecx 1005178825Sdfr ja fastmove_loop 1006178825Sdfr movl -12(%ebp),%eax 1007178825Sdfr addl %eax,%ecx 1008178825Sdfr cmpl $64,%ecx 1009178825Sdfr jae 4b 1010178825Sdfr 1011178825Sdfr/* curpcb->pcb_savefpu = tmp; */ 1012178825Sdfr movl %ecx,-12(%ebp) 1013178825Sdfr movl %esi,-8(%ebp) 1014178825Sdfr movl %edi,-4(%ebp) 1015178825Sdfr movl _curpcb,%edi 1016178825Sdfr addl $PCB_SAVEFPU,%edi 1017178825Sdfr movl %esp,%esi 1018178825Sdfr cld 1019178825Sdfr movl $PCB_SAVEFPU_SIZE>>2,%ecx 1020178825Sdfr rep 1021178825Sdfr movsl 1022178825Sdfr movl -12(%ebp),%ecx 1023178825Sdfr movl -8(%ebp),%esi 1024178825Sdfr movl -4(%ebp),%edi 1025178825Sdfr 1026178825Sdfr/* start_emulating(); */ 1027178825Sdfr smsw %ax 1028178825Sdfr orb $CR0_TS,%al 1029178825Sdfr lmsw %ax 1030178825Sdfr/* npxproc = NULL; */ 1031178825Sdfr movl $0,_npxproc 1032178825Sdfr 1033178825Sdfr ALIGN_TEXT 1034178825Sdfrfastmove_tail: 1035178825Sdfr movl _curpcb,%eax 1036178825Sdfr movl $fastmove_tail_fault,PCB_ONFAULT(%eax) 1037178825Sdfr 1038178825Sdfr movb %cl,%al 1039178825Sdfr shrl $2,%ecx /* copy longword-wise */ 1040178825Sdfr cld 1041178825Sdfr rep 1042178825Sdfr movsl 1043178825Sdfr movb %al,%cl 1044178825Sdfr andb $3,%cl /* copy remaining bytes */ 1045178825Sdfr rep 1046178825Sdfr movsb 1047178825Sdfr 1048178825Sdfr movl %ebp,%esp 1049178825Sdfr popl %ebp 1050178825Sdfr ret 1051178825Sdfr 1052178825Sdfr ALIGN_TEXT 1053178825Sdfrfastmove_fault: 1054178825Sdfr movl _curpcb,%edi 1055178825Sdfr addl $PCB_SAVEFPU,%edi 1056178825Sdfr movl %esp,%esi 1057178825Sdfr cld 1058178825Sdfr movl $PCB_SAVEFPU_SIZE>>2,%ecx 1059178825Sdfr rep 1060178825Sdfr movsl 1061178825Sdfr 1062178825Sdfr smsw %ax 1063178825Sdfr orb $CR0_TS,%al 1064178825Sdfr lmsw %ax 1065178825Sdfr movl $0,_npxproc 1066178825Sdfr 1067178825Sdfrfastmove_tail_fault: 1068178825Sdfr movl %ebp,%esp 1069178825Sdfr popl %ebp 1070178825Sdfr addl $8,%esp 1071178825Sdfr popl %ebx 1072178825Sdfr popl %edi 1073178825Sdfr popl %esi 1074178825Sdfr movl _curpcb,%edx 1075178825Sdfr movl $0,PCB_ONFAULT(%edx) 1076178825Sdfr movl $EFAULT,%eax 1077178825Sdfr ret 1078178825Sdfr#endif /* I586_CPU */ 1079178825Sdfr 1080178825Sdfr/* 1081178825Sdfr * fu{byte,sword,word} : fetch a byte (sword, word) from user memory 1082178825Sdfr */ 1083178825SdfrENTRY(fuword) 1084178825Sdfr movl _curpcb,%ecx 1085178825Sdfr movl $fusufault,PCB_ONFAULT(%ecx) 1086178825Sdfr movl 4(%esp),%edx /* from */ 1087178825Sdfr 1088178825Sdfr cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */ 1089178825Sdfr ja fusufault 1090178825Sdfr 1091178825Sdfr movl (%edx),%eax 1092178825Sdfr movl $0,PCB_ONFAULT(%ecx) 1093178825Sdfr ret 1094178825Sdfr 1095178825Sdfr/* 1096178825Sdfr * These two routines are called from the profiling code, potentially 1097178825Sdfr * at interrupt time. If they fail, that's okay, good things will 1098178825Sdfr * happen later. Fail all the time for now - until the trap code is 1099178825Sdfr * able to deal with this. 1100178825Sdfr */ 1101178825SdfrALTENTRY(suswintr) 1102178825SdfrENTRY(fuswintr) 1103178825Sdfr movl $-1,%eax 1104178825Sdfr ret 1105178825Sdfr 1106178825SdfrENTRY(fusword) 1107178825Sdfr movl _curpcb,%ecx 1108178825Sdfr movl $fusufault,PCB_ONFAULT(%ecx) 1109178825Sdfr movl 4(%esp),%edx 1110178825Sdfr 1111178825Sdfr cmpl $VM_MAXUSER_ADDRESS-2,%edx 1112178825Sdfr ja fusufault 1113178825Sdfr 1114178825Sdfr movzwl (%edx),%eax 1115178825Sdfr movl $0,PCB_ONFAULT(%ecx) 1116178825Sdfr ret 1117178825Sdfr 1118178825SdfrENTRY(fubyte) 1119178825Sdfr movl _curpcb,%ecx 1120178825Sdfr movl $fusufault,PCB_ONFAULT(%ecx) 1121178825Sdfr movl 4(%esp),%edx 1122178825Sdfr 1123178825Sdfr cmpl $VM_MAXUSER_ADDRESS-1,%edx 1124178825Sdfr ja fusufault 1125178825Sdfr 1126178825Sdfr movzbl (%edx),%eax 1127178825Sdfr movl $0,PCB_ONFAULT(%ecx) 1128178825Sdfr ret 1129178825Sdfr 1130178825Sdfr ALIGN_TEXT 1131178825Sdfrfusufault: 1132178825Sdfr movl _curpcb,%ecx 1133178825Sdfr xorl %eax,%eax 1134178825Sdfr movl %eax,PCB_ONFAULT(%ecx) 1135178825Sdfr decl %eax 1136178825Sdfr ret 1137178825Sdfr 1138178825Sdfr/* 1139178825Sdfr * su{byte,sword,word}: write a byte (word, longword) to user memory 1140178825Sdfr */ 1141178825SdfrENTRY(suword) 1142178825Sdfr movl _curpcb,%ecx 1143178825Sdfr movl $fusufault,PCB_ONFAULT(%ecx) 1144178825Sdfr movl 4(%esp),%edx 1145178825Sdfr 1146178825Sdfr#if defined(I386_CPU) 1147178825Sdfr 1148178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 1149178825Sdfr cmpl $CPUCLASS_386,_cpu_class 1150178825Sdfr jne 2f /* we only have to set the right segment selector */ 1151178825Sdfr#endif /* I486_CPU || I586_CPU || I686_CPU */ 1152178825Sdfr 1153178825Sdfr /* XXX - page boundary crossing is still not handled */ 1154178825Sdfr movl %edx,%eax 1155178825Sdfr shrl $IDXSHIFT,%edx 1156178825Sdfr andb $0xfc,%dl 1157178825Sdfr 1158178825Sdfr leal _PTmap(%edx),%ecx 1159178825Sdfr shrl $IDXSHIFT,%ecx 1160178825Sdfr andb $0xfc,%cl 1161178825Sdfr testb $PG_V,_PTmap(%ecx) /* PTE page must be valid */ 1162178825Sdfr je 4f 1163178825Sdfr movb _PTmap(%edx),%dl 1164178825Sdfr andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */ 1165178825Sdfr cmpb $PG_V|PG_RW|PG_U,%dl 1166178825Sdfr je 1f 1167178825Sdfr 1168178825Sdfr4: 1169178825Sdfr /* simulate a trap */ 1170178825Sdfr pushl %eax 1171178825Sdfr call _trapwrite 1172178825Sdfr popl %edx /* remove junk parameter from stack */ 1173178825Sdfr testl %eax,%eax 1174178825Sdfr jnz fusufault 1175178825Sdfr1: 1176178825Sdfr movl 4(%esp),%edx 1177178825Sdfr#endif 1178178825Sdfr 1179178825Sdfr2: 1180178825Sdfr cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */ 1181178825Sdfr ja fusufault 1182178825Sdfr 1183178825Sdfr movl 8(%esp),%eax 1184178825Sdfr movl %eax,(%edx) 1185178825Sdfr xorl %eax,%eax 1186178825Sdfr movl _curpcb,%ecx 1187178825Sdfr movl %eax,PCB_ONFAULT(%ecx) 1188178825Sdfr ret 1189178825Sdfr 1190178825SdfrENTRY(susword) 1191178825Sdfr movl _curpcb,%ecx 1192178825Sdfr movl $fusufault,PCB_ONFAULT(%ecx) 1193178825Sdfr movl 4(%esp),%edx 1194178825Sdfr 1195178825Sdfr#if defined(I386_CPU) 1196178825Sdfr 1197178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 1198178825Sdfr cmpl $CPUCLASS_386,_cpu_class 1199178825Sdfr jne 2f 1200178825Sdfr#endif /* I486_CPU || I586_CPU || I686_CPU */ 1201178825Sdfr 1202178825Sdfr /* XXX - page boundary crossing is still not handled */ 1203178825Sdfr movl %edx,%eax 1204178825Sdfr shrl $IDXSHIFT,%edx 1205178825Sdfr andb $0xfc,%dl 1206178825Sdfr 1207178825Sdfr leal _PTmap(%edx),%ecx 1208178825Sdfr shrl $IDXSHIFT,%ecx 1209178825Sdfr andb $0xfc,%cl 1210178825Sdfr testb $PG_V,_PTmap(%ecx) /* PTE page must be valid */ 1211178825Sdfr je 4f 1212178825Sdfr movb _PTmap(%edx),%dl 1213178825Sdfr andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */ 1214178825Sdfr cmpb $PG_V|PG_RW|PG_U,%dl 1215178825Sdfr je 1f 1216178825Sdfr 1217178825Sdfr4: 1218178825Sdfr /* simulate a trap */ 1219178825Sdfr pushl %eax 1220178825Sdfr call _trapwrite 1221178825Sdfr popl %edx /* remove junk parameter from stack */ 1222178825Sdfr testl %eax,%eax 1223178825Sdfr jnz fusufault 1224178825Sdfr1: 1225178825Sdfr movl 4(%esp),%edx 1226178825Sdfr#endif 1227178825Sdfr 1228178825Sdfr2: 1229178825Sdfr cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */ 1230178825Sdfr ja fusufault 1231178825Sdfr 1232178825Sdfr movw 8(%esp),%ax 1233178825Sdfr movw %ax,(%edx) 1234178825Sdfr xorl %eax,%eax 1235178825Sdfr movl _curpcb,%ecx /* restore trashed register */ 1236178825Sdfr movl %eax,PCB_ONFAULT(%ecx) 1237178825Sdfr ret 1238178825Sdfr 1239178825SdfrALTENTRY(suibyte) 1240178825SdfrENTRY(subyte) 1241178825Sdfr movl _curpcb,%ecx 1242178825Sdfr movl $fusufault,PCB_ONFAULT(%ecx) 1243178825Sdfr movl 4(%esp),%edx 1244178825Sdfr 1245178825Sdfr#if defined(I386_CPU) 1246178825Sdfr 1247178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 1248178825Sdfr cmpl $CPUCLASS_386,_cpu_class 1249178825Sdfr jne 2f 1250178825Sdfr#endif /* I486_CPU || I586_CPU || I686_CPU */ 1251178825Sdfr 1252178825Sdfr movl %edx,%eax 1253178825Sdfr shrl $IDXSHIFT,%edx 1254178825Sdfr andb $0xfc,%dl 1255178825Sdfr 1256178825Sdfr leal _PTmap(%edx),%ecx 1257178825Sdfr shrl $IDXSHIFT,%ecx 1258178825Sdfr andb $0xfc,%cl 1259178825Sdfr testb $PG_V,_PTmap(%ecx) /* PTE page must be valid */ 1260178825Sdfr je 4f 1261178825Sdfr movb _PTmap(%edx),%dl 1262178825Sdfr andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */ 1263178825Sdfr cmpb $PG_V|PG_RW|PG_U,%dl 1264178825Sdfr je 1f 1265178825Sdfr 1266178825Sdfr4: 1267178825Sdfr /* simulate a trap */ 1268178825Sdfr pushl %eax 1269178825Sdfr call _trapwrite 1270178825Sdfr popl %edx /* remove junk parameter from stack */ 1271178825Sdfr testl %eax,%eax 1272178825Sdfr jnz fusufault 1273178825Sdfr1: 1274178825Sdfr movl 4(%esp),%edx 1275178825Sdfr#endif 1276178825Sdfr 1277178825Sdfr2: 1278178825Sdfr cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */ 1279178825Sdfr ja fusufault 1280178825Sdfr 1281178825Sdfr movb 8(%esp),%al 1282178825Sdfr movb %al,(%edx) 1283178825Sdfr xorl %eax,%eax 1284178825Sdfr movl _curpcb,%ecx /* restore trashed register */ 1285178825Sdfr movl %eax,PCB_ONFAULT(%ecx) 1286178825Sdfr ret 1287178825Sdfr 1288178825Sdfr/* 1289178825Sdfr * copyinstr(from, to, maxlen, int *lencopied) 1290178825Sdfr * copy a string from from to to, stop when a 0 character is reached. 1291178825Sdfr * return ENAMETOOLONG if string is longer than maxlen, and 1292178825Sdfr * EFAULT on protection violations. If lencopied is non-zero, 1293178825Sdfr * return the actual length in *lencopied. 1294178825Sdfr */ 1295178825SdfrENTRY(copyinstr) 1296178825Sdfr pushl %esi 1297178825Sdfr pushl %edi 1298178825Sdfr movl _curpcb,%ecx 1299178825Sdfr movl $cpystrflt,PCB_ONFAULT(%ecx) 1300178825Sdfr 1301178825Sdfr movl 12(%esp),%esi /* %esi = from */ 1302178825Sdfr movl 16(%esp),%edi /* %edi = to */ 1303178825Sdfr movl 20(%esp),%edx /* %edx = maxlen */ 1304178825Sdfr 1305178825Sdfr movl $VM_MAXUSER_ADDRESS,%eax 1306178825Sdfr 1307178825Sdfr /* make sure 'from' is within bounds */ 1308178825Sdfr subl %esi,%eax 1309178825Sdfr jbe cpystrflt 1310178825Sdfr 1311178825Sdfr /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */ 1312178825Sdfr cmpl %edx,%eax 1313178825Sdfr jae 1f 1314178825Sdfr movl %eax,%edx 1315178825Sdfr movl %eax,20(%esp) 1316178825Sdfr1: 1317178825Sdfr incl %edx 1318178825Sdfr cld 1319178825Sdfr 1320178825Sdfr2: 1321178825Sdfr decl %edx 1322178825Sdfr jz 3f 1323178825Sdfr 1324178825Sdfr lodsb 1325178825Sdfr stosb 1326178825Sdfr orb %al,%al 1327178825Sdfr jnz 2b 1328178825Sdfr 1329178825Sdfr /* Success -- 0 byte reached */ 1330178825Sdfr decl %edx 1331178825Sdfr xorl %eax,%eax 1332178825Sdfr jmp cpystrflt_x 1333178825Sdfr3: 1334178825Sdfr /* edx is zero - return ENAMETOOLONG or EFAULT */ 1335178825Sdfr cmpl $VM_MAXUSER_ADDRESS,%esi 1336178825Sdfr jae cpystrflt 1337178825Sdfr4: 1338178825Sdfr movl $ENAMETOOLONG,%eax 1339178825Sdfr jmp cpystrflt_x 1340178825Sdfr 1341178825Sdfrcpystrflt: 1342178825Sdfr movl $EFAULT,%eax 1343178825Sdfr 1344178825Sdfrcpystrflt_x: 1345178825Sdfr /* set *lencopied and return %eax */ 1346178825Sdfr movl _curpcb,%ecx 1347178825Sdfr movl $0,PCB_ONFAULT(%ecx) 1348178825Sdfr movl 20(%esp),%ecx 1349178825Sdfr subl %edx,%ecx 1350178825Sdfr movl 24(%esp),%edx 1351178825Sdfr testl %edx,%edx 1352178825Sdfr jz 1f 1353178825Sdfr movl %ecx,(%edx) 1354178825Sdfr1: 1355178825Sdfr popl %edi 1356178825Sdfr popl %esi 1357178825Sdfr ret 1358178825Sdfr 1359178825Sdfr 1360178825Sdfr/* 1361178825Sdfr * copystr(from, to, maxlen, int *lencopied) 1362178825Sdfr */ 1363178825SdfrENTRY(copystr) 1364178825Sdfr pushl %esi 1365178825Sdfr pushl %edi 1366178825Sdfr 1367178825Sdfr movl 12(%esp),%esi /* %esi = from */ 1368178825Sdfr movl 16(%esp),%edi /* %edi = to */ 1369178825Sdfr movl 20(%esp),%edx /* %edx = maxlen */ 1370178825Sdfr incl %edx 1371178825Sdfr cld 1372178825Sdfr1: 1373178825Sdfr decl %edx 1374178825Sdfr jz 4f 1375178825Sdfr lodsb 1376178825Sdfr stosb 1377178825Sdfr orb %al,%al 1378178825Sdfr jnz 1b 1379178825Sdfr 1380178825Sdfr /* Success -- 0 byte reached */ 1381178825Sdfr decl %edx 1382178825Sdfr xorl %eax,%eax 1383178825Sdfr jmp 6f 1384178825Sdfr4: 1385178825Sdfr /* edx is zero -- return ENAMETOOLONG */ 1386178825Sdfr movl $ENAMETOOLONG,%eax 1387178825Sdfr 1388178825Sdfr6: 1389178825Sdfr /* set *lencopied and return %eax */ 1390178825Sdfr movl 20(%esp),%ecx 1391178825Sdfr subl %edx,%ecx 1392178825Sdfr movl 24(%esp),%edx 1393178825Sdfr testl %edx,%edx 1394178825Sdfr jz 7f 1395178825Sdfr movl %ecx,(%edx) 1396178825Sdfr7: 1397178825Sdfr popl %edi 1398178825Sdfr popl %esi 1399178825Sdfr ret 1400178825Sdfr 1401178825SdfrENTRY(bcmp) 1402178825Sdfr pushl %edi 1403178825Sdfr pushl %esi 1404178825Sdfr movl 12(%esp),%edi 1405178825Sdfr movl 16(%esp),%esi 1406178825Sdfr movl 20(%esp),%edx 1407178825Sdfr xorl %eax,%eax 1408178825Sdfr 1409178825Sdfr movl %edx,%ecx 1410178825Sdfr shrl $2,%ecx 1411178825Sdfr cld /* compare forwards */ 1412178825Sdfr repe 1413178825Sdfr cmpsl 1414178825Sdfr jne 1f 1415178825Sdfr 1416178825Sdfr movl %edx,%ecx 1417178825Sdfr andl $3,%ecx 1418178825Sdfr repe 1419178825Sdfr cmpsb 1420178825Sdfr je 2f 1421178825Sdfr1: 1422178825Sdfr incl %eax 1423178825Sdfr2: 1424178825Sdfr popl %esi 1425178825Sdfr popl %edi 1426178825Sdfr ret 1427178825Sdfr 1428178825Sdfr 1429178825Sdfr/* 1430178825Sdfr * Handling of special 386 registers and descriptor tables etc 1431178825Sdfr */ 1432178825Sdfr/* void lgdt(struct region_descriptor *rdp); */ 1433178825SdfrENTRY(lgdt) 1434178825Sdfr /* reload the descriptor table */ 1435178825Sdfr movl 4(%esp),%eax 1436178825Sdfr lgdt (%eax) 1437178825Sdfr 1438178825Sdfr /* flush the prefetch q */ 1439178825Sdfr jmp 1f 1440178825Sdfr nop 1441178825Sdfr1: 1442178825Sdfr /* reload "stale" selectors */ 1443178825Sdfr movl $KDSEL,%eax 1444178825Sdfr movl %ax,%ds 1445178825Sdfr movl %ax,%es 1446178825Sdfr movl %ax,%ss 1447178825Sdfr 1448178825Sdfr /* reload code selector by turning return into intersegmental return */ 1449178825Sdfr movl (%esp),%eax 1450178825Sdfr pushl %eax 1451178825Sdfr# movl $KCSEL,4(%esp) 1452178825Sdfr movl $8,4(%esp) 1453178825Sdfr lret 1454178825Sdfr 1455178825Sdfr/* 1456178825Sdfr * void lidt(struct region_descriptor *rdp); 1457178825Sdfr */ 1458178825SdfrENTRY(lidt) 1459178825Sdfr movl 4(%esp),%eax 1460178825Sdfr lidt (%eax) 1461178825Sdfr ret 1462178825Sdfr 1463178825Sdfr/* 1464178825Sdfr * void lldt(u_short sel) 1465178825Sdfr */ 1466178825SdfrENTRY(lldt) 1467178825Sdfr lldt 4(%esp) 1468178825Sdfr ret 1469178825Sdfr 1470178825Sdfr/* 1471178825Sdfr * void ltr(u_short sel) 1472178825Sdfr */ 1473178825SdfrENTRY(ltr) 1474178825Sdfr ltr 4(%esp) 1475178825Sdfr ret 1476178825Sdfr 1477178825Sdfr/* ssdtosd(*ssdp,*sdp) */ 1478178825SdfrENTRY(ssdtosd) 1479178825Sdfr pushl %ebx 1480178825Sdfr movl 8(%esp),%ecx 1481178825Sdfr movl 8(%ecx),%ebx 1482178825Sdfr shll $16,%ebx 1483178825Sdfr movl (%ecx),%edx 1484178825Sdfr roll $16,%edx 1485178825Sdfr movb %dh,%bl 1486178825Sdfr movb %dl,%bh 1487178825Sdfr rorl $8,%ebx 1488178825Sdfr movl 4(%ecx),%eax 1489178825Sdfr movw %ax,%dx 1490178825Sdfr andl $0xf0000,%eax 1491178825Sdfr orl %eax,%ebx 1492178825Sdfr movl 12(%esp),%ecx 1493178825Sdfr movl %edx,(%ecx) 1494178825Sdfr movl %ebx,4(%ecx) 1495178825Sdfr popl %ebx 1496178825Sdfr ret 1497178825Sdfr 1498178825Sdfr/* load_cr0(cr0) */ 1499178825SdfrENTRY(load_cr0) 1500178825Sdfr movl 4(%esp),%eax 1501178825Sdfr movl %eax,%cr0 1502178825Sdfr ret 1503178825Sdfr 1504178825Sdfr/* rcr0() */ 1505178825SdfrENTRY(rcr0) 1506178825Sdfr movl %cr0,%eax 1507178825Sdfr ret 1508178825Sdfr 1509178825Sdfr/* rcr3() */ 1510178825SdfrENTRY(rcr3) 1511178825Sdfr movl %cr3,%eax 1512178825Sdfr ret 1513178825Sdfr 1514178825Sdfr/* void load_cr3(caddr_t cr3) */ 1515178825SdfrENTRY(load_cr3) 1516178825Sdfr movl 4(%esp),%eax 1517178825Sdfr movl %eax,%cr3 1518178825Sdfr ret 1519178825Sdfr 1520178825Sdfr 1521178825Sdfr/*****************************************************************************/ 1522178825Sdfr/* setjump, longjump */ 1523178825Sdfr/*****************************************************************************/ 1524178825Sdfr 1525178825SdfrENTRY(setjmp) 1526178825Sdfr movl 4(%esp),%eax 1527178825Sdfr movl %ebx,(%eax) /* save ebx */ 1528178825Sdfr movl %esp,4(%eax) /* save esp */ 1529178825Sdfr movl %ebp,8(%eax) /* save ebp */ 1530178825Sdfr movl %esi,12(%eax) /* save esi */ 1531178825Sdfr movl %edi,16(%eax) /* save edi */ 1532178825Sdfr movl (%esp),%edx /* get rta */ 1533178825Sdfr movl %edx,20(%eax) /* save eip */ 1534178825Sdfr xorl %eax,%eax /* return(0); */ 1535178825Sdfr ret 1536178825Sdfr 1537178825SdfrENTRY(longjmp) 1538178825Sdfr movl 4(%esp),%eax 1539178825Sdfr movl (%eax),%ebx /* restore ebx */ 1540178825Sdfr movl 4(%eax),%esp /* restore esp */ 1541178825Sdfr movl 8(%eax),%ebp /* restore ebp */ 1542178825Sdfr movl 12(%eax),%esi /* restore esi */ 1543178825Sdfr movl 16(%eax),%edi /* restore edi */ 1544178825Sdfr movl 20(%eax),%edx /* get rta */ 1545178825Sdfr movl %edx,(%esp) /* put in return frame */ 1546178825Sdfr xorl %eax,%eax /* return(1); */ 1547178825Sdfr incl %eax 1548178825Sdfr ret 1549178825Sdfr 1550178825Sdfr/* 1551178825Sdfr * Here for doing BB-profiling (gcc -a). 1552178825Sdfr * We rely on the "bbset" instead, but need a dummy function. 1553178825Sdfr */ 1554178825SdfrNON_GPROF_ENTRY(__bb_init_func) 1555178825Sdfr movl 4(%esp),%eax 1556178825Sdfr movl $1,(%eax) 1557178825Sdfr .byte 0xc3 /* avoid macro for `ret' */ 1558178825Sdfr