locore.s revision 134
14Srgrimes/*- 24Srgrimes * Copyright (c) 1990 The Regents of the University of California. 34Srgrimes * All rights reserved. 44Srgrimes * 54Srgrimes * This code is derived from software contributed to Berkeley by 64Srgrimes * William Jolitz. 74Srgrimes * 84Srgrimes * Redistribution and use in source and binary forms, with or without 94Srgrimes * modification, are permitted provided that the following conditions 104Srgrimes * are met: 114Srgrimes * 1. Redistributions of source code must retain the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer. 134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer in the 154Srgrimes * documentation and/or other materials provided with the distribution. 164Srgrimes * 3. All advertising materials mentioning features or use of this software 174Srgrimes * must display the following acknowledgement: 184Srgrimes * This product includes software developed by the University of 194Srgrimes * California, Berkeley and its contributors. 204Srgrimes * 4. Neither the name of the University nor the names of its contributors 214Srgrimes * may be used to endorse or promote products derived from this software 224Srgrimes * without specific prior written permission. 234Srgrimes * 244Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 254Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 264Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 274Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 284Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 294Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 304Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 314Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 324Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 334Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 344Srgrimes * SUCH DAMAGE. 354Srgrimes * 364Srgrimes * @(#)locore.s 7.3 (Berkeley) 5/13/91 374Srgrimes * 384Srgrimes * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE 394Srgrimes * -------------------- ----- ---------------------- 404Srgrimes * CURRENT PATCH LEVEL: 5 00158 414Srgrimes * -------------------- ----- ---------------------- 424Srgrimes * 434Srgrimes * 06 Aug 92 Pace Willisson Allow VGA memory to be mapped 444Srgrimes * 28 Nov 92 Frank MacLachlan Aligned addresses and data 454Srgrimes * on 32bit boundaries. 464Srgrimes * 25 Mar 93 Kevin Lahey Add syscall counter for vmstat 474Srgrimes * 20 Apr 93 Bruce Evans New npx-0.5 code 484Srgrimes * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1) 494Srgrimes */ 504Srgrimes 514Srgrimes 524Srgrimes/* 534Srgrimes * locore.s: 4BSD machine support for the Intel 386 544Srgrimes * Preliminary version 554Srgrimes * Written by William F. Jolitz, 386BSD Project 564Srgrimes */ 574Srgrimes 584Srgrimes#include "assym.s" 594Srgrimes#include "machine/psl.h" 604Srgrimes#include "machine/pte.h" 614Srgrimes 624Srgrimes#include "errno.h" 634Srgrimes 644Srgrimes#include "machine/trap.h" 654Srgrimes 664Srgrimes#include "machine/specialreg.h" 674Srgrimes#include "i386/isa/debug.h" 684Srgrimes 694Srgrimes#define KDSEL 0x10 704Srgrimes#define SEL_RPL_MASK 0x0003 714Srgrimes#define TRAPF_CS_OFF (13 * 4) 724Srgrimes 734Srgrimes/* 744Srgrimes * Note: This version greatly munged to avoid various assembler errors 754Srgrimes * that may be fixed in newer versions of gas. Perhaps newer versions 764Srgrimes * will have more pleasant appearance. 774Srgrimes */ 784Srgrimes 794Srgrimes .set IDXSHIFT,10 804Srgrimes .set SYSTEM,0xFE000000 # virtual address of system start 814Srgrimes /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ 824Srgrimes .set SYSPDROFF,0x3F8 # Page dir index of System Base 834Srgrimes 84134Sdg 85134Sdg/* 86134Sdg * Macros 87134Sdg */ 884Srgrimes#define ALIGN_DATA .align 2 894Srgrimes#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */ 904Srgrimes#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */ 914Srgrimes 92134Sdg#define LENTRY(name) ALIGN_TEXT; .globl name; name: 93134Sdg#define ENTRY(name) ALIGN_TEXT; .globl _/**/name; _/**/name: 94134Sdg#define ALTENTRY(name) .globl _/**/name; _/**/name: 95134Sdg 964Srgrimes/* NB: NOP now preserves registers so NOPs can be inserted anywhere */ 974Srgrimes/* XXX: NOP and FASTER_NOP are misleadingly named */ 984Srgrimes#ifdef BROKEN_HARDWARE_AND_OR_SOFTWARE /* XXX - rarely necessary */ 994Srgrimes#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax 1004Srgrimes#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax 1014Srgrimes#else 1024Srgrimes#define FASTER_NOP 1034Srgrimes#define NOP 1044Srgrimes#endif 1054Srgrimes 1064Srgrimes/* 1074Srgrimes * PTmap is recursive pagemap at top of virtual address space. 1084Srgrimes * Within PTmap, the page directory can be found (third indirection). 1094Srgrimes */ 1104Srgrimes .set PDRPDROFF,0x3F7 # Page dir index of Page dir 1114Srgrimes .globl _PTmap, _PTD, _PTDpde, _Sysmap 1124Srgrimes .set _PTmap,0xFDC00000 1134Srgrimes .set _PTD,0xFDFF7000 1144Srgrimes .set _Sysmap,0xFDFF8000 1154Srgrimes .set _PTDpde,0xFDFF7000+4*PDRPDROFF 1164Srgrimes 1174Srgrimes/* 1184Srgrimes * APTmap, APTD is the alternate recursive pagemap. 1194Srgrimes * It's used when modifying another process's page tables. 1204Srgrimes */ 1214Srgrimes .set APDRPDROFF,0x3FE # Page dir index of Page dir 1224Srgrimes .globl _APTmap, _APTD, _APTDpde 1234Srgrimes .set _APTmap,0xFF800000 1244Srgrimes .set _APTD,0xFFBFE000 1254Srgrimes .set _APTDpde,0xFDFF7000+4*APDRPDROFF 1264Srgrimes 1274Srgrimes/* 1284Srgrimes * Access to each processes kernel stack is via a region of 1294Srgrimes * per-process address space (at the beginning), immediatly above 1304Srgrimes * the user process stack. 1314Srgrimes */ 132134Sdg .globl _kstack 1334Srgrimes .set _kstack, USRSTACK 1344Srgrimes .set PPDROFF,0x3F6 1354Srgrimes .set PPTEOFF,0x400-UPAGES # 0x3FE 1364Srgrimes 1374Srgrimes 138134Sdg/*****************************************************************************/ 139134Sdg/* Globals */ 140134Sdg/*****************************************************************************/ 141134Sdg 1424Srgrimes .data 143134Sdg .globl _boothowto, _bootdev, _curpcb 144134Sdg .globl __ucodesel,__udatasel 145134Sdg 146134Sdg .globl _cpu, _cold, _atdevbase, _atdevphys 1474Srgrimes_cpu: .long 0 # are we 386, 386sx, or 486 1484Srgrimes_cold: .long 1 # cold till we are not 1494Srgrimes_atdevbase: .long 0 # location of start of iomem in virtual 1504Srgrimes_atdevphys: .long 0 # location of device mapping ptes (phys) 1514Srgrimes 1524Srgrimes .globl _IdlePTD, _KPTphys 1534Srgrimes_IdlePTD: .long 0 1544Srgrimes_KPTphys: .long 0 1554Srgrimes 156134Sdg .globl _cyloffset, _proc0paddr 157134Sdg_cyloffset: .long 0 158134Sdg_proc0paddr: .long 0 159134Sdg 160134Sdg#ifdef SHOW_A_LOT 161134Sdgbit_colors: .byte GREEN,RED,0,0 162134Sdg#endif 163134Sdg 1644Srgrimes .space 512 1654Srgrimestmpstk: 166134Sdg 167134Sdg 1684Srgrimes .text 169134Sdg/*****************************************************************************/ 170134Sdg/* System Initialisation */ 171134Sdg/*****************************************************************************/ 172134Sdg 173134Sdg/* 174134Sdg * start: jumped to directly from the boot blocks 175134Sdg */ 176134SdgLENTRY(start) 177134Sdg movw $0x1234,%ax 1784Srgrimes movw %ax,0x472 # warm boot 1794Srgrimes jmp 1f 1804Srgrimes .space 0x500 # skip over warm boot shit 1814Srgrimes 1824Srgrimes /* 1834Srgrimes * pass parameters on stack (howto, bootdev, unit, cyloffset) 1844Srgrimes * note: (%esp) is return address of boot 1854Srgrimes * ( if we want to hold onto /boot, it's physical %esp up to _end) 1864Srgrimes */ 1874Srgrimes 1884Srgrimes 1: movl 4(%esp),%eax 1894Srgrimes movl %eax,_boothowto-SYSTEM 1904Srgrimes movl 8(%esp),%eax 1914Srgrimes movl %eax,_bootdev-SYSTEM 1924Srgrimes movl 12(%esp),%eax 1934Srgrimes movl %eax, _cyloffset-SYSTEM 1944Srgrimes 1954Srgrimes /* 1964Srgrimes * Finished with old stack; load new %esp now instead of later so 1974Srgrimes * we can trace this code without having to worry about the trace 1984Srgrimes * trap clobbering the memory test or the zeroing of the bss+bootstrap 1994Srgrimes * page tables. 2004Srgrimes * 2014Srgrimes * XXX - wdboot clears the bss after testing that this is safe. 2024Srgrimes * This is too wasteful - memory below 640K is scarce. The boot 2034Srgrimes * program should check: 2044Srgrimes * text+data <= &stack_variable - more_space_for_stack 2054Srgrimes * text+data+bss+pad+space_for_page_tables <= end_of_memory 2064Srgrimes * Oops, the gdt is in the carcass of the boot program so clearing 2074Srgrimes * the rest of memory is still not possible. 2084Srgrimes */ 2094Srgrimes movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location 2104Srgrimes 2114Srgrimes#ifdef garbage 2124Srgrimes /* count up memory */ 2134Srgrimes 2144Srgrimes xorl %eax,%eax # start with base memory at 0x0 2154Srgrimes #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K 2164Srgrimes movl $ 0xA0,%ecx # look every 4K up to 640K 2174Srgrimes1: movl (%eax),%ebx # save location to check 2184Srgrimes movl $0xa55a5aa5,(%eax) # write test pattern 2194Srgrimes /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */ 2204Srgrimes cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover 2214Srgrimes jne 2f 2224Srgrimes movl %ebx,(%eax) # restore memory 2234Srgrimes addl $ NBPG,%eax 2244Srgrimes loop 1b 2254Srgrimes2: shrl $12,%eax 2264Srgrimes movl %eax,_Maxmem-SYSTEM 2274Srgrimes 2284Srgrimes movl $0x100000,%eax # next, talley remaining memory 2294Srgrimes #movl $((0xFFF000-0x100000)/NBPG),%ecx 2304Srgrimes movl $(0xFFF-0x100),%ecx 2314Srgrimes1: movl (%eax),%ebx # save location to check 2324Srgrimes movl $0xa55a5aa5,(%eax) # write test pattern 2334Srgrimes cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover 2344Srgrimes jne 2f 2354Srgrimes movl %ebx,(%eax) # restore memory 2364Srgrimes addl $ NBPG,%eax 2374Srgrimes loop 1b 2384Srgrimes2: shrl $12,%eax 2394Srgrimes movl %eax,_Maxmem-SYSTEM 2404Srgrimes#endif 2414Srgrimes 2424Srgrimes/* find end of kernel image */ 2434Srgrimes movl $_end-SYSTEM,%ecx 2444Srgrimes addl $ NBPG-1,%ecx 2454Srgrimes andl $~(NBPG-1),%ecx 2464Srgrimes movl %ecx,%esi 2474Srgrimes 2484Srgrimes/* clear bss and memory for bootstrap pagetables. */ 2494Srgrimes movl $_edata-SYSTEM,%edi 2504Srgrimes subl %edi,%ecx 2514Srgrimes addl $(UPAGES+5)*NBPG,%ecx 2524Srgrimes/* 2534Srgrimes * Virtual address space of kernel: 2544Srgrimes * 2554Srgrimes * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap 2564Srgrimes * 0 1 2 3 4 2574Srgrimes */ 2584Srgrimes xorl %eax,%eax # pattern 2594Srgrimes cld 2604Srgrimes rep 2614Srgrimes stosb 2624Srgrimes 2634Srgrimes movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */ 2644Srgrimes 2654Srgrimes#define fillkpt \ 2664Srgrimes1: movl %eax,(%ebx) ; \ 2674Srgrimes addl $ NBPG,%eax ; /* increment physical address */ \ 2684Srgrimes addl $4,%ebx ; /* next pte */ \ 2694Srgrimes loop 1b ; 2704Srgrimes 2714Srgrimes/* 2724Srgrimes * Map Kernel 2734Srgrimes * N.B. don't bother with making kernel text RO, as 386 2744Srgrimes * ignores R/W AND U/S bits on kernel access (only v works) ! 2754Srgrimes * 2764Srgrimes * First step - build page tables 2774Srgrimes */ 2784Srgrimes movl %esi,%ecx # this much memory, 2794Srgrimes shrl $ PGSHIFT,%ecx # for this many pte s 2804Srgrimes addl $ UPAGES+4,%ecx # including our early context 2814Srgrimes movl $0xa0,%ecx # XXX - cover debugger pages 2824Srgrimes movl $PG_V|PG_KW,%eax # having these bits set, 2834Srgrimes lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0, 2844Srgrimes movl %ebx,_KPTphys-SYSTEM # in the kernel page table, 2854Srgrimes fillkpt 2864Srgrimes 2874Srgrimes/* map I/O memory map */ 2884Srgrimes 2894Srgrimes movl $0x100-0xa0,%ecx # for this many pte s, 2904Srgrimes movl $(0xa0000|PG_V|PG_UW),%eax # having these bits set,(perhaps URW?) XXX 06 Aug 92 2914Srgrimes movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes 2924Srgrimes fillkpt 2934Srgrimes 2944Srgrimes /* map proc 0's kernel stack into user page table page */ 2954Srgrimes 2964Srgrimes movl $ UPAGES,%ecx # for this many pte s, 2974Srgrimes lea (1*NBPG)(%esi),%eax # physical address in proc 0 2984Srgrimes lea (SYSTEM)(%eax),%edx 2994Srgrimes movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init 3004Srgrimes orl $PG_V|PG_KW,%eax # having these bits set, 3014Srgrimes lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0 3024Srgrimes addl $(PPTEOFF*4),%ebx 3034Srgrimes fillkpt 3044Srgrimes 3054Srgrimes/* 3064Srgrimes * Construct a page table directory 3074Srgrimes * (of page directory elements - pde's) 3084Srgrimes */ 3094Srgrimes /* install a pde for temporary double map of bottom of VA */ 3104Srgrimes lea (4*NBPG)(%esi),%eax # physical address of kernel page table 3114Srgrimes orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 3124Srgrimes movl %eax,(%esi) # which is where temp maps! 3134Srgrimes 3144Srgrimes /* kernel pde's */ 3154Srgrimes movl $ 3,%ecx # for this many pde s, 3164Srgrimes lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel 3174Srgrimes fillkpt 3184Srgrimes 3194Srgrimes /* install a pde recursively mapping page directory as a page table! */ 3204Srgrimes movl %esi,%eax # phys address of ptd in proc 0 3214Srgrimes orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 3224Srgrimes movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps! 3234Srgrimes 3244Srgrimes /* install a pde to map kernel stack for proc 0 */ 3254Srgrimes lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0 3264Srgrimes orl $PG_V|PG_KW,%eax # pde entry is valid 3274Srgrimes movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps! 3284Srgrimes 3294Srgrimes /* copy and convert stuff from old gdt and idt for debugger */ 3304Srgrimes 3314Srgrimes cmpl $0x0375c339,0x96104 # XXX - debugger signature 3324Srgrimes jne 1f 3334Srgrimes movb $1,_bdb_exists-SYSTEM 3344Srgrimes1: 3354Srgrimes pushal 3364Srgrimes subl $2*6,%esp 3374Srgrimes 3384Srgrimes sgdt (%esp) 3394Srgrimes movl 2(%esp),%esi # base address of current gdt 3404Srgrimes movl $_gdt-SYSTEM,%edi 3414Srgrimes movl %edi,2(%esp) 3424Srgrimes movl $8*18/4,%ecx 3434Srgrimes rep # copy gdt 3444Srgrimes movsl 3454Srgrimes movl $_gdt-SYSTEM,-8+2(%edi) # adjust gdt self-ptr 3464Srgrimes movb $0x92,-8+5(%edi) 3474Srgrimes 3484Srgrimes sidt 6(%esp) 3494Srgrimes movl 6+2(%esp),%esi # base address of current idt 3504Srgrimes movl 8+4(%esi),%eax # convert dbg descriptor to ... 3514Srgrimes movw 8(%esi),%ax 3524Srgrimes movl %eax,bdb_dbg_ljmp+1-SYSTEM # ... immediate offset ... 3534Srgrimes movl 8+2(%esi),%eax 3544Srgrimes movw %ax,bdb_dbg_ljmp+5-SYSTEM # ... and selector for ljmp 3554Srgrimes movl 24+4(%esi),%eax # same for bpt descriptor 3564Srgrimes movw 24(%esi),%ax 3574Srgrimes movl %eax,bdb_bpt_ljmp+1-SYSTEM 3584Srgrimes movl 24+2(%esi),%eax 3594Srgrimes movw %ax,bdb_bpt_ljmp+5-SYSTEM 3604Srgrimes 3614Srgrimes movl $_idt-SYSTEM,%edi 3624Srgrimes movl %edi,6+2(%esp) 3634Srgrimes movl $8*4/4,%ecx 3644Srgrimes rep # copy idt 3654Srgrimes movsl 3664Srgrimes 3674Srgrimes lgdt (%esp) 3684Srgrimes lidt 6(%esp) 3694Srgrimes 3704Srgrimes addl $2*6,%esp 3714Srgrimes popal 3724Srgrimes 3734Srgrimes /* load base of page directory, and enable mapping */ 3744Srgrimes movl %esi,%eax # phys address of ptd in proc 0 3754Srgrimes orl $ I386_CR3PAT,%eax 3764Srgrimes movl %eax,%cr3 # load ptd addr into mmu 3774Srgrimes movl %cr0,%eax # get control word 3784Srgrimes#ifdef USE_486_WRITE_PROTECT 3794Srgrimes orl $CR0_PE|CR0_PG|CR0_WP,%eax # and let s page! 3804Srgrimes#else 3814Srgrimes orl $CR0_PE|CR0_PG,%eax # and let s page! 3824Srgrimes#endif 3834Srgrimes movl %eax,%cr0 # NOW! 3844Srgrimes 3854Srgrimes pushl $begin # jump to high mem! 3864Srgrimes ret 3874Srgrimes 3884Srgrimesbegin: /* now running relocated at SYSTEM where the system is linked to run */ 3894Srgrimes 390134Sdg .globl _Crtat # XXX - locore should not know about 391134Sdg movl _Crtat,%eax # variables of device drivers (pccons)! 3924Srgrimes subl $0xfe0a0000,%eax 3934Srgrimes movl _atdevphys,%edx # get pte PA 3944Srgrimes subl _KPTphys,%edx # remove base of ptes, now have phys offset 3954Srgrimes shll $ PGSHIFT-2,%edx # corresponding to virt offset 3964Srgrimes addl $ SYSTEM,%edx # add virtual base 3974Srgrimes movl %edx, _atdevbase 3984Srgrimes addl %eax,%edx 3994Srgrimes movl %edx,_Crtat 4004Srgrimes 4014Srgrimes /* set up bootstrap stack */ 4024Srgrimes movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location 4034Srgrimes xorl %eax,%eax # mark end of frames 4044Srgrimes movl %eax,%ebp 4054Srgrimes movl _proc0paddr, %eax 4064Srgrimes movl %esi, PCB_CR3(%eax) 4074Srgrimes 4084Srgrimes lea 7*NBPG(%esi),%esi # skip past stack. 4094Srgrimes pushl %esi 4104Srgrimes 4114Srgrimes /* relocate debugger gdt entries */ 4124Srgrimes 4134Srgrimes movl $_gdt+8*9,%eax # adjust slots 9-17 4144Srgrimes movl $9,%ecx 4154Srgrimesreloc_gdt: 4164Srgrimes movb $0xfe,7(%eax) # top byte of base addresses, was 0, 4174Srgrimes addl $8,%eax # now SYSTEM>>24 4184Srgrimes loop reloc_gdt 4194Srgrimes 4204Srgrimes cmpl $0,_bdb_exists 4214Srgrimes je 1f 4224Srgrimes int $3 4234Srgrimes1: 4244Srgrimes 4254Srgrimes call _init386 # wire 386 chip for unix operation 4264Srgrimes 4274Srgrimes movl $0,_PTD 428134Sdg call _main # autoconfiguration, mountroot etc 4294Srgrimes popl %esi 4304Srgrimes 431134Sdg /* 432134Sdg * on return from main(), we are process 1 433134Sdg * set up address space and stack so that we can 'return' to user mode 434134Sdg */ 435134Sdg 4364Srgrimes movl __ucodesel,%eax 4374Srgrimes movl __udatasel,%ecx 4384Srgrimes # build outer stack frame 4394Srgrimes pushl %ecx # user ss 4404Srgrimes pushl $ USRSTACK # user esp 4414Srgrimes pushl %eax # user cs 4424Srgrimes pushl $0 # user ip 4434Srgrimes movl %cx,%ds 4444Srgrimes movl %cx,%es 4454Srgrimes movl %ax,%fs # double map cs to fs 4464Srgrimes movl %cx,%gs # and ds to gs 4474Srgrimes lret # goto user! 4484Srgrimes 4494Srgrimes pushl $lretmsg1 /* "should never get here!" */ 4504Srgrimes call _panic 4514Srgrimeslretmsg1: 4524Srgrimes .asciz "lret: toinit\n" 4534Srgrimes 4544Srgrimes 4554Srgrimes .set exec,59 4564Srgrimes .set exit,1 4574Srgrimes 4584Srgrimes#define LCALL(x,y) .byte 0x9a ; .long y; .word x 4594Srgrimes/* 460134Sdg * Icode is copied out to process 1 and executed in user mode: 461134Sdg * execve("/sbin/init", argv, envp); exit(0); 462134Sdg * If the exec fails, process 1 exits and the system panics. 4634Srgrimes */ 4644SrgrimesENTRY(icode) 4654Srgrimes # pushl $argv-_icode # gas fucks up again 4664Srgrimes movl $argv,%eax 4674Srgrimes subl $_icode,%eax 4684Srgrimes pushl %eax 4694Srgrimes 4704Srgrimes # pushl $init-_icode 4714Srgrimes movl $init,%eax 4724Srgrimes subl $_icode,%eax 4734Srgrimes pushl %eax 4744Srgrimes pushl %eax # dummy out rta 4754Srgrimes 4764Srgrimes movl %esp,%ebp 4774Srgrimes movl $exec,%eax 4784Srgrimes LCALL(0x7,0x0) 4794Srgrimes pushl %eax 4804Srgrimes movl $exit,%eax 4814Srgrimes pushl %eax # dummy out rta 4824Srgrimes LCALL(0x7,0x0) 4834Srgrimes 4844Srgrimesinit: 4854Srgrimes .asciz "/sbin/init" 4864Srgrimes ALIGN_DATA 4874Srgrimesargv: 4884Srgrimes .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6) 4894Srgrimes .long eicode-_icode # argv[1] follows icode after copyout 4904Srgrimes .long 0 4914Srgrimeseicode: 4924Srgrimes 4934Srgrimes .globl _szicode 4944Srgrimes_szicode: 4954Srgrimes .long _szicode-_icode 4964Srgrimes 4974SrgrimesENTRY(sigcode) 4984Srgrimes call 12(%esp) 4994Srgrimes lea 28(%esp),%eax # scp (the call may have clobbered the 5004Srgrimes # copy at 8(%esp)) 5014Srgrimes # XXX - use genassym 5024Srgrimes pushl %eax 5034Srgrimes pushl %eax # junk to fake return address 5044Srgrimes movl $103,%eax # sigreturn() 5054Srgrimes LCALL(0x7,0) # enter kernel with args on stack 5064Srgrimes hlt # never gets here 5074Srgrimes 5084Srgrimes .globl _szsigcode 5094Srgrimes_szsigcode: 5104Srgrimes .long _szsigcode-_sigcode 5114Srgrimes 512134Sdg 513134Sdg/*****************************************************************************/ 514134Sdg/* support routines for GCC, general C-callable functions */ 515134Sdg/*****************************************************************************/ 516134Sdg 5174SrgrimesENTRY(__udivsi3) 5184Srgrimes movl 4(%esp),%eax 5194Srgrimes xorl %edx,%edx 5204Srgrimes divl 8(%esp) 5214Srgrimes ret 5224Srgrimes 5234SrgrimesENTRY(__divsi3) 5244Srgrimes movl 4(%esp),%eax 5254Srgrimes cltd 5264Srgrimes idivl 8(%esp) 5274Srgrimes ret 5284Srgrimes 529134Sdg 5304Srgrimes /* 5314Srgrimes * I/O bus instructions via C 5324Srgrimes */ 533134SdgENTRY(outb) # outb (port, val) 5344Srgrimes movl 4(%esp),%edx 535134Sdg NOP 536134Sdg movl 8(%esp),%eax 537134Sdg outb %al,%dx 538134Sdg NOP 539134Sdg ret 540134Sdg 541134Sdg 542134SdgENTRY(outw) # outw (port, val) 543134Sdg movl 4(%esp),%edx 544134Sdg NOP 545134Sdg movl 8(%esp),%eax 546134Sdg outw %ax,%dx 547134Sdg NOP 548134Sdg ret 549134Sdg 550134Sdg 551134SdgENTRY(outsb) # outsb(port,addr,cnt) 552134Sdg pushl %esi 553134Sdg movw 8(%esp),%dx 554134Sdg movl 12(%esp),%esi 555134Sdg movl 16(%esp),%ecx 556134Sdg cld 557134Sdg NOP 558134Sdg rep 559134Sdg outsb 560134Sdg NOP 561134Sdg movl %esi,%eax 562134Sdg popl %esi 563134Sdg ret 564134Sdg 565134Sdg 566134SdgENTRY(outsw) # outsw(port,addr,cnt) 567134Sdg pushl %esi 568134Sdg movw 8(%esp),%dx 569134Sdg movl 12(%esp),%esi 570134Sdg movl 16(%esp),%ecx 571134Sdg cld 572134Sdg NOP 573134Sdg rep 574134Sdg outsw 575134Sdg NOP 576134Sdg movl %esi,%eax 577134Sdg popl %esi 578134Sdg ret 579134Sdg 580134Sdg 581134SdgENTRY(inb) # val = inb (port) 582134Sdg movl 4(%esp),%edx 5834Srgrimes subl %eax,%eax # clr eax 5844Srgrimes NOP 5854Srgrimes inb %dx,%al 5864Srgrimes ret 5874Srgrimes 5884Srgrimes 589134SdgENTRY(inw) # val = inw (port) 5904Srgrimes movl 4(%esp),%edx 5914Srgrimes subl %eax,%eax # clr eax 5924Srgrimes NOP 5934Srgrimes inw %dx,%ax 5944Srgrimes ret 5954Srgrimes 5964Srgrimes 597134SdgENTRY(insb) # insb(port,addr,cnt) 598134Sdg pushl %edi 599134Sdg movw 8(%esp),%dx 600134Sdg movl 12(%esp),%edi 601134Sdg movl 16(%esp),%ecx 602134Sdg cld 603134Sdg NOP 604134Sdg rep 605134Sdg insb 606134Sdg NOP 607134Sdg movl %edi,%eax 608134Sdg popl %edi 609134Sdg ret 610134Sdg 611134Sdg 612134SdgENTRY(insw) # insw(port,addr,cnt) 613134Sdg pushl %edi 614134Sdg movw 8(%esp),%dx 615134Sdg movl 12(%esp),%edi 616134Sdg movl 16(%esp),%ecx 617134Sdg cld 618134Sdg NOP 619134Sdg rep 620134Sdg insw 621134Sdg NOP 622134Sdg movl %edi,%eax 623134Sdg popl %edi 624134Sdg ret 625134Sdg 626134Sdg 6274SrgrimesENTRY(rtcin) 6284Srgrimes movl 4(%esp),%eax 6294Srgrimes outb %al,$0x70 6304Srgrimes subl %eax,%eax # clr eax 6314Srgrimes inb $0x71,%al 6324Srgrimes ret 6334Srgrimes 6344Srgrimes 6354Srgrimes /* 636134Sdg * bcopy family 6374Srgrimes */ 638134SdgENTRY(bzero) # void bzero(void *base, u_int cnt) 6394Srgrimes pushl %edi 6404Srgrimes movl 8(%esp),%edi 6414Srgrimes movl 12(%esp),%ecx 6424Srgrimes xorl %eax,%eax 6434Srgrimes shrl $2,%ecx 6444Srgrimes cld 6454Srgrimes rep 6464Srgrimes stosl 6474Srgrimes movl 12(%esp),%ecx 6484Srgrimes andl $3,%ecx 6494Srgrimes rep 6504Srgrimes stosb 6514Srgrimes popl %edi 6524Srgrimes ret 6534Srgrimes 6544Srgrimes 655134SdgENTRY(fillw) # fillw (pat,base,cnt) 6564Srgrimes pushl %edi 6574Srgrimes movl 8(%esp),%eax 6584Srgrimes movl 12(%esp),%edi 6594Srgrimes movl 16(%esp),%ecx 6604Srgrimes cld 6614Srgrimes rep 6624Srgrimes stosw 6634Srgrimes popl %edi 6644Srgrimes ret 6654Srgrimes 6664SrgrimesENTRY(bcopyb) 6674Srgrimes pushl %esi 6684Srgrimes pushl %edi 6694Srgrimes movl 12(%esp),%esi 6704Srgrimes movl 16(%esp),%edi 6714Srgrimes movl 20(%esp),%ecx 6724Srgrimes cmpl %esi,%edi /* potentially overlapping? */ 6734Srgrimes jnb 1f 6744Srgrimes cld /* nope, copy forwards */ 675134Sdg rep 6764Srgrimes movsb 6774Srgrimes popl %edi 6784Srgrimes popl %esi 6794Srgrimes ret 6804Srgrimes 6814Srgrimes ALIGN_TEXT 6824Srgrimes1: 6834Srgrimes addl %ecx,%edi /* copy backwards. */ 6844Srgrimes addl %ecx,%esi 6854Srgrimes std 6864Srgrimes decl %edi 6874Srgrimes decl %esi 6884Srgrimes rep 6894Srgrimes movsb 6904Srgrimes popl %edi 6914Srgrimes popl %esi 6924Srgrimes cld 6934Srgrimes ret 6944Srgrimes 6954SrgrimesENTRY(bcopyw) 6964Srgrimes pushl %esi 6974Srgrimes pushl %edi 6984Srgrimes movl 12(%esp),%esi 6994Srgrimes movl 16(%esp),%edi 7004Srgrimes movl 20(%esp),%ecx 7014Srgrimes cmpl %esi,%edi /* potentially overlapping? */ 7024Srgrimes jnb 1f 7034Srgrimes cld /* nope, copy forwards */ 7044Srgrimes shrl $1,%ecx /* copy by 16-bit words */ 7054Srgrimes rep 7064Srgrimes movsw 7074Srgrimes adc %ecx,%ecx /* any bytes left? */ 7084Srgrimes rep 7094Srgrimes movsb 7104Srgrimes popl %edi 7114Srgrimes popl %esi 7124Srgrimes ret 7134Srgrimes 7144Srgrimes ALIGN_TEXT 7154Srgrimes1: 7164Srgrimes addl %ecx,%edi /* copy backwards */ 7174Srgrimes addl %ecx,%esi 7184Srgrimes std 7194Srgrimes andl $1,%ecx /* any fractional bytes? */ 7204Srgrimes decl %edi 7214Srgrimes decl %esi 7224Srgrimes rep 7234Srgrimes movsb 7244Srgrimes movl 20(%esp),%ecx /* copy remainder by 16-bit words */ 7254Srgrimes shrl $1,%ecx 7264Srgrimes decl %esi 7274Srgrimes decl %edi 7284Srgrimes rep 7294Srgrimes movsw 7304Srgrimes popl %edi 7314Srgrimes popl %esi 7324Srgrimes cld 7334Srgrimes ret 7344Srgrimes 7354SrgrimesENTRY(bcopyx) 7364Srgrimes movl 16(%esp),%eax 7374Srgrimes cmpl $2,%eax 7384Srgrimes je _bcopyw 7394Srgrimes cmpl $4,%eax 7404Srgrimes jne _bcopyb 7414Srgrimes /* 7424Srgrimes * Fall through to bcopy. ENTRY() provides harmless fill bytes. 7434Srgrimes */ 7444Srgrimes 745134Sdg 7464Srgrimes /* 7474Srgrimes * (ov)bcopy (src,dst,cnt) 7484Srgrimes * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 7494Srgrimes */ 7504SrgrimesENTRY(bcopy) 751134SdgALTENTRY(ovbcopy) 7524Srgrimes pushl %esi 7534Srgrimes pushl %edi 7544Srgrimes movl 12(%esp),%esi 7554Srgrimes movl 16(%esp),%edi 7564Srgrimes movl 20(%esp),%ecx 7574Srgrimes cmpl %esi,%edi /* potentially overlapping? */ 7584Srgrimes jnb 1f 7594Srgrimes cld /* nope, copy forwards */ 7604Srgrimes shrl $2,%ecx /* copy by 32-bit words */ 7614Srgrimes rep 7624Srgrimes movsl 7634Srgrimes movl 20(%esp),%ecx 7644Srgrimes andl $3,%ecx /* any bytes left? */ 7654Srgrimes rep 7664Srgrimes movsb 7674Srgrimes popl %edi 7684Srgrimes popl %esi 7694Srgrimes ret 7704Srgrimes 7714Srgrimes ALIGN_TEXT 7724Srgrimes1: 7734Srgrimes addl %ecx,%edi /* copy backwards */ 7744Srgrimes addl %ecx,%esi 7754Srgrimes std 7764Srgrimes andl $3,%ecx /* any fractional bytes? */ 7774Srgrimes decl %edi 7784Srgrimes decl %esi 7794Srgrimes rep 7804Srgrimes movsb 7814Srgrimes movl 20(%esp),%ecx /* copy remainder by 32-bit words */ 7824Srgrimes shrl $2,%ecx 7834Srgrimes subl $3,%esi 7844Srgrimes subl $3,%edi 7854Srgrimes rep 7864Srgrimes movsl 7874Srgrimes popl %edi 7884Srgrimes popl %esi 7894Srgrimes cld 7904Srgrimes ret 7914Srgrimes 792134SdgENTRY(ntohl) 793134SdgALTENTRY(htonl) 794134Sdg movl 4(%esp),%eax 795134Sdg#ifdef i486 796134Sdg /* XXX */ 797134Sdg /* Since Gas 1.38 does not grok bswap this has been coded as the 798134Sdg * equivalent bytes. This can be changed back to bswap when we 799134Sdg * upgrade to a newer version of Gas */ 800134Sdg /* bswap %eax */ 801134Sdg .byte 0x0f 802134Sdg .byte 0xc8 803134Sdg#else 804134Sdg xchgb %al,%ah 805134Sdg roll $16,%eax 806134Sdg xchgb %al,%ah 807134Sdg#endif 808134Sdg ret 809134Sdg 810134SdgENTRY(ntohs) 811134SdgALTENTRY(htons) 812134Sdg movzwl 4(%esp),%eax 813134Sdg xchgb %al,%ah 814134Sdg ret 815134Sdg 816134Sdg 817134Sdg#ifdef SHOW_A_LOT 818134Sdg/* 819134Sdg * 'show_bits' was too big when defined as a macro. The line length for some 820134Sdg * enclosing macro was too big for gas. Perhaps the code would have blown 821134Sdg * the cache anyway. 822134Sdg */ 823134Sdg ALIGN_TEXT 824134Sdgshow_bits: 825134Sdg pushl %eax 826134Sdg SHOW_BIT(0) 827134Sdg SHOW_BIT(1) 828134Sdg SHOW_BIT(2) 829134Sdg SHOW_BIT(3) 830134Sdg SHOW_BIT(4) 831134Sdg SHOW_BIT(5) 832134Sdg SHOW_BIT(6) 833134Sdg SHOW_BIT(7) 834134Sdg SHOW_BIT(8) 835134Sdg SHOW_BIT(9) 836134Sdg SHOW_BIT(10) 837134Sdg SHOW_BIT(11) 838134Sdg SHOW_BIT(12) 839134Sdg SHOW_BIT(13) 840134Sdg SHOW_BIT(14) 841134Sdg SHOW_BIT(15) 842134Sdg popl %eax 843134Sdg ret 844134Sdg#endif /* SHOW_A_LOT */ 845134Sdg 846134Sdg 847134Sdg/*****************************************************************************/ 848134Sdg/* copyout and fubyte family */ 849134Sdg/*****************************************************************************/ 850134Sdg/* 851134Sdg * Access user memory from inside the kernel. These routines and possibly 852134Sdg * the math- and DOS emulators should be the only places that do this. 853134Sdg * 854134Sdg * We have to access the memory with user's permissions, so use a segment 855134Sdg * selector with RPL 3. For writes to user space we have to additionally 856134Sdg * check the PTE for write permission, because the 386 does not check 857134Sdg * write permissions when we are executing with EPL 0. The 486 does check 858134Sdg * this if the WP bit is set in CR0, so we can use a simpler version here. 859134Sdg * 860134Sdg * These routines set curpcb->onfault for the time they execute. When a 861134Sdg * protection violation occurs inside the functions, the trap handler 862134Sdg * returns to *curpcb->onfault instead of the function. 863134Sdg */ 864134Sdg/* 865134Sdg * XXX These routines load a segment register every time they execute. 866134Sdg * it would be nicer (faster) if they could depend on %gs. 867134Sdg */ 868134Sdg 869134Sdg 870134SdgENTRY(copyout) # copyout (from_kernel, to_user, len) 8714Srgrimes movl _curpcb, %eax 872134Sdg movl $copyout_fault, PCB_ONFAULT(%eax) 8734Srgrimes pushl %esi 8744Srgrimes pushl %edi 8754Srgrimes pushl %ebx 8764Srgrimes movl 16(%esp), %esi 8774Srgrimes movl 20(%esp), %edi 8784Srgrimes movl 24(%esp), %ebx 879134Sdg orl %ebx, %ebx # nothing to do? 880134Sdg jz done_copyout 8814Srgrimes 882134Sdg#ifdef USE_486_WRITE_PROTECT 883134Sdg /* if WP bit in CR0 is set (n/a on 386), the hardware does the */ 884134Sdg /* write check. We just have to load the right segment selector */ 885134Sdg pushl %es 886134Sdg movl __udatasel, %eax 887134Sdg movl %ax, %es 888134Sdg#else /* USE_486_WRITE_PROTECT */ 889134Sdg /* we have to check each PTE for (write) permission */ 8904Srgrimes 891134Sdg /* compute number of pages */ 892134Sdg movl %edi, %ecx 893134Sdg andl $0x0fff, %ecx 894134Sdg addl %ebx, %ecx 895134Sdg decl %ecx 896134Sdg shrl $IDXSHIFT+2, %ecx 897134Sdg incl %ecx 898134Sdg 899134Sdg /* compute PTE offset for start address */ 900134Sdg movl %edi, %edx 901134Sdg shrl $IDXSHIFT, %edx 902134Sdg andb $0xfc, %dl 903134Sdg 904134Sdg1: /* check PTE for each page */ 905134Sdg movb _PTmap(%edx), %al 906134Sdg andb $0x07, %al /* Pages must be VALID + USERACC + WRITABLE */ 907134Sdg cmpb $0x07, %al 908134Sdg je 2f 909134Sdg 910134Sdg /* simulate a trap */ 911134Sdg pushl %edx 912134Sdg pushl %ecx 913134Sdg shll $IDXSHIFT, %edx 914134Sdg pushl %edx 915134Sdg call _trapwrite /* XXX trapwrite(addr) */ 9164Srgrimes popl %edx 917134Sdg popl %ecx 918134Sdg popl %edx 9194Srgrimes 920134Sdg orl %eax, %eax /* if not ok, return EFAULT */ 921134Sdg jnz copyout_fault 922134Sdg 9234Srgrimes2: 924134Sdg addl $4, %edx 925134Sdg decl %ecx 926134Sdg jnz 1b /* check next page */ 9274Srgrimes 928134Sdg#endif /* USE_486_WRITE_PROTECT */ 929134Sdg 930134Sdg /* now copy it over */ 931134Sdg /* bcopy (%esi, %edi, %ebx) */ 9324Srgrimes cld 933134Sdg movl %ebx, %ecx 934134Sdg shrl $2, %ecx 9354Srgrimes rep 9364Srgrimes movsl 937134Sdg movb %bl, %cl 938134Sdg andb $3, %cl 9394Srgrimes rep 9404Srgrimes movsb 941134Sdg#ifdef USE_486_WRITE_PROTECT 942134Sdg popl %es 9434Srgrimes#endif 9444Srgrimes 945134Sdgdone_copyout: 9464Srgrimes popl %ebx 9474Srgrimes popl %edi 9484Srgrimes popl %esi 9494Srgrimes xorl %eax,%eax 9504Srgrimes movl _curpcb,%edx 9514Srgrimes movl %eax,PCB_ONFAULT(%edx) 9524Srgrimes ret 9534Srgrimes 954134Sdgcopyout_fault: 955134Sdg#ifdef USE_486_WRITE_PROTECT 956134Sdg popl %es 957134Sdg#endif 9584Srgrimes popl %ebx 9594Srgrimes popl %edi 9604Srgrimes popl %esi 961134Sdg movl _curpcb, %edx 962134Sdg movl $0, PCB_ONFAULT(%edx) 963134Sdg movl $EFAULT, %eax 9644Srgrimes ret 9654Srgrimes 966134Sdg 967134SdgENTRY(copyin) # copyin (from_user, to_kernel, len) 9684Srgrimes movl _curpcb,%eax 969134Sdg movl $copyin_fault, PCB_ONFAULT(%eax) 9704Srgrimes pushl %esi 9714Srgrimes pushl %edi 972134Sdg movl 12(%esp),%esi # caddr_t from 973134Sdg movl 16(%esp),%edi # caddr_t to 974134Sdg movl 20(%esp),%ecx # size_t len 975134Sdg movl %ecx,%edx 976134Sdg pushl %ds 977134Sdg movl __udatasel,%ax # access 'from' via user data segment 978134Sdg movl %ax,%ds 979134Sdg 980134Sdg movb %cl,%al 981134Sdg shrl $2,%ecx # copy longword-wise 9824Srgrimes cld 9834Srgrimes rep 9844Srgrimes movsl 985134Sdg movb %al,%cl 986134Sdg andb $3,%cl # copy remaining bytes 9874Srgrimes rep 9884Srgrimes movsb 989134Sdg 990134Sdg popl %ds 9914Srgrimes popl %edi 9924Srgrimes popl %esi 993134Sdg xorl %eax, %eax 994134Sdg movl _curpcb, %edx 995134Sdg movl %eax, PCB_ONFAULT(%edx) 9964Srgrimes ret 9974Srgrimes 998134Sdgcopyin_fault: 999134Sdg popl %ds 10004Srgrimes popl %edi 10014Srgrimes popl %esi 1002134Sdg movl _curpcb, %edx 1003134Sdg movl $0, PCB_ONFAULT(%edx) 1004134Sdg movl $EFAULT, %eax 1005134Sdg ret 1006134Sdg 1007134Sdg /* 1008134Sdg * fu{byte,sword,word} : fetch a byte (sword, word) from user memory 1009134Sdg */ 1010134SdgENTRY(fuword) 1011134SdgALTENTRY(fuiword) 1012134Sdg movl __udatasel,%eax 1013134Sdg movl %ax,%gs 1014134Sdg movl _curpcb,%ecx 1015134Sdg movl $fusufault,PCB_ONFAULT(%ecx) 1016134Sdg movl 4(%esp),%edx 1017134Sdg gs 1018134Sdg movl (%edx),%eax 1019134Sdg movl $0,PCB_ONFAULT(%ecx) 1020134Sdg ret 1021134Sdg 1022134SdgENTRY(fusword) 1023134Sdg movl __udatasel,%eax 1024134Sdg movl %ax,%gs 1025134Sdg movl _curpcb,%ecx 1026134Sdg movl $fusufault,PCB_ONFAULT(%ecx) 1027134Sdg movl 4(%esp),%edx 1028134Sdg gs 1029134Sdg movzwl (%edx),%eax 1030134Sdg movl $0,PCB_ONFAULT(%ecx) 1031134Sdg ret 1032134Sdg 1033134SdgENTRY(fubyte) 1034134SdgALTENTRY(fuibyte) 1035134Sdg movl __udatasel,%eax 1036134Sdg movl %ax,%gs 1037134Sdg movl _curpcb,%ecx 1038134Sdg movl $fusufault,PCB_ONFAULT(%ecx) 1039134Sdg movl 4(%esp),%edx 1040134Sdg gs 1041134Sdg movzbl (%edx),%eax 1042134Sdg movl $0,PCB_ONFAULT(%ecx) 1043134Sdg ret 1044134Sdg 1045134Sdgfusufault: 1046134Sdg movl _curpcb,%ecx 10474Srgrimes xorl %eax,%eax 1048134Sdg movl %eax,PCB_ONFAULT(%ecx) 1049134Sdg decl %eax 10504Srgrimes ret 10514Srgrimes 1052134Sdg /* 1053134Sdg * su{byte,sword,word}: write a byte (word, longword) to user memory 1054134Sdg */ 1055134Sdg#ifdef USE_486_WRITE_PROTECT 1056134Sdg /* 1057134Sdg * we only have to set the right segment selector. 1058134Sdg */ 1059134SdgENTRY(suword) 1060134SdgALTENTRY(suiword) 1061134Sdg movl __udatasel,%eax 1062134Sdg movl %ax,%gs 1063134Sdg movl _curpcb,%ecx 1064134Sdg movl $fusufault,PCB_ONFAULT(%ecx) 1065134Sdg movl 4(%esp),%edx 1066134Sdg movl 8(%esp),%eax 1067134Sdg gs 1068134Sdg movl %eax,(%edx) 1069134Sdg movl $0,PCB_ONFAULT(%ecx) 10704Srgrimes ret 1071134Sdg 1072134SdgENTRY(susword) 1073134Sdg movl __udatasel,%eax 1074134Sdg movl %ax,%gs 1075134Sdg movl _curpcb,%ecx 1076134Sdg movl $fusufault,PCB_ONFAULT(%ecx) 1077134Sdg movl 4(%esp),%edx 1078134Sdg movw 8(%esp),%ax 1079134Sdg gs 1080134Sdg movw %ax,(%edx) 1081134Sdg movl $0,PCB_ONFAULT(%ecx) 1082134Sdg ret 1083134Sdg 1084134SdgENTRY(subyte) 1085134SdgALTENTRY(suibyte) 1086134Sdg movl __udatasel,%eax 1087134Sdg movl %ax,%gs 1088134Sdg movl _curpcb,%ecx 1089134Sdg movl $fusufault,PCB_ONFAULT(%ecx) 1090134Sdg movl 4(%esp),%edx 1091134Sdg movb 8(%esp),%al 1092134Sdg gs 1093134Sdg movb %al,(%edx) 1094134Sdg movl $0,PCB_ONFAULT(%ecx) 1095134Sdg ret 10964Srgrimes 10974Srgrimes 1098134Sdg#else /* USE_486_WRITE_PROTECT */ 1099134Sdg /* 1100134Sdg * here starts the trouble again: check PTE, twice if word crosses 1101134Sdg * a page boundary. 1102134Sdg */ 1103134Sdg # XXX - page boundary crossing is not handled yet 1104134Sdg 1105134SdgENTRY(subyte) 1106134SdgENTRY(suibyte) 1107134Sdg movl _curpcb, %ecx 1108134Sdg movl $fusufault, PCB_ONFAULT(%ecx) 1109134Sdg movl 4(%esp), %edx 1110134Sdg movl %edx, %eax 1111134Sdg shrl $IDXSHIFT, %edx 1112134Sdg andb $0xfc, %dl 1113134Sdg movb _PTmap(%edx), %dl 1114134Sdg andb $0x7, %dl /* must be VALID + USERACC + WRITE */ 1115134Sdg cmpb $0x7, %dl 1116134Sdg je 1f 1117134Sdg /* simulate a trap */ 1118134Sdg pushl %eax 1119134Sdg call _trapwrite 1120134Sdg popl %edx 1121134Sdg orl %eax, %eax 1122134Sdg jnz fusufault 1123134Sdg1: 1124134Sdg movl 4(%esp), %edx 1125134Sdg movl 8(%esp), %eax 1126134Sdg movb %al, (%edx) 1127134Sdg xorl %eax, %eax 1128134Sdg movl _curpcb, %ecx 1129134Sdg movl %eax, PCB_ONFAULT(%ecx) 11304Srgrimes ret 11314Srgrimes 1132134SdgENTRY(susword) 1133134Sdg movl _curpcb, %ecx 1134134Sdg movl $fusufault, PCB_ONFAULT(%ecx) 1135134Sdg movl 4(%esp), %edx 1136134Sdg movl %edx, %eax 1137134Sdg shrl $IDXSHIFT, %edx 1138134Sdg andb $0xfc, %dl 1139134Sdg movb _PTmap(%edx), %dl 1140134Sdg andb $0x7, %dl /* must be VALID + USERACC + WRITE */ 1141134Sdg cmpb $0x7, %dl 1142134Sdg je 1f 1143134Sdg /* simulate a trap */ 1144134Sdg pushl %eax 1145134Sdg call _trapwrite 1146134Sdg popl %edx 1147134Sdg orl %eax, %eax 1148134Sdg jnz fusufault 1149134Sdg1: 1150134Sdg movl 4(%esp), %edx 1151134Sdg movl 8(%esp), %eax 1152134Sdg movw %ax, (%edx) 1153134Sdg xorl %eax, %eax 1154134Sdg movl _curpcb, %ecx 1155134Sdg movl %eax, PCB_ONFAULT(%ecx) 1156134Sdg ret 1157134Sdg 1158134SdgENTRY(suword) 1159134SdgENTRY(suiword) 1160134Sdg movl _curpcb, %ecx 1161134Sdg movl $fusufault, PCB_ONFAULT(%ecx) 1162134Sdg movl 4(%esp), %edx 1163134Sdg movl %edx, %eax 1164134Sdg shrl $IDXSHIFT, %edx 1165134Sdg andb $0xfc, %dl 1166134Sdg movb _PTmap(%edx), %dl 1167134Sdg andb $0x7, %dl /* must be VALID + USERACC + WRITE */ 1168134Sdg cmpb $0x7, %dl 1169134Sdg je 1f 1170134Sdg /* simulate a trap */ 1171134Sdg pushl %eax 1172134Sdg call _trapwrite 1173134Sdg popl %edx 1174134Sdg orl %eax, %eax 1175134Sdg jnz fusufault 1176134Sdg1: 1177134Sdg movl 4(%esp), %edx 1178134Sdg movl 8(%esp), %eax 1179134Sdg movl %eax, 0(%edx) 1180134Sdg xorl %eax, %eax 1181134Sdg movl _curpcb, %ecx 1182134Sdg movl %eax, PCB_ONFAULT(%ecx) 1183134Sdg ret 1184134Sdg 1185134Sdg#endif /* USE_486_WRITE_PROTECT */ 1186134Sdg/* 1187134Sdg * copyoutstr(from, to, maxlen, int *lencopied) 1188134Sdg * copy a string from from to to, stop when a 0 character is reached. 1189134Sdg * return ENAMETOOLONG if string is longer than maxlen, and 1190134Sdg * EFAULT on protection violations. If lencopied is non-zero, 1191134Sdg * return the actual length in *lencopied. 1192134Sdg */ 1193134Sdg#ifdef USE_486_WRITE_PROTECT 1194134Sdg 1195134SdgENTRY(copyoutstr) 1196134Sdg pushl %esi 11974Srgrimes pushl %edi 1198134Sdg movl _curpcb, %ecx 1199134Sdg movl $cpystrflt, PCB_ONFAULT(%ecx) 1200134Sdg 1201134Sdg movl 12(%esp), %esi # %esi = from 1202134Sdg movl 16(%esp), %edi # %edi = to 1203134Sdg movl 20(%esp), %edx # %edx = maxlen 1204134Sdg movl __udatasel,%eax 1205134Sdg movl %ax,%gs 1206134Sdg incl %edx 1207134Sdg 1208134Sdg1: 1209134Sdg decl %edx 1210134Sdg jz 4f 1211134Sdg lodsb 1212134Sdg gs 1213134Sdg stosb 1214134Sdg orb %al,%al 1215134Sdg jnz 1b 1216134Sdg /* Success -- 0 byte reached */ 1217134Sdg decl %edx 1218134Sdg xorl %eax, %eax 1219134Sdg jmp 6f 1220134Sdg4: 1221134Sdg /* edx is zero -- return ENAMETOOLONG */ 1222134Sdg movl $ENAMETOOLONG, %eax 1223134Sdg jmp 6f 1224134Sdg 1225134Sdg#else /* USE_486_WRITE_PROTECT */ 1226134Sdg 1227134SdgENTRY(copyoutstr) 1228134Sdg pushl %esi 1229134Sdg pushl %edi 1230134Sdg movl _curpcb, %ecx 1231134Sdg movl $cpystrflt, PCB_ONFAULT(%ecx) 1232134Sdg 1233134Sdg movl 12(%esp), %esi # %esi = from 1234134Sdg movl 16(%esp), %edi # %edi = to 1235134Sdg movl 20(%esp), %edx # %edx = maxlen 1236134Sdg1: 1237134Sdg movl %edi, %eax 1238134Sdg shrl $IDXSHIFT, %eax 1239134Sdg andb $0xfc, %al 1240134Sdg movb _PTmap(%eax), %al 1241134Sdg andb $7, %al 1242134Sdg cmpb $7, %al 1243134Sdg je 2f 1244134Sdg 1245134Sdg /* simulate trap */ 1246134Sdg pushl %edx 1247134Sdg pushl %edi 1248134Sdg call _trapwrite 12494Srgrimes popl %edi 1250134Sdg popl %edx 1251134Sdg orl %eax, %eax 1252134Sdg jnz cpystrflt 12534Srgrimes 1254134Sdg2: /* copy up to end of this page */ 1255134Sdg movl %edi, %eax 1256134Sdg andl $0x0fff, %eax 1257134Sdg movl $NBPG, %ecx 1258134Sdg subl %eax, %ecx /* ecx = NBPG - (src % NBPG) */ 1259134Sdg cmpl %ecx, %edx 1260134Sdg jge 3f 1261134Sdg movl %edx, %ecx /* ecx = min (ecx, edx) */ 1262134Sdg3: 1263134Sdg orl %ecx, %ecx 1264134Sdg jz 4f 1265134Sdg decl %ecx 1266134Sdg decl %edx 1267134Sdg lodsb 1268134Sdg stosb 1269134Sdg orb %al, %al 1270134Sdg jnz 3b 1271134Sdg 1272134Sdg /* Success -- 0 byte reached */ 1273134Sdg decl %edx 1274134Sdg xorl %eax, %eax 1275134Sdg jmp 6f 1276134Sdg 1277134Sdg4: /* next page */ 1278134Sdg orl %edx, %edx 1279134Sdg jnz 1b 1280134Sdg /* edx is zero -- return ENAMETOOLONG */ 1281134Sdg movl $ENAMETOOLONG, %eax 1282134Sdg jmp 6f 1283134Sdg#endif /* USE_486_WRITE_PROTECT */ 1284134Sdg 1285134Sdg/* 1286134Sdg * copyinstr(from, to, maxlen, int *lencopied) 1287134Sdg * copy a string from from to to, stop when a 0 character is reached. 1288134Sdg * return ENAMETOOLONG if string is longer than maxlen, and 1289134Sdg * EFAULT on protection violations. If lencopied is non-zero, 1290134Sdg * return the actual length in *lencopied. 1291134Sdg */ 1292134SdgENTRY(copyinstr) 12934Srgrimes pushl %esi 1294134Sdg pushl %edi 1295134Sdg movl _curpcb, %ecx 1296134Sdg movl $cpystrflt, PCB_ONFAULT(%ecx) 1297134Sdg 1298134Sdg movl 12(%esp), %esi # %esi = from 1299134Sdg movl 16(%esp), %edi # %edi = to 1300134Sdg movl 20(%esp), %edx # %edx = maxlen 1301134Sdg movl __udatasel,%eax 1302134Sdg movl %ax,%gs 1303134Sdg incl %edx 1304134Sdg 1305134Sdg1: 1306134Sdg decl %edx 1307134Sdg jz 4f 1308134Sdg gs 1309134Sdg lodsb 1310134Sdg stosb 1311134Sdg orb %al,%al 1312134Sdg jnz 1b 1313134Sdg /* Success -- 0 byte reached */ 1314134Sdg decl %edx 1315134Sdg xorl %eax, %eax 1316134Sdg jmp 6f 1317134Sdg4: 1318134Sdg /* edx is zero -- return ENAMETOOLONG */ 1319134Sdg movl $ENAMETOOLONG, %eax 1320134Sdg jmp 6f 1321134Sdg 1322134Sdgcpystrflt: 1323134Sdg movl $EFAULT, %eax 1324134Sdg6: /* set *lencopied and return %eax */ 1325134Sdg movl _curpcb, %ecx 1326134Sdg movl $0, PCB_ONFAULT(%ecx) 1327134Sdg movl 20(%esp), %ecx 1328134Sdg subl %edx, %ecx 1329134Sdg movl 24(%esp), %edx 1330134Sdg orl %edx, %edx 1331134Sdg jz 7f 1332134Sdg movl %ecx, (%edx) 1333134Sdg7: 1334134Sdg popl %edi 13354Srgrimes popl %esi 13364Srgrimes ret 13374Srgrimes 1338134Sdg 1339134Sdg/* 1340134Sdg * copystr(from, to, maxlen, int *lencopied) 1341134Sdg */ 1342134SdgENTRY(copystr) 13434Srgrimes pushl %esi 1344134Sdg pushl %edi 1345134Sdg 1346134Sdg movl 12(%esp), %esi # %esi = from 1347134Sdg movl 16(%esp), %edi # %edi = to 1348134Sdg movl 20(%esp), %edx # %edx = maxlen 1349134Sdg incl %edx 1350134Sdg 1351134Sdg1: 1352134Sdg decl %edx 1353134Sdg jz 4f 1354134Sdg lodsb 1355134Sdg stosb 1356134Sdg orb %al,%al 1357134Sdg jnz 1b 1358134Sdg /* Success -- 0 byte reached */ 1359134Sdg decl %edx 1360134Sdg xorl %eax, %eax 1361134Sdg jmp 6f 1362134Sdg4: 1363134Sdg /* edx is zero -- return ENAMETOOLONG */ 1364134Sdg movl $ENAMETOOLONG, %eax 1365134Sdg 1366134Sdg6: /* set *lencopied and return %eax */ 1367134Sdg movl 20(%esp), %ecx 1368134Sdg subl %edx, %ecx 1369134Sdg movl 24(%esp), %edx 1370134Sdg orl %edx, %edx 1371134Sdg jz 7f 1372134Sdg movl %ecx, (%edx) 1373134Sdg7: 1374134Sdg popl %edi 13754Srgrimes popl %esi 13764Srgrimes ret 13774Srgrimes 1378134Sdg/*****************************************************************************/ 1379134Sdg/* Handling of special 386 registers and descriptor tables etc */ 1380134Sdg/*****************************************************************************/ 13814Srgrimes /* 13824Srgrimes * void lgdt(struct region_descriptor *rdp); 13834Srgrimes */ 13844SrgrimesENTRY(lgdt) 13854Srgrimes /* reload the descriptor table */ 13864Srgrimes movl 4(%esp),%eax 13874Srgrimes lgdt (%eax) 13884Srgrimes /* flush the prefetch q */ 13894Srgrimes jmp 1f 13904Srgrimes nop 13914Srgrimes1: 13924Srgrimes /* reload "stale" selectors */ 13934Srgrimes movl $KDSEL,%eax 13944Srgrimes movl %ax,%ds 13954Srgrimes movl %ax,%es 13964Srgrimes movl %ax,%ss 13974Srgrimes 13984Srgrimes /* reload code selector by turning return into intersegmental return */ 13994Srgrimes movl (%esp),%eax 14004Srgrimes pushl %eax 14014Srgrimes # movl $KCSEL,4(%esp) 14024Srgrimes movl $8,4(%esp) 14034Srgrimes lret 14044Srgrimes 14054Srgrimes /* 14064Srgrimes * void lidt(struct region_descriptor *rdp); 14074Srgrimes */ 14084SrgrimesENTRY(lidt) 14094Srgrimes movl 4(%esp),%eax 14104Srgrimes lidt (%eax) 14114Srgrimes ret 14124Srgrimes 14134Srgrimes /* 14144Srgrimes * void lldt(u_short sel) 14154Srgrimes */ 14164SrgrimesENTRY(lldt) 14174Srgrimes lldt 4(%esp) 14184Srgrimes ret 14194Srgrimes 14204Srgrimes /* 14214Srgrimes * void ltr(u_short sel) 14224Srgrimes */ 14234SrgrimesENTRY(ltr) 14244Srgrimes ltr 4(%esp) 14254Srgrimes ret 14264Srgrimes 1427134SdgENTRY(ssdtosd) # ssdtosd(*ssdp,*sdp) 14284Srgrimes pushl %ebx 14294Srgrimes movl 8(%esp),%ecx 14304Srgrimes movl 8(%ecx),%ebx 14314Srgrimes shll $16,%ebx 14324Srgrimes movl (%ecx),%edx 14334Srgrimes roll $16,%edx 14344Srgrimes movb %dh,%bl 14354Srgrimes movb %dl,%bh 14364Srgrimes rorl $8,%ebx 14374Srgrimes movl 4(%ecx),%eax 14384Srgrimes movw %ax,%dx 14394Srgrimes andl $0xf0000,%eax 14404Srgrimes orl %eax,%ebx 14414Srgrimes movl 12(%esp),%ecx 14424Srgrimes movl %edx,(%ecx) 14434Srgrimes movl %ebx,4(%ecx) 14444Srgrimes popl %ebx 14454Srgrimes ret 14464Srgrimes 1447134Sdg 1448134SdgENTRY(tlbflush) # tlbflush() 1449134Sdg movl %cr3,%eax 1450134Sdg orl $ I386_CR3PAT,%eax 1451134Sdg movl %eax,%cr3 14524Srgrimes ret 1453134Sdg 1454134Sdg 1455134SdgENTRY(lcr0) # lcr0(cr0) 1456134SdgALTENTRY(load_cr0) 1457134Sdg movl 4(%esp),%eax 1458134Sdg movl %eax,%cr0 14594Srgrimes ret 1460134Sdg 1461134Sdg 1462134SdgENTRY(rcr0) # rcr0() 1463134Sdg movl %cr0,%eax 14644Srgrimes ret 14654Srgrimes 1466134Sdg 1467134SdgENTRY(rcr2) # rcr2() 1468134Sdg movl %cr2,%eax 14694Srgrimes ret 14704Srgrimes 14714Srgrimes 1472134SdgENTRY(rcr3) # rcr3() 1473134SdgALTENTRY(_cr3) 1474134Sdg movl %cr3,%eax 14754Srgrimes ret 14764Srgrimes 1477134Sdg 1478134Sdg /* 1479134Sdg * void lcr3(caddr_t cr3) 1480134Sdg */ 1481134SdgENTRY(lcr3) 1482134SdgALTENTRY(load_cr3) 1483134Sdg movl 4(%esp),%eax 1484134Sdg orl $ I386_CR3PAT,%eax 1485134Sdg movl %eax,%cr3 14864Srgrimes ret 14874Srgrimes 1488134Sdg 1489134Sdg/*****************************************************************************/ 1490134Sdg/* setjump, longjump */ 1491134Sdg/*****************************************************************************/ 1492134Sdg 14934SrgrimesENTRY(setjmp) 14944Srgrimes movl 4(%esp),%eax 14954Srgrimes movl %ebx, (%eax) # save ebx 14964Srgrimes movl %esp, 4(%eax) # save esp 14974Srgrimes movl %ebp, 8(%eax) # save ebp 14984Srgrimes movl %esi,12(%eax) # save esi 14994Srgrimes movl %edi,16(%eax) # save edi 15004Srgrimes movl (%esp),%edx # get rta 15014Srgrimes movl %edx,20(%eax) # save eip 15024Srgrimes xorl %eax,%eax # return (0); 15034Srgrimes ret 15044Srgrimes 15054SrgrimesENTRY(longjmp) 15064Srgrimes movl 4(%esp),%eax 15074Srgrimes movl (%eax),%ebx # restore ebx 15084Srgrimes movl 4(%eax),%esp # restore esp 15094Srgrimes movl 8(%eax),%ebp # restore ebp 15104Srgrimes movl 12(%eax),%esi # restore esi 15114Srgrimes movl 16(%eax),%edi # restore edi 15124Srgrimes movl 20(%eax),%edx # get rta 15134Srgrimes movl %edx,(%esp) # put in return frame 15144Srgrimes xorl %eax,%eax # return (1); 15154Srgrimes incl %eax 15164Srgrimes ret 1517134Sdg 1518134Sdg 1519134Sdg/*****************************************************************************/ 1520134Sdg/* Scheduling */ 1521134Sdg/*****************************************************************************/ 1522134Sdg 15234Srgrimes/* 15244Srgrimes * The following primitives manipulate the run queues. 15254Srgrimes * _whichqs tells which of the 32 queues _qs 15264Srgrimes * have processes in them. Setrq puts processes into queues, Remrq 15274Srgrimes * removes them from queues. The running process is on no queue, 15284Srgrimes * other processes are on a queue related to p->p_pri, divided by 4 15294Srgrimes * actually to shrink the 0-127 range of priorities into the 32 available 15304Srgrimes * queues. 15314Srgrimes */ 15324Srgrimes 15334Srgrimes .globl _whichqs,_qs,_cnt,_panic 15344Srgrimes .comm _noproc,4 15354Srgrimes .comm _runrun,4 15364Srgrimes 15374Srgrimes/* 15384Srgrimes * Setrq(p) 15394Srgrimes * 15404Srgrimes * Call should be made at spl6(), and p->p_stat should be SRUN 15414Srgrimes */ 15424SrgrimesENTRY(setrq) 15434Srgrimes movl 4(%esp),%eax 15444Srgrimes cmpl $0,P_RLINK(%eax) # should not be on q already 15454Srgrimes je set1 15464Srgrimes pushl $set2 15474Srgrimes call _panic 15484Srgrimesset1: 15494Srgrimes movzbl P_PRI(%eax),%edx 15504Srgrimes shrl $2,%edx 15514Srgrimes btsl %edx,_whichqs # set q full bit 15524Srgrimes shll $3,%edx 15534Srgrimes addl $_qs,%edx # locate q hdr 15544Srgrimes movl %edx,P_LINK(%eax) # link process on tail of q 15554Srgrimes movl P_RLINK(%edx),%ecx 15564Srgrimes movl %ecx,P_RLINK(%eax) 15574Srgrimes movl %eax,P_RLINK(%edx) 15584Srgrimes movl %eax,P_LINK(%ecx) 15594Srgrimes ret 15604Srgrimes 15614Srgrimesset2: .asciz "setrq" 15624Srgrimes 15634Srgrimes/* 15644Srgrimes * Remrq(p) 15654Srgrimes * 15664Srgrimes * Call should be made at spl6(). 15674Srgrimes */ 15684SrgrimesENTRY(remrq) 15694Srgrimes movl 4(%esp),%eax 15704Srgrimes movzbl P_PRI(%eax),%edx 15714Srgrimes shrl $2,%edx 15724Srgrimes btrl %edx,_whichqs # clear full bit, panic if clear already 15734Srgrimes jb rem1 15744Srgrimes pushl $rem3 15754Srgrimes call _panic 15764Srgrimesrem1: 15774Srgrimes pushl %edx 15784Srgrimes movl P_LINK(%eax),%ecx # unlink process 15794Srgrimes movl P_RLINK(%eax),%edx 15804Srgrimes movl %edx,P_RLINK(%ecx) 15814Srgrimes movl P_RLINK(%eax),%ecx 15824Srgrimes movl P_LINK(%eax),%edx 15834Srgrimes movl %edx,P_LINK(%ecx) 15844Srgrimes popl %edx 15854Srgrimes movl $_qs,%ecx 15864Srgrimes shll $3,%edx 15874Srgrimes addl %edx,%ecx 15884Srgrimes cmpl P_LINK(%ecx),%ecx # q still has something? 15894Srgrimes je rem2 15904Srgrimes shrl $3,%edx # yes, set bit as still full 15914Srgrimes btsl %edx,_whichqs 15924Srgrimesrem2: 15934Srgrimes movl $0,P_RLINK(%eax) # zap reverse link to indicate off list 15944Srgrimes ret 15954Srgrimes 15964Srgrimesrem3: .asciz "remrq" 15974Srgrimessw0: .asciz "swtch" 15984Srgrimes 15994Srgrimes/* 16004Srgrimes * When no processes are on the runq, Swtch branches to idle 16014Srgrimes * to wait for something to come ready. 16024Srgrimes */ 1603134SdgLENTRY(Idle) 16044Srgrimes sti 16054Srgrimes SHOW_STI 1606134Sdgidle_loop: 16074Srgrimes call _spl0 16084Srgrimes cmpl $0,_whichqs 16094Srgrimes jne sw1 1610134Sdg hlt # wait for interrupt 1611134Sdg jmp idle_loop 16124Srgrimes 16134Srgrimes SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */ 16144Srgrimesbadsw: 16154Srgrimes pushl $sw0 16164Srgrimes call _panic 16174Srgrimes /*NOTREACHED*/ 16184Srgrimes 16194Srgrimes/* 16204Srgrimes * Swtch() 16214Srgrimes */ 16224SrgrimesENTRY(swtch) 16234Srgrimes 16244Srgrimes incl _cnt+V_SWTCH 16254Srgrimes 16264Srgrimes /* switch to new process. first, save context as needed */ 16274Srgrimes 16284Srgrimes movl _curproc,%ecx 16294Srgrimes 16304Srgrimes /* if no process to save, don't bother */ 16314Srgrimes testl %ecx,%ecx 16324Srgrimes je sw1 16334Srgrimes 16344Srgrimes movl P_ADDR(%ecx),%ecx 16354Srgrimes 16364Srgrimes movl (%esp),%eax # Hardware registers 16374Srgrimes movl %eax, PCB_EIP(%ecx) 16384Srgrimes movl %ebx, PCB_EBX(%ecx) 16394Srgrimes movl %esp, PCB_ESP(%ecx) 16404Srgrimes movl %ebp, PCB_EBP(%ecx) 16414Srgrimes movl %esi, PCB_ESI(%ecx) 16424Srgrimes movl %edi, PCB_EDI(%ecx) 16434Srgrimes 16444Srgrimes#ifdef NPX 16454Srgrimes /* have we used fp, and need a save? */ 16464Srgrimes mov _curproc,%eax 16474Srgrimes cmp %eax,_npxproc 16484Srgrimes jne 1f 16494Srgrimes pushl %ecx /* h/w bugs make saving complicated */ 16504Srgrimes leal PCB_SAVEFPU(%ecx),%eax 16514Srgrimes pushl %eax 16524Srgrimes call _npxsave /* do it in a big C function */ 16534Srgrimes popl %eax 16544Srgrimes popl %ecx 16554Srgrimes1: 16564Srgrimes#endif 16574Srgrimes 16584Srgrimes movl _CMAP2,%eax # save temporary map PTE 16594Srgrimes movl %eax,PCB_CMAP2(%ecx) # in our context 16604Srgrimes movl $0,_curproc # out of process 16614Srgrimes 16624Srgrimes # movw _cpl, %ax 16634Srgrimes # movw %ax, PCB_IML(%ecx) # save ipl 16644Srgrimes 16654Srgrimes /* save is done, now choose a new process or idle */ 16664Srgrimessw1: 16674Srgrimes cli 16684Srgrimes SHOW_CLI 16694Srgrimes movl _whichqs,%edi 16704Srgrimes2: 16714Srgrimes # XXX - bsf is sloow 16724Srgrimes bsfl %edi,%eax # find a full q 1673134Sdg je Idle # if none, idle 16744Srgrimes # XX update whichqs? 16754Srgrimesswfnd: 16764Srgrimes btrl %eax,%edi # clear q full status 16774Srgrimes jnb 2b # if it was clear, look for another 16784Srgrimes movl %eax,%ebx # save which one we are using 16794Srgrimes 16804Srgrimes shll $3,%eax 16814Srgrimes addl $_qs,%eax # select q 16824Srgrimes movl %eax,%esi 16834Srgrimes 16844Srgrimes#ifdef DIAGNOSTIC 16854Srgrimes cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) 16864Srgrimes je badsw # not possible 16874Srgrimes#endif 16884Srgrimes 16894Srgrimes movl P_LINK(%eax),%ecx # unlink from front of process q 16904Srgrimes movl P_LINK(%ecx),%edx 16914Srgrimes movl %edx,P_LINK(%eax) 16924Srgrimes movl P_RLINK(%ecx),%eax 16934Srgrimes movl %eax,P_RLINK(%edx) 16944Srgrimes 16954Srgrimes cmpl P_LINK(%ecx),%esi # q empty 16964Srgrimes je 3f 16974Srgrimes btsl %ebx,%edi # nope, set to indicate full 16984Srgrimes3: 16994Srgrimes movl %edi,_whichqs # update q status 17004Srgrimes 17014Srgrimes movl $0,%eax 17024Srgrimes movl %eax,_want_resched 17034Srgrimes 17044Srgrimes#ifdef DIAGNOSTIC 17054Srgrimes cmpl %eax,P_WCHAN(%ecx) 17064Srgrimes jne badsw 17074Srgrimes cmpb $ SRUN,P_STAT(%ecx) 17084Srgrimes jne badsw 17094Srgrimes#endif 17104Srgrimes 17114Srgrimes movl %eax,P_RLINK(%ecx) /* isolate process to run */ 17124Srgrimes movl P_ADDR(%ecx),%edx 17134Srgrimes movl PCB_CR3(%edx),%ebx 17144Srgrimes 17154Srgrimes /* switch address space */ 17164Srgrimes movl %ebx,%cr3 17174Srgrimes 17184Srgrimes /* restore context */ 17194Srgrimes movl PCB_EBX(%edx), %ebx 17204Srgrimes movl PCB_ESP(%edx), %esp 17214Srgrimes movl PCB_EBP(%edx), %ebp 17224Srgrimes movl PCB_ESI(%edx), %esi 17234Srgrimes movl PCB_EDI(%edx), %edi 17244Srgrimes movl PCB_EIP(%edx), %eax 17254Srgrimes movl %eax, (%esp) 17264Srgrimes 17274Srgrimes movl PCB_CMAP2(%edx),%eax # get temporary map 17284Srgrimes movl %eax,_CMAP2 # reload temporary map PTE 17294Srgrimes 17304Srgrimes movl %ecx,_curproc # into next process 17314Srgrimes movl %edx,_curpcb 17324Srgrimes 17334Srgrimes pushl %edx # save p to return 17344Srgrimes/* 17354Srgrimes * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1? 17364Srgrimes * I think restoring the cpl is unnecessary, but we must turn off the cli 17374Srgrimes * now that spl*() don't do it as a side affect. 17384Srgrimes */ 17394Srgrimes pushl PCB_IML(%edx) 17404Srgrimes sti 17414Srgrimes SHOW_STI 17424Srgrimes#if 0 17434Srgrimes call _splx 17444Srgrimes#endif 17454Srgrimes addl $4,%esp 17464Srgrimes/* 17474Srgrimes * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the 17484Srgrimes * same way. Better return a value. 17494Srgrimes */ 17504Srgrimes popl %eax # return (p); 17514Srgrimes ret 17524Srgrimes 17534SrgrimesENTRY(mvesp) 17544Srgrimes movl %esp,%eax 17554Srgrimes ret 17564Srgrimes/* 17574Srgrimes * struct proc *swtch_to_inactive(p) ; struct proc *p; 17584Srgrimes * 17594Srgrimes * At exit of a process, move off the address space of the 17604Srgrimes * process and onto a "safe" one. Then, on a temporary stack 17614Srgrimes * return and run code that disposes of the old state. 17624Srgrimes * Since this code requires a parameter from the "old" stack, 17634Srgrimes * pass it back as a return value. 17644Srgrimes */ 17654SrgrimesENTRY(swtch_to_inactive) 17664Srgrimes popl %edx # old pc 17674Srgrimes popl %eax # arg, our return value 17684Srgrimes movl _IdlePTD,%ecx 17694Srgrimes movl %ecx,%cr3 # good bye address space 17704Srgrimes #write buffer? 17714Srgrimes movl $tmpstk-4,%esp # temporary stack, compensated for call 17724Srgrimes jmp %edx # return, execute remainder of cleanup 17734Srgrimes 17744Srgrimes/* 17754Srgrimes * savectx(pcb, altreturn) 17764Srgrimes * Update pcb, saving current processor state and arranging 17774Srgrimes * for alternate return ala longjmp in swtch if altreturn is true. 17784Srgrimes */ 17794SrgrimesENTRY(savectx) 17804Srgrimes movl 4(%esp), %ecx 17814Srgrimes movw _cpl, %ax 17824Srgrimes movw %ax, PCB_IML(%ecx) 17834Srgrimes movl (%esp), %eax 17844Srgrimes movl %eax, PCB_EIP(%ecx) 17854Srgrimes movl %ebx, PCB_EBX(%ecx) 17864Srgrimes movl %esp, PCB_ESP(%ecx) 17874Srgrimes movl %ebp, PCB_EBP(%ecx) 17884Srgrimes movl %esi, PCB_ESI(%ecx) 17894Srgrimes movl %edi, PCB_EDI(%ecx) 17904Srgrimes 17914Srgrimes#ifdef NPX 17924Srgrimes /* 17934Srgrimes * If npxproc == NULL, then the npx h/w state is irrelevant and the 17944Srgrimes * state had better already be in the pcb. This is true for forks 17954Srgrimes * but not for dumps (the old book-keeping with FP flags in the pcb 17964Srgrimes * always lost for dumps because the dump pcb has 0 flags). 17974Srgrimes * 17984Srgrimes * If npxproc != NULL, then we have to save the npx h/w state to 17994Srgrimes * npxproc's pcb and copy it to the requested pcb, or save to the 18004Srgrimes * requested pcb and reload. Copying is easier because we would 18014Srgrimes * have to handle h/w bugs for reloading. We used to lose the 18024Srgrimes * parent's npx state for forks by forgetting to reload. 18034Srgrimes */ 18044Srgrimes mov _npxproc,%eax 18054Srgrimes testl %eax,%eax 18064Srgrimes je 1f 18074Srgrimes 18084Srgrimes pushl %ecx 18094Srgrimes movl P_ADDR(%eax),%eax 18104Srgrimes leal PCB_SAVEFPU(%eax),%eax 18114Srgrimes pushl %eax 18124Srgrimes pushl %eax 18134Srgrimes call _npxsave 18144Srgrimes popl %eax 18154Srgrimes popl %eax 18164Srgrimes popl %ecx 18174Srgrimes 18184Srgrimes pushl %ecx 18194Srgrimes pushl $108+8*2 /* XXX h/w state size + padding */ 18204Srgrimes leal PCB_SAVEFPU(%ecx),%ecx 18214Srgrimes pushl %ecx 18224Srgrimes pushl %eax 18234Srgrimes call _bcopy 18244Srgrimes addl $12,%esp 18254Srgrimes popl %ecx 18264Srgrimes1: 18274Srgrimes#endif 18284Srgrimes 18294Srgrimes movl _CMAP2, %edx # save temporary map PTE 18304Srgrimes movl %edx, PCB_CMAP2(%ecx) # in our context 18314Srgrimes 18324Srgrimes cmpl $0, 8(%esp) 18334Srgrimes je 1f 18344Srgrimes movl %esp, %edx # relocate current sp relative to pcb 18354Srgrimes subl $_kstack, %edx # (sp is relative to kstack): 18364Srgrimes addl %edx, %ecx # pcb += sp - kstack; 18374Srgrimes movl %eax, (%ecx) # write return pc at (relocated) sp@ 18384Srgrimes # this mess deals with replicating register state gcc hides 18394Srgrimes movl 12(%esp),%eax 18404Srgrimes movl %eax,12(%ecx) 18414Srgrimes movl 16(%esp),%eax 18424Srgrimes movl %eax,16(%ecx) 18434Srgrimes movl 20(%esp),%eax 18444Srgrimes movl %eax,20(%ecx) 18454Srgrimes movl 24(%esp),%eax 18464Srgrimes movl %eax,24(%ecx) 18474Srgrimes1: 18484Srgrimes xorl %eax, %eax # return 0 18494Srgrimes ret 18504Srgrimes 18514Srgrimes/* 18524Srgrimes * addupc(int pc, struct uprof *up, int ticks): 18534Srgrimes * update profiling information for the user process. 18544Srgrimes */ 18554SrgrimesENTRY(addupc) 18564Srgrimes pushl %ebp 18574Srgrimes movl %esp,%ebp 18584Srgrimes movl 12(%ebp),%edx /* up */ 18594Srgrimes movl 8(%ebp),%eax /* pc */ 18604Srgrimes 18614Srgrimes subl PR_OFF(%edx),%eax /* pc -= up->pr_off */ 18624Srgrimes jl L1 /* if (pc < 0) return */ 18634Srgrimes 18644Srgrimes shrl $1,%eax /* praddr = pc >> 1 */ 18654Srgrimes imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */ 18664Srgrimes shrl $15,%eax /* praddr = praddr << 15 */ 18674Srgrimes andl $-2,%eax /* praddr &= ~1 */ 18684Srgrimes 18694Srgrimes cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */ 18704Srgrimes ja L1 18714Srgrimes 18724Srgrimes/* addl %eax,%eax /* praddr -> word offset */ 18734Srgrimes addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */ 18744Srgrimes movl 16(%ebp),%ecx /* ticks */ 18754Srgrimes 18764Srgrimes movl _curpcb,%edx 18774Srgrimes movl $proffault,PCB_ONFAULT(%edx) 18784Srgrimes addl %ecx,(%eax) /* storage location += ticks */ 18794Srgrimes movl $0,PCB_ONFAULT(%edx) 18804SrgrimesL1: 18814Srgrimes leave 18824Srgrimes ret 18834Srgrimes 18844Srgrimes ALIGN_TEXT 18854Srgrimesproffault: 18864Srgrimes /* if we get a fault, then kill profiling all together */ 18874Srgrimes movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */ 18884Srgrimes movl 12(%ebp),%ecx 18894Srgrimes movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */ 18904Srgrimes leave 18914Srgrimes ret 18924Srgrimes 1893134Sdg# To be done: 1894134SdgENTRY(astoff) 18954Srgrimes ret 18964Srgrimes 18974Srgrimes 1898134Sdg/*****************************************************************************/ 1899134Sdg/* Trap handling */ 1900134Sdg/*****************************************************************************/ 19014Srgrimes/* 19024Srgrimes * Trap and fault vector routines 19034Srgrimes * 19044Srgrimes * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose 19054Srgrimes * control. The sti's give the standard losing behaviour for ddb and kgdb. 19064Srgrimes */ 19074Srgrimes#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name: 19084Srgrimes#define TRAP(a) pushl $(a) ; jmp alltraps 19094Srgrimes#ifdef KGDB 1910134Sdg# define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps 19114Srgrimes#else 1912134Sdg# define BPTTRAP(a) sti; TRAP(a) 19134Srgrimes#endif 19144Srgrimes 19154SrgrimesIDTVEC(div) 19164Srgrimes pushl $0; TRAP(T_DIVIDE) 19174SrgrimesIDTVEC(dbg) 19184Srgrimes#ifdef BDBTRAP 19194Srgrimes BDBTRAP(dbg) 19204Srgrimes#endif 19214Srgrimes pushl $0; BPTTRAP(T_TRCTRAP) 19224SrgrimesIDTVEC(nmi) 19234Srgrimes pushl $0; TRAP(T_NMI) 19244SrgrimesIDTVEC(bpt) 19254Srgrimes#ifdef BDBTRAP 19264Srgrimes BDBTRAP(bpt) 19274Srgrimes#endif 19284Srgrimes pushl $0; BPTTRAP(T_BPTFLT) 19294SrgrimesIDTVEC(ofl) 19304Srgrimes pushl $0; TRAP(T_OFLOW) 19314SrgrimesIDTVEC(bnd) 19324Srgrimes pushl $0; TRAP(T_BOUND) 19334SrgrimesIDTVEC(ill) 19344Srgrimes pushl $0; TRAP(T_PRIVINFLT) 19354SrgrimesIDTVEC(dna) 19364Srgrimes pushl $0; TRAP(T_DNA) 19374SrgrimesIDTVEC(dble) 19384Srgrimes TRAP(T_DOUBLEFLT) 19394Srgrimes /*PANIC("Double Fault");*/ 19404SrgrimesIDTVEC(fpusegm) 19414Srgrimes pushl $0; TRAP(T_FPOPFLT) 19424SrgrimesIDTVEC(tss) 19434Srgrimes TRAP(T_TSSFLT) 19444Srgrimes /*PANIC("TSS not valid");*/ 19454SrgrimesIDTVEC(missing) 19464Srgrimes TRAP(T_SEGNPFLT) 19474SrgrimesIDTVEC(stk) 19484Srgrimes TRAP(T_STKFLT) 19494SrgrimesIDTVEC(prot) 19504Srgrimes TRAP(T_PROTFLT) 19514SrgrimesIDTVEC(page) 19524Srgrimes TRAP(T_PAGEFLT) 19534SrgrimesIDTVEC(rsvd) 19544Srgrimes pushl $0; TRAP(T_RESERVED) 19554SrgrimesIDTVEC(fpu) 19564Srgrimes#ifdef NPX 19574Srgrimes /* 19584Srgrimes * Handle like an interrupt so that we can call npxintr to clear the 19594Srgrimes * error. It would be better to handle npx interrupts as traps but 19604Srgrimes * this is difficult for nested interrupts. 19614Srgrimes */ 19624Srgrimes pushl $0 /* dummy error code */ 19634Srgrimes pushl $T_ASTFLT 19644Srgrimes pushal 19654Srgrimes nop /* silly, the bug is for popal and it only 19664Srgrimes * bites when the next instruction has a 19674Srgrimes * complicated address mode */ 19684Srgrimes pushl %ds 19694Srgrimes pushl %es /* now the stack frame is a trap frame */ 19704Srgrimes movl $KDSEL,%eax 19714Srgrimes movl %ax,%ds 19724Srgrimes movl %ax,%es 19734Srgrimes pushl _cpl 19744Srgrimes pushl $0 /* dummy unit to finish building intr frame */ 19754Srgrimes incl _cnt+V_TRAP 19764Srgrimes call _npxintr 19774Srgrimes jmp doreti 19784Srgrimes#else 19794Srgrimes pushl $0; TRAP(T_ARITHTRAP) 19804Srgrimes#endif 19814Srgrimes /* 17 - 31 reserved for future exp */ 19824SrgrimesIDTVEC(rsvd0) 19834Srgrimes pushl $0; TRAP(17) 19844SrgrimesIDTVEC(rsvd1) 19854Srgrimes pushl $0; TRAP(18) 19864SrgrimesIDTVEC(rsvd2) 19874Srgrimes pushl $0; TRAP(19) 19884SrgrimesIDTVEC(rsvd3) 19894Srgrimes pushl $0; TRAP(20) 19904SrgrimesIDTVEC(rsvd4) 19914Srgrimes pushl $0; TRAP(21) 19924SrgrimesIDTVEC(rsvd5) 19934Srgrimes pushl $0; TRAP(22) 19944SrgrimesIDTVEC(rsvd6) 19954Srgrimes pushl $0; TRAP(23) 19964SrgrimesIDTVEC(rsvd7) 19974Srgrimes pushl $0; TRAP(24) 19984SrgrimesIDTVEC(rsvd8) 19994Srgrimes pushl $0; TRAP(25) 20004SrgrimesIDTVEC(rsvd9) 20014Srgrimes pushl $0; TRAP(26) 20024SrgrimesIDTVEC(rsvd10) 20034Srgrimes pushl $0; TRAP(27) 20044SrgrimesIDTVEC(rsvd11) 20054Srgrimes pushl $0; TRAP(28) 20064SrgrimesIDTVEC(rsvd12) 20074Srgrimes pushl $0; TRAP(29) 20084SrgrimesIDTVEC(rsvd13) 20094Srgrimes pushl $0; TRAP(30) 20104SrgrimesIDTVEC(rsvd14) 20114Srgrimes pushl $0; TRAP(31) 20124Srgrimes 20134Srgrimes SUPERALIGN_TEXT 20144Srgrimesalltraps: 20154Srgrimes pushal 20164Srgrimes nop 20174Srgrimes pushl %ds 20184Srgrimes pushl %es 20194Srgrimes movl $KDSEL,%eax 20204Srgrimes movl %ax,%ds 20214Srgrimes movl %ax,%es 20224Srgrimescalltrap: 20234Srgrimes incl _cnt+V_TRAP 20244Srgrimes call _trap 20254Srgrimes /* 20264Srgrimes * Return through doreti to handle ASTs. Have to change trap frame 20274Srgrimes * to interrupt frame. 20284Srgrimes */ 20294Srgrimes movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */ 20304Srgrimes pushl _cpl 20314Srgrimes pushl $0 /* dummy unit */ 20324Srgrimes jmp doreti 20334Srgrimes 20344Srgrimes#ifdef KGDB 20354Srgrimes/* 20364Srgrimes * This code checks for a kgdb trap, then falls through 20374Srgrimes * to the regular trap code. 20384Srgrimes */ 2039134Sdg SUPERALIGN_TEXT 20404Srgrimesbpttraps: 20414Srgrimes pushal 20424Srgrimes nop 20434Srgrimes pushl %es 20444Srgrimes pushl %ds 20454Srgrimes movl $KDSEL,%eax 20464Srgrimes movl %ax,%ds 20474Srgrimes movl %ax,%es 20484Srgrimes testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) 20494Srgrimes # non-kernel mode? 20504Srgrimes jne calltrap # yes 20514Srgrimes call _kgdb_trap_glue 20524Srgrimes jmp calltrap 20534Srgrimes#endif 20544Srgrimes 20554Srgrimes/* 20564Srgrimes * Call gate entry for syscall 20574Srgrimes */ 2058134Sdg SUPERALIGN_TEXT 20594SrgrimesIDTVEC(syscall) 20604Srgrimes pushfl # only for stupid carry bit and more stupid wait3 cc kludge 20614Srgrimes # XXX - also for direction flag (bzero, etc. clear it) 20624Srgrimes pushal # only need eax,ecx,edx - trap resaves others 20634Srgrimes nop 20644Srgrimes movl $KDSEL,%eax # switch to kernel segments 20654Srgrimes movl %ax,%ds 20664Srgrimes movl %ax,%es 2067134Sdg incl _cnt+V_SYSCALL # kml 3/25/93 20684Srgrimes call _syscall 20694Srgrimes /* 20704Srgrimes * Return through doreti to handle ASTs. Have to change syscall frame 20714Srgrimes * to interrupt frame. 20724Srgrimes * 20734Srgrimes * XXX - we should have set up the frame earlier to avoid the 20744Srgrimes * following popal/pushal (not much can be done to avoid shuffling 20754Srgrimes * the flags). Consistent frames would simplify things all over. 20764Srgrimes */ 20774Srgrimes movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */ 20784Srgrimes movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */ 20794Srgrimes movl 32+8(%esp),%ecx 20804Srgrimes movl %ebx,32+0(%esp) 20814Srgrimes movl %ecx,32+4(%esp) 20824Srgrimes movl %eax,32+8(%esp) 20834Srgrimes popal 20844Srgrimes nop 20854Srgrimes pushl $0 /* dummy error code */ 20864Srgrimes pushl $T_ASTFLT 20874Srgrimes pushal 20884Srgrimes nop 20894Srgrimes movl __udatasel,%eax /* switch back to user segments */ 2090134Sdg pushl %eax /* XXX - better to preserve originals? */ 2091134Sdg pushl %eax 20924Srgrimes pushl _cpl 20934Srgrimes pushl $0 20944Srgrimes jmp doreti 20954Srgrimes 20964Srgrimes 2097134Sdg/*****************************************************************************/ 2098134Sdg/* include generated interrupt vectors and ISA intr code */ 2099134Sdg/*****************************************************************************/ 21004Srgrimes 21014Srgrimes#include "i386/isa/vector.s" 21024Srgrimes#include "i386/isa/icu.s" 2103