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.8 (Berkeley) 05/20/92 11 */ 12 13#include "assym.s" 14#include "machine/psl.h" 15#include "machine/pte.h" 16 17#include "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 $argv-_icode # gas fucks up again 322 movl $argv,%eax 323 subl $_icode,%eax 324 pushl %eax 325 326 # pushl $init-_icode 327 movl $init,%eax 328 subl $_icode,%eax 329 pushl %eax 330 pushl %eax # dummy out rta 331 332 movl %esp,%ebp 333 movl $exec,%eax 334 LCALL(0x7,0x0) 335 pushl %eax 336 movl $exit,%eax 337 pushl %eax # dummy out rta 338 LCALL(0x7,0x0) 339 340init: 341 .asciz "/sbin/init" 342 .align 2 343argv: 344 .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6) 345 .long eicode-_icode # argv[1] follows icode after copyout 346 .long 0 347eicode: 348 349_szicode: 350 .long _szicode-_icode 351 352 .globl _sigcode,_szsigcode 353_sigcode: 354 movl 12(%esp),%eax # unsure if call will dec stack 1st 355 call %eax 356 xorl %eax,%eax # smaller movl $103,%eax 357 movb $103,%al # sigreturn() 358 LCALL(0x7,0) # enter kernel with args on stack 359 hlt # never gets here 360 361_szsigcode: 362 .long _szsigcode-_sigcode 363 364 .globl ___udivsi3 365___udivsi3: 366 movl 4(%esp),%eax 367 xorl %edx,%edx 368 divl 8(%esp) 369 ret 370 371 .globl ___divsi3 372___divsi3: 373 movl 4(%esp),%eax 374 xorl %edx,%edx 375 cltd 376 idivl 8(%esp) 377 ret 378 379 .globl _inb 380_inb: movl 4(%esp),%edx 381 # inb $0x84,%al # Compaq SystemPro 382 subl %eax,%eax # clr eax 383 NOP 384 inb %dx,%al 385 NOP 386 ret 387 388 389 .globl _rtcin 390_rtcin: movl 4(%esp),%eax 391 outb %al,$0x70 392 subl %eax,%eax # clr eax 393 inb $0x71,%al # Compaq SystemPro 394 ret 395 396 .globl _outb 397_outb: movl 4(%esp),%edx 398 movl 8(%esp),%eax 399 NOP 400 outb %al,%dx 401 # inb $0x84,%al 402 NOP 403 ret 404 405 # 406 # bzero (base,cnt) 407 # 408 409 .globl _bzero 410 .globl _blkclr 411_bzero: 412_blkclr: 413 pushl %edi 414 movl 8(%esp),%edi 415 movl 12(%esp),%ecx 416 xorl %eax,%eax 417 shrl $2,%ecx 418 cld 419 rep 420 stosl 421 movl 12(%esp),%ecx 422 andl $3,%ecx 423 rep 424 stosb 425 popl %edi 426 ret 427 428 # 429 # fillw (pat,base,cnt) 430 # 431 432 .globl _fillw 433_fillw: 434 pushl %edi 435 movl 8(%esp),%eax 436 movl 12(%esp),%edi 437 movl 16(%esp),%ecx 438 cld 439 rep 440 stosw 441 popl %edi 442 ret 443 444 # 445 # bcopy (src,dst,cnt) 446 # NOTE: does not (yet) handle overlapped copies 447 # 448 449 .globl _bcopy 450_bcopy: 451 pushl %esi 452 pushl %edi 453 movl 12(%esp),%esi 454 movl 16(%esp),%edi 455 movl 20(%esp),%ecx 456 shrl $2,%ecx 457 cld 458 rep 459 movsl 460 movl 20(%esp),%ecx 461 andl $3,%ecx 462 rep 463 movsb 464 popl %edi 465 popl %esi 466 xorl %eax,%eax 467 ret 468 469 # 470 # ovbcopy (src,dst,cnt) 471 # NOTE: does not (yet) work doing words at a time 472 # 473 474 .globl _ovbcopy 475_ovbcopy: 476 pushl %esi 477 pushl %edi 478 movl 12(%esp),%esi 479 movl 16(%esp),%edi 480 movl 20(%esp),%ecx 481 addl %ecx,%esi /* copy from end to beginning */ 482 addl %ecx,%edi 483 decl %esi 484 decl %edi 485 std /* decrementing as we go */ 486 rep 487 movsb 488 popl %edi 489 popl %esi 490 xorl %eax,%eax 491 cld 492 ret 493 494 .globl _copyout 495_copyout: 496 movl _curpcb,%eax 497 movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate 498 pushl %esi 499 pushl %edi 500 movl 12(%esp),%esi 501 movl 16(%esp),%edi 502 movl 20(%esp),%ecx 503 shrl $2,%ecx 504 cld 505 rep 506 movsl 507 movl 20(%esp),%ecx 508 andl $3,%ecx 509 rep 510 movsb 511 popl %edi 512 popl %esi 513 xorl %eax,%eax 514 movl _curpcb,%edx 515 movl %eax,PCB_ONFAULT(%edx) 516 ret 517 518 .globl _copyin 519_copyin: 520 movl _curpcb,%eax 521 movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate 522 pushl %esi 523 pushl %edi 524 movl 12(%esp),%esi 525 movl 16(%esp),%edi 526 movl 20(%esp),%ecx 527 shrl $2,%ecx 528 cld 529 rep 530 movsl 531 movl 20(%esp),%ecx 532 andl $3,%ecx 533 rep 534 movsb 535 popl %edi 536 popl %esi 537 xorl %eax,%eax 538 movl _curpcb,%edx 539 movl %eax,PCB_ONFAULT(%edx) 540 ret 541 542cpyflt: popl %edi 543 popl %esi 544 movl _curpcb,%edx 545 movl $0,PCB_ONFAULT(%edx) 546 movl $ EFAULT,%eax 547 ret 548 549 # insb(port,addr,cnt) 550 .globl _insb 551_insb: 552 pushl %edi 553 movw 8(%esp),%dx 554 movl 12(%esp),%edi 555 movl 16(%esp),%ecx 556 cld 557 NOP 558 rep 559 insb 560 NOP 561 movl %edi,%eax 562 popl %edi 563 ret 564 565 # insw(port,addr,cnt) 566 .globl _insw 567_insw: 568 pushl %edi 569 movw 8(%esp),%dx 570 movl 12(%esp),%edi 571 movl 16(%esp),%ecx 572 cld 573 NOP 574 .byte 0x66,0xf2,0x6d # rep insw 575 NOP 576 movl %edi,%eax 577 popl %edi 578 ret 579 580 # outsw(port,addr,cnt) 581 .globl _outsw 582_outsw: 583 pushl %esi 584 movw 8(%esp),%dx 585 movl 12(%esp),%esi 586 movl 16(%esp),%ecx 587 cld 588 NOP 589 .byte 0x66,0xf2,0x6f # rep outsw 590 NOP 591 movl %esi,%eax 592 popl %esi 593 ret 594 595 # lgdt(*gdt, ngdt) 596 .globl _lgdt 597 # .globl _gdt 598xxx: .word 31 599 .long 0 600_lgdt: 601 movl 4(%esp),%eax 602 movl %eax,xxx+2 603 movl 8(%esp),%eax 604 movw %ax,xxx 605 lgdt xxx 606 jmp 1f 607 NOP 6081: movw $0x10,%ax 609 movw %ax,%ds 610 movw %ax,%es 611 movw %ax,%ss 612 movl 0(%esp),%eax 613 pushl %eax 614 movl $8,4(%esp) 615 lret 616 617 # lidt(*idt, nidt) 618 .globl _lidt 619yyy: .word 255 620 .long 0 621_lidt: 622 movl 4(%esp),%eax 623 movl %eax,yyy+2 624 movl 8(%esp),%eax 625 movw %ax,yyy 626 lidt yyy 627 ret 628 629 # lldt(sel) 630 .globl _lldt 631_lldt: 632 movl 4(%esp),%eax 633 lldt %eax 634 ret 635 636 # ltr(sel) 637 .globl _ltr 638_ltr: 639 movl 4(%esp),%eax 640 ltr %eax 641 ret 642 643 # lcr3(cr3) 644 .globl _lcr3 645 .globl _load_cr3 646_load_cr3: 647_lcr3: 648 inb $0x84,%al # check wristwatch 649 movl 4(%esp),%eax 650 orl $ I386_CR3PAT,%eax 651 652 movl $tmpstk2,%edx 653 movl (%edx),%ecx # touch stack, fault if not there 654 movl %ecx,(%edx) 655 movl %esp,%ecx 656 movl %edx,%esp 657 658 movl %eax,%cr3 659 inb $0x84,%al # check wristwatch 660 661 movl (%ecx),%edx # touch stack, fault if not there 662 movl %edx,(%ecx) 663 movl %ecx,%esp 664 ret 665 666 # tlbflush() 667 .globl _tlbflush 668_tlbflush: 669 inb $0x84,%al # check wristwatch 670 movl %cr3,%eax 671 orl $ I386_CR3PAT,%eax 672 673 movl $tmpstk2,%edx 674 movl (%edx),%ecx # touch stack, fault if not there 675 movl %ecx,(%edx) 676 movl %esp,%ecx 677 movl %edx,%esp 678 679 movl %eax,%cr3 680 inb $0x84,%al # check wristwatch 681 682 movl (%ecx),%edx # touch stack, fault if not there 683 movl %edx,(%ecx) 684 movl %ecx,%esp 685 ret 686 687 # lcr0(cr0) 688 .globl _lcr0,_load_cr0 689_lcr0: 690_load_cr0: 691 movl 4(%esp),%eax 692 movl %eax,%cr0 693 ret 694 695 # rcr0() 696 .globl _rcr0 697_rcr0: 698 movl %cr0,%eax 699 ret 700 701 # rcr2() 702 .globl _rcr2 703_rcr2: 704 movl %cr2,%eax 705 ret 706 707 # rcr3() 708 .globl _rcr3 709 .globl __cr3 710__cr3: 711_rcr3: 712 movl %cr3,%eax 713 ret 714 715 # ssdtosd(*ssdp,*sdp) 716 .globl _ssdtosd 717_ssdtosd: 718 pushl %ebx 719 movl 8(%esp),%ecx 720 movl 8(%ecx),%ebx 721 shll $16,%ebx 722 movl (%ecx),%edx 723 roll $16,%edx 724 movb %dh,%bl 725 movb %dl,%bh 726 rorl $8,%ebx 727 movl 4(%ecx),%eax 728 movw %ax,%dx 729 andl $0xf0000,%eax 730 orl %eax,%ebx 731 movl 12(%esp),%ecx 732 movl %edx,(%ecx) 733 movl %ebx,4(%ecx) 734 popl %ebx 735 ret 736 737/* 738 * {fu,su},{byte,word} 739 */ 740ALTENTRY(fuiword) 741ENTRY(fuword) 742 movl _curpcb,%ecx 743 movl $fusufault,PCB_ONFAULT(%ecx) 744 movl 4(%esp),%edx 745 # .byte 0x65 # use gs 746 movl 0(%edx),%eax 747 movl $0,PCB_ONFAULT(%ecx) 748 ret 749 750ENTRY(fusword) 751 movl _curpcb,%ecx 752 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 753 movl 4(%esp),%edx 754 # .byte 0x65 # use gs 755 movzwl 0(%edx),%eax 756 movl $0,PCB_ONFAULT(%ecx) 757 ret 758 759ALTENTRY(fuibyte) 760ENTRY(fubyte) 761 movl _curpcb,%ecx 762 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 763 movl 4(%esp),%edx 764 # .byte 0x65 # use gs 765 movzbl 0(%edx),%eax 766 movl $0,PCB_ONFAULT(%ecx) 767 ret 768 769fusufault: 770 movl _curpcb,%ecx 771 xorl %eax,%eax 772 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 773 decl %eax 774 ret 775 776ALTENTRY(suiword) 777ENTRY(suword) 778 movl _curpcb,%ecx 779 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 780 movl 4(%esp),%edx 781 movl 8(%esp),%eax 782 # .byte 0x65 # use gs 783 movl %eax,0(%edx) 784 xorl %eax,%eax 785 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 786 ret 787 788ENTRY(susword) 789 movl _curpcb,%ecx 790 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 791 movl 4(%esp),%edx 792 movl 8(%esp),%eax 793 # .byte 0x65 # use gs 794 movw %ax,0(%edx) 795 xorl %eax,%eax 796 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 797 ret 798 799ALTENTRY(suibyte) 800ENTRY(subyte) 801 movl _curpcb,%ecx 802 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 803 movl 4(%esp),%edx 804 movl 8(%esp),%eax 805 # .byte 0x65 # use gs 806 movb %eax,0(%edx) 807 xorl %eax,%eax 808 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 809 ret 810 811 ENTRY(setjmp) 812 movl 4(%esp),%eax 813 movl %ebx, 0(%eax) # save ebx 814 movl %esp, 4(%eax) # save esp 815 movl %ebp, 8(%eax) # save ebp 816 movl %esi,12(%eax) # save esi 817 movl %edi,16(%eax) # save edi 818 movl (%esp),%edx # get rta 819 movl %edx,20(%eax) # save eip 820 xorl %eax,%eax # return (0); 821 ret 822 823#ifdef notdef 824 ENTRY(longjmp) 825 movl 4(%esp),%eax 826 movl 0(%eax),%ebx # restore ebx 827 movl 4(%eax),%esp # restore esp 828 movl 8(%eax),%ebp # restore ebp 829 movl 12(%eax),%esi # restore esi 830 movl 16(%eax),%edi # restore edi 831 movl 20(%eax),%edx # get rta 832 movl %edx,(%esp) # put in return frame 833 xorl %eax,%eax # return (1); 834 incl %eax 835 ret 836#endif 837/* 838 * The following primitives manipulate the run queues. 839 * _whichqs tells which of the 32 queues _qs 840 * have processes in them. Setrq puts processes into queues, Remrq 841 * removes them from queues. The running process is on no queue, 842 * other processes are on a queue related to p->p_pri, divided by 4 843 * actually to shrink the 0-127 range of priorities into the 32 available 844 * queues. 845 */ 846 847 .globl _whichqs,_qs,_cnt,_panic 848 .comm _noproc,4 849 .comm _runrun,4 850 851/* 852 * Setrq(p) 853 * 854 * Call should be made at spl6(), and p->p_stat should be SRUN 855 */ 856ENTRY(setrq) 857 movl 4(%esp),%eax 858 cmpl $0,P_RLINK(%eax) # should not be on q already 859 je set1 860 pushl $set2 861 call _panic 862set1: 863 movzbl P_PRI(%eax),%edx 864 shrl $2,%edx 865 btsl %edx,_whichqs # set q full bit 866 shll $3,%edx 867 addl $_qs,%edx # locate q hdr 868 movl %edx,P_LINK(%eax) # link process on tail of q 869 movl P_RLINK(%edx),%ecx 870 movl %ecx,P_RLINK(%eax) 871 movl %eax,P_RLINK(%edx) 872 movl %eax,P_LINK(%ecx) 873 ret 874 875set2: .asciz "setrq" 876 877/* 878 * Remrq(p) 879 * 880 * Call should be made at spl6(). 881 */ 882ENTRY(remrq) 883 movl 4(%esp),%eax 884 movzbl P_PRI(%eax),%edx 885 shrl $2,%edx 886 btrl %edx,_whichqs # clear full bit, panic if clear already 887 jb rem1 888 pushl $rem3 889 call _panic 890rem1: 891 pushl %edx 892 movl P_LINK(%eax),%ecx # unlink process 893 movl P_RLINK(%eax),%edx 894 movl %edx,P_RLINK(%ecx) 895 movl P_RLINK(%eax),%ecx 896 movl P_LINK(%eax),%edx 897 movl %edx,P_LINK(%ecx) 898 popl %edx 899 movl $_qs,%ecx 900 shll $3,%edx 901 addl %edx,%ecx 902 cmpl P_LINK(%ecx),%ecx # q still has something? 903 je rem2 904 shrl $3,%edx # yes, set bit as still full 905 btsl %edx,_whichqs 906rem2: 907 movl $0,P_RLINK(%eax) # zap reverse link to indicate off list 908 ret 909 910rem3: .asciz "remrq" 911sw0: .asciz "swtch" 912 913/* 914 * When no processes are on the runq, Swtch branches to idle 915 * to wait for something to come ready. 916 */ 917 .globl Idle 918Idle: 919idle: 920 call _spl0 921 cmpl $0,_whichqs 922 jne sw1 923 hlt # wait for interrupt 924 jmp idle 925 926badsw: 927 pushl $sw0 928 call _panic 929 /*NOTREACHED*/ 930 931/* 932 * Swtch() 933 */ 934ENTRY(swtch) 935 936 incl _cnt+V_SWTCH 937 938 /* switch to new process. first, save context as needed */ 939 940 movl _curproc,%ecx 941 movl P_ADDR(%ecx),%ecx 942 943 944 movl (%esp),%eax # Hardware registers 945 movl %eax, PCB_EIP(%ecx) 946 movl %ebx, PCB_EBX(%ecx) 947 movl %esp, PCB_ESP(%ecx) 948 movl %ebp, PCB_EBP(%ecx) 949 movl %esi, PCB_ESI(%ecx) 950 movl %edi, PCB_EDI(%ecx) 951 952#if 0 && NNPX > 0 953 movb PCB_FLAGS(%ecx),%al 954 /* have we used fp, and need a save? */ 955 andb $ FP_WASUSED|FP_NEEDSSAVE,%al 956 cmpb $ FP_WASUSED|FP_NEEDSSAVE,%al 957 jne 1f 958 movl %cr0,%eax /* insure fp is enabled */ 959 andb $0xfb,%al 960 movl %eax,%cr0 961 fnsave PCB_SAVEFPU(%ecx) 962 orb $4,%al /* disable it */ 963 movl %eax,%cr0 964 movb PCB_FLAGS(%ecx),%al 965 xorb $ FP_NEEDSSAVE,%al /* save processed */ 966 movb %al,PCB_FLAGS(%ecx) 9671: 968#endif 969 970 movl _CMAP2,%eax # save temporary map PTE 971 movl %eax,PCB_CMAP2(%ecx) # in our context 972 973 movw _cpl, %ax 974 movw %ax, PCB_IML(%ecx) # save ipl 975 976 movl $tmpstk2,%edx 977 movl (%edx),%eax # touch stack, fault if not there 978 movl %eax,(%edx) 979 movl %edx,%esp 980 movl $pcb2,_curpcb 981 982 /* save is done, now choose a new process or idle */ 983sw1: 984 cli # XXX? 985 movl _whichqs,%edi 9862: 987 bsfl %edi,%eax # find a full q 988 jz idle # if none, idle 989 # XX update whichqs? 990swfnd: 991 btrl %eax,%edi # clear q full status 992 jnb 2b # if it was clear, look for another 993 movl %eax,%ebx # save which one we are using 994 995 shll $3,%eax 996 addl $_qs,%eax # select q 997 movl %eax,%esi 998 999#ifdef DIAGNOSTIC 1000 cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) 1001 je badsw # not possible 1002#endif 1003 1004 movl P_LINK(%eax),%ecx # unlink from front of process q 1005 movl P_LINK(%ecx),%edx 1006 movl %edx,P_LINK(%eax) 1007 movl P_RLINK(%ecx),%eax 1008 movl %eax,P_RLINK(%edx) 1009 1010 cmpl P_LINK(%ecx),%esi # q empty 1011 je 3f 1012 btsl %ebx,%edi # nope, set to indicate full 10133: 1014 movl %edi,_whichqs # update q status 1015 1016 movl $0,%eax 1017 movl %ecx,_curproc 1018 movl %eax,_want_resched 1019 1020#ifdef DIAGNOSTIC 1021 cmpl %eax,P_WCHAN(%ecx) 1022 jne badsw 1023 cmpb $ SRUN,P_STAT(%ecx) 1024 jne badsw 1025#endif 1026 1027 movl %eax,P_RLINK(%ecx) /* isolate process to run */ 1028 movl P_ADDR(%ecx),%edx 1029 movl %edx,_curpcb 1030 inb $0x84,%al # flush write buffers 1031 movl PCB_CR3(%edx),%ebx 1032 1033 /* switch address space */ 1034 cli 1035 orl $ I386_CR3PAT,%ebx 1036 movl %ebx,%cr3 # context switch address space 1037 1038 jmp 7f 1039 nop 1040 7: inb $0x84,%al # flush write buffers 1041 movl PCB_ESP(%edx), %ecx 1042 movl (%ecx),%eax # touch stack, fault if not there 1043 movl %eax,(%ecx) 1044 movl %ecx,%esp 1045 1046 /* restore context */ 1047 movl PCB_EBX(%edx), %ebx 1048 movl PCB_ESP(%edx), %esp 1049 movl PCB_EBP(%edx), %ebp 1050 movl PCB_ESI(%edx), %esi 1051 movl PCB_EDI(%edx), %edi 1052 movl PCB_EIP(%edx), %eax 1053 movl %eax, (%esp) 1054 1055#if NNPX > 0 1056#ifdef notdef 1057 movb PCB_FLAGS(%edx),%al 1058 /* if fp could be used, a dna trap will do a restore */ 1059 testb $ FP_WASUSED,%al 1060 je 1f 1061 orb $ FP_NEEDSRESTORE,PCB_FLAGS(%ecx) 10621: 1063#endif 1064 movl %cr0,%eax 1065 orb $4,%al /* disable it */ 1066 movl %eax,%cr0 1067#endif 1068 1069 movl PCB_CMAP2(%edx),%eax # get temporary map 1070 movl %eax,_CMAP2 # reload temporary map PTE 1071 1072 pushl PCB_IML(%edx) 1073 call _splx 1074 popl %eax 1075 1076 movl %edx,%eax # return (1); 1077 ret 1078 1079/* 1080 * struct proc *swtch_to_inactive(p) ; struct proc *p; 1081 * 1082 * At exit of a process, move off the address space of the 1083 * process and onto a "safe" one. Then, on a temporary stack 1084 * return and run code that disposes of the old state. 1085 * Since this code requires a parameter from the "old" stack, 1086 * pass it back as a return value. 1087 */ 1088ENTRY(swtch_to_inactive) 1089 1090 movl $tmpstk2-4,%ecx # temporary stack, compensated for call 1091 movl (%ecx),%eax # touch stack, fault if not there 1092 movl %eax,(%ecx) 1093 1094 popl %edx # old pc 1095 popl %eax # arg, our return value 1096 inb $0x84,%al # flush write buffers 1097 1098 movl %ecx,%esp 1099 1100 movl _IdlePTD,%ecx 1101 1102 movl %ecx,%cr3 # good bye address space 1103 inb $0x84,%al # flush write buffers 1104 1105 #write buffer? 1106 movl $pcb2,_curpcb 1107 jmp %edx # return, execute remainder of cleanup 1108 1109/* 1110 * savectx(pcb, altreturn) 1111 * Update pcb, saving current processor state and arranging 1112 * for alternate return ala longjmp in swtch if altreturn is true. 1113 */ 1114ENTRY(savectx) 1115 movl 4(%esp), %ecx 1116 movw _cpl, %ax 1117 movw %ax, PCB_IML(%ecx) 1118 movl (%esp), %eax 1119 movl %eax, PCB_EIP(%ecx) 1120 movl %ebx, PCB_EBX(%ecx) 1121 movl %esp, PCB_ESP(%ecx) 1122 movl %ebp, PCB_EBP(%ecx) 1123 movl %esi, PCB_ESI(%ecx) 1124 movl %edi, PCB_EDI(%ecx) 1125#if 0 && NNPX > 0 1126 /* have we ever used fp, and need to save? */ 1127 testb $ FP_WASUSED, PCB_FLAGS(%ecx) 1128 je 1f 1129 movl %cr0, %edx 1130 andb $0xfb, %dl 1131 movl %edx, %cr0 1132 fnsave PCB_SAVEFPU(%ecx) 1133 orb $4, %edx 1134 movl %edx, %cr0 11351: 1136#endif 1137 movl _CMAP2, %edx # save temporary map PTE 1138 movl %edx, PCB_CMAP2(%ecx) # in our context 1139 1140 cmpl $0, 8(%esp) 1141 je 1f 1142 movl %esp, %edx # relocate current sp relative to pcb 1143 subl $_kstack, %edx # (sp is relative to kstack): 1144 addl %edx, %ecx # pcb += sp - kstack; 1145 movl %eax, (%ecx) # write return pc at (relocated) sp@ 1146 # this mess deals with replicating register state gcc hides 1147 movl 12(%esp),%eax 1148 movl %eax,12(%ecx) 1149 movl 16(%esp),%eax 1150 movl %eax,16(%ecx) 1151 movl 20(%esp),%eax 1152 movl %eax,20(%ecx) 1153 movl 24(%esp),%eax 1154 movl %eax,24(%ecx) 11551: 1156 xorl %eax, %eax # return 0 1157 ret 1158 1159 .globl _mvesp 1160_mvesp: movl %esp,%eax 1161 ret 1162 1163/* 1164 * update profiling information for the user 1165 * addupc(pc, up, ticks) struct uprof *up; 1166 */ 1167 1168ENTRY(addupc) 1169 movl 4(%esp),%eax /* pc */ 1170 movl 8(%esp),%ecx /* up */ 1171 1172 /* does sampled pc fall within bottom of profiling window? */ 1173 subl PR_OFF(%ecx),%eax /* pc -= up->pr_off; */ 1174 jl 1f /* if (pc < 0) return; */ 1175 1176 /* construct scaled index */ 1177 shrl $1,%eax /* reduce pc to a short index */ 1178 mull PR_SCALE(%ecx) /* pc*up->pr_scale */ 1179 shrdl $15,%edx,%eax /* praddr >> 15 */ 1180 cmpl $0,%edx /* if overflow, ignore */ 1181 jne 1f 1182 andb $0xfe,%al /* praddr &= ~1 */ 1183 1184 /* within profiling buffer? if so, compute address */ 1185 cmpl %eax,PR_SIZE(%ecx) /* if (praddr > up->pr_size) return; */ 1186 jg 1f 1187 addl PR_BASE(%ecx),%eax /* praddr += up->pr_base; */ 1188 1189 /* tally ticks to selected counter */ 1190 movl _curpcb,%ecx 1191 movl $proffault,PCB_ONFAULT(%ecx) #in case we page/protection violate 1192 movl 12(%esp),%edx /* ticks */ 1193 addw %dx,(%eax) 1194 movl $0,PCB_ONFAULT(%ecx) 11951: ret 1196 1197proffault: 1198 /* disable profiling if we get a fault */ 1199 movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0; */ 1200 movl _curpcb,%ecx 1201 movl $0,PCB_ONFAULT(%ecx) 1202 ret 1203 1204.data 1205 .globl _cyloffset, _curpcb 1206_cyloffset: .long 0 1207 .globl _proc0paddr 1208_proc0paddr: .long 0 1209LF: .asciz "swtch %x" 1210 1211.text 1212 .globl _astoff 1213_astoff: 1214 movl $0,_astpending 1215 ret 1216 1217#define IDTVEC(name) .align 4; .globl _X/**/name; _X/**/name: 1218#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ 1219 call _panic; 1: .asciz msg 1220#define PRINTF(n,msg) pushal ; pushl 1f; call _printf; MSG(msg) ; \ 1221 popl %eax ; popal 1222#define MSG(msg) .data; 1: .asciz msg; .text 1223 1224 .text 1225 1226/* 1227 * Trap and fault vector routines 1228 */ 1229#define TRAP(a) pushl $a ; jmp alltraps 1230#ifdef KGDB 1231#define BPTTRAP(a) pushl $a ; jmp bpttraps 1232#else 1233#define BPTTRAP(a) TRAP(a) 1234#endif 1235 1236IDTVEC(div) 1237 pushl $0; TRAP(T_DIVIDE) 1238IDTVEC(dbg) 1239 pushl $0; BPTTRAP(T_TRCTRAP) 1240IDTVEC(nmi) 1241 pushl $0; TRAP(T_NMI) 1242IDTVEC(bpt) 1243 pushl $0; BPTTRAP(T_BPTFLT) 1244IDTVEC(ofl) 1245 pushl $0; TRAP(T_OFLOW) 1246IDTVEC(bnd) 1247 pushl $0; TRAP(T_BOUND) 1248IDTVEC(ill) 1249 pushl $0; TRAP(T_PRIVINFLT) 1250IDTVEC(dna) 1251 pushl $0; TRAP(T_DNA) 1252IDTVEC(dble) 1253 TRAP(T_DOUBLEFLT) 1254 /*PANIC("Double Fault");*/ 1255IDTVEC(fpusegm) 1256 pushl $0; TRAP(T_FPOPFLT) 1257IDTVEC(tss) 1258 TRAP(T_TSSFLT) 1259 /*PANIC("TSS not valid");*/ 1260IDTVEC(missing) 1261 TRAP(T_SEGNPFLT) 1262IDTVEC(stk) 1263 TRAP(T_STKFLT) 1264IDTVEC(prot) 1265 TRAP(T_PROTFLT) 1266IDTVEC(page) 1267 TRAP(T_PAGEFLT) 1268IDTVEC(rsvd) 1269 pushl $0; TRAP(T_RESERVED) 1270IDTVEC(fpu) 1271 pushl $0; TRAP(T_ARITHTRAP) 1272 /* 17 - 31 reserved for future exp */ 1273IDTVEC(rsvd0) 1274 pushl $0; TRAP(17) 1275IDTVEC(rsvd1) 1276 pushl $0; TRAP(18) 1277IDTVEC(rsvd2) 1278 pushl $0; TRAP(19) 1279IDTVEC(rsvd3) 1280 pushl $0; TRAP(20) 1281IDTVEC(rsvd4) 1282 pushl $0; TRAP(21) 1283IDTVEC(rsvd5) 1284 pushl $0; TRAP(22) 1285IDTVEC(rsvd6) 1286 pushl $0; TRAP(23) 1287IDTVEC(rsvd7) 1288 pushl $0; TRAP(24) 1289IDTVEC(rsvd8) 1290 pushl $0; TRAP(25) 1291IDTVEC(rsvd9) 1292 pushl $0; TRAP(26) 1293IDTVEC(rsvd10) 1294 pushl $0; TRAP(27) 1295IDTVEC(rsvd11) 1296 pushl $0; TRAP(28) 1297IDTVEC(rsvd12) 1298 pushl $0; TRAP(29) 1299IDTVEC(rsvd13) 1300 pushl $0; TRAP(30) 1301IDTVEC(rsvd14) 1302 pushl $0; TRAP(31) 1303 1304alltraps: 1305 pushal 1306 push %ds 1307 push %es 1308 movw $0x10,%ax 1309 movw %ax,%ds 1310 movw %ax,%es 1311calltrap: 1312 incl _cnt+V_TRAP 1313 call _trap 1314 1315 cli 1316 1317 /* this value may also be used in return_to_user_mode */ 1318 movl 0x34(%esp),%esi /* previous cs */ 1319 andl $3,%esi 1320 jz trap_return 1321 1322 cmpl $0,_astpending 1323 jnz do_astflt 1324 1325 cmpw $0,_cpl 1326 jnz return_to_user_mode /* in icu.s */ 1327 1328trap_return: 1329 pop %es 1330 pop %ds 1331 popal 1332 nop 1333 addl $8,%esp # pop type, code 1334 iret 1335 1336do_astflt: 1337 /* pop off the old trap frame, then create a new one that 1338 * will give trap() another chance 1339 */ 1340 pop %es 1341 pop %ds 1342 popa 1343 addl $8,%esp 1344 1345 pushl $0 1346 TRAP (T_ASTFLT) 1347 /* NORETURN */ 1348 1349 1350 1351#ifdef KGDB 1352/* 1353 * This code checks for a kgdb trap, then falls through 1354 * to the regular trap code. 1355 */ 1356bpttraps: 1357 pushal 1358 push %es 1359 push %ds 1360 movw $0x10,%ax 1361 movw %ax,%ds 1362 movw %ax,%es 1363 movzwl 52(%esp),%eax 1364 test $3,%eax 1365 jne calltrap 1366 call _kgdb_trap_glue 1367 jmp calltrap 1368#endif 1369 1370/* 1371 * Call gate entry for syscall 1372 */ 1373 1374IDTVEC(syscall) 1375 pushfl # only for stupid carry bit and more stupid wait3 cc kludge 1376 pushal # only need eax,ecx,edx - trap resaves others 1377 movw $0x10,%ax # switch to kernel segments 1378 movw %ax,%ds 1379 movw %ax,%es 1380 call _syscall 1381 1382 cli 1383 1384 cmpl $0,_astpending 1385 jnz syscall_ast 1386 1387 cmpw $0,_cpl 1388 jnz syscall_fix_cpl 1389 1390 movw __udatasel,%ax # switch back to user segments 1391 movw %ax,%ds 1392 movw %ax,%es 1393 popal 1394 nop 1395 popfl 1396 lret 1397 1398syscall_ast: 1399 movw __udatasel,%ax 1400 movw %ax,%ds 1401 movw %ax,%es 1402 popal 1403 1404 /* convert to trap frame 1405 * stack is now ss, sp, cs, ip, flags 1406 * we want ss, sp, flags, cs, ip 1407 * offsets 16 12 8 4 0 1408 */ 1409 xchgl %eax,8(%esp) /* now eax has cs */ 1410 xchgl %eax,4(%esp) /* now eax has ip */ 1411 xchgl %eax,0(%esp) /* now eax has flags */ 1412 xchgl %eax,8(%esp) /* now eax has its original value */ 1413 pushl $0 1414 TRAP (T_ASTFLT) 1415 /* NORETURN */ 1416 1417syscall_fix_cpl: 1418 movw __udatasel,%ax 1419 movw %ax,%ds 1420 movw %ax,%es 1421 popal 1422 1423 /* convert to trap frame 1424 * stack is now ss, sp, cs, ip, flags 1425 * we want ss, sp, flags, cs, ip 1426 * offsets 16 12 8 4 0 1427 */ 1428 xchgl %eax,8(%esp) /* now eax has cs */ 1429 xchgl %eax,4(%esp) /* now eax has ip */ 1430 xchgl %eax,0(%esp) /* now eax has flags */ 1431 xchgl %eax,8(%esp) /* now eax has its original value */ 1432 1433 pushl $0 1434 pushl $ T_ASTFLT 1435 1436 pushal 1437 nop 1438 push %ds 1439 push %es 1440 movw $0x10,%ax 1441 movw %ax,%ds 1442 movw %ax,%es 1443 1444 movl $1, %esi /* non-zero to indicate return to user mode */ 1445 jmp return_to_user_mode /* in icu.s */ 1446 1447 1448ENTRY(htonl) 1449ENTRY(ntohl) 1450 movl 4(%esp),%eax 1451 xchgb %al,%ah 1452 roll $16,%eax 1453 xchgb %al,%ah 1454 ret 1455 1456ENTRY(htons) 1457ENTRY(ntohs) 1458 movzwl 4(%esp),%eax 1459 xchgb %al,%ah 1460 ret 1461 1462/* DELAY(n) delay about n microseconds */ 1463ENTRY(DELAY) 1464 movl 4(%esp), %ecx 1465 incl %ecx /* make DELAY(0) go through the loop just once */ 1466 1467 /* 1468 * 0x80 is the manufacturing test port, which should be safe to 1469 * write to on any motherboard. The output instruction will 1470 * be executed at bus speed, rather than processor speed, so 1471 * it will be about 750ns on any ISA or EISA machine. 1472 */ 14731: 1474 outb %al, $0x80 1475 loop 1b 1476 ret 1477 1478#include "vector.s" 1479#include "i386/isa/icu.s" 1480