support.s revision 1703
1/*- 2 * Copyright (c) 1993 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $Id: support.s,v 1.10 1994/06/06 14:23:49 davidg Exp $ 34 */ 35 36#include "assym.s" /* system definitions */ 37#include "errno.h" /* error return codes */ 38#include "machine/asmacros.h" /* miscellaneous asm macros */ 39#include "machine/cputypes.h" /* types of CPUs */ 40 41#define KDSEL 0x10 /* kernel data selector */ 42#define IDXSHIFT 10 43 44/* 45 * Support routines for GCC, general C-callable functions 46 */ 47ENTRY(__udivsi3) 48 movl 4(%esp),%eax 49 xorl %edx,%edx 50 divl 8(%esp) 51 ret 52 53ENTRY(__divsi3) 54 movl 4(%esp),%eax 55 cltd 56 idivl 8(%esp) 57 ret 58 59 /* 60 * I/O bus instructions via C 61 */ 62ENTRY(inb) /* val = inb(port) */ 63 movl 4(%esp),%edx 64 subl %eax,%eax 65 inb %dx,%al 66 NOP 67 ret 68 69ENTRY(inw) /* val = inw(port) */ 70 movl 4(%esp),%edx 71 subl %eax,%eax 72 inw %dx,%ax 73 NOP 74 ret 75 76ENTRY(insb) /* insb(port, addr, cnt) */ 77 pushl %edi 78 movl 8(%esp),%edx 79 movl 12(%esp),%edi 80 movl 16(%esp),%ecx 81 cld 82 rep 83 insb 84 NOP 85 movl %edi,%eax 86 popl %edi 87 ret 88 89ENTRY(insw) /* insw(port, addr, cnt) */ 90 pushl %edi 91 movl 8(%esp),%edx 92 movl 12(%esp),%edi 93 movl 16(%esp),%ecx 94 cld 95 rep 96 insw 97 NOP 98 movl %edi,%eax 99 popl %edi 100 ret 101 102ENTRY(insl) /* insl(port, addr, cnt) */ 103 pushl %edi 104 movl 8(%esp),%edx 105 movl 12(%esp),%edi 106 movl 16(%esp),%ecx 107 cld 108 rep 109 insl 110 NOP 111 movl %edi,%eax 112 popl %edi 113 ret 114 115ENTRY(rtcin) /* rtcin(val) */ 116 movl 4(%esp),%eax 117 outb %al,$0x70 118 NOP 119 xorl %eax,%eax 120 inb $0x71,%al 121 NOP 122 ret 123 124ENTRY(outb) /* outb(port, val) */ 125 movl 4(%esp),%edx 126 movl 8(%esp),%eax 127 outb %al,%dx 128 NOP 129 ret 130 131ENTRY(outw) /* outw(port, val) */ 132 movl 4(%esp),%edx 133 movl 8(%esp),%eax 134 outw %ax,%dx 135 NOP 136 ret 137 138ENTRY(outsb) /* outsb(port, addr, cnt) */ 139 pushl %esi 140 movl 8(%esp),%edx 141 movl 12(%esp),%esi 142 movl 16(%esp),%ecx 143 cld 144 rep 145 outsb 146 NOP 147 movl %esi,%eax 148 popl %esi 149 ret 150 151ENTRY(outsw) /* outsw(port, addr, cnt) */ 152 pushl %esi 153 movl 8(%esp),%edx 154 movl 12(%esp),%esi 155 movl 16(%esp),%ecx 156 cld 157 rep 158 outsw 159 NOP 160 movl %esi,%eax 161 popl %esi 162 ret 163 164ENTRY(outsl) /* outsl(port, addr, cnt) */ 165 pushl %esi 166 movl 8(%esp),%edx 167 movl 12(%esp),%esi 168 movl 16(%esp),%ecx 169 cld 170 rep 171 outsl 172 NOP 173 movl %esi,%eax 174 popl %esi 175 ret 176 177/* 178 * bcopy family 179 */ 180 181/* 182 * void bzero(void *base, u_int cnt) 183 * Special code for I486 because stosl uses lots 184 * of clocks. Makes little or no difference on DX2 type 185 * machines, but stosl is about 1/2 as fast as 186 * memory moves on a standard DX !!!!! 187 */ 188ALTENTRY(blkclr) 189ENTRY(bzero) 190#if defined(I486_CPU) 191 cmpl $CPUCLASS_486,_cpu_class 192 jz 1f 193#endif 194 195 pushl %edi 196 movl 8(%esp),%edi 197 movl 12(%esp),%ecx 198 xorl %eax,%eax 199 shrl $2,%ecx 200 cld 201 rep 202 stosl 203 movl 12(%esp),%ecx 204 andl $3,%ecx 205 rep 206 stosb 207 popl %edi 208 ret 209 210#if defined(I486_CPU) 211 SUPERALIGN_TEXT 2121: 213 movl 4(%esp),%edx 214 movl 8(%esp),%ecx 215 xorl %eax,%eax 216/ 217/ do 64 byte chunks first 218/ 219/ XXX this is probably over-unrolled at least for DX2's 220/ 2212: 222 cmpl $64,%ecx 223 jb 3f 224 movl %eax,(%edx) 225 movl %eax,4(%edx) 226 movl %eax,8(%edx) 227 movl %eax,12(%edx) 228 movl %eax,16(%edx) 229 movl %eax,20(%edx) 230 movl %eax,24(%edx) 231 movl %eax,28(%edx) 232 movl %eax,32(%edx) 233 movl %eax,36(%edx) 234 movl %eax,40(%edx) 235 movl %eax,44(%edx) 236 movl %eax,48(%edx) 237 movl %eax,52(%edx) 238 movl %eax,56(%edx) 239 movl %eax,60(%edx) 240 addl $64,%edx 241 subl $64,%ecx 242 jnz 2b 243 ret 244 245/ 246/ do 16 byte chunks 247/ 248 SUPERALIGN_TEXT 2493: 250 cmpl $16,%ecx 251 jb 4f 252 movl %eax,(%edx) 253 movl %eax,4(%edx) 254 movl %eax,8(%edx) 255 movl %eax,12(%edx) 256 addl $16,%edx 257 subl $16,%ecx 258 jnz 3b 259 ret 260 261/ 262/ do 4 byte chunks 263/ 264 SUPERALIGN_TEXT 2654: 266 cmpl $4,%ecx 267 jb 5f 268 movl %eax,(%edx) 269 addl $4,%edx 270 subl $4,%ecx 271 jnz 4b 272 ret 273 274/ 275/ do 1 byte chunks 276/ a jump table seems to be faster than a loop or more range reductions 277/ 278/ XXX need a const section for non-text 279/ 280 SUPERALIGN_TEXT 281jtab: 282 .long do0 283 .long do1 284 .long do2 285 .long do3 286 287 SUPERALIGN_TEXT 2885: 289 jmp jtab(,%ecx,4) 290 291 SUPERALIGN_TEXT 292do3: 293 movw %ax,(%edx) 294 movb %al,2(%edx) 295 ret 296 297 SUPERALIGN_TEXT 298do2: 299 movw %ax,(%edx) 300 ret 301 302 SUPERALIGN_TEXT 303do1: 304 movb %al,(%edx) 305 306 SUPERALIGN_TEXT 307do0: 308 ret 309#endif /* I486_CPU */ 310 311/* fillw(pat, base, cnt) */ 312ENTRY(fillw) 313 pushl %edi 314 movl 8(%esp),%eax 315 movl 12(%esp),%edi 316 movl 16(%esp),%ecx 317 cld 318 rep 319 stosw 320 popl %edi 321 ret 322 323/* filli(pat, base, cnt) */ 324ENTRY(filli) 325 pushl %edi 326 movl 8(%esp),%eax 327 movl 12(%esp),%edi 328 movl 16(%esp),%ecx 329 cld 330 rep 331 stosl 332 popl %edi 333 ret 334 335ENTRY(bcopyb) 336bcopyb: 337 pushl %esi 338 pushl %edi 339 movl 12(%esp),%esi 340 movl 16(%esp),%edi 341 movl 20(%esp),%ecx 342 cmpl %esi,%edi /* potentially overlapping? */ 343 jnb 1f 344 cld /* nope, copy forwards */ 345 rep 346 movsb 347 popl %edi 348 popl %esi 349 ret 350 351 ALIGN_TEXT 3521: 353 addl %ecx,%edi /* copy backwards. */ 354 addl %ecx,%esi 355 std 356 decl %edi 357 decl %esi 358 rep 359 movsb 360 popl %edi 361 popl %esi 362 cld 363 ret 364 365ENTRY(bcopyw) 366bcopyw: 367 pushl %esi 368 pushl %edi 369 movl 12(%esp),%esi 370 movl 16(%esp),%edi 371 movl 20(%esp),%ecx 372 cmpl %esi,%edi /* potentially overlapping? */ 373 jnb 1f 374 shrl $1,%ecx /* copy by 16-bit words */ 375 cld /* nope, copy forwards */ 376 rep 377 movsw 378 adc %ecx,%ecx /* any bytes left? */ 379 rep 380 movsb 381 popl %edi 382 popl %esi 383 ret 384 385 ALIGN_TEXT 3861: 387 addl %ecx,%edi /* copy backwards */ 388 addl %ecx,%esi 389 andl $1,%ecx /* any fractional bytes? */ 390 decl %edi 391 decl %esi 392 std 393 rep 394 movsb 395 movl 20(%esp),%ecx /* copy remainder by 16-bit words */ 396 shrl $1,%ecx 397 decl %esi 398 decl %edi 399 rep 400 movsw 401 popl %edi 402 popl %esi 403 cld 404 ret 405 406ENTRY(bcopyx) 407 movl 16(%esp),%eax 408 cmpl $2,%eax 409 je bcopyw /* not _bcopyw, to avoid multiple mcounts */ 410 cmpl $4,%eax 411 je bcopy /* XXX the shared ret's break mexitcount */ 412 jmp bcopyb 413 414/* 415 * (ov)bcopy(src, dst, cnt) 416 * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 417 */ 418ALTENTRY(ovbcopy) 419ENTRY(bcopy) 420bcopy: 421 pushl %esi 422 pushl %edi 423 movl 12(%esp),%esi 424 movl 16(%esp),%edi 425 movl 20(%esp),%ecx 426 cmpl %esi,%edi /* potentially overlapping? */ 427 jnb 1f 428 shrl $2,%ecx /* copy by 32-bit words */ 429 cld /* nope, copy forwards */ 430 rep 431 movsl 432 movl 20(%esp),%ecx 433 andl $3,%ecx /* any bytes left? */ 434 rep 435 movsb 436 popl %edi 437 popl %esi 438 ret 439 440 ALIGN_TEXT 4411: 442 addl %ecx,%edi /* copy backwards */ 443 addl %ecx,%esi 444 andl $3,%ecx /* any fractional bytes? */ 445 decl %edi 446 decl %esi 447 std 448 rep 449 movsb 450 movl 20(%esp),%ecx /* copy remainder by 32-bit words */ 451 shrl $2,%ecx 452 subl $3,%esi 453 subl $3,%edi 454 rep 455 movsl 456 popl %edi 457 popl %esi 458 cld 459 ret 460 461ALTENTRY(ntohl) 462ENTRY(htonl) 463 movl 4(%esp),%eax 464#ifdef i486 465/* XXX */ 466/* Since Gas 1.38 does not grok bswap this has been coded as the 467 * equivalent bytes. This can be changed back to bswap when we 468 * upgrade to a newer version of Gas 469 */ 470 /* bswap %eax */ 471 .byte 0x0f 472 .byte 0xc8 473#else 474 xchgb %al,%ah 475 roll $16,%eax 476 xchgb %al,%ah 477#endif 478 ret 479 480ALTENTRY(ntohs) 481ENTRY(htons) 482 movzwl 4(%esp),%eax 483 xchgb %al,%ah 484 ret 485 486/*****************************************************************************/ 487/* copyout and fubyte family */ 488/*****************************************************************************/ 489/* 490 * Access user memory from inside the kernel. These routines and possibly 491 * the math- and DOS emulators should be the only places that do this. 492 * 493 * We have to access the memory with user's permissions, so use a segment 494 * selector with RPL 3. For writes to user space we have to additionally 495 * check the PTE for write permission, because the 386 does not check 496 * write permissions when we are executing with EPL 0. The 486 does check 497 * this if the WP bit is set in CR0, so we can use a simpler version here. 498 * 499 * These routines set curpcb->onfault for the time they execute. When a 500 * protection violation occurs inside the functions, the trap handler 501 * returns to *curpcb->onfault instead of the function. 502 */ 503 504 505ENTRY(copyout) /* copyout(from_kernel, to_user, len) */ 506 movl _curpcb,%eax 507 movl $copyout_fault,PCB_ONFAULT(%eax) 508 pushl %esi 509 pushl %edi 510 pushl %ebx 511 movl 16(%esp),%esi 512 movl 20(%esp),%edi 513 movl 24(%esp),%ebx 514 orl %ebx,%ebx /* anything to do? */ 515 jz done_copyout 516 517 /* 518 * Check explicitly for non-user addresses. If 486 write protection 519 * is being used, this check is essential because we are in kernel 520 * mode so the h/w does not provide any protection against writing 521 * kernel addresses. 522 * 523 * Otherwise, it saves having to load and restore %es to get the 524 * usual segment-based protection (the destination segment for movs 525 * is always %es). The other explicit checks for user-writablility 526 * are not quite sufficient. They fail for the user area because 527 * we mapped the user area read/write to avoid having an #ifdef in 528 * vm_machdep.c. They fail for user PTEs and/or PTDs! (107 529 * addresses including 0xff800000 and 0xfc000000). I'm not sure if 530 * this can be fixed. Marking the PTEs supervisor mode and the 531 * PDE's user mode would almost work, but there may be a problem 532 * with the self-referential PDE. 533 */ 534 movl %edi,%eax 535 addl %ebx,%eax 536 jc copyout_fault 537/* 538 * XXX STOP USING VM_MAXUSER_ADDRESS. 539 * It is an end address, not a max, so every time it is used correctly it 540 * looks like there is an off by one error, and of course it caused an off 541 * by one error in several places. 542 */ 543 cmpl $VM_MAXUSER_ADDRESS,%eax 544 ja copyout_fault 545 546#if defined(I386_CPU) 547 548#if defined(I486_CPU) || defined(I586_CPU) 549 cmpl $CPUCLASS_386,_cpu_class 550 jne 3f 551#endif 552/* 553 * We have to check each PTE for user write permission. 554 * The checking may cause a page fault, so it is important to set 555 * up everything for return via copyout_fault before here. 556 */ 557 /* compute number of pages */ 558 movl %edi,%ecx 559 andl $NBPG-1,%ecx 560 addl %ebx,%ecx 561 decl %ecx 562 shrl $IDXSHIFT+2,%ecx 563 incl %ecx 564 565 /* compute PTE offset for start address */ 566 movl %edi,%edx 567 shrl $IDXSHIFT,%edx 568 andb $0xfc,%dl 569 5701: /* check PTE for each page */ 571 movb _PTmap(%edx),%al 572 andb $0x07,%al /* Pages must be VALID + USERACC + WRITABLE */ 573 cmpb $0x07,%al 574 je 2f 575 576 /* simulate a trap */ 577 pushl %edx 578 pushl %ecx 579 shll $IDXSHIFT,%edx 580 pushl %edx 581 call _trapwrite /* trapwrite(addr) */ 582 popl %edx 583 popl %ecx 584 popl %edx 585 586 orl %eax,%eax /* if not ok, return EFAULT */ 587 jnz copyout_fault 588 5892: 590 addl $4,%edx 591 decl %ecx 592 jnz 1b /* check next page */ 593#endif /* I386_CPU */ 594 595 /* bcopy(%esi, %edi, %ebx) */ 5963: 597 movl %ebx,%ecx 598 shrl $2,%ecx 599 cld 600 rep 601 movsl 602 movb %bl,%cl 603 andb $3,%cl 604 rep 605 movsb 606 607done_copyout: 608 popl %ebx 609 popl %edi 610 popl %esi 611 xorl %eax,%eax 612 movl _curpcb,%edx 613 movl %eax,PCB_ONFAULT(%edx) 614 ret 615 616 ALIGN_TEXT 617copyout_fault: 618 popl %ebx 619 popl %edi 620 popl %esi 621 movl _curpcb,%edx 622 movl $0,PCB_ONFAULT(%edx) 623 movl $EFAULT,%eax 624 ret 625 626/* copyin(from_user, to_kernel, len) */ 627ENTRY(copyin) 628 movl _curpcb,%eax 629 movl $copyin_fault,PCB_ONFAULT(%eax) 630 pushl %esi 631 pushl %edi 632 movl 12(%esp),%esi /* caddr_t from */ 633 movl 16(%esp),%edi /* caddr_t to */ 634 movl 20(%esp),%ecx /* size_t len */ 635 636 /* 637 * make sure address is valid 638 */ 639 movl %esi,%edx 640 addl %ecx,%edx 641 jc copyin_fault 642 cmpl $VM_MAXUSER_ADDRESS,%edx 643 ja copyin_fault 644 645 movb %cl,%al 646 shrl $2,%ecx /* copy longword-wise */ 647 cld 648 rep 649 movsl 650 movb %al,%cl 651 andb $3,%cl /* copy remaining bytes */ 652 rep 653 movsb 654 655 popl %edi 656 popl %esi 657 xorl %eax,%eax 658 movl _curpcb,%edx 659 movl %eax,PCB_ONFAULT(%edx) 660 ret 661 662 ALIGN_TEXT 663copyin_fault: 664 popl %edi 665 popl %esi 666 movl _curpcb,%edx 667 movl $0,PCB_ONFAULT(%edx) 668 movl $EFAULT,%eax 669 ret 670 671/* 672 * fu{byte,sword,word} : fetch a byte (sword, word) from user memory 673 */ 674ALTENTRY(fuiword) 675ENTRY(fuword) 676 movl _curpcb,%ecx 677 movl $fusufault,PCB_ONFAULT(%ecx) 678 movl 4(%esp),%edx /* from */ 679 680 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */ 681 ja fusufault 682 683 movl (%edx),%eax 684 movl $0,PCB_ONFAULT(%ecx) 685 ret 686 687/* 688 * These two routines are called from the profiling code, potentially 689 * at interrupt time. If they fail, that's okay, good things will 690 * happen later. Fail all the time for now - until the trap code is 691 * able to deal with this. 692 */ 693ALTENTRY(suswintr) 694ENTRY(fuswintr) 695 movl $-1,%eax 696 ret 697 698ENTRY(fusword) 699 movl _curpcb,%ecx 700 movl $fusufault,PCB_ONFAULT(%ecx) 701 movl 4(%esp),%edx 702 703 cmpl $VM_MAXUSER_ADDRESS-2,%edx 704 ja fusufault 705 706 movzwl (%edx),%eax 707 movl $0,PCB_ONFAULT(%ecx) 708 ret 709 710ALTENTRY(fuibyte) 711ENTRY(fubyte) 712 movl _curpcb,%ecx 713 movl $fusufault,PCB_ONFAULT(%ecx) 714 movl 4(%esp),%edx 715 716 cmpl $VM_MAXUSER_ADDRESS-1,%edx 717 ja fusufault 718 719 movzbl (%edx),%eax 720 movl $0,PCB_ONFAULT(%ecx) 721 ret 722 723 ALIGN_TEXT 724fusufault: 725 movl _curpcb,%ecx 726 xorl %eax,%eax 727 movl %eax,PCB_ONFAULT(%ecx) 728 decl %eax 729 ret 730 731/* 732 * su{byte,sword,word}: write a byte (word, longword) to user memory 733 */ 734ALTENTRY(suiword) 735ENTRY(suword) 736 movl _curpcb,%ecx 737 movl $fusufault,PCB_ONFAULT(%ecx) 738 movl 4(%esp),%edx 739 740#if defined(I386_CPU) 741 742#if defined(I486_CPU) || defined(I586_CPU) 743 cmpl $CPUCLASS_386,_cpu_class 744 jne 2f /* we only have to set the right segment selector */ 745#endif /* I486_CPU || I586_CPU */ 746 747 /* XXX - page boundary crossing is still not handled */ 748 movl %edx,%eax 749 shrl $IDXSHIFT,%edx 750 andb $0xfc,%dl 751 movb _PTmap(%edx),%dl 752 andb $0x7,%dl /* must be VALID + USERACC + WRITE */ 753 cmpb $0x7,%dl 754 je 1f 755 756 /* simulate a trap */ 757 pushl %eax 758 call _trapwrite 759 popl %edx /* remove junk parameter from stack */ 760 movl _curpcb,%ecx /* restore trashed register */ 761 orl %eax,%eax 762 jnz fusufault 7631: 764 movl 4(%esp),%edx 765#endif 766 7672: 768 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */ 769 ja fusufault 770 771 movl 8(%esp),%eax 772 movl %eax,(%edx) 773 xorl %eax,%eax 774 movl %eax,PCB_ONFAULT(%ecx) 775 ret 776 777ENTRY(susword) 778 movl _curpcb,%ecx 779 movl $fusufault,PCB_ONFAULT(%ecx) 780 movl 4(%esp),%edx 781 782#if defined(I386_CPU) 783 784#if defined(I486_CPU) || defined(I586_CPU) 785 cmpl $CPUCLASS_386,_cpu_class 786 jne 2f 787#endif /* I486_CPU || I586_CPU */ 788 789 /* XXX - page boundary crossing is still not handled */ 790 movl %edx,%eax 791 shrl $IDXSHIFT,%edx 792 andb $0xfc,%dl 793 movb _PTmap(%edx),%dl 794 andb $0x7,%dl /* must be VALID + USERACC + WRITE */ 795 cmpb $0x7,%dl 796 je 1f 797 798 /* simulate a trap */ 799 pushl %eax 800 call _trapwrite 801 popl %edx /* remove junk parameter from stack */ 802 movl _curpcb,%ecx /* restore trashed register */ 803 orl %eax,%eax 804 jnz fusufault 8051: 806 movl 4(%esp),%edx 807#endif 808 8092: 810 cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */ 811 ja fusufault 812 813 movw 8(%esp),%ax 814 movw %ax,(%edx) 815 xorl %eax,%eax 816 movl %eax,PCB_ONFAULT(%ecx) 817 ret 818 819ALTENTRY(suibyte) 820ENTRY(subyte) 821 movl _curpcb,%ecx 822 movl $fusufault,PCB_ONFAULT(%ecx) 823 movl 4(%esp),%edx 824 825#if defined(I386_CPU) 826 827#if defined(I486_CPU) || defined(I586_CPU) 828 cmpl $CPUCLASS_386,_cpu_class 829 jne 2f 830#endif /* I486_CPU || I586_CPU */ 831 832 movl %edx,%eax 833 shrl $IDXSHIFT,%edx 834 andb $0xfc,%dl 835 movb _PTmap(%edx),%dl 836 andb $0x7,%dl /* must be VALID + USERACC + WRITE */ 837 cmpb $0x7,%dl 838 je 1f 839 840 /* simulate a trap */ 841 pushl %eax 842 call _trapwrite 843 popl %edx /* remove junk parameter from stack */ 844 movl _curpcb,%ecx /* restore trashed register */ 845 orl %eax,%eax 846 jnz fusufault 8471: 848 movl 4(%esp),%edx 849#endif 850 8512: 852 cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */ 853 ja fusufault 854 855 movb 8(%esp),%al 856 movb %al,(%edx) 857 xorl %eax,%eax 858 movl %eax,PCB_ONFAULT(%ecx) 859 ret 860 861/* 862 * copyoutstr(from, to, maxlen, int *lencopied) 863 * copy a string from from to to, stop when a 0 character is reached. 864 * return ENAMETOOLONG if string is longer than maxlen, and 865 * EFAULT on protection violations. If lencopied is non-zero, 866 * return the actual length in *lencopied. 867 */ 868ENTRY(copyoutstr) 869 pushl %esi 870 pushl %edi 871 movl _curpcb,%ecx 872 movl $cpystrflt,PCB_ONFAULT(%ecx) /* XXX rename copyoutstr_fault */ 873 874 movl 12(%esp),%esi /* %esi = from */ 875 movl 16(%esp),%edi /* %edi = to */ 876 movl 20(%esp),%edx /* %edx = maxlen */ 877 cld 878 879#if defined(I386_CPU) 880 881#if defined(I486_CPU) || defined(I586_CPU) 882 cmpl $CPUCLASS_386,_cpu_class 883 jne 5f 884#endif /* I486_CPU || I586_CPU */ 885 8861: 887 /* 888 * It suffices to check that the first byte is in user space, because 889 * we look at a page at a time and the end address is on a page 890 * boundary. 891 */ 892 cmpl $VM_MAXUSER_ADDRESS-1,%edi 893 ja cpystrflt 894 895 movl %edi,%eax 896 shrl $IDXSHIFT,%eax 897 andb $0xfc,%al 898 movb _PTmap(%eax),%al 899 andb $7,%al 900 cmpb $7,%al 901 je 2f 902 903 /* simulate trap */ 904 pushl %edx 905 pushl %edi 906 call _trapwrite 907 cld 908 popl %edi 909 popl %edx 910 orl %eax,%eax 911 jnz cpystrflt 912 9132: /* copy up to end of this page */ 914 movl %edi,%eax 915 andl $NBPG-1,%eax 916 movl $NBPG,%ecx 917 subl %eax,%ecx /* ecx = NBPG - (src % NBPG) */ 918 cmpl %ecx,%edx 919 jae 3f 920 movl %edx,%ecx /* ecx = min(ecx, edx) */ 9213: 922 orl %ecx,%ecx 923 jz 4f 924 decl %ecx 925 decl %edx 926 lodsb 927 stosb 928 orb %al,%al 929 jnz 3b 930 931 /* Success -- 0 byte reached */ 932 decl %edx 933 xorl %eax,%eax 934 jmp 6f 935 9364: /* next page */ 937 orl %edx,%edx 938 jnz 1b 939 940 /* edx is zero -- return ENAMETOOLONG */ 941 movl $ENAMETOOLONG,%eax 942 jmp cpystrflt_x 943#endif /* I386_CPU */ 944 945#if defined(I486_CPU) || defined(I586_CPU) 9465: 947 incl %edx 9481: 949 decl %edx 950 jz 2f 951 /* 952 * XXX - would be faster to rewrite this function to use 953 * strlen() and copyout(). 954 */ 955 cmpl $VM_MAXUSER_ADDRESS-1,%edi 956 ja cpystrflt 957 958 lodsb 959 stosb 960 orb %al,%al 961 jnz 1b 962 963 /* Success -- 0 byte reached */ 964 decl %edx 965 xorl %eax,%eax 966 jmp cpystrflt_x 9672: 968 /* edx is zero -- return ENAMETOOLONG */ 969 movl $ENAMETOOLONG,%eax 970 jmp cpystrflt_x 971 972#endif /* I486_CPU || I586_CPU */ 973 974/* 975 * This was split from copyinstr_fault mainly because pushing gs changes the 976 * stack offsets. It's better to have it separate for mcounting too. 977 */ 978cpystrflt: 979 movl $EFAULT,%eax 980cpystrflt_x: 981 /* set *lencopied and return %eax */ 982 movl _curpcb,%ecx 983 movl $0,PCB_ONFAULT(%ecx) 984 movl 20(%esp),%ecx 985 subl %edx,%ecx 986 movl 24(%esp),%edx 987 orl %edx,%edx 988 jz 1f 989 movl %ecx,(%edx) 9901: 991 popl %edi 992 popl %esi 993 ret 994 995 996/* 997 * copyinstr(from, to, maxlen, int *lencopied) 998 * copy a string from from to to, stop when a 0 character is reached. 999 * return ENAMETOOLONG if string is longer than maxlen, and 1000 * EFAULT on protection violations. If lencopied is non-zero, 1001 * return the actual length in *lencopied. 1002 */ 1003ENTRY(copyinstr) 1004 pushl %esi 1005 pushl %edi 1006 movl _curpcb,%ecx 1007 movl $copyinstr_fault,PCB_ONFAULT(%ecx) 1008 1009 movl 12(%esp),%esi /* %esi = from */ 1010 movl 16(%esp),%edi /* %edi = to */ 1011 movl 20(%esp),%edx /* %edx = maxlen */ 1012 /* 1013 * XXX should avoid touching gs. Either copy the string in and 1014 * check the bounds later or get its length and check the bounds 1015 * and then use copyin(). 1016 */ 1017 pushl %gs 1018 movl __udatasel,%eax 1019 movl %ax,%gs 1020 incl %edx 1021 cld 10221: 1023 decl %edx 1024 jz 2f 1025 gs 1026 lodsb 1027 stosb 1028 orb %al,%al 1029 jnz 1b 1030 1031 /* Success -- 0 byte reached */ 1032 decl %edx 1033 xorl %eax,%eax 1034 jmp 3f 10352: 1036 /* edx is zero -- return ENAMETOOLONG */ 1037 movl $ENAMETOOLONG,%eax 1038 jmp 3f 1039 1040 ALIGN_TEXT 1041copyinstr_fault: 1042 movl $EFAULT,%eax 10433: 1044 /* set *lencopied and return %eax */ 1045 movl _curpcb,%ecx 1046 movl $0,PCB_ONFAULT(%ecx) 1047 movl 24(%esp),%ecx 1048 subl %edx,%ecx 1049 movl 28(%esp),%edx 1050 orl %edx,%edx 1051 jz 4f 1052 movl %ecx,(%edx) 10534: 1054 popl %gs 1055 popl %edi 1056 popl %esi 1057 ret 1058 1059 1060/* 1061 * copystr(from, to, maxlen, int *lencopied) 1062 */ 1063ENTRY(copystr) 1064 pushl %esi 1065 pushl %edi 1066 1067 movl 12(%esp),%esi /* %esi = from */ 1068 movl 16(%esp),%edi /* %edi = to */ 1069 movl 20(%esp),%edx /* %edx = maxlen */ 1070 incl %edx 1071 cld 10721: 1073 decl %edx 1074 jz 4f 1075 lodsb 1076 stosb 1077 orb %al,%al 1078 jnz 1b 1079 1080 /* Success -- 0 byte reached */ 1081 decl %edx 1082 xorl %eax,%eax 1083 jmp 6f 10844: 1085 /* edx is zero -- return ENAMETOOLONG */ 1086 movl $ENAMETOOLONG,%eax 1087 10886: 1089 /* set *lencopied and return %eax */ 1090 movl 20(%esp),%ecx 1091 subl %edx,%ecx 1092 movl 24(%esp),%edx 1093 orl %edx,%edx 1094 jz 7f 1095 movl %ecx,(%edx) 10967: 1097 popl %edi 1098 popl %esi 1099 ret 1100 1101/* 1102 * Handling of special 386 registers and descriptor tables etc 1103 */ 1104/* void lgdt(struct region_descriptor *rdp); */ 1105ENTRY(lgdt) 1106 /* reload the descriptor table */ 1107 movl 4(%esp),%eax 1108 lgdt (%eax) 1109 1110 /* flush the prefetch q */ 1111 jmp 1f 1112 nop 11131: 1114 /* reload "stale" selectors */ 1115 movl $KDSEL,%eax 1116 movl %ax,%ds 1117 movl %ax,%es 1118 movl %ax,%ss 1119 1120 /* reload code selector by turning return into intersegmental return */ 1121 movl (%esp),%eax 1122 pushl %eax 1123# movl $KCSEL,4(%esp) 1124 movl $8,4(%esp) 1125 lret 1126 1127/* 1128 * void lidt(struct region_descriptor *rdp); 1129 */ 1130ENTRY(lidt) 1131 movl 4(%esp),%eax 1132 lidt (%eax) 1133 ret 1134 1135/* 1136 * void lldt(u_short sel) 1137 */ 1138ENTRY(lldt) 1139 lldt 4(%esp) 1140 ret 1141 1142/* 1143 * void ltr(u_short sel) 1144 */ 1145ENTRY(ltr) 1146 ltr 4(%esp) 1147 ret 1148 1149/* ssdtosd(*ssdp,*sdp) */ 1150ENTRY(ssdtosd) 1151 pushl %ebx 1152 movl 8(%esp),%ecx 1153 movl 8(%ecx),%ebx 1154 shll $16,%ebx 1155 movl (%ecx),%edx 1156 roll $16,%edx 1157 movb %dh,%bl 1158 movb %dl,%bh 1159 rorl $8,%ebx 1160 movl 4(%ecx),%eax 1161 movw %ax,%dx 1162 andl $0xf0000,%eax 1163 orl %eax,%ebx 1164 movl 12(%esp),%ecx 1165 movl %edx,(%ecx) 1166 movl %ebx,4(%ecx) 1167 popl %ebx 1168 ret 1169 1170/* load_cr0(cr0) */ 1171ENTRY(load_cr0) 1172 movl 4(%esp),%eax 1173 movl %eax,%cr0 1174 ret 1175 1176/* rcr0() */ 1177ENTRY(rcr0) 1178 movl %cr0,%eax 1179 ret 1180 1181/* rcr3() */ 1182ENTRY(rcr3) 1183 movl %cr3,%eax 1184 ret 1185 1186/* void load_cr3(caddr_t cr3) */ 1187ENTRY(load_cr3) 1188 movl 4(%esp),%eax 1189 orl $I386_CR3PAT,%eax 1190 movl %eax,%cr3 1191 ret 1192 1193 1194/*****************************************************************************/ 1195/* setjump, longjump */ 1196/*****************************************************************************/ 1197 1198ENTRY(setjmp) 1199 movl 4(%esp),%eax 1200 movl %ebx,(%eax) /* save ebx */ 1201 movl %esp,4(%eax) /* save esp */ 1202 movl %ebp,8(%eax) /* save ebp */ 1203 movl %esi,12(%eax) /* save esi */ 1204 movl %edi,16(%eax) /* save edi */ 1205 movl (%esp),%edx /* get rta */ 1206 movl %edx,20(%eax) /* save eip */ 1207 xorl %eax,%eax /* return(0); */ 1208 ret 1209 1210ENTRY(longjmp) 1211 movl 4(%esp),%eax 1212 movl (%eax),%ebx /* restore ebx */ 1213 movl 4(%eax),%esp /* restore esp */ 1214 movl 8(%eax),%ebp /* restore ebp */ 1215 movl 12(%eax),%esi /* restore esi */ 1216 movl 16(%eax),%edi /* restore edi */ 1217 movl 20(%eax),%edx /* get rta */ 1218 movl %edx,(%esp) /* put in return frame */ 1219 xorl %eax,%eax /* return(1); */ 1220 incl %eax 1221 ret 1222