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