1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)locore.s 7.10 (Berkeley) 10/11/92 11 */ 12 13#include "assym.s" 14#include <machine/psl.h> 15#include <machine/pte.h> 16 17#include <sys/errno.h> 18 19#include <machine/trap.h> 20 21#include "npx.h" 22 23/* 24 * Note: This version greatly munged to avoid various assembler errors 25 * that may be fixed in newer versions of gas. Perhaps newer versions 26 * will have more pleasant appearance. 27 */ 28 29 .set IDXSHIFT,10 30 .set SYSTEM,0xFE000000 # virtual address of system start 31 /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ 32 .set SYSPDROFF,0x3F8 # Page dir index of System Base 33 34/* IBM "compatible" nop - sensitive macro on "fast" 386 machines */ 35#define NOP ; 36 37/* 38 * PTmap is recursive pagemap at top of virtual address space. 39 * Within PTmap, the page directory can be found (third indirection). 40 */ 41 .set PDRPDROFF,0x3F7 # Page dir index of Page dir 42 .globl _PTmap, _PTD, _PTDpde 43 .set _PTmap,0xFDC00000 44 .set _PTD,0xFDFF7000 45 .set _PTDpde,0xFDFF7000+4*PDRPDROFF 46 47/* 48 * APTmap, APTD is the alternate recursive pagemap. 49 * It's used when modifying another process's page tables. 50 */ 51 .set APDRPDROFF,0x3FE # Page dir index of Page dir 52 .globl _APTmap, _APTD, _APTDpde 53 .set _APTmap,0xFF800000 54 .set _APTD,0xFFBFE000 55 .set _APTDpde,0xFDFF7000+4*APDRPDROFF 56 57/* 58 * Access to each processes kernel stack is via a region of 59 * per-process address space (at the beginning), immediatly above 60 * the user process stack. 61 */ 62 .set _kstack, USRSTACK 63 .globl _kstack 64 .set PPDROFF,0x3F6 65 .set PPTEOFF,0x400-UPAGES # 0x3FE 66 67#define ENTRY(name) \ 68 .globl _/**/name; _/**/name: 69#define ALTENTRY(name) \ 70 .globl _/**/name; _/**/name: 71 72/* 73 * Initialization 74 */ 75 .data 76 .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys 77_cpu: .long 0 # are we 386, 386sx, or 486 78_cold: .long 1 # cold till we are not 79_atdevbase: .long 0 # location of start of iomem in virtual 80_atdevphys: .long 0 # location of device mapping ptes (phys) 81 82 .globl _IdlePTD, _KPTphys 83_IdlePTD: .long 0 84_KPTphys: .long 0 85 86pcb: 87 .space 8192 88tmpstk: 89pcb2: 90 .space 8192 91tmpstk2: 92 .text 93 .globl start 94 #start: 95 .set start,0 96 movw $0x1234,%ax 97 movw %ax,0x472 # warm boot 98 jmp 1f 99 .space 0x500 # skip over warm boot shit 100 101 /* enable a20! yecchh!! - move this to bootstrap? */ 1021: inb $0x64,%al 103 andb $2,%al 104 jnz 1b 105 movb $0xd1,%al 106 NOP 107 outb %al,$0x64 108 NOP 1091: inb $0x64,%al 110 andb $2,%al 111 jnz 1b 112 movb $0xdf,%al 113 NOP 114 outb %al,$0x60 115 116 /* 117 * pass parameters on stack (howto, bootdev, unit, cyloffset) 118 * note: 0(%esp) is return address of boot 119 * ( if we want to hold onto /boot, it's physical %esp up to _end) 120 */ 121 122 1: movl 4(%esp),%eax 123 movl %eax,_boothowto-SYSTEM 124 movl 8(%esp),%eax 125 movl %eax,_bootdev-SYSTEM 126 movl 12(%esp),%eax 127 movl %eax, _cyloffset-SYSTEM 128 129 /* count up memory */ 130 131 xorl %edx,%edx # start with base memory at 0x0 132 #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K 133 movl $ 0xA0,%ecx # look every 4K up to 640K 1341: movl 0(%edx),%ebx # save location to check 135 movl $0xa55a5aa5,0(%edx) # write test pattern 136 137 inb $0x84,%al # flush write buffer 138 /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */ 139 140 cmpl $0xa55a5aa5,0(%edx) # does not check yet for rollover 141 jne 2f 142 movl %ebx,0(%edx) # restore memory 143 addl $ NBPG,%edx 144 loop 1b 145 146 movl $0x100000,%edx # next, talley remaining memory 147 #movl $((0xFFF000-0x100000)/NBPG),%ecx 148 movl $(0xFFF-0x100),%ecx 1491: movl 0(%edx),%ebx # save location to check 150 movl $0xa55a5aa5,0(%edx) # write test pattern 151 cmpl $0xa55a5aa5,0(%edx) # does not check yet for rollover 152 jne 2f 153 movl %ebx,0(%edx) # restore memory 154 addl $ NBPG,%edx 155 loop 1b 1562: shrl $12,%edx 157 movl %edx,_Maxmem-SYSTEM 158 159/* find end of kernel image */ 160 movl $_end-SYSTEM,%ecx 161 addl $ NBPG-1,%ecx 162 andl $~(NBPG-1),%ecx 163 movl %ecx,%esi 164 165/* clear bss and memory for bootstrap pagetables. */ 166 movl $_edata-SYSTEM,%edi 167 subl %edi,%ecx 168 addl $(UPAGES+5)*NBPG,%ecx 169/* 170 * Virtual address space of kernel: 171 * 172 * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap 173 * 0 1 2 3 4 174 */ 175 xorl %eax,%eax # pattern 176 cld 177 rep 178 stosb 179 180 movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */ 181 movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location 182 183#define fillkpt \ 1841: movl %eax,0(%ebx) ; \ 185 addl $ NBPG,%eax ; /* increment physical address */ \ 186 addl $4,%ebx ; /* next pte */ \ 187 loop 1b ; 188 189/* 190 * Map Kernel 191 * N.B. don't bother with making kernel text RO, as 386 192 * ignores R/W AND U/S bits on kernel access (only v works) ! 193 * 194 * First step - build page tables 195 */ 196 movl %esi,%ecx # this much memory, 197 shrl $ PGSHIFT,%ecx # for this many pte s 198 addl $ UPAGES+4,%ecx # including our early context 199 movl $ PG_V,%eax # having these bits set, 200 lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0, 201 movl %ebx,_KPTphys-SYSTEM # in the kernel page table, 202 fillkpt 203 204/* map I/O memory map */ 205 206 movl $0x100-0xa0,%ecx # for this many pte s, 207 movl $(0xa0000|PG_V),%eax # having these bits set, (perhaps URW?) 208 movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes 209 fillkpt 210 211 /* map proc 0's kernel stack into user page table page */ 212 213 movl $ UPAGES,%ecx # for this many pte s, 214 lea (1*NBPG)(%esi),%eax # physical address in proc 0 215 lea (SYSTEM)(%eax),%edx 216 movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init 217 orl $ PG_V|PG_URKW,%eax # having these bits set, 218 lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0 219 addl $(PPTEOFF*4),%ebx 220 fillkpt 221 222/* 223 * Construct a page table directory 224 * (of page directory elements - pde's) 225 */ 226 /* install a pde for temporary double map of bottom of VA */ 227 lea (4*NBPG)(%esi),%eax # physical address of kernel page table 228 orl $ PG_V,%eax # pde entry is valid 229 movl %eax,(%esi) # which is where temp maps! 230 231 /* kernel pde's */ 232 movl $ 3,%ecx # for this many pde s, 233 lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel 234 fillkpt 235 236 /* install a pde recursively mapping page directory as a page table! */ 237 movl %esi,%eax # phys address of ptd in proc 0 238 orl $ PG_V,%eax # pde entry is valid 239 movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps! 240 241 /* install a pde to map kernel stack for proc 0 */ 242 lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0 243 orl $ PG_V,%eax # pde entry is valid 244 movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps! 245 246 /* load base of page directory, and enable mapping */ 247 movl %esi,%eax # phys address of ptd in proc 0 248 orl $ I386_CR3PAT,%eax 249 movl %eax,%cr3 # load ptd addr into mmu 250 movl %cr0,%eax # get control word 251 orl $0x80000001,%eax # and let s page! 252 movl %eax,%cr0 # NOW! 253 254 pushl $begin # jump to high mem! 255 ret 256 257begin: /* now running relocated at SYSTEM where the system is linked to run */ 258 259 .globl _Crtat 260 movl _Crtat,%eax 261 subl $0xfe0a0000,%eax 262 movl _atdevphys,%edx # get pte PA 263 subl _KPTphys,%edx # remove base of ptes, now have phys offset 264 shll $ PGSHIFT-2,%edx # corresponding to virt offset 265 addl $ SYSTEM,%edx # add virtual base 266 movl %edx, _atdevbase 267 addl %eax,%edx 268 movl %edx,_Crtat 269 270 /* set up bootstrap stack */ 271 movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location 272 xorl %eax,%eax # mark end of frames 273 movl %eax,%ebp 274 movl _proc0paddr, %eax 275 movl %esi, PCB_CR3(%eax) 276 277 lea 7*NBPG(%esi),%esi # skip past stack. 278 pushl %esi 279 280 call _init386 # wire 386 chip for unix operation 281 popl %esi 282 283 movl $0,_PTD 284 call _main 285 286 .globl __ucodesel,__udatasel 287 movzwl __ucodesel,%eax 288 movzwl __udatasel,%ecx 289 # build outer stack frame 290 pushl %ecx # user ss 291 pushl $ USRSTACK # user esp 292 pushl %eax # user cs 293 pushl $0 # user ip 294 movw %cx,%ds 295 movw %cx,%es 296 # movw %ax,%fs # double map cs to fs 297 # movw %cx,%gs # and ds to gs 298 lret # goto user! 299 300 pushl $lretmsg1 /* "should never get here!" */ 301 call _panic 302lretmsg1: 303 .asciz "lret: toinit\n" 304 305 .globl __exit 306__exit: 307 call _reset_cpu 308 /* NOTREACHED */ 309 310 .set exec,59 311 .set exit,1 312 .globl _icode 313 .globl _szicode 314 315#define LCALL(x,y) .byte 0x9a ; .long y; .word x 316/* 317 * Icode is copied out to process 1 to exec /etc/init. 318 * If the exec fails, process 1 exits. 319 */ 320_icode: 321 pushl $0 /* environment */ 322 323 # pushl $argv-_icode # gas fucks up again 324 movl $argv,%eax 325 subl $_icode,%eax 326 pushl %eax 327 328 # pushl $init-_icode 329 movl $init,%eax 330 subl $_icode,%eax 331 pushl %eax 332 pushl %eax # dummy out rta 333 334 movl %esp,%ebp 335 movl $exec,%eax 336 LCALL(0x7,0x0) 337 pushl %eax 338 movl $exit,%eax 339 pushl %eax # dummy out rta 340 LCALL(0x7,0x0) 341 342init: 343 .asciz "/sbin/init" 344 .align 2 345argv: 346 .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6) 347 .long eicode-_icode # argv[1] follows icode after copyout 348 .long 0 349eicode: 350 351_szicode: 352 .long _szicode-_icode 353 354 .globl _sigcode,_szsigcode 355_sigcode: 356 movl 12(%esp),%eax # unsure if call will dec stack 1st 357 call %eax 358 xorl %eax,%eax # smaller movl $103,%eax 359 movb $103,%al # sigreturn() 360 LCALL(0x7,0) # enter kernel with args on stack 361 hlt # never gets here 362 363_szsigcode: 364 .long _szsigcode-_sigcode 365 366 .globl ___udivsi3 367___udivsi3: 368 movl 4(%esp),%eax 369 xorl %edx,%edx 370 divl 8(%esp) 371 ret 372 373 .globl ___divsi3 374___divsi3: 375 movl 4(%esp),%eax 376 xorl %edx,%edx 377 cltd 378 idivl 8(%esp) 379 ret 380 381 .globl _inb 382_inb: movl 4(%esp),%edx 383 # inb $0x84,%al # Compaq SystemPro 384 subl %eax,%eax # clr eax 385 NOP 386 inb %dx,%al 387 NOP 388 ret 389 390 391 .globl _rtcin 392_rtcin: movl 4(%esp),%eax 393 outb %al,$0x70 394 subl %eax,%eax # clr eax 395 inb $0x71,%al # Compaq SystemPro 396 ret 397 398 .globl _outb 399_outb: movl 4(%esp),%edx 400 movl 8(%esp),%eax 401 NOP 402 outb %al,%dx 403 # inb $0x84,%al 404 NOP 405 ret 406 407 # 408 # bzero (base,cnt) 409 # 410 411 .globl _bzero 412 .globl _blkclr 413_bzero: 414_blkclr: 415 pushl %edi 416 movl 8(%esp),%edi 417 movl 12(%esp),%ecx 418 xorl %eax,%eax 419 shrl $2,%ecx 420 cld 421 rep 422 stosl 423 movl 12(%esp),%ecx 424 andl $3,%ecx 425 rep 426 stosb 427 popl %edi 428 ret 429 430 # 431 # fillw (pat,base,cnt) 432 # 433 434 .globl _fillw 435_fillw: 436 pushl %edi 437 movl 8(%esp),%eax 438 movl 12(%esp),%edi 439 movl 16(%esp),%ecx 440 cld 441 rep 442 stosw 443 popl %edi 444 ret 445 446 # 447 # bcopy (src,dst,cnt) 448 # NOTE: does not (yet) handle overlapped copies 449 # 450 451 .globl _bcopy 452_bcopy: 453 pushl %esi 454 pushl %edi 455 movl 12(%esp),%esi 456 movl 16(%esp),%edi 457 movl 20(%esp),%ecx 458 shrl $2,%ecx 459 cld 460 rep 461 movsl 462 movl 20(%esp),%ecx 463 andl $3,%ecx 464 rep 465 movsb 466 popl %edi 467 popl %esi 468 xorl %eax,%eax 469 ret 470 471 # 472 # ovbcopy (src,dst,cnt) 473 # NOTE: does not (yet) work doing words at a time 474 # 475 476 .globl _ovbcopy 477_ovbcopy: 478 pushl %esi 479 pushl %edi 480 movl 12(%esp),%esi 481 movl 16(%esp),%edi 482 movl 20(%esp),%ecx 483 addl %ecx,%esi /* copy from end to beginning */ 484 addl %ecx,%edi 485 decl %esi 486 decl %edi 487 std /* decrementing as we go */ 488 rep 489 movsb 490 popl %edi 491 popl %esi 492 xorl %eax,%eax 493 cld 494 ret 495 496 .globl _copyin 497_copyin: 498 movl _curpcb,%eax 499 movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate 500 pushl %esi 501 pushl %edi 502 movl 12(%esp),%esi 503 movl 16(%esp),%edi 504 movl 20(%esp),%ecx 505 506 /* if dest >= USRSTACK, return error */ 507 cmpl $ USRSTACK, %esi 508 jae cpyflt 509 510 /* if USRSTACK-dest < len, return error */ 511 movl $ USRSTACK, %eax 512 subl %esi, %eax 513 cmpl %ecx, %eax 514 jb cpyflt 515 516 shrl $2,%ecx 517 cld 518 rep 519 movsl 520 movl 20(%esp),%ecx 521 andl $3,%ecx 522 rep 523 movsb 524 popl %edi 525 popl %esi 526 xorl %eax,%eax 527 movl _curpcb,%edx 528 movl %eax,PCB_ONFAULT(%edx) 529 ret 530 531cpyflt: popl %edi 532 popl %esi 533 movl _curpcb,%edx 534 movl $0,PCB_ONFAULT(%edx) 535 movl $ EFAULT,%eax 536 ret 537 538 # insb(port,addr,cnt) 539 .globl _insb 540_insb: 541 pushl %edi 542 movw 8(%esp),%dx 543 movl 12(%esp),%edi 544 movl 16(%esp),%ecx 545 cld 546 NOP 547 rep 548 insb 549 NOP 550 movl %edi,%eax 551 popl %edi 552 ret 553 554 # insw(port,addr,cnt) 555 .globl _insw 556_insw: 557 pushl %edi 558 movw 8(%esp),%dx 559 movl 12(%esp),%edi 560 movl 16(%esp),%ecx 561 cld 562 NOP 563 .byte 0x66,0xf2,0x6d # rep insw 564 NOP 565 movl %edi,%eax 566 popl %edi 567 ret 568 569 # outsw(port,addr,cnt) 570 .globl _outsw 571_outsw: 572 pushl %esi 573 movw 8(%esp),%dx 574 movl 12(%esp),%esi 575 movl 16(%esp),%ecx 576 cld 577 NOP 578 .byte 0x66,0xf2,0x6f # rep outsw 579 NOP 580 movl %esi,%eax 581 popl %esi 582 ret 583 584 # lgdt(*gdt, ngdt) 585 .globl _lgdt 586 # .globl _gdt 587xxx: .word 31 588 .long 0 589_lgdt: 590 movl 4(%esp),%eax 591 movl %eax,xxx+2 592 movl 8(%esp),%eax 593 movw %ax,xxx 594 lgdt xxx 595 jmp 1f 596 NOP 5971: movw $0x10,%ax 598 movw %ax,%ds 599 movw %ax,%es 600 movw %ax,%ss 601 movl 0(%esp),%eax 602 pushl %eax 603 movl $8,4(%esp) 604 lret 605 606 # lidt(*idt, nidt) 607 .globl _lidt 608yyy: .word 255 609 .long 0 610_lidt: 611 movl 4(%esp),%eax 612 movl %eax,yyy+2 613 movl 8(%esp),%eax 614 movw %ax,yyy 615 lidt yyy 616 ret 617 618 # lldt(sel) 619 .globl _lldt 620_lldt: 621 movl 4(%esp),%eax 622 lldt %eax 623 ret 624 625 # ltr(sel) 626 .globl _ltr 627_ltr: 628 movl 4(%esp),%eax 629 ltr %eax 630 ret 631 632 # lcr3(cr3) 633 .globl _lcr3 634 .globl _load_cr3 635_load_cr3: 636_lcr3: 637 inb $0x84,%al # check wristwatch 638 movl 4(%esp),%eax 639 orl $ I386_CR3PAT,%eax 640 641 movl $tmpstk2,%edx 642 movl (%edx),%ecx # touch stack, fault if not there 643 movl %ecx,(%edx) 644 movl %esp,%ecx 645 movl %edx,%esp 646 647 movl %eax,%cr3 648 inb $0x84,%al # check wristwatch 649 650 movl (%ecx),%edx # touch stack, fault if not there 651 movl %edx,(%ecx) 652 movl %ecx,%esp 653 ret 654 655 # tlbflush() 656 .globl _tlbflush 657_tlbflush: 658 inb $0x84,%al # check wristwatch 659 movl %cr3,%eax 660 orl $ I386_CR3PAT,%eax 661 662 movl $tmpstk2,%edx 663 movl (%edx),%ecx # touch stack, fault if not there 664 movl %ecx,(%edx) 665 movl %esp,%ecx 666 movl %edx,%esp 667 668 movl %eax,%cr3 669 inb $0x84,%al # check wristwatch 670 671 movl (%ecx),%edx # touch stack, fault if not there 672 movl %edx,(%ecx) 673 movl %ecx,%esp 674 ret 675 676 # lcr0(cr0) 677 .globl _lcr0,_load_cr0 678_lcr0: 679_load_cr0: 680 movl 4(%esp),%eax 681 movl %eax,%cr0 682 ret 683 684 # rcr0() 685 .globl _rcr0 686_rcr0: 687 movl %cr0,%eax 688 ret 689 690 # rcr2() 691 .globl _rcr2 692_rcr2: 693 movl %cr2,%eax 694 ret 695 696 # rcr3() 697 .globl _rcr3 698 .globl __cr3 699__cr3: 700_rcr3: 701 movl %cr3,%eax 702 ret 703 704 # ssdtosd(*ssdp,*sdp) 705 .globl _ssdtosd 706_ssdtosd: 707 pushl %ebx 708 movl 8(%esp),%ecx 709 movl 8(%ecx),%ebx 710 shll $16,%ebx 711 movl (%ecx),%edx 712 roll $16,%edx 713 movb %dh,%bl 714 movb %dl,%bh 715 rorl $8,%ebx 716 movl 4(%ecx),%eax 717 movw %ax,%dx 718 andl $0xf0000,%eax 719 orl %eax,%ebx 720 movl 12(%esp),%ecx 721 movl %edx,(%ecx) 722 movl %ebx,4(%ecx) 723 popl %ebx 724 ret 725 726/* 727 * {fu,su},{byte,word} 728 */ 729ALTENTRY(fuiword) 730ENTRY(fuword) 731 movl _curpcb,%ecx 732 movl $fusufault,PCB_ONFAULT(%ecx) 733 movl 4(%esp),%edx 734 735 cmpl $ USRSTACK - 3, %edx 736 jae fusufault 737 738 # .byte 0x65 # use gs 739 movl 0(%edx),%eax 740 movl $0,PCB_ONFAULT(%ecx) 741 ret 742 743ALTENTRY(fuibyte) 744ENTRY(fubyte) 745 movl _curpcb,%ecx 746 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 747 movl 4(%esp),%edx 748 749 cmpl $ USRSTACK, %edx 750 jae fusufault 751 752 # .byte 0x65 # use gs 753 movzbl 0(%edx),%eax 754 movl $0,PCB_ONFAULT(%ecx) 755 ret 756 757fusufault: 758 movl _curpcb,%ecx 759 xorl %eax,%eax 760 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 761 decl %eax 762 ret 763 764 765/* 766 * There is a little bit of duplicated code so we can avoid flushing the 767 * prefetch queue in the common case. 768 */ 769 770ALTENTRY(suiword) 771ENTRY(suword) 772 movl 4(%esp), %eax /* address */ 773 774 cmpl $ USRSTACK, %eax 775 jae return_minus_one 776 777 /* check if the destination crosses a page boundary */ 778 movl %eax, %ecx 779 andl $ NBPG - 1, %ecx 780 cmpl $ NBPG - 4, %ecx 781 ja suword_breakup 782 783 /* make sure the page table is present */ 784 movl %eax, %ecx 785 shrl $ PDRSHIFT, %ecx 786 movl _PTD(,%ecx,4), %ecx 787 andl $ PG_V, %ecx 788 jnz suword_fault 789 790 /* now make sure the page is present with user write permission */ 791 movl %eax, %ecx 792 shrl $ PGSHIFT, %ecx 793 movl _PTmap(,%ecx,4), %ecx 794 andl $ PG_V | PG_UW, %ecx 795 cmpl $ PG_V | PG_UW, %ecx 796 jnz suword_fault 797 798 movl 8(%esp), %ecx 799 movl %ecx, (%eax) 800 xorl %eax, %eax 801 ret 802 803suword_fault: 804 /* 805 * this is a slow case anyway, so build a frame to make the debugger 806 * more useful 807 */ 808 pushl %ebp 809 movl %esp, %ebp 810 811 pushl %eax 812 call _user_write_fault 813 814 leave 815 816 cmpl $0, %eax 817 jnz return_minus_one 818 819 movl 4(%esp), %eax 820 movl 8(%esp), %ecx 821 movl %ecx, (%eax) 822 xorl %eax, %eax 823 ret 824 825 826suword_breakup: 827 /* crosses page boundary ... do each byte separately */ 828 pushl %ebp 829 movl %esp, %ebp 830 pushl %esi 831 pushl %edi 832 pushl %ebx 833 834 movl %eax, %edi 835 movl 12(%ebp), %ebx 836 movl $4, %esi 837 838suword_breakup_loop: 839 pushl %ebx 840 pushl %edi 841 call _subyte 842 addl $8, %esp 843 844 cmpl $-1, %eax 845 jz suword_breakup_error 846 847 incl %edi 848 shrl $8, %ebx 849 decl %esi 850 jnz suword_breakup_loop 851 852 xorl %eax, %eax 853 popl %ebx 854 popl %edi 855 popl %esi 856 leave 857 ret 858 859suword_breakup_error: 860 movl $-1, %eax 861 popl %ebx 862 popl %edi 863 popl %esi 864 leave 865 ret 866 867ALTENTRY(suibyte) 868ENTRY(subyte) 869 movl 4(%esp), %eax /* address */ 870 871 cmpl $ USRSTACK, %eax 872 jae return_minus_one 873 874 /* make sure the page table is present */ 875 movl %eax, %ecx 876 shrl $ PDRSHIFT, %ecx 877 movl _PTD(,%ecx,4), %ecx 878 andl $ PG_V, %ecx 879 jnz subyte_fault 880 881 /* now make sure the page is present with user write permission */ 882 movl %eax, %ecx 883 shrl $ PGSHIFT, %ecx 884 movl _PTmap(,%ecx,4), %ecx 885 andl $ PG_V | PG_UW, %ecx 886 cmpl $ PG_V | PG_UW, %ecx 887 jnz subyte_fault 888 889 movl 8(%esp), %ecx 890 movb %cl, (%eax) 891 xorl %eax, %eax 892 ret 893 894subyte_fault: 895 pushl %ebp 896 movl %esp, %ebp 897 898 pushl %eax 899 call _user_write_fault 900 901 leave 902 903 cmpl $0, %eax 904 jnz return_minus_one 905 906 movl 4(%esp), %eax 907 movl 8(%esp), %ecx 908 movb %cl, (%eax) 909 xorl %eax, %eax 910 ret 911 912return_minus_one: 913 movl $-1, %eax 914 ret 915 916 ENTRY(setjmp) 917 movl 4(%esp),%eax 918 movl %ebx, 0(%eax) # save ebx 919 movl %esp, 4(%eax) # save esp 920 movl %ebp, 8(%eax) # save ebp 921 movl %esi,12(%eax) # save esi 922 movl %edi,16(%eax) # save edi 923 movl (%esp),%edx # get rta 924 movl %edx,20(%eax) # save eip 925 xorl %eax,%eax # return (0); 926 ret 927 928#ifdef notdef 929 ENTRY(longjmp) 930 movl 4(%esp),%eax 931 movl 0(%eax),%ebx # restore ebx 932 movl 4(%eax),%esp # restore esp 933 movl 8(%eax),%ebp # restore ebp 934 movl 12(%eax),%esi # restore esi 935 movl 16(%eax),%edi # restore edi 936 movl 20(%eax),%edx # get rta 937 movl %edx,(%esp) # put in return frame 938 xorl %eax,%eax # return (1); 939 incl %eax 940 ret 941#endif 942/* 943 * The following primitives manipulate the run queues. 944 * _whichqs tells which of the 32 queues _qs 945 * have processes in them. Setrq puts processes into queues, Remrq 946 * removes them from queues. The running process is on no queue, 947 * other processes are on a queue related to p->p_pri, divided by 4 948 * actually to shrink the 0-127 range of priorities into the 32 available 949 * queues. 950 */ 951 952 .globl _whichqs,_qs,_cnt,_panic 953 .comm _noproc,4 954 .comm _runrun,4 955 956/* 957 * Setrq(p) 958 * 959 * Call should be made at spl6(), and p->p_stat should be SRUN 960 */ 961ENTRY(setrq) 962 movl 4(%esp),%eax 963 cmpl $0,P_RLINK(%eax) # should not be on q already 964 je set1 965 pushl $set2 966 call _panic 967set1: 968 movzbl P_PRI(%eax),%edx 969 shrl $2,%edx 970 btsl %edx,_whichqs # set q full bit 971 shll $3,%edx 972 addl $_qs,%edx # locate q hdr 973 movl %edx,P_LINK(%eax) # link process on tail of q 974 movl P_RLINK(%edx),%ecx 975 movl %ecx,P_RLINK(%eax) 976 movl %eax,P_RLINK(%edx) 977 movl %eax,P_LINK(%ecx) 978 ret 979 980set2: .asciz "setrq" 981 982/* 983 * Remrq(p) 984 * 985 * Call should be made at spl6(). 986 */ 987ENTRY(remrq) 988 movl 4(%esp),%eax 989 movzbl P_PRI(%eax),%edx 990 shrl $2,%edx 991 btrl %edx,_whichqs # clear full bit, panic if clear already 992 jb rem1 993 pushl $rem3 994 call _panic 995rem1: 996 pushl %edx 997 movl P_LINK(%eax),%ecx # unlink process 998 movl P_RLINK(%eax),%edx 999 movl %edx,P_RLINK(%ecx) 1000 movl P_RLINK(%eax),%ecx 1001 movl P_LINK(%eax),%edx 1002 movl %edx,P_LINK(%ecx) 1003 popl %edx 1004 movl $_qs,%ecx 1005 shll $3,%edx 1006 addl %edx,%ecx 1007 cmpl P_LINK(%ecx),%ecx # q still has something? 1008 je rem2 1009 shrl $3,%edx # yes, set bit as still full 1010 btsl %edx,_whichqs 1011rem2: 1012 movl $0,P_RLINK(%eax) # zap reverse link to indicate off list 1013 ret 1014 1015rem3: .asciz "remrq" 1016sw0: .asciz "swtch" 1017 1018/* 1019 * When no processes are on the runq, Swtch branches to idle 1020 * to wait for something to come ready. 1021 */ 1022 .globl Idle 1023Idle: 1024idle: 1025 call _spl0 1026 cmpl $0,_whichqs 1027 jne sw1 1028 hlt # wait for interrupt 1029 jmp idle 1030 1031badsw: 1032 pushl $sw0 1033 call _panic 1034 /*NOTREACHED*/ 1035 1036/* 1037 * Swtch() 1038 */ 1039ENTRY(swtch) 1040 1041 incl _cnt+V_SWTCH 1042 1043 /* switch to new process. first, save context as needed */ 1044 1045 movl _curproc,%ecx 1046 movl P_ADDR(%ecx),%ecx 1047 1048 1049 movl (%esp),%eax # Hardware registers 1050 movl %eax, PCB_EIP(%ecx) 1051 movl %ebx, PCB_EBX(%ecx) 1052 movl %esp, PCB_ESP(%ecx) 1053 movl %ebp, PCB_EBP(%ecx) 1054 movl %esi, PCB_ESI(%ecx) 1055 movl %edi, PCB_EDI(%ecx) 1056 1057#if 0 && NNPX > 0 1058 movb PCB_FLAGS(%ecx),%al 1059 /* have we used fp, and need a save? */ 1060 andb $ FP_WASUSED|FP_NEEDSSAVE,%al 1061 cmpb $ FP_WASUSED|FP_NEEDSSAVE,%al 1062 jne 1f 1063 movl %cr0,%eax /* insure fp is enabled */ 1064 andb $0xfb,%al 1065 movl %eax,%cr0 1066 fnsave PCB_SAVEFPU(%ecx) 1067 orb $4,%al /* disable it */ 1068 movl %eax,%cr0 1069 movb PCB_FLAGS(%ecx),%al 1070 xorb $ FP_NEEDSSAVE,%al /* save processed */ 1071 movb %al,PCB_FLAGS(%ecx) 10721: 1073#endif 1074 1075 movl _CMAP2,%eax # save temporary map PTE 1076 movl %eax,PCB_CMAP2(%ecx) # in our context 1077 1078 movw _cpl, %ax 1079 movw %ax, PCB_IML(%ecx) # save ipl 1080 1081 movl $tmpstk2,%edx 1082 movl (%edx),%eax # touch stack, fault if not there 1083 movl %eax,(%edx) 1084 movl %edx,%esp 1085 movl $pcb2,_curpcb 1086 1087 /* save is done, now choose a new process or idle */ 1088sw1: 1089 cli # XXX? 1090 movl _whichqs,%edi 10912: 1092 bsfl %edi,%eax # find a full q 1093 jz idle # if none, idle 1094 # XX update whichqs? 1095swfnd: 1096 btrl %eax,%edi # clear q full status 1097 jnb 2b # if it was clear, look for another 1098 movl %eax,%ebx # save which one we are using 1099 1100 shll $3,%eax 1101 addl $_qs,%eax # select q 1102 movl %eax,%esi 1103 1104#ifdef DIAGNOSTIC 1105 cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) 1106 je badsw # not possible 1107#endif 1108 1109 movl P_LINK(%eax),%ecx # unlink from front of process q 1110 movl P_LINK(%ecx),%edx 1111 movl %edx,P_LINK(%eax) 1112 movl P_RLINK(%ecx),%eax 1113 movl %eax,P_RLINK(%edx) 1114 1115 cmpl P_LINK(%ecx),%esi # q empty 1116 je 3f 1117 btsl %ebx,%edi # nope, set to indicate full 11183: 1119 movl %edi,_whichqs # update q status 1120 1121 movl $0,%eax 1122 movl %ecx,_curproc 1123 movl %eax,_want_resched 1124 1125#ifdef DIAGNOSTIC 1126 cmpl %eax,P_WCHAN(%ecx) 1127 jne badsw 1128 cmpb $ SRUN,P_STAT(%ecx) 1129 jne badsw 1130#endif 1131 1132 movl %eax,P_RLINK(%ecx) /* isolate process to run */ 1133 movl P_ADDR(%ecx),%edx 1134 movl %edx,_curpcb 1135 inb $0x84,%al # flush write buffers 1136 movl PCB_CR3(%edx),%ebx 1137 1138 /* switch address space */ 1139 cli 1140 orl $ I386_CR3PAT,%ebx 1141 movl %ebx,%cr3 # context switch address space 1142 1143 jmp 7f 1144 nop 1145 7: inb $0x84,%al # flush write buffers 1146 movl PCB_ESP(%edx), %ecx 1147 movl (%ecx),%eax # touch stack, fault if not there 1148 movl %eax,(%ecx) 1149 movl %ecx,%esp 1150 1151 /* restore context */ 1152 movl PCB_EBX(%edx), %ebx 1153 movl PCB_ESP(%edx), %esp 1154 movl PCB_EBP(%edx), %ebp 1155 movl PCB_ESI(%edx), %esi 1156 movl PCB_EDI(%edx), %edi 1157 movl PCB_EIP(%edx), %eax 1158 movl %eax, (%esp) 1159 1160#if NNPX > 0 1161#ifdef notdef 1162 movb PCB_FLAGS(%edx),%al 1163 /* if fp could be used, a dna trap will do a restore */ 1164 testb $ FP_WASUSED,%al 1165 je 1f 1166 orb $ FP_NEEDSRESTORE,PCB_FLAGS(%ecx) 11671: 1168#endif 1169 movl %cr0,%eax 1170 orb $4,%al /* disable it */ 1171 movl %eax,%cr0 1172#endif 1173 1174 movl PCB_CMAP2(%edx),%eax # get temporary map 1175 movl %eax,_CMAP2 # reload temporary map PTE 1176 1177 pushl PCB_IML(%edx) 1178 call _splx 1179 popl %eax 1180 1181 movl %edx,%eax # return (1); 1182 ret 1183 1184/* 1185 * struct proc *swtch_to_inactive(p) ; struct proc *p; 1186 * 1187 * At exit of a process, move off the address space of the 1188 * process and onto a "safe" one. Then, on a temporary stack 1189 * return and run code that disposes of the old state. 1190 * Since this code requires a parameter from the "old" stack, 1191 * pass it back as a return value. 1192 */ 1193ENTRY(swtch_to_inactive) 1194 1195 movl $tmpstk2-4,%ecx # temporary stack, compensated for call 1196 movl (%ecx),%eax # touch stack, fault if not there 1197 movl %eax,(%ecx) 1198 1199 popl %edx # old pc 1200 popl %eax # arg, our return value 1201 inb $0x84,%al # flush write buffers 1202 1203 movl %ecx,%esp 1204 1205 movl _IdlePTD,%ecx 1206 1207 movl %ecx,%cr3 # good bye address space 1208 inb $0x84,%al # flush write buffers 1209 1210 #write buffer? 1211 movl $pcb2,_curpcb 1212 jmp %edx # return, execute remainder of cleanup 1213 1214/* 1215 * savectx(pcb, altreturn) 1216 * Update pcb, saving current processor state and arranging 1217 * for alternate return ala longjmp in swtch if altreturn is true. 1218 */ 1219ENTRY(savectx) 1220 movl 4(%esp), %ecx 1221 movw _cpl, %ax 1222 movw %ax, PCB_IML(%ecx) 1223 movl (%esp), %eax 1224 movl %eax, PCB_EIP(%ecx) 1225 movl %ebx, PCB_EBX(%ecx) 1226 movl %esp, PCB_ESP(%ecx) 1227 movl %ebp, PCB_EBP(%ecx) 1228 movl %esi, PCB_ESI(%ecx) 1229 movl %edi, PCB_EDI(%ecx) 1230#if 0 && NNPX > 0 1231 /* have we ever used fp, and need to save? */ 1232 testb $ FP_WASUSED, PCB_FLAGS(%ecx) 1233 je 1f 1234 movl %cr0, %edx 1235 andb $0xfb, %dl 1236 movl %edx, %cr0 1237 fnsave PCB_SAVEFPU(%ecx) 1238 orb $4, %edx 1239 movl %edx, %cr0 12401: 1241#endif 1242 movl _CMAP2, %edx # save temporary map PTE 1243 movl %edx, PCB_CMAP2(%ecx) # in our context 1244 1245 cmpl $0, 8(%esp) 1246 je 1f 1247 movl %esp, %edx # relocate current sp relative to pcb 1248 subl $_kstack, %edx # (sp is relative to kstack): 1249 addl %edx, %ecx # pcb += sp - kstack; 1250 movl %eax, (%ecx) # write return pc at (relocated) sp@ 1251 # this mess deals with replicating register state gcc hides 1252 movl 12(%esp),%eax 1253 movl %eax,12(%ecx) 1254 movl 16(%esp),%eax 1255 movl %eax,16(%ecx) 1256 movl 20(%esp),%eax 1257 movl %eax,20(%ecx) 1258 movl 24(%esp),%eax 1259 movl %eax,24(%ecx) 12601: 1261 xorl %eax, %eax # return 0 1262 ret 1263 1264 .globl _mvesp 1265_mvesp: movl %esp,%eax 1266 ret 1267 1268/* 1269 * update profiling information for the user 1270 * addupc(pc, up, ticks) struct uprof *up; 1271 */ 1272 1273ENTRY(addupc) 1274 movl 4(%esp),%eax /* pc */ 1275 movl 8(%esp),%ecx /* up */ 1276 1277 /* does sampled pc fall within bottom of profiling window? */ 1278 subl PR_OFF(%ecx),%eax /* pc -= up->pr_off; */ 1279 jl 1f /* if (pc < 0) return; */ 1280 1281 /* construct scaled index */ 1282 shrl $1,%eax /* reduce pc to a short index */ 1283 mull PR_SCALE(%ecx) /* pc*up->pr_scale */ 1284 shrdl $15,%edx,%eax /* praddr >> 15 */ 1285 cmpl $0,%edx /* if overflow, ignore */ 1286 jne 1f 1287 andb $0xfe,%al /* praddr &= ~1 */ 1288 1289 /* within profiling buffer? if so, compute address */ 1290 cmpl %eax,PR_SIZE(%ecx) /* if (praddr > up->pr_size) return; */ 1291 jg 1f 1292 addl PR_BASE(%ecx),%eax /* praddr += up->pr_base; */ 1293 1294 /* tally ticks to selected counter */ 1295 movl _curpcb,%ecx 1296 movl $proffault,PCB_ONFAULT(%ecx) #in case we page/protection violate 1297 movl 12(%esp),%edx /* ticks */ 1298 addw %dx,(%eax) 1299 movl $0,PCB_ONFAULT(%ecx) 13001: ret 1301 1302proffault: 1303 /* disable profiling if we get a fault */ 1304 movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0; */ 1305 movl _curpcb,%ecx 1306 movl $0,PCB_ONFAULT(%ecx) 1307 ret 1308 1309.data 1310 .globl _cyloffset, _curpcb 1311_cyloffset: .long 0 1312 .globl _proc0paddr 1313_proc0paddr: .long 0 1314LF: .asciz "swtch %x" 1315 1316.text 1317 .globl _astoff 1318_astoff: 1319 movl $0,_astpending 1320 ret 1321 1322#define IDTVEC(name) .align 4; .globl _X/**/name; _X/**/name: 1323#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ 1324 call _panic; 1: .asciz msg 1325#define PRINTF(n,msg) pushal ; pushl 1f; call _printf; MSG(msg) ; \ 1326 popl %eax ; popal 1327#define MSG(msg) .data; 1: .asciz msg; .text 1328 1329 .text 1330 1331/* 1332 * Trap and fault vector routines 1333 */ 1334#define TRAP(a) pushl $a ; jmp alltraps 1335#ifdef KGDB 1336#define BPTTRAP(a) pushl $a ; jmp bpttraps 1337#else 1338#define BPTTRAP(a) TRAP(a) 1339#endif 1340 1341IDTVEC(div) 1342 pushl $0; TRAP(T_DIVIDE) 1343IDTVEC(dbg) 1344 pushl $0; BPTTRAP(T_TRCTRAP) 1345IDTVEC(nmi) 1346 pushl $0; TRAP(T_NMI) 1347IDTVEC(bpt) 1348 pushl $0; BPTTRAP(T_BPTFLT) 1349IDTVEC(ofl) 1350 pushl $0; TRAP(T_OFLOW) 1351IDTVEC(bnd) 1352 pushl $0; TRAP(T_BOUND) 1353IDTVEC(ill) 1354 pushl $0; TRAP(T_PRIVINFLT) 1355IDTVEC(dna) 1356 pushl $0; TRAP(T_DNA) 1357IDTVEC(dble) 1358 TRAP(T_DOUBLEFLT) 1359 /*PANIC("Double Fault");*/ 1360IDTVEC(fpusegm) 1361 pushl $0; TRAP(T_FPOPFLT) 1362IDTVEC(tss) 1363 TRAP(T_TSSFLT) 1364 /*PANIC("TSS not valid");*/ 1365IDTVEC(missing) 1366 TRAP(T_SEGNPFLT) 1367IDTVEC(stk) 1368 TRAP(T_STKFLT) 1369IDTVEC(prot) 1370 TRAP(T_PROTFLT) 1371IDTVEC(page) 1372 TRAP(T_PAGEFLT) 1373IDTVEC(rsvd) 1374 pushl $0; TRAP(T_RESERVED) 1375IDTVEC(fpu) 1376 pushl $0; TRAP(T_ARITHTRAP) 1377 /* 17 - 31 reserved for future exp */ 1378IDTVEC(rsvd0) 1379 pushl $0; TRAP(17) 1380IDTVEC(rsvd1) 1381 pushl $0; TRAP(18) 1382IDTVEC(rsvd2) 1383 pushl $0; TRAP(19) 1384IDTVEC(rsvd3) 1385 pushl $0; TRAP(20) 1386IDTVEC(rsvd4) 1387 pushl $0; TRAP(21) 1388IDTVEC(rsvd5) 1389 pushl $0; TRAP(22) 1390IDTVEC(rsvd6) 1391 pushl $0; TRAP(23) 1392IDTVEC(rsvd7) 1393 pushl $0; TRAP(24) 1394IDTVEC(rsvd8) 1395 pushl $0; TRAP(25) 1396IDTVEC(rsvd9) 1397 pushl $0; TRAP(26) 1398IDTVEC(rsvd10) 1399 pushl $0; TRAP(27) 1400IDTVEC(rsvd11) 1401 pushl $0; TRAP(28) 1402IDTVEC(rsvd12) 1403 pushl $0; TRAP(29) 1404IDTVEC(rsvd13) 1405 pushl $0; TRAP(30) 1406IDTVEC(rsvd14) 1407 pushl $0; TRAP(31) 1408 1409alltraps: 1410 pushal 1411 push %ds 1412 push %es 1413 movw $0x10,%ax 1414 movw %ax,%ds 1415 movw %ax,%es 1416calltrap: 1417 incl _cnt+V_TRAP 1418 call _trap 1419 1420 cli 1421 1422 /* this value may also be used in return_to_user_mode */ 1423 movl 0x34(%esp),%esi /* previous cs */ 1424 andl $3,%esi 1425 jz trap_return 1426 1427 cmpl $0,_astpending 1428 jnz do_astflt 1429 1430 cmpw $0,_cpl 1431 jnz return_to_user_mode /* in icu.s */ 1432 1433trap_return: 1434 pop %es 1435 pop %ds 1436 popal 1437 nop 1438 addl $8,%esp # pop type, code 1439 iret 1440 1441do_astflt: 1442 /* pop off the old trap frame, then create a new one that 1443 * will give trap() another chance 1444 */ 1445 pop %es 1446 pop %ds 1447 popa 1448 addl $8,%esp 1449 1450 pushl $0 1451 TRAP (T_ASTFLT) 1452 /* NORETURN */ 1453 1454 1455 1456#ifdef KGDB 1457/* 1458 * This code checks for a kgdb trap, then falls through 1459 * to the regular trap code. 1460 */ 1461bpttraps: 1462 pushal 1463 push %es 1464 push %ds 1465 movw $0x10,%ax 1466 movw %ax,%ds 1467 movw %ax,%es 1468 movzwl 52(%esp),%eax 1469 test $3,%eax 1470 jne calltrap 1471 call _kgdb_trap_glue 1472 jmp calltrap 1473#endif 1474 1475/* 1476 * Call gate entry for syscall 1477 */ 1478 1479IDTVEC(syscall) 1480 pushfl # only for stupid carry bit and more stupid wait3 cc kludge 1481 pushal # only need eax,ecx,edx - trap resaves others 1482 movw $0x10,%ax # switch to kernel segments 1483 movw %ax,%ds 1484 movw %ax,%es 1485 call _syscall 1486 1487 cli 1488 1489 cmpl $0,_astpending 1490 jnz syscall_ast 1491 1492 cmpw $0,_cpl 1493 jnz syscall_fix_cpl 1494 1495 movw __udatasel,%ax # switch back to user segments 1496 movw %ax,%ds 1497 movw %ax,%es 1498 popal 1499 nop 1500 popfl 1501 lret 1502 1503syscall_ast: 1504 movw __udatasel,%ax 1505 movw %ax,%ds 1506 movw %ax,%es 1507 popal 1508 1509 /* convert to trap frame 1510 * stack is now ss, sp, cs, ip, flags 1511 * we want ss, sp, flags, cs, ip 1512 * offsets 16 12 8 4 0 1513 */ 1514 xchgl %eax,8(%esp) /* now eax has cs */ 1515 xchgl %eax,4(%esp) /* now eax has ip */ 1516 xchgl %eax,0(%esp) /* now eax has flags */ 1517 xchgl %eax,8(%esp) /* now eax has its original value */ 1518 pushl $0 1519 TRAP (T_ASTFLT) 1520 /* NORETURN */ 1521 1522syscall_fix_cpl: 1523 movw __udatasel,%ax 1524 movw %ax,%ds 1525 movw %ax,%es 1526 popal 1527 1528 /* convert to trap frame 1529 * stack is now ss, sp, cs, ip, flags 1530 * we want ss, sp, flags, cs, ip 1531 * offsets 16 12 8 4 0 1532 */ 1533 xchgl %eax,8(%esp) /* now eax has cs */ 1534 xchgl %eax,4(%esp) /* now eax has ip */ 1535 xchgl %eax,0(%esp) /* now eax has flags */ 1536 xchgl %eax,8(%esp) /* now eax has its original value */ 1537 1538 pushl $0 1539 pushl $ T_ASTFLT 1540 1541 pushal 1542 nop 1543 push %ds 1544 push %es 1545 movw $0x10,%ax 1546 movw %ax,%ds 1547 movw %ax,%es 1548 1549 movl $1, %esi /* non-zero to indicate return to user mode */ 1550 jmp return_to_user_mode /* in icu.s */ 1551 1552 1553ENTRY(htonl) 1554ENTRY(ntohl) 1555 movl 4(%esp),%eax 1556 xchgb %al,%ah 1557 roll $16,%eax 1558 xchgb %al,%ah 1559 ret 1560 1561ENTRY(htons) 1562ENTRY(ntohs) 1563 movzwl 4(%esp),%eax 1564 xchgb %al,%ah 1565 ret 1566 1567/* DELAY(n) delay about n microseconds */ 1568ENTRY(DELAY) 1569 movl 4(%esp), %ecx 1570 incl %ecx /* make DELAY(0) go through the loop just once */ 1571 1572 /* 1573 * 0x80 is the manufacturing test port, which should be safe to 1574 * write to on any motherboard. The output instruction will 1575 * be executed at bus speed, rather than processor speed, so 1576 * it will be about 750ns on any ISA or EISA machine. 1577 */ 15781: 1579 outb %al, $0x80 1580 loop 1b 1581 ret 1582 1583#include "vector.s" 1584#include <i386/isa/icu.s> 1585