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.3 (Berkeley) 05/13/91 11 */ 12 13 14/* 15 * locore.s: 4BSD machine support for the Intel 386 16 * Preliminary version 17 * Written by William F. Jolitz, 386BSD Project 18 */ 19 20#include "assym.s" 21#include "machine/psl.h" 22#include "machine/pte.h" 23 24#include "errno.h" 25 26#include "machine/trap.h" 27 28/* 29 * Note: This version greatly munged to avoid various assembler errors 30 * that may be fixed in newer versions of gas. Perhaps newer versions 31 * will have more pleasant appearance. 32 */ 33 34 .set IDXSHIFT,10 35 .set SYSTEM,0xFE000000 # virtual address of system start 36 /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ 37 .set SYSPDROFF,0x3F8 # Page dir index of System Base 38 39/* IBM "compatible" nop - sensitive macro on "fast" 386 machines */ 40#define NOP ; 41 42/* 43 * PTmap is recursive pagemap at top of virtual address space. 44 * Within PTmap, the page directory can be found (third indirection). 45 */ 46 .set PDRPDROFF,0x3F7 # Page dir index of Page dir 47 .globl _PTmap, _PTD, _PTDpde 48 .set _PTmap,0xFDC00000 49 .set _PTD,0xFDFF7000 50 .set _PTDpde,0xFDFF7000+4*PDRPDROFF 51 52/* 53 * APTmap, APTD is the alternate recursive pagemap. 54 * It's used when modifying another process's page tables. 55 */ 56 .set APDRPDROFF,0x3FE # Page dir index of Page dir 57 .globl _APTmap, _APTD, _APTDpde 58 .set _APTmap,0xFF800000 59 .set _APTD,0xFFBFE000 60 .set _APTDpde,0xFDFF7000+4*APDRPDROFF 61 62/* 63 * Access to each processes kernel stack is via a region of 64 * per-process address space (at the beginning), immediatly above 65 * the user process stack. 66 */ 67 .set _kstack, USRSTACK 68 .globl _kstack 69 .set PPDROFF,0x3F6 70 .set PPTEOFF,0x400-UPAGES # 0x3FE 71 72#define ENTRY(name) \ 73 .globl _/**/name; _/**/name: 74#define ALTENTRY(name) \ 75 .globl _/**/name; _/**/name: 76 77/* 78 * Initialization 79 */ 80 .data 81 .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys 82_cpu: .long 0 # are we 386, 386sx, or 486 83_cold: .long 1 # cold till we are not 84_atdevbase: .long 0 # location of start of iomem in virtual 85_atdevphys: .long 0 # location of device mapping ptes (phys) 86 87 .globl _IdlePTD, _KPTphys 88_IdlePTD: .long 0 89_KPTphys: .long 0 90 91 .space 512 92tmpstk: 93 .text 94 .globl start 95start: movw $0x1234,%ax 96 movw %ax,0x472 # warm boot 97 jmp 1f 98 .space 0x500 # skip over warm boot shit 99 100 /* enable a20! yecchh!! - move this to bootstrap? */ 1011: inb $0x64,%al 102 andb $2,%al 103 jnz 1b 104 movb $0xd1,%al 105 NOP 106 outb %al,$0x64 107 NOP 1081: inb $0x64,%al 109 andb $2,%al 110 jnz 1b 111 movb $0xdf,%al 112 NOP 113 outb %al,$0x60 114 115 /* 116 * pass parameters on stack (howto, bootdev, unit, cyloffset) 117 * note: 0(%esp) is return address of boot 118 * ( if we want to hold onto /boot, it's physical %esp up to _end) 119 */ 120 121 1: movl 4(%esp),%eax 122 movl %eax,_boothowto-SYSTEM 123 movl 8(%esp),%eax 124 movl %eax,_bootdev-SYSTEM 125 movl 12(%esp),%eax 126 movl %eax, _cyloffset-SYSTEM 127 128 /* count up memory */ 129 130 xorl %eax,%eax # start with base memory at 0x0 131 #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K 132 movl $ 0xA0,%ecx # look every 4K up to 640K 1331: movl 0(%eax),%ebx # save location to check 134 movl $0xa55a5aa5,0(%eax) # write test pattern 135 /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */ 136 cmpl $0xa55a5aa5,0(%eax) # does not check yet for rollover 137 jne 2f 138 movl %ebx,0(%eax) # restore memory 139 addl $ NBPG,%eax 140 loop 1b 1412: shrl $12,%eax 142 movl %eax,_Maxmem-SYSTEM 143 144 movl $0x100000,%eax # next, talley remaining memory 145 #movl $((0xFFF000-0x100000)/NBPG),%ecx 146 movl $(0xFFF-0x100),%ecx 1471: movl 0(%eax),%ebx # save location to check 148 movl $0xa55a5aa5,0(%eax) # write test pattern 149 cmpl $0xa55a5aa5,0(%eax) # does not check yet for rollover 150 jne 2f 151 movl %ebx,0(%eax) # restore memory 152 addl $ NBPG,%eax 153 loop 1b 1542: shrl $12,%eax 155 movl %eax,_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 280 movl $0,_PTD 281 call _main 282 popl %esi 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 xorl %eax,%eax 487 cld 488 ret 489 490 .globl _copyout 491_copyout: 492 movl _curpcb,%eax 493 movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate 494 pushl %esi 495 pushl %edi 496 movl 12(%esp),%esi 497 movl 16(%esp),%edi 498 movl 20(%esp),%ecx 499 shrl $2,%ecx 500 cld 501 rep 502 movsl 503 movl 20(%esp),%ecx 504 andl $3,%ecx 505 rep 506 movsb 507 popl %edi 508 popl %esi 509 xorl %eax,%eax 510 movl _curpcb,%edx 511 movl %eax,PCB_ONFAULT(%edx) 512 ret 513 514 .globl _copyin 515_copyin: 516 movl _curpcb,%eax 517 movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate 518 pushl %esi 519 pushl %edi 520 movl 12(%esp),%esi 521 movl 16(%esp),%edi 522 movl 20(%esp),%ecx 523 shrl $2,%ecx 524 cld 525 rep 526 movsl 527 movl 20(%esp),%ecx 528 andl $3,%ecx 529 rep 530 movsb 531 popl %edi 532 popl %esi 533 xorl %eax,%eax 534 movl _curpcb,%edx 535 movl %eax,PCB_ONFAULT(%edx) 536 ret 537 538cpyflt: popl %edi 539 popl %esi 540 movl _curpcb,%edx 541 movl $0,PCB_ONFAULT(%edx) 542 movl $ EFAULT,%eax 543 ret 544 545 # insb(port,addr,cnt) 546 .globl _insb 547_insb: 548 pushl %edi 549 movw 8(%esp),%dx 550 movl 12(%esp),%edi 551 movl 16(%esp),%ecx 552 cld 553 NOP 554 rep 555 insb 556 NOP 557 movl %edi,%eax 558 popl %edi 559 ret 560 561 # insw(port,addr,cnt) 562 .globl _insw 563_insw: 564 pushl %edi 565 movw 8(%esp),%dx 566 movl 12(%esp),%edi 567 movl 16(%esp),%ecx 568 cld 569 NOP 570 .byte 0x66,0xf2,0x6d # rep insw 571 NOP 572 movl %edi,%eax 573 popl %edi 574 ret 575 576 # outsw(port,addr,cnt) 577 .globl _outsw 578_outsw: 579 pushl %esi 580 movw 8(%esp),%dx 581 movl 12(%esp),%esi 582 movl 16(%esp),%ecx 583 cld 584 NOP 585 .byte 0x66,0xf2,0x6f # rep outsw 586 NOP 587 movl %esi,%eax 588 popl %esi 589 ret 590 591 # lgdt(*gdt, ngdt) 592 .globl _lgdt 593 # .globl _gdt 594xxx: .word 31 595 .long 0 596_lgdt: 597 movl 4(%esp),%eax 598 movl %eax,xxx+2 599 movl 8(%esp),%eax 600 movw %ax,xxx 601 lgdt xxx 602 jmp 1f 603 NOP 6041: movw $0x10,%ax 605 movw %ax,%ds 606 movw %ax,%es 607 movw %ax,%ss 608 movl 0(%esp),%eax 609 pushl %eax 610 movl $8,4(%esp) 611 lret 612 613 # lidt(*idt, nidt) 614 .globl _lidt 615yyy: .word 255 616 .long 0 617_lidt: 618 movl 4(%esp),%eax 619 movl %eax,yyy+2 620 movl 8(%esp),%eax 621 movw %ax,yyy 622 lidt yyy 623 ret 624 625 # lldt(sel) 626 .globl _lldt 627_lldt: 628 movl 4(%esp),%eax 629 lldt %eax 630 ret 631 632 # ltr(sel) 633 .globl _ltr 634_ltr: 635 movl 4(%esp),%eax 636 ltr %eax 637 ret 638 639 # lcr3(cr3) 640 .globl _lcr3 641 .globl _load_cr3 642_load_cr3: 643_lcr3: 644 inb $0x84,%al # check wristwatch 645 movl 4(%esp),%eax 646 orl $ I386_CR3PAT,%eax 647 movl %eax,%cr3 648 inb $0x84,%al # check wristwatch 649 ret 650 651 # tlbflush() 652 .globl _tlbflush 653_tlbflush: 654 inb $0x84,%al # check wristwatch 655 movl %cr3,%eax 656 orl $ I386_CR3PAT,%eax 657 movl %eax,%cr3 658 inb $0x84,%al # check wristwatch 659 ret 660 661 # lcr0(cr0) 662 .globl _lcr0,_load_cr0 663_lcr0: 664_load_cr0: 665 movl 4(%esp),%eax 666 movl %eax,%cr0 667 ret 668 669 # rcr0() 670 .globl _rcr0 671_rcr0: 672 movl %cr0,%eax 673 ret 674 675 # rcr2() 676 .globl _rcr2 677_rcr2: 678 movl %cr2,%eax 679 ret 680 681 # rcr3() 682 .globl _rcr3 683 .globl __cr3 684__cr3: 685_rcr3: 686 movl %cr3,%eax 687 ret 688 689 # ssdtosd(*ssdp,*sdp) 690 .globl _ssdtosd 691_ssdtosd: 692 pushl %ebx 693 movl 8(%esp),%ecx 694 movl 8(%ecx),%ebx 695 shll $16,%ebx 696 movl (%ecx),%edx 697 roll $16,%edx 698 movb %dh,%bl 699 movb %dl,%bh 700 rorl $8,%ebx 701 movl 4(%ecx),%eax 702 movw %ax,%dx 703 andl $0xf0000,%eax 704 orl %eax,%ebx 705 movl 12(%esp),%ecx 706 movl %edx,(%ecx) 707 movl %ebx,4(%ecx) 708 popl %ebx 709 ret 710 711/* 712 * {fu,su},{byte,word} 713 */ 714ALTENTRY(fuiword) 715ENTRY(fuword) 716 movl _curpcb,%ecx 717 movl $fusufault,PCB_ONFAULT(%ecx) 718 movl 4(%esp),%edx 719 # .byte 0x65 # use gs 720 movl 0(%edx),%eax 721 movl $0,PCB_ONFAULT(%ecx) 722 ret 723 724ENTRY(fusword) 725 movl _curpcb,%ecx 726 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 727 movl 4(%esp),%edx 728 # .byte 0x65 # use gs 729 movzwl 0(%edx),%eax 730 movl $0,PCB_ONFAULT(%ecx) 731 ret 732 733ALTENTRY(fuibyte) 734ENTRY(fubyte) 735 movl _curpcb,%ecx 736 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 737 movl 4(%esp),%edx 738 # .byte 0x65 # use gs 739 movzbl 0(%edx),%eax 740 movl $0,PCB_ONFAULT(%ecx) 741 ret 742 743fusufault: 744 movl _curpcb,%ecx 745 xorl %eax,%eax 746 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 747 decl %eax 748 ret 749 750ALTENTRY(suiword) 751ENTRY(suword) 752 movl _curpcb,%ecx 753 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 754 movl 4(%esp),%edx 755 movl 8(%esp),%eax 756 # .byte 0x65 # use gs 757 movl %eax,0(%edx) 758 xorl %eax,%eax 759 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 760 ret 761 762ENTRY(susword) 763 movl _curpcb,%ecx 764 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 765 movl 4(%esp),%edx 766 movl 8(%esp),%eax 767 # .byte 0x65 # use gs 768 movw %ax,0(%edx) 769 xorl %eax,%eax 770 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 771 ret 772 773ALTENTRY(suibyte) 774ENTRY(subyte) 775 movl _curpcb,%ecx 776 movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate 777 movl 4(%esp),%edx 778 movl 8(%esp),%eax 779 # .byte 0x65 # use gs 780 movb %eax,0(%edx) 781 xorl %eax,%eax 782 movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate 783 ret 784 785 ENTRY(setjmp) 786 movl 4(%esp),%eax 787 movl %ebx, 0(%eax) # save ebx 788 movl %esp, 4(%eax) # save esp 789 movl %ebp, 8(%eax) # save ebp 790 movl %esi,12(%eax) # save esi 791 movl %edi,16(%eax) # save edi 792 movl (%esp),%edx # get rta 793 movl %edx,20(%eax) # save eip 794 xorl %eax,%eax # return (0); 795 ret 796 797#ifdef notdef 798 ENTRY(longjmp) 799 movl 4(%esp),%eax 800 movl 0(%eax),%ebx # restore ebx 801 movl 4(%eax),%esp # restore esp 802 movl 8(%eax),%ebp # restore ebp 803 movl 12(%eax),%esi # restore esi 804 movl 16(%eax),%edi # restore edi 805 movl 20(%eax),%edx # get rta 806 movl %edx,(%esp) # put in return frame 807 xorl %eax,%eax # return (1); 808 incl %eax 809 ret 810#endif 811/* 812 * The following primitives manipulate the run queues. 813 * _whichqs tells which of the 32 queues _qs 814 * have processes in them. Setrq puts processes into queues, Remrq 815 * removes them from queues. The running process is on no queue, 816 * other processes are on a queue related to p->p_pri, divided by 4 817 * actually to shrink the 0-127 range of priorities into the 32 available 818 * queues. 819 */ 820 821 .globl _whichqs,_qs,_cnt,_panic 822 .comm _noproc,4 823 .comm _runrun,4 824 825/* 826 * Setrq(p) 827 * 828 * Call should be made at spl6(), and p->p_stat should be SRUN 829 */ 830ENTRY(setrq) 831 movl 4(%esp),%eax 832 cmpl $0,P_RLINK(%eax) # should not be on q already 833 je set1 834 pushl $set2 835 call _panic 836set1: 837 movzbl P_PRI(%eax),%edx 838 shrl $2,%edx 839 btsl %edx,_whichqs # set q full bit 840 shll $3,%edx 841 addl $_qs,%edx # locate q hdr 842 movl %edx,P_LINK(%eax) # link process on tail of q 843 movl P_RLINK(%edx),%ecx 844 movl %ecx,P_RLINK(%eax) 845 movl %eax,P_RLINK(%edx) 846 movl %eax,P_LINK(%ecx) 847 ret 848 849set2: .asciz "setrq" 850 851/* 852 * Remrq(p) 853 * 854 * Call should be made at spl6(). 855 */ 856ENTRY(remrq) 857 movl 4(%esp),%eax 858 movzbl P_PRI(%eax),%edx 859 shrl $2,%edx 860 btrl %edx,_whichqs # clear full bit, panic if clear already 861 jb rem1 862 pushl $rem3 863 call _panic 864rem1: 865 pushl %edx 866 movl P_LINK(%eax),%ecx # unlink process 867 movl P_RLINK(%eax),%edx 868 movl %edx,P_RLINK(%ecx) 869 movl P_RLINK(%eax),%ecx 870 movl P_LINK(%eax),%edx 871 movl %edx,P_LINK(%ecx) 872 popl %edx 873 movl $_qs,%ecx 874 shll $3,%edx 875 addl %edx,%ecx 876 cmpl P_LINK(%ecx),%ecx # q still has something? 877 je rem2 878 shrl $3,%edx # yes, set bit as still full 879 btsl %edx,_whichqs 880rem2: 881 movl $0,P_RLINK(%eax) # zap reverse link to indicate off list 882 ret 883 884rem3: .asciz "remrq" 885sw0: .asciz "swtch" 886 887/* 888 * When no processes are on the runq, Swtch branches to idle 889 * to wait for something to come ready. 890 */ 891 .globl Idle 892Idle: 893idle: 894 call _spl0 895 cmpl $0,_whichqs 896 jne sw1 897 hlt # wait for interrupt 898 jmp idle 899 900badsw: 901 pushl $sw0 902 call _panic 903 /*NOTREACHED*/ 904 905/* 906 * Swtch() 907 */ 908ENTRY(swtch) 909 910 incl _cnt+V_SWTCH 911 912 /* switch to new process. first, save context as needed */ 913 914 movl _curproc,%ecx 915 movl P_ADDR(%ecx),%ecx 916 917 918 movl (%esp),%eax # Hardware registers 919 movl %eax, PCB_EIP(%ecx) 920 movl %ebx, PCB_EBX(%ecx) 921 movl %esp, PCB_ESP(%ecx) 922 movl %ebp, PCB_EBP(%ecx) 923 movl %esi, PCB_ESI(%ecx) 924 movl %edi, PCB_EDI(%ecx) 925 926#ifdef NPX 927 movb PCB_FLAGS(%ecx),%al 928 /* have we used fp, and need a save? */ 929 andb $ FP_WASUSED|FP_NEEDSSAVE,%al 930 cmpb $ FP_WASUSED|FP_NEEDSSAVE,%al 931 jne 1f 932 movl %cr0,%eax /* insure fp is enabled */ 933 andb $0xfb,%al 934 movl %eax,%cr0 935 fnsave PCB_SAVEFPU(%ecx) 936 orb $4,%al /* disable it */ 937 movl %eax,%cr0 938 movb PCB_FLAGS(%ecx),%al 939 xorb $ FP_NEEDSSAVE,%al /* save processed */ 940 movb %al,PCB_FLAGS(%ecx) 9411: 942#endif 943 944 movl _CMAP2,%eax # save temporary map PTE 945 movl %eax,PCB_CMAP2(%ecx) # in our context 946 947 movw _cpl, %ax 948 movw %ax, PCB_IML(%ecx) # save ipl 949 950 /* save is done, now choose a new process or idle */ 951sw1: 952 cli # XXX? 953 movl _whichqs,%edi 9542: 955 bsfl %edi,%eax # find a full q 956 jz idle # if none, idle 957 # XX update whichqs? 958swfnd: 959 btrl %eax,%edi # clear q full status 960 jnb 2b # if it was clear, look for another 961 movl %eax,%ebx # save which one we are using 962 963 shll $3,%eax 964 addl $_qs,%eax # select q 965 movl %eax,%esi 966 967#ifdef DIAGNOSTIC 968 cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) 969 je badsw # not possible 970#endif 971 972 movl P_LINK(%eax),%ecx # unlink from front of process q 973 movl P_LINK(%ecx),%edx 974 movl %edx,P_LINK(%eax) 975 movl P_RLINK(%ecx),%eax 976 movl %eax,P_RLINK(%edx) 977 978 cmpl P_LINK(%ecx),%esi # q empty 979 je 3f 980 btsl %ebx,%edi # nope, set to indicate full 9813: 982 movl %edi,_whichqs # update q status 983 984 movl $0,%eax 985 movl %ecx,_curproc 986 movl %eax,_want_resched 987 988#ifdef DIAGNOSTIC 989 cmpl %eax,P_WCHAN(%ecx) 990 jne badsw 991 cmpb $ SRUN,P_STAT(%ecx) 992 jne badsw 993#endif 994 995 movl %eax,P_RLINK(%ecx) /* isolate process to run */ 996 movl P_ADDR(%ecx),%edx 997 movl %edx,_curpcb 998 movl PCB_CR3(%edx),%ebx 999 1000 /* switch address space */ 1001 movl %esp,%ecx 1002 movl $tmpstk,%esp 1003 orl $ I386_CR3PAT,%ebx 1004 inb $0x84,%al # flush write buffers 1005 movl %ebx,%cr3 # context switch address space 1006 movl (%ecx),%eax # touch stack, fault if not there 1007 movl %eax,(%ecx) 1008 movl %ecx,%esp 1009 1010 /* restore context */ 1011 movl PCB_EBX(%edx), %ebx 1012 movl PCB_ESP(%edx), %esp 1013 movl PCB_EBP(%edx), %ebp 1014 movl PCB_ESI(%edx), %esi 1015 movl PCB_EDI(%edx), %edi 1016 movl PCB_EIP(%edx), %eax 1017 movl %eax, (%esp) 1018 1019#ifdef NPX 1020 movb PCB_FLAGS(%edx),%al 1021 /* if fp could be used, a dna trap will do a restore */ 1022 testb $ FP_WASUSED,%al 1023 je 1f 1024 orb $ FP_NEEDSRESTORE,PCB_FLAGS(%ecx) 10251: 1026#endif 1027 1028 movl PCB_CMAP2(%edx),%eax # get temporary map 1029 movl %eax,_CMAP2 # reload temporary map PTE 1030 1031 pushl PCB_IML(%edx) 1032 call _splx 1033 popl %eax 1034 1035 movl %edx,%eax # return (1); 1036 ret 1037 1038/* 1039 * struct proc *swtch_to_inactive(p) ; struct proc *p; 1040 * 1041 * At exit of a process, move off the address space of the 1042 * process and onto a "safe" one. Then, on a temporary stack 1043 * return and run code that disposes of the old state. 1044 * Since this code requires a parameter from the "old" stack, 1045 * pass it back as a return value. 1046 */ 1047ENTRY(swtch_to_inactive) 1048 popl %edx # old pc 1049 popl %eax # arg, our return value 1050 movl _IdlePTD,%ecx 1051 movl %ecx,%cr3 # good bye address space 1052 #write buffer? 1053 movl $tmpstk-4,%esp # temporary stack, compensated for call 1054 jmp %edx # return, execute remainder of cleanup 1055 1056/* 1057 * savectx(pcb, altreturn) 1058 * Update pcb, saving current processor state and arranging 1059 * for alternate return ala longjmp in swtch if altreturn is true. 1060 */ 1061ENTRY(savectx) 1062 movl 4(%esp), %ecx 1063 movw _cpl, %ax 1064 movw %ax, PCB_IML(%ecx) 1065 movl (%esp), %eax 1066 movl %eax, PCB_EIP(%ecx) 1067 movl %ebx, PCB_EBX(%ecx) 1068 movl %esp, PCB_ESP(%ecx) 1069 movl %ebp, PCB_EBP(%ecx) 1070 movl %esi, PCB_ESI(%ecx) 1071 movl %edi, PCB_EDI(%ecx) 1072#ifdef NPX 1073 /* have we ever used fp, and need to save? */ 1074 testb $ FP_WASUSED, PCB_FLAGS(%ecx) 1075 je 1f 1076 movl %cr0, %edx 1077 andb $0xfb, %dl 1078 movl %edx, %cr0 1079 fnsave PCB_SAVEFPU(%ecx) 1080 orb $4, %edx 1081 movl %edx, %cr0 10821: 1083#endif 1084 movl _CMAP2, %edx # save temporary map PTE 1085 movl %edx, PCB_CMAP2(%ecx) # in our context 1086 1087 cmpl $0, 8(%esp) 1088 je 1f 1089 movl %esp, %edx # relocate current sp relative to pcb 1090 subl $_kstack, %edx # (sp is relative to kstack): 1091 addl %edx, %ecx # pcb += sp - kstack; 1092 movl %eax, (%ecx) # write return pc at (relocated) sp@ 1093 # this mess deals with replicating register state gcc hides 1094 movl 12(%esp),%eax 1095 movl %eax,12(%ecx) 1096 movl 16(%esp),%eax 1097 movl %eax,16(%ecx) 1098 movl 20(%esp),%eax 1099 movl %eax,20(%ecx) 1100 movl 24(%esp),%eax 1101 movl %eax,24(%ecx) 11021: 1103 xorl %eax, %eax # return 0 1104 ret 1105 1106/* 1107 * update profiling information for the user 1108 * addupc(pc, up, ticks) struct uprof *up; 1109 */ 1110 1111ENTRY(addupc) 1112 movl 4(%esp),%eax /* pc */ 1113 movl 8(%esp),%ecx /* up */ 1114 1115 /* does sampled pc fall within bottom of profiling window? */ 1116 subl PR_OFF(%ecx),%eax /* pc -= up->pr_off; */ 1117 jl 1f /* if (pc < 0) return; */ 1118 1119 /* construct scaled index */ 1120 shrl $1,%eax /* reduce pc to a short index */ 1121 mull PR_SCALE(%ecx) /* pc*up->pr_scale */ 1122 shrdl $15,%edx,%eax /* praddr >> 15 */ 1123 cmpl $0,%edx /* if overflow, ignore */ 1124 jne 1f 1125 andb $0xfe,%al /* praddr &= ~1 */ 1126 1127 /* within profiling buffer? if so, compute address */ 1128 cmpl %eax,PR_SIZE(%ecx) /* if (praddr > up->pr_size) return; */ 1129 jg 1f 1130 addl PR_BASE(%ecx),%eax /* praddr += up->pr_base; */ 1131 1132 /* tally ticks to selected counter */ 1133 movl _curpcb,%ecx 1134 movl $proffault,PCB_ONFAULT(%ecx) #in case we page/protection violate 1135 movl 12(%esp),%edx /* ticks */ 1136 addw %dx,(%eax) 1137 movl $0,PCB_ONFAULT(%ecx) 11381: ret 1139 1140proffault: 1141 /* disable profiling if we get a fault */ 1142 movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0; */ 1143 movl _curpcb,%ecx 1144 movl $0,PCB_ONFAULT(%ecx) 1145 ret 1146 1147.data 1148 .globl _cyloffset, _curpcb 1149_cyloffset: .long 0 1150 .globl _proc0paddr 1151_proc0paddr: .long 0 1152LF: .asciz "swtch %x" 1153 1154.text 1155 # To be done: 1156 .globl _astoff 1157_astoff: 1158 ret 1159 1160#define IDTVEC(name) .align 4; .globl _X/**/name; _X/**/name: 1161#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ 1162 call _panic; 1: .asciz msg 1163#define PRINTF(n,msg) pushal ; pushl 1f; call _printf; MSG(msg) ; \ 1164 popl %eax ; popal 1165#define MSG(msg) .data; 1: .asciz msg; .text 1166 1167 .text 1168 1169/* 1170 * Trap and fault vector routines 1171 */ 1172#define TRAP(a) pushl $a ; jmp alltraps 1173#ifdef KGDB 1174#define BPTTRAP(a) pushl $a ; jmp bpttraps 1175#else 1176#define BPTTRAP(a) TRAP(a) 1177#endif 1178 1179IDTVEC(div) 1180 pushl $0; TRAP(T_DIVIDE) 1181IDTVEC(dbg) 1182 pushl $0; BPTTRAP(T_TRCTRAP) 1183IDTVEC(nmi) 1184 pushl $0; TRAP(T_NMI) 1185IDTVEC(bpt) 1186 pushl $0; BPTTRAP(T_BPTFLT) 1187IDTVEC(ofl) 1188 pushl $0; TRAP(T_OFLOW) 1189IDTVEC(bnd) 1190 pushl $0; TRAP(T_BOUND) 1191IDTVEC(ill) 1192 pushl $0; TRAP(T_PRIVINFLT) 1193IDTVEC(dna) 1194 pushl $0; TRAP(T_DNA) 1195IDTVEC(dble) 1196 TRAP(T_DOUBLEFLT) 1197 /*PANIC("Double Fault");*/ 1198IDTVEC(fpusegm) 1199 pushl $0; TRAP(T_FPOPFLT) 1200IDTVEC(tss) 1201 TRAP(T_TSSFLT) 1202 /*PANIC("TSS not valid");*/ 1203IDTVEC(missing) 1204 TRAP(T_SEGNPFLT) 1205IDTVEC(stk) 1206 TRAP(T_STKFLT) 1207IDTVEC(prot) 1208 TRAP(T_PROTFLT) 1209IDTVEC(page) 1210 TRAP(T_PAGEFLT) 1211IDTVEC(rsvd) 1212 pushl $0; TRAP(T_RESERVED) 1213IDTVEC(fpu) 1214 pushl $0; TRAP(T_ARITHTRAP) 1215 /* 17 - 31 reserved for future exp */ 1216IDTVEC(rsvd0) 1217 pushl $0; TRAP(17) 1218IDTVEC(rsvd1) 1219 pushl $0; TRAP(18) 1220IDTVEC(rsvd2) 1221 pushl $0; TRAP(19) 1222IDTVEC(rsvd3) 1223 pushl $0; TRAP(20) 1224IDTVEC(rsvd4) 1225 pushl $0; TRAP(21) 1226IDTVEC(rsvd5) 1227 pushl $0; TRAP(22) 1228IDTVEC(rsvd6) 1229 pushl $0; TRAP(23) 1230IDTVEC(rsvd7) 1231 pushl $0; TRAP(24) 1232IDTVEC(rsvd8) 1233 pushl $0; TRAP(25) 1234IDTVEC(rsvd9) 1235 pushl $0; TRAP(26) 1236IDTVEC(rsvd10) 1237 pushl $0; TRAP(27) 1238IDTVEC(rsvd11) 1239 pushl $0; TRAP(28) 1240IDTVEC(rsvd12) 1241 pushl $0; TRAP(29) 1242IDTVEC(rsvd13) 1243 pushl $0; TRAP(30) 1244IDTVEC(rsvd14) 1245 pushl $0; TRAP(31) 1246 1247alltraps: 1248 pushal 1249 push %ds 1250 push %es 1251 movw $0x10,%ax 1252 movw %ax,%ds 1253 movw %ax,%es 1254calltrap: 1255 incl _cnt+V_TRAP 1256 call _trap 1257 pop %es 1258 pop %ds 1259 popal 1260 nop 1261 addl $8,%esp # pop type, code 1262 iret 1263 1264#ifdef KGDB 1265/* 1266 * This code checks for a kgdb trap, then falls through 1267 * to the regular trap code. 1268 */ 1269bpttraps: 1270 pushal 1271 push %es 1272 push %ds 1273 movw $0x10,%ax 1274 movw %ax,%ds 1275 movw %ax,%es 1276 movzwl 52(%esp),%eax 1277 test $3,%eax 1278 jne calltrap 1279 call _kgdb_trap_glue 1280 jmp calltrap 1281#endif 1282 1283/* 1284 * Call gate entry for syscall 1285 */ 1286 1287IDTVEC(syscall) 1288 pushfl # only for stupid carry bit and more stupid wait3 cc kludge 1289 pushal # only need eax,ecx,edx - trap resaves others 1290 movw $0x10,%ax # switch to kernel segments 1291 movw %ax,%ds 1292 movw %ax,%es 1293 call _syscall 1294 movw __udatasel,%ax # switch back to user segments 1295 movw %ax,%ds 1296 movw %ax,%es 1297 popal 1298 nop 1299 popfl 1300 lret 1301 1302ENTRY(htonl) 1303ENTRY(ntohl) 1304 movl 4(%esp),%eax 1305 xchgb %al,%ah 1306 roll $16,%eax 1307 xchgb %al,%ah 1308 ret 1309 1310ENTRY(htons) 1311ENTRY(ntohs) 1312 movzwl 4(%esp),%eax 1313 xchgb %al,%ah 1314 ret 1315 1316#include "vector.s" 1317#include "i386/isa/icu.s" 1318