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.386.c% 9 * 10 * @(#)locore.s 5.6 (Berkeley) 11/25/90 11 */ 12 13/* 14 * locore.s: 4BSD machine support for the Intel 386 15 * Preliminary version 16 * Written by William F. Jolitz, 386BSD Project 17 */ 18 19#include "psl.h" 20#include "pte.h" 21 22#include "errno.h" 23#include "cmap.h" 24 25#include "../i386/trap.h" 26 27/* 28 * Note: This version greatly munged to avoid various assembler errors 29 * that may be fixed in newer versions of gas. Perhaps newer versions 30 * will have more pleasant appearance. 31 */ 32 33 .set IDXSHIFT,10 34 .set SYSTEM,0xFE000000 # virtual address of system start 35 /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ 36 .set SYSPDROFF,0x3F8 # Page dir 37 38 .set IOPHYSmem,0xa0000 39 40/* IBM "compatible" nop - sensitive macro on "fast" 386 machines */ 41#define NOP jmp 7f ; nop ; 7: jmp 7f ; nop ; 7: 42 43/* 44 * User structure is UPAGES at top of user space. 45 */ 46 .set _u,0xFDFFE000 47 .globl _u 48 .set UPDROFF,0x3F7 49 .set UPTEOFF,0x3FE 50 51#define ENTRY(name) \ 52 .globl _/**/name; _/**/name: 53#define ALTENTRY(name) \ 54 .globl _/**/name; _/**/name: 55 56/* 57 * System page table 58 * Mbmap and Usrptmap are enlarged by CLSIZE entries 59 * as they are managed by resource maps starting with index 1 or CLSIZE. 60 */ 61#define SYSMAP(mname, vname, npte) \ 62_/**/mname: .globl _/**/mname; \ 63 .space (npte)*4; \ 64 .set _/**/vname,ptes*NBPG+SYSTEM; \ 65 .globl _/**/vname; \ 66 .set ptes,ptes + npte 67#define ZSYSMAP(mname, vname, npte) \ 68_/**/mname: .globl _/**/mname; \ 69 .set _/**/vname,ptes*NBPG+SYSTEM; \ 70 .globl _/**/vname; 71 72 .data 73 # assumed to start at data mod 4096 74 .set ptes,0 75 SYSMAP(Sysmap,Sysbase,SYSPTSIZE) 76 SYSMAP(Forkmap,forkutl,UPAGES) 77 SYSMAP(Xswapmap,xswaputl,UPAGES) 78 SYSMAP(Xswap2map,xswap2utl,UPAGES) 79 SYSMAP(Swapmap,swaputl,UPAGES) 80 SYSMAP(Pushmap,pushutl,UPAGES) 81 SYSMAP(Vfmap,vfutl,UPAGES) 82 SYSMAP(CMAP1,CADDR1,1) 83 SYSMAP(CMAP2,CADDR2,1) 84 SYSMAP(mmap,vmmap,1) 85 SYSMAP(alignmap,alignutl,1) /* XXX */ 86 SYSMAP(msgbufmap,msgbuf,MSGBUFPTECNT) 87 /* SYSMAP(EMCmap,EMCbase,1) */ 88 SYSMAP(Npxmap,npxutl,UPAGES) 89 SYSMAP(Swtchmap,Swtchbase,UPAGES) 90 .set mbxxx,(NMBCLUSTERS*MCLBYTES) 91 .set mbyyy,(mbxxx>>PGSHIFT) 92 .set mbpgs,(mbyyy+CLSIZE) 93 SYSMAP(Mbmap,mbutl,mbpgs) 94 /* 95 * XXX: NEED way to compute kmem size from maxusers, 96 * device complement 97 */ 98 SYSMAP(kmempt,kmembase,300*CLSIZE) 99#ifdef GPROF 100 SYSMAP(profmap,profbase,600*CLSIZE) 101#endif 102 .set atmemsz,0x100000-0xa0000 103 .set atpgs,(atmemsz>>PGSHIFT) 104 SYSMAP(ATDevmem,atdevbase,atpgs) 105/*#define USRIOSIZE 30*/ 106 SYSMAP(Usriomap,usrio,USRIOSIZE+CLSIZE) /* for PHYSIO */ 107 ZSYSMAP(ekmempt,kmemlimit,0) 108 SYSMAP(Usrptmap,usrpt,USRPTSIZE+CLSIZE) 109 110eSysmap: 111 # .set _Syssize,(eSysmap-_Sysmap)/4 112 .set _Syssize,ptes 113 .globl _Syssize 114 115 /* align on next page boundary */ 116 # . = . + NBPG - 1 & -NBPG /* align to page boundry-does not work*/ 117 # .space (PGSIZE - ((eSysmap-_Sysmap) % PGSIZE)) % PGSIZE 118 .set sz,(4*ptes)%NBPG 119 # .set rptes,(ptes)%1024 120 # .set rptes,1024-rptes 121 # .set ptes,ptes+rptes 122 .set Npdes,10 123 # .space (NBPG - sz) 124 125/* 126 * Initialization 127 */ 128 .data 129 .globl _cpu, _boothowto, _bootdev, _cyloffset, _Maxmem 130_cpu: .long 0 # are we 386, 386sx, or 486 131 .text 132 .globl start 133start: # This is assumed to be location zero! 134 movw $0x1234,%ax 135 movw %ax,0x472 # warm boot 136 jmp 1f 137 .space 0x500 # skip over warm boot shit 138 139 /* enable a20! yecchh!! */ 1401: inb $0x64,%al 141 andb $2,%al 142 jnz 1b 143 movb $0xd1,%al 144 NOP 145 outb %al,$0x64 146 NOP 1471: inb $0x64,%al 148 andb $2,%al 149 jnz 1b 150 movb $0xdf,%al 151 NOP 152 outb %al,$0x60 153 154 /* pass parameters on stack (howto, bootdev, unit, cyloffset) */ 155 156 movl 4(%esp),%eax 157 movl %eax,_boothowto-SYSTEM 158 movl 8(%esp),%eax 159 movl %eax,_bootdev-SYSTEM 160 movl 12(%esp),%eax 161 movl %eax, _cyloffset-SYSTEM 162 163 /* count up memory */ 164 165 xorl %eax,%eax # start with base memory at 0x0 166 #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K 167 movl $ 0xA0,%ecx # look every 4K up to 640K 1681: movl 0(%eax),%ebx # save location to check 169 movl $0xa55a5aa5,0(%eax) # write test pattern 170 cmpl $0xa55a5aa5,0(%eax) # does not check yet for rollover 171 jne 2f 172 movl %ebx,0(%eax) # restore memory 173 addl $ NBPG,%eax 174 loop 1b 1752: shrl $12,%eax 176 movl %eax,_Maxmem-SYSTEM 177 178 movl $0x100000,%eax # next, talley remaining memory 179 #movl $((0xFFF000-0x100000)/NBPG),%ecx 180 movl $(0xFFF-0x100),%ecx 1811: movl 0(%eax),%ebx # save location to check 182 movl $0xa55a5aa5,0(%eax) # write test pattern 183 cmpl $0xa55a5aa5,0(%eax) # does not check yet for rollover 184 jne 2f 185 movl %ebx,0(%eax) # restore memory 186 addl $ NBPG,%eax 187 loop 1b 1882: shrl $12,%eax 189 movl %eax,_Maxmem-SYSTEM 190 191/* clear memory. */ 192 movl $_edata-SYSTEM,%edi 193 movl $_end-SYSTEM,%ecx 194 addl $ NBPG-1,%ecx 195 andl $~(NBPG-1),%ecx 196 movl %ecx,%esi 197 subl %edi,%ecx 198 addl $(UPAGES*NBPG)+NBPG+NBPG+NBPG,%ecx 199 # txt+data+proc zero pt+u. 200 # any other junk? 201 # addl $ NBPG-1,%ecx 202 # andl $~(NBPG-1),%ecx 203 # shrl $2,%ecx # convert to long word count 204 xorl %eax,%eax # pattern 205 cld 206 rep 207 stosb 208 209 /* pass parameters on stack (howto, bootdev, unit, cyloffset) */ 210 211 movl 4(%esp),%eax 212 movl %eax,_boothowto-SYSTEM 213 movl 8(%esp),%eax 214 movl %eax,_bootdev-SYSTEM 215 movl 12(%esp),%eax 216 movl %eax, _cyloffset-SYSTEM 217 218#ifdef notdef 219 220 movl $0x36000,%edi 221 movl $0x68000,%ecx 222 xorl %eax,%eax # pattern 223 cld 224 rep 225 stosb 226 227#endif 228 movl $0x100000,%edi 229 movl $0x200000,%ecx 230 xorl %eax,%eax # pattern 231 cld 232 rep 233 stosb 234/* 235 * Map Kernel 236 * N.B. don't bother with making kernel text RO, as 386 237 * ignores R/W AND U/S bits on kernel access (only v works) ! 238 * 239 * First step - build page tables 240 */ 241 movl %esi,%ecx # this much memory, 242 shrl $ PGSHIFT,%ecx # for this many pte s 243 movl $ PG_V,%eax # having these bits set, 244 movl $_Sysmap-SYSTEM,%ebx # in the kernel page table, 245 # fill in kernel page table. 2461: movl %eax,0(%ebx) 247 addl $ NBPG,%eax # increment physical address 248 addl $4,%ebx # next pte 249 loop 1b 250 251/* temporary double map virt == real */ 252 253 movl $1024,%ecx # for this many pte s, 254 movl $ PG_V,%eax # having these bits set, 255 movl $_Sysmap+4096-SYSTEM,%ebx # in the temporary page table, 256 # fill in kernel page table. 2571: movl %eax,0(%ebx) 258 addl $ NBPG,%eax # increment physical address 259 addl $4,%ebx # next pte 260 loop 1b 261 262/* map I/O memory map */ 263 264 movl $atpgs,%ecx # for this many pte s, 265 movl $(IOPHYSmem|PG_V),%eax # having these bits set, (perhaps URW?) 266 movl $_ATDevmem-SYSTEM,%ebx # in the temporary page table, 267 # fill in kernel page table. 2681: movl %eax,0(%ebx) 269 addl $ NBPG,%eax # increment physical address 270 addl $4,%ebx # next pte 271 loop 1b 272 273/* map proc 0's page table (P1 region) */ 274 275 movl $_Usrptmap-SYSTEM,%ebx # get pt map address 276 lea (0*NBPG)(%esi),%eax # physical address of pt in proc 0 277 orl $ PG_V,%eax # having these bits set, 278 movl %eax,0(%ebx) 279 280 /* map proc 0's _u */ 281 282 movl $ UPAGES,%ecx # for this many pte s, 283 lea (2*NBPG)(%esi),%eax # physical address of _u in proc 0 284 orl $ PG_V|PG_URKW,%eax # having these bits set, 285 lea (0*NBPG)(%esi),%ebx # physical address of stack pt in proc 0 286 addl $(UPTEOFF*4),%ebx 287 # fill in proc 0 stack page table. 2881: movl %eax,0(%ebx) 289 addl $ NBPG,%eax # increment physical address 290 addl $4,%ebx # next pte 291 loop 1b 292 293 /*# map proc 0's page directory*/ 294 lea (1*NBPG)(%esi),%eax # physical address of ptd in proc 0 295 movl %eax,%edi # remember ptd physical address 296#ifdef dubious 297 orl $ PG_V|PG_URKW,%eax # having these bits set, 298 lea (0*NBPG)(%esi),%ebx # physical address of stack pt in proc 0 299 addl $(UPTEOFF*4),%ebx 300 addl $(UPAGES*4),%ebx 301 movl %eax,0(%ebx) 302#endif 303 304/* 305 * Construct a page table directory 306 * (of page directory elements - pde's) 307 */ 308 /* kernel pde's */ 309 movl $_Sysmap-SYSTEM,%eax # physical address of kernel page table 310 orl $ PG_V,%eax # pde entry is valid 311 movl $ Npdes,%ecx # for this many pde s, 312 movl %edi,%ebx # phys address of ptd in proc 0 313 addl $(SYSPDROFF*4), %ebx # offset of pde for kernel 3141: movl %eax,0(%ebx) 315 addl $ NBPG,%eax # increment physical address 316 addl $4,%ebx # next pde 317 loop 1b 318 # install a pde for temporary double map 319 movl $_Sysmap+4096-SYSTEM,%eax # physical address of temp page table 320 # movl $_Sysmap-SYSTEM,%eax # physical address of temp page table 321 orl $ PG_V,%eax # pde entry is valid 322 movl %edi,%ebx # phys address of ptd in proc 0 323 movl %eax,0(%ebx) # which is where temp maps! 324 # install a pde to map _u for proc 0 325 lea (0*NBPG)(%esi),%eax # physical address of pt in proc 0 326 orl $ PG_V,%eax # pde entry is valid 327 movl %edi,%ebx # phys address of ptd in proc 0 328 addl $(UPDROFF*4), %ebx # offset of pde for kernel 329 movl %eax,0(%ebx) # which is where _u maps! 330 331 movl %edi,%eax # phys address of ptd in proc 0 332 orl $ I386_CR3PAT,%eax 333 movl %eax,%cr3 # load ptd addr into mmu 334 movl %cr0,%eax # get control word 335 orl $0x80000001,%eax # and let s page! 336 movl %eax,%cr0 # NOW! 337 338 pushl $begin # jump to high mem! 339 ret # jmp $begin does not work 340begin: 341 movl $_Sysbase,%eax # kernel stack just below system 342 movl %eax,%esp 343 xorl %eax,%eax # mark end of frames 344 movl %eax,%ebp 345 346 movl _Crtat,%eax # initialize Crt video ram address 347 subl $ IOPHYSmem,%eax 348 addl $_atdevbase,%eax 349 movl %eax,_Crtat 350 351 call _init386 # wire 386 chip for unix operation 352 353/* initialize (slightly) the pcb */ 354 movl $_u,%eax # proc0 u-area 355 movl $_usrpt,%ecx 356 movl %ecx,PCB_P0BR(%eax) # p0br: SVA of text/data user PT 357 xorl %ecx,%ecx 358 movl %ecx,PCB_P0LR(%eax) # p0lr: 0 (doesn t really exist) 359 movl $_usrpt+NBPG,%ecx # addr of end of PT 360 subl $ P1PAGES*4,%ecx # backwards size of P1 region 361 movl %ecx,PCB_P1BR(%eax) # p1br: P1PAGES from end of PT 362 movl $ P1PAGES-UPAGES,PCB_P1LR(%eax) # p1lr: vax style 363 movl $ CLSIZE,PCB_SZPT(%eax) # page table size 364 # fninit 365 # pushl $0x262 366 # fldcw 0(%esp) 367 # popl %ecx 368 # fnsave PCB_SAVEFPU(%eax) 369 movl %edi,PCB_CR3(%eax) 370 pushl %edi # cr3 371 movl %esi,%eax 372 addl $(UPAGES*NBPG)+NBPG+NBPG+NBPG,%eax 373 shrl $ PGSHIFT,%eax 374 pushl %eax # firstaddr 375 376 pushl $20 # install signal trampoline code 377 pushl $_u+PCB_SIGC 378 pushl $sigcode 379 call _bcopy 380 addl $12,%esp 381 382 call _main 383 384 .globl __ucodesel,__udatasel 385 movzwl __ucodesel,%eax 386 movzwl __udatasel,%ecx 387 # build outer stack frame 388 pushl %ecx # user ss 389 pushl $_u # user esp 390 pushl %eax # user cs 391 pushl $0 # user ip 392 movw %cx,%ds 393 movw %cx,%es 394 movw %ax,%fs # double map cs to fs 395 movw %cx,%gs # and ds to gs 396 lret # goto user! 397 398 .globl __exit 399__exit: 400 call _reset_cpu 401 lidt xaxa # invalidate interrupt descriptor 402 movl $0,%esp # hardware "freeze" fault 403 ret 404xaxa: .long 0,0 405 406 .set exec,11 407 .set exit,1 408 .globl _icode 409 .globl _initflags 410 .globl _szicode 411/* gas fucks up offset -- */ 412#define LCALL(x,y) .byte 0x9a ; .long y; .word x 413/* 414 * Icode is copied out to process 1 to exec /etc/init. 415 * If the exec fails, process 1 exits. 416 */ 417_icode: 418 # pushl $argv-_icode 419 movl $argv,%eax 420 subl $_icode,%eax 421 pushl %eax 422 423 # pushl $init-_icode 424 movl $init,%eax 425 subl $_icode,%eax 426 pushl %eax 427 pushl %eax # dummy out rta 428 429 movl %esp,%ebp 430 movl $exec,%eax 431 LCALL(0x7,0x0) 432 pushl %eax 433 movl $exit,%eax 434 pushl %eax # dummy out rta 435 LCALL(0x7,0x0) 436 437init: .asciz "/etc/init" 438 .align 2 439_initflags: 440 .long 0 441argv: .long init-_icode 442 .long _initflags-_icode 443 .long 0 444_szicode: 445 .long _szicode-_icode 446sigcode: 447 movl 12(%esp),%eax # unsure if call will dec stack 1st 448 call %eax 449 xorl %eax,%eax # smaller movl $103,%eax 450 movb $103,%al # sigreturn() 451 LCALL(0x7,0) # enter kernel with args on stack 452 hlt # never gets here 453 454 455 .globl ___udivsi3 456___udivsi3: 457 movl 4(%esp),%eax 458 xorl %edx,%edx 459 divl 8(%esp) 460 ret 461 462 .globl ___divsi3 463___divsi3: 464 movl 4(%esp),%eax 465 xorl %edx,%edx 466 cltd 467 idivl 8(%esp) 468 ret 469 470 .globl _inb 471_inb: movl 4(%esp),%edx 472 subl %eax,%eax # clr eax 473 NOP 474 inb %dx,%al 475 NOP 476 ret 477 478 .globl _outb 479_outb: movl 4(%esp),%edx 480 movl 8(%esp),%eax 481 NOP 482 outb %al,%dx 483 NOP 484 ret 485 486 # 487 # bzero (base,cnt) 488 # 489 490 .globl _bzero 491 .globl _blkclr 492_bzero: 493_blkclr: 494 pushl %edi 495 movl 8(%esp),%edi 496 movl 12(%esp),%ecx 497 xorl %eax,%eax 498 shrl $2,%ecx 499 cld 500 rep 501 stosl 502 movl 12(%esp),%ecx 503 andl $3,%ecx 504 rep 505 stosb 506 popl %edi 507 ret 508 509 # 510 # fillw (pat,base,cnt) 511 # 512 513 .globl _fillw 514_fillw: 515 pushl %edi 516 movl 8(%esp),%eax 517 movl 12(%esp),%edi 518 movl 16(%esp),%ecx 519 # xorl %eax,%eax 520 cld 521 rep 522 stosw 523 popl %edi 524 ret 525 526 # 527 # bcopy (src,dst,cnt) 528 # NOTE: does not (yet) handle overlapped copies 529 # 530 531 .globl _bcopy 532_bcopy: 533 pushl %esi 534 pushl %edi 535 movl 12(%esp),%esi 536 movl 16(%esp),%edi 537 movl 20(%esp),%ecx 538 shrl $2,%ecx 539 cld 540 rep 541 movsl 542 movl 20(%esp),%ecx 543 andl $3,%ecx 544 rep 545 movsb 546 popl %edi 547 popl %esi 548 xorl %eax,%eax 549 ret 550 551 .globl _copyout 552_copyout: 553 movl $cpyflt,_nofault # in case we page/protection violate 554 pushl %esi 555 pushl %edi 556 movl 12(%esp),%esi 557 movl 16(%esp),%edi 558 movl 20(%esp),%ecx 559 shrl $2,%ecx 560 cld 561 rep 562 movsl 563 movl 20(%esp),%ecx 564 andl $3,%ecx 565 rep 566 movsb 567 popl %edi 568 popl %esi 569 xorl %eax,%eax 570 movl %eax,_nofault 571 ret 572 573 .globl _copyin 574_copyin: 575 movl $cpyflt,_nofault # in case we page/protection violate 576 pushl %esi 577 pushl %edi 578 movl 12(%esp),%esi 579 movl 16(%esp),%edi 580 movl 20(%esp),%ecx 581 shrl $2,%ecx 582 cld 583 rep 584 movsl 585 movl 20(%esp),%ecx 586 andl $3,%ecx 587 rep 588 movsb 589 popl %edi 590 popl %esi 591 xorl %eax,%eax 592 movl %eax,_nofault 593 ret 594 595cpyflt: popl %edi 596 popl %esi 597 xorl %eax,%eax 598 movl %eax,_nofault 599 movl $ EFAULT,%eax 600 ret 601 602 # insb(port,addr,cnt) 603 .globl _insb 604_insb: 605 pushl %edi 606 movw 8(%esp),%dx 607 movl 12(%esp),%edi 608 movl 16(%esp),%ecx 609 cld 610 NOP 611 rep 612 insb 613 NOP 614 movl %edi,%eax 615 popl %edi 616 ret 617 618 # insw(port,addr,cnt) 619 .globl _insw 620_insw: 621 pushl %edi 622 movw 8(%esp),%dx 623 movl 12(%esp),%edi 624 movl 16(%esp),%ecx 625 cld 626 NOP 627 .byte 0x66,0xf2,0x6d # rep insw 628 NOP 629 movl %edi,%eax 630 popl %edi 631 ret 632 633 # outsw(port,addr,cnt) 634 .globl _outsw 635_outsw: 636 pushl %esi 637 movw 8(%esp),%dx 638 movl 12(%esp),%esi 639 movl 16(%esp),%ecx 640 cld 641 NOP 642 .byte 0x66,0xf2,0x6f # rep outsw 643 NOP 644 movl %esi,%eax 645 popl %esi 646 ret 647 648 # lgdt(*gdt, ngdt) 649 .globl _lgdt 650 # .globl _gdt 651xxx: .word 31 652 .long 0 653_lgdt: 654 movl 4(%esp),%eax 655 movl %eax,xxx+2 656 movl 8(%esp),%eax 657 movw %ax,xxx 658 lgdt xxx 659 jmp 1f 660 NOP 6611: movw $0x10,%ax 662 movw %ax,%ds 663 movw %ax,%es 664 movw %ax,%ss 665 movl 0(%esp),%eax 666 pushl %eax 667 movl $8,4(%esp) 668 lret 669 670 # lidt(*idt, nidt) 671 .globl _lidt 672yyy: .word 255 673 .long 0 674_lidt: 675 movl 4(%esp),%eax 676 movl %eax,yyy+2 677 movl 8(%esp),%eax 678 movw %ax,yyy 679 lidt yyy 680 ret 681 682 # lldt(sel) 683 .globl _lldt 684_lldt: 685 movl 4(%esp),%eax 686 lldt %eax 687 ret 688 689 # ltr(sel) 690 .globl _ltr 691_ltr: 692 movl 4(%esp),%eax 693 ltr %eax 694 ret 695 696 # lcr3(cr3) 697 .globl _lcr3 698 .globl _load_cr3 699_load_cr3: 700_lcr3: 701 movl 4(%esp),%eax 702 orl $ I386_CR3PAT,%eax 703 movl %eax,%cr3 704 movl %cr3,%eax 705 ret 706 707 # lcr0(cr0) 708 .globl _lcr0 709_lcr0: 710 movl 4(%esp),%eax 711 movl %eax,%cr0 712 ret 713 714 # rcr0() 715 .globl _rcr0 716_rcr0: 717 movl %cr0,%eax 718 ret 719 720 # rcr2() 721 .globl _rcr2 722_rcr2: 723 movl %cr2,%eax 724 ret 725 726 # rcr3() 727 .globl _rcr3 728 .globl __cr3 729__cr3: 730_rcr3: 731 movl %cr3,%eax 732 ret 733 734 # ssdtosd(*ssdp,*sdp) 735 .globl _ssdtosd 736_ssdtosd: 737 pushl %ebx 738 movl 8(%esp),%ecx 739 movl 8(%ecx),%ebx 740 shll $16,%ebx 741 movl (%ecx),%edx 742 roll $16,%edx 743 movb %dh,%bl 744 movb %dl,%bh 745 rorl $8,%ebx 746 movl 4(%ecx),%eax 747 movw %ax,%dx 748 andl $0xf0000,%eax 749 orl %eax,%ebx 750 movl 12(%esp),%ecx 751 movl %edx,(%ecx) 752 movl %ebx,4(%ecx) 753 popl %ebx 754 ret 755 756/* 757 * {fu,su},{byte,word} 758 */ 759ALTENTRY(fuiword) 760ENTRY(fuword) 761 movl $fusufault,_nofault # in case we page/protection violate 762 movl 4(%esp),%edx 763 .byte 0x65 # use gs 764 movl 0(%edx),%eax 765 xorl %edx,%edx 766 movl %edx,_nofault 767 ret 768 769ENTRY(fusword) 770 movl $fusufault,_nofault # in case we page/protection violate 771 movl 4(%esp),%edx 772 .byte 0x65 # use gs 773 movzwl 0(%edx),%eax 774 xorl %edx,%edx 775 movl %edx,_nofault 776 ret 777 778ALTENTRY(fuibyte) 779ENTRY(fubyte) 780 movl $fusufault,_nofault # in case we page/protection violate 781 movl 4(%esp),%edx 782 .byte 0x65 # use gs 783 movzbl 0(%edx),%eax 784 xorl %edx,%edx 785 movl %edx,_nofault 786 ret 787 788fusufault: 789 xorl %eax,%eax 790 movl %eax,_nofault 791 decl %eax 792 ret 793 794ALTENTRY(suiword) 795ENTRY(suword) 796 movl $fusufault,_nofault # in case we page/protection violate 797 movl 4(%esp),%edx 798 movl 8(%esp),%eax 799 .byte 0x65 # use gs 800 movl %eax,0(%edx) 801 xorl %eax,%eax 802 movl %eax,_nofault 803 ret 804 805ENTRY(susword) 806 movl $fusufault,_nofault # in case we page/protection violate 807 movl 4(%esp),%edx 808 movl 8(%esp),%eax 809 .byte 0x65 # use gs 810 movw %ax,0(%edx) 811 xorl %eax,%eax 812 movl %eax,_nofault 813 ret 814 815ALTENTRY(suibyte) 816ENTRY(subyte) 817 movl $fusufault,_nofault # in case we page/protection violate 818 movl 4(%esp),%edx 819 movl 8(%esp),%eax 820 .byte 0x65 # use gs 821 movb %eax,0(%edx) 822 xorl %eax,%eax 823 movl %eax,_nofault 824 ret 825 826 ALTENTRY(savectx) 827 ENTRY(setjmp) 828 movl 4(%esp),%eax 829 movl %ebx, 0(%eax) # save ebx 830 movl %esp, 4(%eax) # save esp 831 movl %ebp, 8(%eax) # save ebp 832 movl %esi,12(%eax) # save esi 833 movl %edi,16(%eax) # save edi 834 movl (%esp),%edx # get rta 835 movl %edx,20(%eax) # save eip 836 xorl %eax,%eax # return (0); 837 ret 838 839 ENTRY(longjmp) 840 movl 4(%esp),%eax 841 movl 0(%eax),%ebx # restore ebx 842 movl 4(%eax),%esp # restore esp 843 movl 8(%eax),%ebp # restore ebp 844 movl 12(%eax),%esi # restore esi 845 movl 16(%eax),%edi # restore edi 846 movl 20(%eax),%edx # get rta 847 movl %edx,(%esp) # put in return frame 848 xorl %eax,%eax # return (1); 849 incl %eax 850 ret 851/* 852 * The following primitives manipulate the run queues. 853 * _whichqs tells which of the 32 queues _qs 854 * have processes in them. Setrq puts processes into queues, Remrq 855 * removes them from queues. The running process is on no queue, 856 * other processes are on a queue related to p->p_pri, divided by 4 857 * actually to shrink the 0-127 range of priorities into the 32 available 858 * queues. 859 */ 860 861 .globl _whichqs,_qs,_cnt,_panic 862 .comm _noproc,4 863 .comm _runrun,4 864 865/* 866 * Setrq(p) 867 * 868 * Call should be made at spl6(), and p->p_stat should be SRUN 869 */ 870ENTRY(setrq) 871 movl 4(%esp),%eax 872 cmpl $0,P_RLINK(%eax) # should not be on q already 873 je set1 874 pushl $set2 875 call _panic 876set1: 877 movzbl P_PRI(%eax),%edx 878 shrl $2,%edx 879 btsl %edx,_whichqs # set q full bit 880 shll $3,%edx 881 addl $_qs,%edx # locate q hdr 882 movl %edx,P_LINK(%eax) # link process on tail of q 883 movl P_RLINK(%edx),%ecx 884 movl %ecx,P_RLINK(%eax) 885 movl %eax,P_RLINK(%edx) 886 movl %eax,P_LINK(%ecx) 887 ret 888 889set2: .asciz "setrq" 890 891/* 892 * Remrq(p) 893 * 894 * Call should be made at spl6(). 895 */ 896ENTRY(remrq) 897 movl 4(%esp),%eax 898 movzbl P_PRI(%eax),%edx 899 shrl $2,%edx 900 btrl %edx,_whichqs # clear full bit, panic if clear already 901 jb rem1 902 pushl $rem3 903 call _panic 904rem1: 905 pushl %edx 906 movl P_LINK(%eax),%ecx # unlink process 907 movl P_RLINK(%eax),%edx 908 movl %edx,P_RLINK(%ecx) 909 movl P_RLINK(%eax),%ecx 910 movl P_LINK(%eax),%edx 911 movl %edx,P_LINK(%ecx) 912 popl %edx 913 movl $_qs,%ecx 914 shll $3,%edx 915 addl %edx,%ecx 916 cmpl P_LINK(%ecx),%ecx # q still has something? 917 je rem2 918 shrl $3,%edx # yes, set bit as still full 919 btsl %edx,_whichqs 920rem2: 921 movl $0,P_RLINK(%eax) # zap reverse link to indicate off list 922 ret 923 924rem3: .asciz "remrq" 925sw0: .asciz "swtch" 926sw01: .asciz "swtch1" 927sw02: .asciz "swtch2" 928 929/* 930 * When no processes are on the runq, Swtch branches to idle 931 * to wait for something to come ready. 932 */ 933 .globl Idle 934Idle: 935idle: 936 call _spl0 937 cmpl $0,_whichqs 938 jne sw1 939 hlt # wait for interrupt 940 jmp idle 941 942badsw: 943 pushl $sw0 944 call _panic 945 /*NOTREACHED*/ 946 947/* 948 * Swtch() 949 */ 950ENTRY(swtch) 951 movl _cpl,%eax 952 movl %eax,_u+PCB_IML 953 movl $1,%eax 954 movl %eax,_noproc 955 incl _cnt+V_SWTCH 956sw1: 957 cli 958 bsfl _whichqs,%eax # find a full q 959 jz idle # if none, idle 960swfnd: 961 btrl %eax,_whichqs # clear q full status 962 jnb sw1 # if it was clear, look for another 963 pushl %eax # save which one we are using 964 shll $3,%eax 965 addl $_qs,%eax # select q 966 pushl %eax 967 968 cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) 969 je badsw # not possible 970 movl P_LINK(%eax),%ecx # unlink from front of process q 971 movl P_LINK(%ecx),%edx 972 movl %edx,P_LINK(%eax) 973 movl P_RLINK(%ecx),%eax 974 movl %eax,P_RLINK(%edx) 975 976 popl %eax 977 popl %edx 978 cmpl P_LINK(%ecx),%eax # q empty 979 je sw2 980 btsl %edx,_whichqs # nope, indicate full 981sw2: 982 movl $0,%eax 983 movl %eax,_noproc 984 movl %eax,_runrun 985 cmpl $0,P_WCHAN(%ecx) 986 jne badsw 987 cmpb $ SRUN,P_STAT(%ecx) 988 jne badsw 989 movl %eax,P_RLINK(%ecx) 990 991 movl P_ADDR(%ecx),%edx 992 movl (%edx),%eax 993 movl %eax,_Swtchmap 994 movl 4(%edx),%eax 995 movl %eax,_Swtchmap+4 996 # movl %cr3,%eax 997 # orl $ I386_CR3PAT,%eax 998 # movl %eax,%cr3 999 movl _Swtchbase+PCB_CR3,%edx 1000 1001 # pushal; pushl %edx ; pushl P_CR3(%ecx); pushl $l2; call _pg; popl %eax ; popl %eax; popl %eax ; popal ; .data ; l2: .asciz "s %x %x " ; .text 1002 1003/* switch to new process. first, save context as needed */ 1004 movl $_u,%ecx 1005 1006 movl (%esp),%eax # Hardware registers 1007 movl %eax, PCB_EIP(%ecx) 1008 movl %ebx, PCB_EBX(%ecx) 1009 movl %esp, PCB_ESP(%ecx) 1010 movl %ebp, PCB_EBP(%ecx) 1011 movl %esi, PCB_ESI(%ecx) 1012 movl %edi, PCB_EDI(%ecx) 1013 1014 fsave PCB_SAVEFPU(%ecx) 1015 1016 movl _CMAP2,%eax # save temporary map PTE 1017 movl %eax,PCB_CMAP2(%ecx) # in our context 1018 1019 orl $ I386_CR3PAT,%edx 1020 movl %edx,%cr3 # context switch 1021 1022 movl $_u,%ecx 1023 # .globl __gsel_tss 1024 # movw __gsel_tss,%ax 1025 # ltr %ax 1026 1027/* restore context */ 1028 movl PCB_EBX(%ecx), %ebx 1029 movl PCB_ESP(%ecx), %esp 1030 movl PCB_EBP(%ecx), %ebp 1031 movl PCB_ESI(%ecx), %esi 1032 movl PCB_EDI(%ecx), %edi 1033 movl PCB_EIP(%ecx), %eax 1034 movl %eax, (%esp) 1035 1036 frstor PCB_SAVEFPU(%ecx) 1037 1038 movl PCB_CMAP2(%ecx),%eax # get temporary map 1039 movl %eax,_CMAP2 # reload temporary map PTE 1040#ifdef FPUNOTYET 1041#endif 1042 cmpl $0,PCB_SSWAP(%ecx) # do an alternate return? 1043 jne res3 # yes, go reload regs 1044 1045 pushl PCB_IML(%ecx) 1046 call _splx 1047 popl %eax 1048 movl $0,%eax 1049 ret 1050 1051res3: 1052 xorl %eax,%eax # inline restore context 1053 xchgl PCB_SSWAP(%ecx),%eax # addr of saved context, clear it 1054 1055 #pushal; pushl 20(%eax); pushl $l2; call _printf; popl %eax ; popl %eax; popal ; .data ; l2: .asciz "s %x\n" ; .text 1056 1057 movl 0(%eax),%ebx # restore ebx 1058 movl 4(%eax),%esp # restore esp 1059 movl 8(%eax),%ebp # restore ebp 1060 movl 12(%eax),%esi # restore esi 1061 movl 16(%eax),%edi # restore edi 1062 movl 20(%eax),%edx # get rta 1063 movl %edx,(%esp) # put in return frame 1064 call _spl0 1065 xorl %eax,%eax # return (1); 1066 incl %eax 1067 ret 1068 1069/* 1070 * Resume(p_addr) 1071 * current just used to fillout u. tss so fork can fake a return to swtch 1072 * [ all thats really needed is esp and eip ] 1073 */ 1074ENTRY(resume) 1075 # movl 4(%esp),%ecx 1076 movl $_u,%ecx 1077 movl (%esp),%eax 1078 movl %eax, PCB_EIP(%ecx) 1079 movl %ebx, PCB_EBX(%ecx) 1080 movl %esp, PCB_ESP(%ecx) 1081 movl %ebp, PCB_EBP(%ecx) 1082 movl %esi, PCB_ESI(%ecx) 1083 movl %edi, PCB_EDI(%ecx) 1084#ifdef FPUNOTYET 1085#endif 1086 fsave PCB_SAVEFPU(%ecx) 1087 movl _cpl,%eax 1088 movl %eax,PCB_IML(%ecx) 1089 movl $0,%eax 1090 ret 1091 1092.data 1093 .globl _cyloffset 1094_cyloffset: .long 0 1095 .globl _nofault 1096_nofault: .long 0 1097.text 1098 # To be done: 1099 .globl _addupc 1100 .globl _astoff 1101 .globl _doadump 1102 .globl _inittodr 1103 .globl _physaddr 1104_addupc: 1105 .byte 0xcc 1106_astoff: 1107 ret 1108_doadump: 1109 .byte 0xcc 1110_physaddr: 1111 .byte 0xcc 1112 1113#define IDTVEC(name) .align 4; .globl _X/**/name; _X/**/name: 1114/*#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ 1115 call _panic; 1: .asciz msg*/ 1116#define PRINTF(n,msg) pushal ; pushl 1f; call _printf; MSG(msg) ; popl %eax ; popal 1117#define MSG(msg) .data; 1: .asciz msg; .text 1118 1119 .text 1120 1121/* 1122 * Trap and fault vector routines 1123 */ 1124#define TRAP(a) pushl $ a; jmp alltraps 1125 1126IDTVEC(div) 1127 pushl $0; TRAP(T_DIVIDE) 1128IDTVEC(dbg) 1129 pushl $0; TRAP(T_TRCTRAP) 1130IDTVEC(nmi) 1131 pushl $0; TRAP(T_NMI) 1132IDTVEC(bpt) 1133 pushl $0; TRAP(T_BPTFLT) 1134IDTVEC(ofl) 1135 pushl $0; TRAP(T_OFLOW) 1136IDTVEC(bnd) 1137 pushl $0; TRAP(T_BOUND) 1138IDTVEC(ill) 1139 pushl $0; TRAP(T_PRIVINFLT) 1140IDTVEC(dna) 1141 pushl $0; TRAP(T_DNA) 1142IDTVEC(dble) 1143 TRAP(T_DOUBLEFLT) 1144 /*PANIC("Double Fault");*/ 1145IDTVEC(fpusegm) 1146 pushl $0; TRAP(T_FPOPFLT) 1147IDTVEC(tss) 1148 TRAP(T_TSSFLT) 1149 /*PANIC("TSS not valid");*/ 1150IDTVEC(missing) 1151 TRAP(T_SEGNPFLT) 1152IDTVEC(stk) 1153 TRAP(T_STKFLT) 1154IDTVEC(prot) 1155 TRAP(T_PROTFLT) 1156IDTVEC(page) 1157 TRAP(T_PAGEFLT) 1158IDTVEC(rsvd) 1159 pushl $0; TRAP(T_RESERVED) 1160IDTVEC(fpu) 1161 pushl $0; TRAP(T_ARITHTRAP) 1162 /* 17 - 31 reserved for future exp */ 1163IDTVEC(rsvd0) 1164 pushl $0; TRAP(17) 1165IDTVEC(rsvd1) 1166 pushl $0; TRAP(18) 1167IDTVEC(rsvd2) 1168 pushl $0; TRAP(19) 1169IDTVEC(rsvd3) 1170 pushl $0; TRAP(20) 1171IDTVEC(rsvd4) 1172 pushl $0; TRAP(21) 1173IDTVEC(rsvd5) 1174 pushl $0; TRAP(22) 1175IDTVEC(rsvd6) 1176 pushl $0; TRAP(23) 1177IDTVEC(rsvd7) 1178 pushl $0; TRAP(24) 1179IDTVEC(rsvd8) 1180 pushl $0; TRAP(25) 1181IDTVEC(rsvd9) 1182 pushl $0; TRAP(26) 1183IDTVEC(rsvd10) 1184 pushl $0; TRAP(27) 1185IDTVEC(rsvd11) 1186 pushl $0; TRAP(28) 1187IDTVEC(rsvd12) 1188 pushl $0; TRAP(29) 1189IDTVEC(rsvd13) 1190 pushl $0; TRAP(30) 1191IDTVEC(rsvd14) 1192 pushl $0; TRAP(31) 1193 1194alltraps: 1195 pushal 1196 push %ds 1197 push %es 1198 movw $0x10,%ax 1199 movw %ax,%ds 1200 movw %ax,%es 1201 incl _cnt+V_TRAP 1202 call _trap 1203 1204#ifdef junk 1205 cmpl $0xfc000000,12*4(%esp) # is it a user pc 1206 ja 1f 1207 cmpw $0x1f,13*4(%esp) # is it a user cs 1208 je 1f 1209 .data ; lx: .asciz "t user cs %x?" ; .text 12102: 1211 movl 13*4(%esp),%eax 1212 pushl %eax 1213 pushl $lx 1214 call _pg 1215 popl %eax ; popl %eax 1216 jmp 2b 12171: 1218#endif junk 1219 1220 pop %es 1221 pop %ds 1222 popal 1223 addl $8,%esp # pop type, code 1224 iret 1225 1226/* 1227 * Call gate entry for syscall 1228 */ 1229 1230IDTVEC(syscall) 1231 pushfl # only for stupid carry bit and more stupid wait3 cc kludge 1232 pushal # only need eax,ecx,edx - trap resaves others 1233 movw $0x10,%ax # switch to kernel segments 1234 movw %ax,%ds 1235 movw %ax,%es 1236 call _syscall 1237 1238#ifdef notdef 1239 cmpw $0x1f,10*4(%esp) # is user cs what it should be? 1240 jz 1f 1241 .data ; lz: .asciz "s user cs %x?" ; .text 12422: 1243 movl 10*4(%esp),%eax 1244 pushl %eax 1245 pushl $lz 1246 call _pg 1247 jmp 2b 12481: 1249#endif 1250 1251 movw __udatasel,%ax # switch back to user segments 1252 movw %ax,%ds 1253 movw %ax,%es 1254 popal 1255 popfl 1256 lret # back we go, we hope! 1257 1258ENTRY(htonl) 1259ENTRY(ntohl) 1260 movl 4(%esp),%eax 1261 xchgb %al,%ah 1262 roll $16,%eax 1263 xchgb %al,%ah 1264 ret 1265 1266ENTRY(htons) 1267ENTRY(ntohs) 1268 movzwl 4(%esp),%eax 1269 xchgb %al,%ah 1270 ret 1271