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